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

المسارات

ثلاثة تحمل الأحداث، والرابع يحمل الشخص الذي وقعت له. الالتقاط التلقائي — مشاهدات الصفحات والتمرير ومؤقتات الخمول التي يجمعها السكربت وحده — مسار آخر. يغذّي التحليلات والمُطلِقات السلوكية، لكنه لا يفتح مُطلِق حدث أبداً. والتعمّد لا يُستنتج من اسم الحدث إطلاقاً.

المصادقة

track وtrack/batch يتطلبان مفتاحاً سرياً:
أنشئه من الإعدادات ← مفاتيح API. والمفاتيح القديمة hamla_live_… تبقى صالحة. المفتاح المنشور (pk_live_…) يجتاز المصادقة لكنه يُرفض بـ 403 على هذين المسارين: هو يُشحن داخل مصدر الصفحة، وقبوله هنا يعني أن أي زائر يستطيع اختلاق إيرادات. ولا يرسل أي من المسارين ترويسات CORS ولا يستجيب لـ OPTIONS، وهذا مقصود — الصفحة التي لا تستطيع اجتياز CORS لا تُغرى بتضمين مفتاح سري. المفتاح يحدد نشاطاً تجارياً واحداً بالضبط. وحقل businessId في الجسم اختياري؛ فإن وُجد وخالف المفتاح رُفض الطلب بدل أن يُعاد كتابته بصمت.

POST /api/sdk/track

يسجّل حدثاً واحداً وقع للتو.

الحقول

حقل identity

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

الرد

الأخطاء

POST /api/sdk/track/batch

يسجّل حتى 500 حدث وقعت سابقاً. المفردات نفسها، وقواعد الحقول نفسها، والمفتاح السري نفسه.
مصفوفة events تقبل من 1 إلى 500 عنصر. وكل عنصر يقبل كل حقول track عدا visitorId و context — فالتاريخ المُعاد تشغيله لا يحمل جلسة متصفح ولا طلباً حياً، فلا شيء رأى ترويسة User-Agent ولا دولة.

ما لا يفعله الاستيراد عمداً

وكل ما ينبغي للاستيراد فعله يحدث: جهات الاتصال تُطابَق أو تُنشأ، والأنشطة تنزل بتاريخها الحقيقي في occurredAt، وإحصاءات أول وآخر وعدد المرات تتحدث (والصفوف غير المرتبة تُعالَج)، والسمات والوسوم تُطبَّق، وvalue يُحتسب ضمن الإيراد.

الرد

العناصر تفشل منفردة — الصف الخاطئ يبلّغ عن موضعه وسببه، وبقية الدفعة تنزل.
حقل warnings محدود بخمسين مدخلاً حتى لا يطغى عمود واحد خاطئ التسمية على الرد كله. أعطِ كل صف idempotencyKey ويصبح تشغيل الاستيراد كاملاً مرة أخرى آمناً.

POST /api/sdk/identify

يقول من هو الشخص — وبماذا تناديه. رفيق track: هوية وملف، بلا حدث. يظهر في السجل الزمني للشخص باسم identified، ولا يُحسب أبداً نموذجاً ولا عميلاً محتملاً ولا تحويلاً. واستدعاؤه في كل صفحة يفتحها شخص مسجّل الدخول آمن.
يطابق أو يُنشئ: المجهول يصير جهة اتصال، والمعروف يُثرى. وآمن أن تناديه عند كل تسجيل دخول — حقول الملف تُملأ فراغاتها ولا تُستبدل أبداً.

الحقول

حقل profile

وسبب واحد يجعل إرسال الاسم يستحق: {{contact.firstName}} في الحملة. بدونه تفتتح كل رسالة بـ «مرحباً صديقي».

حقل context — للتسجيل الذي يتم على خادمك

حزمة المتصفح لا تحتاج شيئاً من هذا: طلبها هو الشخص نفسه، فتقرأ حملة الجهاز والدولة منه مباشرة. أما التسجيل الذي يكتمل على خادمك فهو النقيض — الطلب الذي يصل حملة قادم من مركز بياناتك. وبلا context تبقى جهة الاتصال بلا جهاز وبلا دولة، وليست ثغرة صغيرة: سؤالا «في أي الدول عملائي؟» و«كم منهم يسجّل من الهاتف؟» بلا إجابة عن كل من دخل عبر ردّ OAuth أو نموذج يُعرض من الخادم أو تطبيق جوال. اقرأ القيم من الطلب الذي قام به الشخص فعلاً — user-agent وترويسة الموقع التي يضيفها مستضيفك (x-vercel-ip-country أو cf-ipcountry):
يشترط مفتاحاً سرياً، للسبب نفسه الذي تشترطه له traits: هذا ادّعاء عن شخص. ومن مُنادٍ بلا مفتاح يُتجاهل مع تنبيه في warnings، وتُستخدم ترويسات الطلب نفسه بدلاً منه. وإن لم ترسل context لم تسجّل حملة شيئاً بدل أن تخمّن — فمنطقة استضافتك ليست حيث يعيش عميلك. ويُؤخذ الموقع دولةً ومنطقةً ومدينة لا عنوان IP عن قصد: حملة تحفظ المكان ولا تحفظ العنوان.

المصادقة، على غير العادة

هذا هو مسار الكتابة الوحيد الذي يخدم أيضاً من لا مفتاح لديه، لأن حزم المتصفح المنشورة لا تستطيع إرسال ترويسة Authorization ولا تُحدَّث بعد أن تصل ذاكرة CDN لدى العميل. ومع ذلك يستحق المفتاح الإرسال من الخادم: يحصر الكتابة في نشاطك ويجعلها منسوبة، كما أن traits تشترطه.

الرد

قيمة linkedVisitor تكون true حين يكون هذا النداء هو ما ربط المتصفح المجهول بالشخص — اللحظة التي تتوقف فيها زياراته السابقة، والحملة التي جاءت به، عن كونها مجهولة. وwarnings غائبة حين يصل كل شيء كما أُرسل.

‏hamla.track() — مسار المتصفح

للأفعال المتعمَّدة التي تحدث فعلاً داخل الصفحة. بلا مفتاح، لأنه لا يوجد مفتاح يمكن شحنه بأمان إلى متصفح.
يُستخدم اسم الحدث حرفياً. ولأن كود الصفحة نفسه اختار إرساله، فهو يُعدّ متعمَّداً ويستطيع بدء حملة — بخلاف أحداث الالتقاط التلقائي المسافرة في الدفعة نفسها. أما ما يتعلق بالمال أو بسجلاتك الخاصة فمكانه مسار الخادم، حيث يوجد المفتاح وحيث لا يستطيع زائر تعديل الوقائع.

ماذا يفعل الحدث بعد تخزينه

حقول الشرائح

جهة الاتصال التي لا تملك الحدث تُقيَّم كغير معرّفة في كل المقاييس، بما فيها count. لذلك «أقل من 5 مرات، بما في ذلك ولا مرة» هي count < 5 أو not_exists، وليست صفراً صامتاً.

الأسماء التي تحرّك مرحلة الرحلة

أسماؤك الخاصة تُسجَّل وتُستخدم كاملة، لكنها لا تحرّك المرحلة. استعِر من هذه حين تناسبك: نقرة البريد التي تسجّلها حملة تُقرأ بحسب وجهة رابطها. النقرة نحو نشاطك (موقعك أو منتجك أو صفحة الحجز أو متجر التطبيقات أو محادثة معك) تعني «مهتم». والنقرة على حساب في شبكة اجتماعية تُحسب تفاعلاً ولا تغيّر المرحلة. أما نقرة إلغاء الاشتراك، أو فاحص بريد يفتح كل الروابط في ثوانٍ، فلا تحرّك أحداً. وحدث email_clicked الذي ترسله بنفسك يُحسب دائماً.

ماذا يعني الحدث

event كلمتك أنت. وtype كلمتنا نحن، وهي إحدى عشرة كلمة لا غير. لست مضطراً لإرسال type أبداً — تستنتج حملة من المبلغ ومن الأسماء التي تعرفها أصلاً. وحين ترسله لا يبقى شيء للتخمين.
عيادة تسميه treatment_completed، ومدرسة تسميه lesson_finished، وكلاهما purchase. اسمك أنت لا يُترجَم ولا يُستبدَل ولا يُقارَن بقائمة — يُحفظ كما أرسلته بالضبط، ويبقى هو ما تُكتب به تقاريرك وشرائحك ومُطلِقاتك.
booking هو النوع الذي يستحق الانتباه. كل المفردات التحليلية الأخرى صُمِّمت للمتاجر الإلكترونية، حيث أن تقول نعم هو أن تدفع. الموعد المؤكَّد والعقد الموقَّع التزامات حقيقية لا يتحرك فيها مال — فهي booking لا purchase، ولن تظهر في الإيراد ولن ترفع متوسط قيمة الطلب لديك. وحين يحمل أحدها مبلغاً فعلاً، أرسل المبلغ وتحتسبه حملة.والتجربة المجانية ليست booking: أن تجرّب ليس أن تدفع. trial_started هي checkout_started — بدأ ولم يُكمل — فصاحب التجربة مهتم، ويصبح عميلاً عند أول دفعة.

ما الذي تعرفه حساباتك الإعلانية

حين تربط Google Ads أو Meta، تخبرها حملة بالنتائج التي جاءت من نقرات إعلاناتها، بحسب type لا بحسب اسم حدثك: purchase (مع المبلغ) وbooking وlead وsignup وtrial وcontact وapplication، يصل كلٌّ منها إلى Google كإجراء تحويل مستقل وإلى Meta كحدثها القياسي (Purchase وSchedule وLead وCompleteRegistration وStartTrial وContact وSubmitApplication). فحدث treatment_completed المُرسَل مع type: "purchase" يصل إلى حسابك الإعلاني تماماً كحدث purchase من متجر. والسجل المستورَد لا يُبلَّغ عنه أبداً.

إن لم ترسل شيئاً

تقرر حملة بهذا الترتيب:
  1. type إن أرسلته. يفوز دائماً.
  2. وجود value. المال تحرَّك، مهما سميت الحدث. والمبلغ السالب استرداد.
  3. اسم تعرفه حملة أصلاً. محفوظ كي تبقى التكاملات المكتوبة قبل وجود type تعمل تماماً كما كانت.
وإن لم ينطبق أي منها، يُسجَّل الحدث ويبقى قابلاً للتشريح ويستطيع أن يبدأ حملة — لكنه لا يدّعي أنه إيراد. وهذه الأسماء كاملة. لست بحاجة إليها — type يقول الشيء نفسه بأي مفردات — لكن لا شيء ترسله اليوم يتغير معناه بسببها.
لا يُحتسب مبلغ في صمت أبداً. إن أرسلت value ولم تستطع حملة تحديد معناه، قال لك الرد ذلك في warnings بدل أن يخزنه ويمضي. وكل رد يعيد إليك interpreted أيضاً، فترى القرار من أول طلب لا في تقرير بعد أسابيع.

السمات والحقول المخصصة

traits تكتب الحالة الراهنة لجهة الاتصال، والحدث يسجّل ما جرى. أرسل الاثنين في نداء واحد. وأول مرة يصل فيها مفتاح سمة جديد، تنشئ حملة الحقل المخصص المقابل وتستنتج نوعه: 3 يصبح رقماً، وtrue منطقياً، و"2026-08-08" تاريخاً، وما عدا ذلك نصاً. ويظهر في العملاء ← إدارة العملاء ← الحقول المخصصة، وتستطيع الشرائح التصفية عليه فوراً. قاعدتان، وكلتاهما تظهران في مصفوفة warnings:
  • المفاتيح بصيغة snake_case — businesses_count لا Businesses-Count.
  • الحقل يحتفظ بنوعه الأول. فبعد أن يصبح businesses_count رقماً، تُتجاهَل قيمة "lots" لاحقاً بدل إفساد المخزَّن.

الحدود

ومحدِّد المعدل يفشل مفتوحاً: إن تعذّر الوصول إليه سُمح بالطلبات بدل رفضها.

حزمة Node

npm install @gethamla/node تغلّف المسارات نفسها — ولا شيء تفعله غير متاح عبر HTTP عادي.
track وidentify ترسلان دون انتظار ولا ترميان استثناءً أبداً — فنداء تسويقي يجب ألّا يكسر عملية دفع. وtrackNow تعيد DeliveryResult حين تريد أن تعرف. وtrackBatch تعيد ترقيم مواضع الفشل بحسب مصفوفتك أنت، وترفض visitorId للسبب نفسه الذي يرفضه المسار.