أحداث البحث
أحداث البحث
أخبر 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" }
]
}'
عمليات البحث التي تقبل الأحداث
لا يُقبل الحدث إلا عندما يكون البحث الذي يشير إليه مؤهَّلًا للأحداث:
- حمل طلب
GET /searchترويسةX-Navvo-Session، أُرسلت لأن المستخدم وافق. - لم يحمل ذلك الطلب
Sec-GPC: 1ولاDNT: 1. - لم يكن الاستعلام ولا نتيجته الأولى ضمن تصنيف حسّاس (الصحة أو الدين). فلا تربط Navvo عمليات البحث هذه بجلسة أبدًا.
- ترسل الحدث خلال 7 أيام من البحث، وبـمفتاح API نفسه الذي استخدمه البحث.
لا تذكر استجابة البحث ما إذا كان مؤهَّلًا، ولا حاجة لأن تعرف. أرسل الأحداث لعمليات البحث التي أرسلت فيها معرّف جلسة. تعود غير المؤهَّلة منها محتسبة في rejected، ولا يتأثّر شيء آخر.
جسم الطلب
كل عنصر في events[]:
| الحقل | النوع | مطلوب | ملاحظات |
|---|---|---|---|
queryId | string | نعم | قيمة queryId من استجابة GET /search التي تصرّف المستخدم بناءً عليها. |
type | string | نعم | click أو conversion. |
name | string | نعم | الإجراء. انظر الجدول أدناه. |
placeId | string | أحدهما | معرّف id للمكان من النتيجة. |
slug | string | أحدهما | معرّف رابط المكان slug، إن لم يكن معرّفه لديك. وتتولّى Navvo تحليله. |
position | number | لا | ترتيب النتيجة بدءًا من 1 في قائمة Navvo: (page − 1) × limit + index + 1. وهو للعلم فقط، لأن Navvo تحسب الموضع بنفسها من النتائج التي أعادتها. |
uiPosition | number | لا | الموضع بدءًا من 1 الذي ظهرت فيه النتيجة في واجهتك أنت، إن كنت تدمج صفوفًا أخرى كالأماكن المحفوظة أو العناوين. تستخدمه Navvo لدراسة التصميم. |
type | name | أرسله عندما يقوم المستخدم بـ… |
|---|---|---|
click | open_place | فتح نتيجة (لوحة تفاصيلها أو صفحتها). |
conversion | directions | طلب الاتجاهات إليها. |
conversion | navigate | بدء الملاحة خطوة بخطوة إليها. |
conversion | save | حفظها في المفضّلة أو في قائمة. |
conversion | call | النقر على رقم هاتفها. |
conversion | website | فتح موقعها الإلكتروني. |
conversion | share | مشاركتها. |
يمكنك إرسال تحويل دون نقرة قبله، مثلًا من زرّ «الاتجاهات» في صفّ النتيجة. أحداث الوصول غير مدعومة.
الاستجابة (202)
{ "accepted": 1, "rejected": 1, "reasons": { "not_eligible": 1 } }
| الحقل | النوع | الوصف |
|---|---|---|
accepted | number | الأحداث المخزَّنة. |
rejected | number | الأحداث المُسقَطة. |
reasons | object | يظهر فقط عند رفض شيء ما: عدد لكل رمز سبب. |
| رمز السبب | المعنى |
|---|---|
invalid_query_id | queryId غير صالح لهذا الاستدعاء: فهو مشوَّه أو جرى تعديله، أو أُرسل الحدث بمفتاح 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 كيلوبايت لكل طلب فيبقيان منطبقين. |