Navvo
مرجع الواجهة البرمجية

أحداث البحث

أبلِغ عن نتيجة البحث التي فتحها المستخدم وما فعله بعدها — أحداث نقر وتحويل مشروطة بالموافقة، تقيس جودة البحث وتحسّنها.

أحداث البحث

أخبر Navvo بنتيجة البحث التي فتحها المستخدم (نقرة) وبما فعله بها بعد ذلك (تحويل، مثل طلب الاتجاهات أو الاتصال أو الحفظ). تستخدم Navvo الأحداث لقياس جودة البحث: كم مرة يفتح الناس نتيجة، وإلى أيّ عمق في القائمة ينقرون، وأيّ عمليات البحث لا تقود إلى شيء. وتستخدمها أيضًا لاكتشاف مشكلات الترتيب. الأحداث اختيارية، ويعمل البحث بالطريقة نفسها دونها.

الأحداث مشروطة بالموافقة. لا تقبلها Navvo إلا لعمليات بحث أُرسلت مع ترويسة X-Navvo-Session، وهي ترويسة لا ترسلها إلا بعد موافقة المستخدم. وتشرح صفحة تحليلات البحث والخصوصية النموذج كاملًا.

المصادقة: مفتاح API نفسه الذي نفّذ البحث. واستدعاءات الأحداث غير مُقاسة.


POST /search/events

curl -s -X POST "https://navvo.io/api/v1/search/events" \
  -H "x-api-key: nvvo_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      { "queryId": "AaDxmIYgiEC1I4ZdHCWiERmR", "type": "click", "name": "open_place",
        "placeId": "e3bacbd9-1e5d-474c-b84e-2fe7e1556541", "position": 1 },
      { "queryId": "AaDxmIYgiEC1I4ZdHCWiERmR", "type": "conversion", "name": "directions",
        "placeId": "e3bacbd9-1e5d-474c-b84e-2fe7e1556541" }
    ]
  }'

عمليات البحث التي تقبل الأحداث

لا يُقبل الحدث إلا عندما يكون البحث الذي يشير إليه مؤهَّلًا للأحداث:

  1. حمل طلب GET /search ترويسة X-Navvo-Session، أُرسلت لأن المستخدم وافق.
  2. لم يحمل ذلك الطلب Sec-GPC: 1 ولا DNT: 1.
  3. لم يكن الاستعلام ولا نتيجته الأولى ضمن تصنيف حسّاس (الصحة أو الدين). فلا تربط Navvo عمليات البحث هذه بجلسة أبدًا.
  4. ترسل الحدث خلال 7 أيام من البحث، وبـمفتاح API نفسه الذي استخدمه البحث.

لا تذكر استجابة البحث ما إذا كان مؤهَّلًا، ولا حاجة لأن تعرف. أرسل الأحداث لعمليات البحث التي أرسلت فيها معرّف جلسة. تعود غير المؤهَّلة منها محتسبة في rejected، ولا يتأثّر شيء آخر.

جسم الطلب

events
array required
من 1 إلى 20 حدثًا (انظر أدناه). ولا يتجاوز حجم الجسم كله 16 كيلوبايت.

كل عنصر في events[]:

الحقلالنوعمطلوبملاحظات
queryIdstringنعمقيمة queryId من استجابة GET /search التي تصرّف المستخدم بناءً عليها.
typestringنعمclick أو conversion.
namestringنعمالإجراء. انظر الجدول أدناه.
placeIdstringأحدهمامعرّف id للمكان من النتيجة.
slugstringأحدهمامعرّف رابط المكان slug، إن لم يكن معرّفه لديك. وتتولّى Navvo تحليله.
positionnumberلاترتيب النتيجة بدءًا من 1 في قائمة Navvo: (page − 1) × limit + index + 1. وهو للعلم فقط، لأن Navvo تحسب الموضع بنفسها من النتائج التي أعادتها.
uiPositionnumberلاالموضع بدءًا من 1 الذي ظهرت فيه النتيجة في واجهتك أنت، إن كنت تدمج صفوفًا أخرى كالأماكن المحفوظة أو العناوين. تستخدمه Navvo لدراسة التصميم.
typenameأرسله عندما يقوم المستخدم بـ…
clickopen_placeفتح نتيجة (لوحة تفاصيلها أو صفحتها).
conversiondirectionsطلب الاتجاهات إليها.
conversionnavigateبدء الملاحة خطوة بخطوة إليها.
conversionsaveحفظها في المفضّلة أو في قائمة.
conversioncallالنقر على رقم هاتفها.
conversionwebsiteفتح موقعها الإلكتروني.
conversionshareمشاركتها.

يمكنك إرسال تحويل دون نقرة قبله، مثلًا من زرّ «الاتجاهات» في صفّ النتيجة. أحداث الوصول غير مدعومة.

الاستجابة (202)

{ "accepted": 1, "rejected": 1, "reasons": { "not_eligible": 1 } }
الحقلالنوعالوصف
acceptednumberالأحداث المخزَّنة.
rejectednumberالأحداث المُسقَطة.
reasonsobjectيظهر فقط عند رفض شيء ما: عدد لكل رمز سبب.
رمز السببالمعنى
invalid_query_idqueryId غير صالح لهذا الاستدعاء: فهو مشوَّه أو جرى تعديله، أو أُرسل الحدث بمفتاح API غير المفتاح الذي نفّذ البحث (فتوقيع المعرّف يشمل المفتاح).
expiredمضى على البحث أكثر من 7 أيام.
key_mismatchنُفِّذ البحث بمفتاح API وأُرسل الحدث دون مفتاح، أو العكس.
not_eligibleلم يكن البحث مؤهَّلًا للأحداث: لم يكن هناك معرّف جلسة، أو أرسل المتصفّح إشارة خصوصية، أو كان الاستعلام حسّاسًا. ويُعاد أيضًا لكل حدث ما دامت تحليلات البحث للمشروع موقوفة.
invalid_nameقيمة name غير مسموحة لذلك الـ type، مثل arrive، أو open_place كتحويل.
missing_placeلم يُرسَل placeId ولا slug.
unknown_placeلا يطابق slug أي مكان.
unavailableجمع الأحداث غير متاح مؤقتًا.
تعني 202 أن Navvo قبلت الدفعة، وتُكتب خلال ثوانٍ. وإرسال الحدث نفسه مرتين لا يضرّ، لأن كل تركيبة (queryId, type, name, place) تُخزَّن مرة واحدة. لا تُعِد إرسال الأحداث المرفوضة: إعادة المحاولة لا تعالج أيًّا من الأسباب أعلاه.

كيف تُستخدم الأحداث

  • تربط Navvo كل حدث ببحثه عبر queryId. ولا تُحتسب النقرة في مقاييس البحث إلا إذا كان المكان ضمن أول 20 نتيجة أعادها ذلك البحث.
  • لا تُستخدم النقرات على النتائج المُروَّجة أو المُموَّلة أبدًا لتعلّم الترتيب.
  • تُحفظ الأحداث 90 يومًا، وتُحذف الأحداث التي لم يصل سجلّ بحثها قط بعد نحو 24 ساعة. وإذا أوقف مشروعٌ تحليلات البحث، تتوقّف Navvo خلال دقيقة تقريبًا عن قبول الأحداث لمفاتيحه وتحذف الأحداث المخزَّنة سابقًا. وتسرد صفحة تحليلات البحث والخصوصية ما تحتفظ به Navvo ومدته.

إرسال الأحداث من تطبيق أو متصفّح

// Call when the user opens a result. `search` is the GET /search response the result came from.
function reportClick(search, place, index) {
  const position = (search.places.page - 1) * search.places.limit + index + 1;
  return fetch("https://navvo.io/api/v1/search/events", {
    method: "POST",
    keepalive: true, // survives the page navigating away
    headers: { "Content-Type": "application/json", "x-api-key": KEY },
    body: JSON.stringify({
      events: [{ queryId: search.queryId, type: "click", name: "open_place", placeId: place.id, position }],
    }),
  }).catch(() => {}); // analytics must never break your UI
}
  • استخدم fetch مع keepalive: true. فـ navigator.sendBeacon لا يستطيع إرسال ترويسة x-api-key.
  • إذا كان خادمك يمرّر البحث ليحفظ مفتاحك سرًّا، فمرّر الأحداث بالطريقة نفسها، لأن الحدث يجب أن يحمل المفتاح الذي استخدمه البحث.
  • لا يُقبل طلب من متصفّح دون مفتاح API إلا من مواقع Navvo نفسها. وعلى صفحات الأطراف الثالثة إرسال مفتاحها.
  • لا ترسل أحداثًا لاستجابة بحث قُدِّمت من ذاكرة تخزين مؤقت. ولهذا السبب تحمل استجابات البحث Cache-Control: no-store.
  • إذا جمعت عدة أحداث (مثلًا عند إخفاء الصفحة)، فأرسل حتى 20 منها في طلب واحد.

باستخدام حِزم Navvo البرمجية

ترسل حزمة الويب (@navvo/maps-js 0.2) وحزمة Node (@navvo/sdk 0.2) الأحداث نيابةً عنك بالمفتاح الذي استخدمه البحث، وتستخدم حزمة الويب keepalive:

// Browser: @navvo/maps-js
import { NavvoServices, createSearchSessionId } from "@navvo/maps-js";
const services = new NavvoServices({ apiKey: KEY });
const session = createSearchSessionId(); // only if your user agreed to it
const r = await services.search("rumi cafe", { session });
const hit = r.items[0];
await services.sendSearchEvent({ queryId: r.queryId!, type: "click", placeId: hit.id, position: hit.position });

// Server: @navvo/sdk
const res = await navvo.search("rumi cafe", { session });
await navvo.sendSearchEvent({ queryId: res.queryId!, type: "conversion", name: "directions", placeId, position });

في حزمة الويب تحمل كلّ نتيجة موضعها position بدءًا من 1، مع احتساب إزاحة الصفحة. وراجع دليل حزمة Node.js لجهة الخادم.

الأخطاء

الحالةمتى
400الجسم ليس { "events": [...] } بعدد أحداث من 1 إلى 20، أو يفتقد حدثٌ queryId أو type أو name، أو يستخدم type غير click/conversion، أو يحمل حقلًا من نوع خاطئ.
403طلب من متصفّح دون مفتاح API جاء من موقع غير مواقع Navvo.
413حجم الجسم أكبر من 16 كيلوبايت.
429أكثر من 60 طلبًا في الدقيقة من عنوان IP واحد للعميل (RATE_LIMITED، مع ترويسة Retry-After بالثواني). ولا ينطبق هذا الحدّ على المفتاح غير المحدود، مثل خادم شريك يمرّر أحداث مستخدميه؛ أما حدّا 20 حدثًا و16 كيلوبايت لكل طلب فيبقيان منطبقين.
Copyright © 2026