تخطّ إلى المحتوى الرئيسي

عُقد Canvas

تُبنى مسارات Canvas بأنواع مختلفة من العُقد تحدد طريقة تقدم المستخدمين في الأتمتة. يغطي هذا الدليل كل العُقد المتاحة وسلوكها.

عُقد المشغّل​

تحدد عُقد المشغّل كيفية دخول المستخدمين إلى Canvas.

المشغلات المتاحة​

نوع المشغّلالوصف
Eventيدخل المستخدم عند تنفيذه حدثًا محددًا
Entity Changeيدخل المستخدم عند تغير سجل كيان ذي صلة
APIيدخل المستخدم عبر استدعاء API
Scheduleيدخل المستخدمون وفق جدول متكرر
WhatsApp Messageيدخل المستخدم عند إرسال رسالة WhatsApp
Inbound SMSتدخل جهة اتصال معروفة عند إرسال SMS؛ صفِّ حسب حساب SMS ونوع الرسالة وشروط Message Text / Message Type

دخول الشريحة ليس مشغّلًا. للدخول الناتج عن شيء فعله الشخص، استخدم مشغّل حدث مع فلتر؛ وللدخول الناتج عن مرور الوقت، استخدم رحلة متكررة على الشريحة.

فحص التكرار - نفس الشيء مرتين​

يمكن لمشغّل الحدث أن يشترط أن يكون الحدث الوارد تكرارًا: N مرة على الأقل من هذا الحدث لنفس الشخص، خلال آخر D يومًا، بنفس قيم الخصائص التي تختارها - مع احتساب الحدث الذي وصل الآن. يدخل الشخص تمامًا عند التكرار رقم N المطابق؛ أما التكرارات بقيم أخرى فلا تُدخله أبدًا.

المثال الذي بُني لأجله: شخص نظر إلى نفس الفندق لنفس التواريخ مرتين.

الإعدادالقيمة
الحدثhotel_viewed
التكرار2 مرة على الأقل خلال آخر 2 يوم
بنفسhotel، check_in

النظرة الثانية إلى Casa Azul لأيام 3-5 أكتوبر تبدأ الرحلة. النظرة الأولى إلى Casa Azul، أو النظرة إلى أي فندق آخر، لا تبدأها - فالعدّ مقيّد بـ hotel وcheck_in الخاصين بالحدث الوارد.

ضع هذا الفحص على المشغّل، وليس في خطوة شرط. رحلة تدخل عند كل hotel_viewed وتسأل «مرتين؟» من الداخل كانت ستُدخل الشخص عند النظرة الأولى؛ ومع منع إعادة الدخول، لم تكن النظرة الثانية لتبدأها أبدًا. المشغّل يطرح السؤال قبل أن يُستهلك الدخول.

كيف يُقيَّم: عند وصول الحدث، يعدّ المشغّل أحداث hotel_viewed المخزّنة لهذا الشخص داخل النافذة الزمنية والتي يساوي فيها hotel وcheck_in قيمتَي الحدث الوارد، ويستبعد من العدّ معرّف الحدث الوارد نفسه ويضيف واحدًا للحدث ذاته - فتكون الإجابة نفسها سواء وصل الحدث إلى مخزن التحليلات أم لا. خلف الستار، الفحص هو فلتر الحدث sameProperties المشروح تحت عُقد التفريع، مع مقارنة كل خاصية بـقيمة الحدث المُشغِّل.

عُقد الرسائل​

ترسل عُقد الرسائل اتصالات إلى المستخدمين عبر قنوات متعددة.

القنوات المدعومة​

  • Email: أرسل Emails مخصصة.
  • SMS: أرسل رسائل نصية (في حساب Delivyr اختر قالبًا معتمدًا واملأ متغيراته - راجع حسابات Delivyr).
  • Push Notifications: أرسل إشعارات Push للجوال.
  • WhatsApp: أرسل قوالب WhatsApp أو ردودًا.
  • Webhook: استدع API خارجيًا بنص مبني بقوالب Liquid.
الرسائل داخل التطبيق تُعرض ولا تُرسل

الرسائل داخل التطبيق قناة تختارها داخل عقدة الرسالة، إلى جانب البريد و SMS والإشعارات و WhatsApp و Viber. تختلف عن غيرها: تُوضع الرسالة في قائمة انتظار وتُعرض عند فتح المستخدم لتطبيقك في المرة التالية بدلاً من دفعها إليه، فليس لها إيصال "أُرسلت" أو "سُلّمت" خاص بها - راجع عقد رسالة داخل التطبيق.

تختار القناة من عُقدة Message نفسها. يوجد Webhook في منتقي القنوات نفسه مع Email وSMS، وله منشئ طلب خاص: الطريقة والرؤوس والنص والمصادقة وإعادة المحاولة وانتظار اختياري لربط الاستجابة. استخدم Send test لتشغيل استدعاء عينة، ثم انقر أي حقل في الاستجابة لربطه بمتغير رحلة، أو الصق استجابة عينة لتأليف الربط دون استدعاء حي. عند تفعيل ربط الاستجابة، تستطيع أيضًا تفعيل on-error output: منفذ ثانٍ تتبعه الرحلة عند فشل الطلب أو انتهاء مهلته. اتركه بلا توصيل للمتابعة على المخرج العادي، fail-open.

يبني Send test الطلب لـ جهة الاتصال التجريبية التي تختارها. تُحمَّل جهة الاتصال الحقيقية (Random user أو Select existing user) من مساحة العمل وتُعرض تمامًا كما في الإرسال الفعلي - {{ user.id }} هو المعرّف الداخلي لجهة الاتصال، وكل الحقول والسمات الأخرى تأتي من ملفها. أما Custom user فهي جهة اتصال مختلَقة، لذا تأخذ حقولها الفارغة قيمًا تجريبية. بعد الاختبار، بدّل النتيجة بين الاستجابة المستلمة والطلب المرسل لترى الطريقة والرابط والرؤوس والنص التي أُرسلت بالضبط؛ وتُخفى بيانات الاعتماد (رؤوس Authorization ومفتاح API والتوقيع).

البوابات المطبقة على Webhooks

تستدعي قناة Webhook خدمة خارجية بدل صندوق وارد لشخص، لذلك لا تُدار موافقة الاشتراك لـ Webhooks: لا opt-in لـ Webhook ولا تمنعه تفضيلات اشتراك الجمهور. لكن ما عدا ذلك يطبق افتراضيًا:

  • الساعات الهادئة وحدود التكرار تمنع Webhooks افتراضيًا، مثل الرسائل؛ فلا ينبغي لـ Webhook الذي يمثل تواصلاً مع عميل، كتشغيل رسالة في نظام آخر، أن يعمل ضمن نافذة هدوء العميل. إذا كان Webhook استدعاءً خالصًا من نظام إلى نظام، مثل مزامنة CRM أو تشغيل مهمة خلفية، حدد System call - skip quiet hours & frequency caps لتجاوز الاثنين.
  • قوائم الحظر تطبق دائمًا: لا يطلق اتصال محظور Webhook. لا يغير مربع System call ذلك.
  • الفوترة: تُحسب جهات الاتصال التي يطلق Webhook بشأنها كملفات متفاعلة قابلة للفوترة، مثل مستلمي الرسائل. راجع كيفية احتساب الاستخدام.

سلوك التقدم بعد الرسالة​

مهم

يتقدم المستخدمون إلى الخطوة التالية فور وضع الرسالة في طابور الإرسال. لا تنتظر Canvas وصول الرسالة إلى صندوق وارد المستخدم.

هذا الأسلوب معيار الصناعة، ويتيح:

  • القابلية للتوسع: معالجة ملايين المستخدمين دون حجب.
  • الأداء: لا يبطئ تنفيذ Canvas أوقات تسليم الرسائل.
  • الموثوقية: يعالج Workers مخصصون التسليم مع إعادة المحاولة.

معنى "message sent":

  1. تُخصص الرسالة ببيانات المستخدم.
  2. تُضاف إلى طابور الإرسال.
  3. يتقدم المستخدم إلى خطوة Canvas التالية.
  4. يعالج Worker مخصص الطابور ويسلم الرسائل.

ضمانات التسليم:

  • تعاد محاولة الرسائل حتى 3 مرات بتراجع أسي.
  • تسجل الرسائل الفاشلة للتحقيق.
  • يُعالج تتبع التسليم، الفتح والنقر والارتداد، منفصلًا.

تفرض عُقد الرسائل موافقة الاشتراك وقت الإرسال لكل قناة؛ إنها البوابة نفسها التي تطبقها الحملات، لذلك تعامل الرحلة والحملة جهة الاتصال نفسها بالطريقة نفسها. تتحكم subscription preference لجمهور Canvas في صرامة البوابة:

  • Subscribed، الافتراضي: يرسل فقط لجهات الاتصال التي وافقت على القناة، subscribed أو opted_in. تُتخطى جهات الاتصال الملغية صراحة والتي لا تملك سجل اشتراك إطلاقًا.
  • Confirmed: مشتركو double opt-in المؤكدون فقط.
  • All: يرسل بغض النظر عن حالة الاشتراك، وهو تجاوز "send even to unsubscribed" المعاملي الصريح.

تفاصيل القنوات:

  • يتخطى Email عناوين الارتداد الدائم أيضًا.
  • Push متسامح: إذ يمنح الإذن على الجهاز لا عبر سجل opt-in، يُرسل Push ما لم تكن جهة الاتصال ألغت اشتراكها صراحة؛ تتلقى جهة الاتصال بلا سجل Push.

لا تُخرج الرسالة المتخطاة جهة الاتصال من الرحلة: تُتخطى الرسالة فقط وتتقدم جهة الاتصال للخطوة التالية، فتعمل Webhook وUpdate User والفرع وغيرها للجميع. يعاد فحص الموافقة عند كل إرسال، فتُحترم تغييرات الاشتراك في خطوة سابقة أو مركز التفضيلات في الرسالة التالية؛ لا شيء يثبت عند الدخول.

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

مجموعات الاشتراك لكل رقم، SMS/WhatsApp​

تفرض SMS وWhatsApp البوابة نفسها لمجموعة الاشتراك لكل رقم / لكل WABA التي تطبقها الحملات. تصبح قائمة اشتراك مربوطة بمرسل محدد مجموعة ذلك المرسل: مجموعات SMS لكل رقم إرسال ومجموعات WhatsApp لكل WABA. تُتخطى جهة الاتصال التي ألغت الاشتراك من مجموعة رقم الإرسال أو WABA للرسالة، لكنها تتقدم للخطوة التالية ككل الإرسالات المتخطاة.

تحدد مجموعة إلغاء الاشتراك التي تُفحص بالمرسل المختار في عُقدة الرسالة: رقم SMS لرسالة SMS وWABA لرسالة WhatsApp. عند عدم الاختيار يستخدم مرسل SMS الافتراضي لمساحة العمل أو WABA الافتراضي، وتُفحص مجموعته.

الوقت الهادئ​

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

  • Skip: لا ترسل الرسالة وتتقدم جهة الاتصال للخطوة التالية.
  • Delay: تؤجل عُقدة الرسالة حتى إغلاق النافذة، ثم يعاد تشغيلها وإرسالها.

يطابق ذلك الحملات: فقد يؤجل Email ليلًا بينما يتخطى SMS، لذلك تطبق الساعات الهادئة باتساق سواء وصل المستخدم عبر حملة أو رحلة.

إرسال رسالة اختبار​

تحتوي كل عُقدة رسالة على زر Send test message في نافذة الإعداد. استخدمه للتحقق من التخصيص واتصال الموفر قبل النشر.

تغطية القنوات:

  • Email: يفتح نافذة إرسال اختبار بمنتقي المستخدم نفسه، random / existing / custom، وتجاوز Email المستلم.
  • SMS: يفتح النافذة نفسها مع تجاوز رقم الهاتف.
  • WhatsApp: مثل SMS، مع وجوب أن يكون القالب المختار في حالة approved.

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

عرض الاختبار يطابق الإرسال الحي

تمر إرسالات الاختبار في المسار نفسه للإرسال الحي: تُحل رموز التخصيص والسمات المخصصة وContent Blocks بالطريقة نفسها، فما تتلقاه في الاختبار هو ما سيتلقاه جمهورك بالضبط.

القوالب في خطوة الرسالة​

  • يربط "From template" في البريد الإلكتروني و**"From template" داخل التطبيق** الخطوة بقالب محفوظ. يختار تغيير القالب قالبًا آخر وتتبعه الخطوة من حينها - لا يُنسخ شيء إلى الخطوة، لذلك لا يضيع شيء.
  • تنسخ خطوات الإشعارات الفورية وWebhook قالبًا عبر Start from template. اختيار قالب آخر فوق محتوى عدّلته يطلب التأكيد قبل الاستبدال؛ أما المحتوى الذي بقي تمامًا كما تركه آخر قالب فيُستبدل دون سؤال.
  • حفظ كقالب (البريد الإلكتروني بـ Drag & drop أو Custom HTML، والإشعارات الفورية، وداخل التطبيق بـ Drag & drop أو HTML) يحفظ المحتوى الحالي للخطوة كقالب جديد، باسم افتراضي "اسم الرحلة - القناة" ووسوم اختيارية. تحتفظ الخطوة بمحتواها ولا ترتبط بالقالب الجديد. يتطلب صلاحية تحرير القوالب.

محتجزة بواسطة Joryio​

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

عُقد رسالة داخل التطبيق​

تعمل الرسائل داخل التطبيق بطريقة مختلفة عن كل القنوات الأخرى، لذلك لها عقدة خاصة بها. البريد الإلكتروني والرسائل النصية والإشعارات وWhatsApp تُرسل إلى الشخص. أما الرسالة داخل التطبيق فتُعرض عند فتح الشخص لتطبيقك في المرة التالية - لذا فإن هذه العقدة لا "ترسل" شيئًا. إنها تضع الرسالة في قائمة انتظار لذلك المستخدم، ويعرضها تطبيقك في الجلسة المؤهلة التالية.

أضِفها من مربّع رسالة داخل التطبيق في لوحة عناصر المُنشئ.

ما الذي تضبطه​

  • الرسالة (مطلوبة) - من أين يأتي المحتوى. تفتح العقدة بنفس الخيار الموجود في عقدة البريد الإلكتروني:
    • اكتبوها هنا - تُكتب في العقدة وتُستخدم في هذه الخطوة فقط. اختاروا محررًا: Drag & drop (كتل مرئية وصور)، أو كلاسيكي - نمط التطبيق (عنوان ونص وصورة وأزرار يرسمها تطبيقكم بخطوطه وألوانه، فيُعرض حتى في التطبيقات التي تحظر HTML)، أو HTML.
    • استخدام حملة - إعادة استخدام حملة داخل التطبيق بنيتموها من قبل، بما فيها متغيراتها.
    • من قالب - ربط قالب داخل التطبيق محفوظ من Brand Studio. تعرض الخطوة القالب كما هو عند إدراج الرسالة في الطابور، فتعديل القالب يحدّث كل رحلة تستخدمه.
  • التخطيط - نافذة منبثقة أو شريط أو منزلق من الأسفل أو ملء الشاشة (القالب المبني لتخطيط معيّن يجلبه معه).
  • الأولوية - عاجلة / عالية / عادية / منخفضة. عندما تكون عدة رسائل مؤهلة في اللحظة نفسها، تُعرض الأعلى أولوية أولًا، ويُحسم التعادل بالأقدم أولًا حتى لا تُدفن رسالة منتظرة تحت رسائل أحدث. رسائل الرحلة وحملات التطبيق تتنافس في الترتيب نفسه.
  • عدد مرات العرض - العرض مرة واحدة (افتراضي)، أو العرض حتى N مرات (مع فاصل زمني أدنى اختياري بين المرات)، أو العرض حتى النقر أو الإغلاق.
  • التوقف عن المحاولة بعد N يومًا - إذا لم يفتح الشخص التطبيق خلال هذه المدة، تنتهي صلاحية الرسالة دون أن تُرى. الافتراضي 7 أيام.
  • الانتظار حتى العرض (اختياري) - راجع أدناه.

متى تكمل الرحلة؟​

افتراضيًا تكمل الرحلة فورًا بعد إدراج الرسالة في قائمة الانتظار - وهو سلوك "أرسِل وواصِل" نفسه المتّبع في القنوات الأخرى، لأنه لا يمكن معرفة متى سيفتح الشخص تطبيقك.

فعّل الانتظار حتى العرض لإبقاء الشخص عند هذه الخطوة حتى يرى الرسالة فعليًا. وإن لم يفتح التطبيق خلال نافذة الانتظار (24 ساعة افتراضيًا) تكمل الرحلة على أي حال - فهي لا تتوقف أبدًا بسبب رسالة لم تُرَ.

متى تنتظر

استخدم الانتظار حتى العرض عندما تكون الخطوة التالية منطقية فقط بعد أن يرى الشخص الرسالة - مثل "اعرض نصيحة الإعداد، ثم انتظر، ثم أرسل بريدًا لمن رآها". واتركه معطّلًا للتنبيهات البسيطة.

حدود التكرار​

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

التقارير​

تُقدّم العقدة تقاريرها كأي خطوة رسالة أخرى، بمصطلحات التطبيق:

  • عُرضت تُحتسب تسليمًا للعقدة (في التطبيق، العرض هو التسليم)
  • نُقر عليها يحصي النقرات على الرسالة
  • لا توجد خطوة فُتحت داخل التطبيق - المسار هو عُرضت ← نُقر عليها

تستخدم التحويلات المنسوبة إلى الرحلة نافذة الإسناد ونموذجه نفسيهما المستخدمين في القنوات الأخرى.

عُقد التأخير​

توقف عُقد التأخير تقدم المستخدم. تغطي أربعة أنواع الأنماط الشائعة.

أنواع التأخير​

النوعمتى تستخدمه
Durationانتظار مدة ثابتة بعد وصول المستخدم للخطوة، مثل "wait 7 days".
Calendar dateانتظار تاريخ محدد ووقت اليوم، مثل "release on 2026-05-17 at 10:00". يخرج المستخدمون الداخلون بعد تلك اللحظة من الرحلة.
Day of weekانتظار الوقوع التالي ليوم أسبوع ووقت محددين، مثل "next Monday at 12:00".
This person's best timeانتظار الوقوع التالي للساعة التي يفتح فيها هذا الشخص الرسائل عادةً أو يطلب فيها عادةً، وقبلها ببضع دقائق اختياريًا، مثل "ساعة طلبه المعتادة، قبل 30 دقيقة". انظر أفضل وقت لهذا الشخص.

Duration​

الإعدادالوصف
Wait forرقم ووحدة: Minutes / Hours / Days / Weeks.
Then wait until a specific time of dayاختياري. بعد انتهاء المدة، استمر في الانتظار حتى وقت اليوم المختار في المنطقة الزمنية المختارة.
TimezoneCompany / User local / UTC؛ يستخدمه خيار وقت اليوم.

Calendar date​

الإعدادالوصف
Dateتاريخ ISO مستهدف. قابل للاختيار من التقويم المضمن؛ انقر يومًا للاختيار واستخدم الأسهم للتنقل بين الأشهر.
Timeمنتقيا الساعة والدقيقة.
TimezoneCompany / User local / UTC.

Day of week​

الإعدادالوصف
Day & timeيوم الأسبوع مع الساعة والدقيقة. صف المعاينة ذي 7 خلايا أعلى النافذة قابل للنقر أيضًا.
TimezoneCompany / User local / UTC.
If a user arrives after the cutoffWait، الافتراضي، ينقله إلى وقوع الأسبوع التالي. Advance يشغل فورًا كي لا يخسر أسبوعًا.

أفضل وقت لهذا الشخص​

رسالة استعادة تصل في 19:30 لشخص يطلب عادةً في 20:00: ينتظر هذا الوضع الوقوع التالي لساعة الذروة الخاصة بالشخص، في منطقته الزمنية، ناقص وقت الاستباق.

الإعدادالوصف
Based onWhen they usually open messages (فتحاته وقراءاته ونقراته على الرسائل، تُحصى لكل قناة، انظر أدناه) أو When they usually order (طلباته المنفذة).
For channelللفتحات فقط. Next message's channel (auto) (الافتراضي) يقرأ اللوحة: قناة خطوة الرسالة التالية بعد هذا التأخير، عندما تؤدي كل المسارات من التأخير إلى قناة واحدة. أو اختر قناة بالاسم: البريد الإلكتروني، SMS، WhatsApp، الإشعارات، داخل التطبيق، Viber.
Lead timeالدقائق قبل الساعة التي يُطلق فيها الشخص (0-1440). 30 على ذروة 20:00 يطلق في 19:30.
TimezoneUser local time (الافتراضي؛ سمة timezone للشخص، ويعود إلى Company time إن غابت) أو Company time.

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

كيف تُختار الساعة لقناة، بالترتيب:

  1. القناة نفسها: لدى الشخص 3 أحداث على الأقل في هذه القناة: الساعة التي تضم أكثرها.
  2. الجهاز نفسه: وإلا، 3 أحداث على الأقل عبر عائلة جهاز القناة: عائلة الهاتف (الإشعارات، WhatsApp، Viber، SMS، داخل التطبيق) أو عائلة المكتب (البريد الإلكتروني). نقرتا SMS وخمس نقرات إشعارات تمنح انتظار SMS ساعة الإشعارات.
  3. أي قناة: وإلا، 3 أحداث على الأقل في أي قناة.
  4. مساحة العمل: وإلا، ساعة ذروة مساحة العمل كلها لهذه القناة وعائلة جهازها (تُحدَّث كل 10 دقائق).
  5. الافتراضي: مساحة عمل بلا أي سجل: 10:00 للبريد الإلكتروني، 19:00 لعائلة الهاتف.

يستخدم When they usually order، وكذلك انتظار الفتحات الذي لا يمكن تحديد قناته من اللوحة (لا خطوة رسالة لاحقة، أو تفرعات إلى قنوات مختلفة)، السلسلة الأقصر: شخصي (3 أحداث) - مساحة العمل - الافتراضي (10:00 للفتحات، 19:00 للطلبات).

الأشخاص الذين ليس لديهم سجل كافٍ يستخدمون الساعة المعتادة لمساحة العمل؛ لا أحد ينتظر عشوائيًا. إذا مرت اللحظة المستهدفة اليوم بالفعل، أو بقي عليها أقل من خمس دقائق، ينتظر الشخص لحظة الغد. ينطبق حد 30 يومًا كما في كل تأخير.

تعرض بطاقة Purchase Behavior في ملف الشخص جدول أفضل وقت حسب القناة: صف لكل قناة لدى مساحة العمل سجل فيها، إضافة إلى الطلبات، مع الساعة ومصدرها ("فتحاتهم"، "عادة الهاتف"، "أي قناة"، "نمط مساحة العمل"، "الافتراضي")، لترى ما ستفعله الرحلة قبل نشرها. وتسجل كل خطوة تأخير القناة والدرجة التي استخدمتها، كي يعد تقرير الرحلة الانتظارات الشخصية مقابل انتظارات مساحة العمل.

تخصيص التأخير​

مفتاح في كل نوع. عند تفعيله يقرأ التأخير متغيرًا لكل مستخدم بدل قيمة ثابتة:

المصدريقرأ من
Context variablesexecution.context[varName]، سياق الدخول للرحلة، الافتراضي القديم.
User custom attributeuser.attributes.<varName> وحقول المستخدم العليا.
Event propertyخاصية من الحدث: آخر حدث طابقته عقدة Behavior Split، وإلا فالحدث الذي بدأ الرحلة (waitDays أو properties.waitDays). إذا كانت الخاصية مفقودة أو غير صالحة، لا ينتظر التأخير - تسجّل الخطوة ذلك في delayVariableMissing ويُسجَّل تحذير.

في Calendar date / Day of week مع متغير مخصص، تستطيع ضبط offset، زائد أو ناقص بالساعات/الأيام/الأسابيع، مثل "send 3 days before the renewal date".

التاريخ المخصص الذي لا يحمل منطقة زمنية خاصة به (2026-10-16T09:00:00، أو تاريخ فقط مثل 2026-10-16 ويعني منتصف الليل) يُقرأ في المنطقة الزمنية البديلة للخطوة - Company أو User local أو UTC. أما القيمة التي تحمل إزاحتها الخاصة (2026-10-16T09:00:00+03:00، أو Z في آخرها) فتحتفظ بها.

حل المنطقة الزمنية​

الوضعيحل إلى
Company timeالمنطقة الزمنية لمساحة العمل، أو المنطقة الزمنية للمؤسسة من الإعدادات عندما لا تكون لمساحة العمل منطقة، وإلا UTC - المنطقة نفسها التي تستخدمها الحملات.
User local timeuser.attributes.timezone، تضبطه SDK. يعود إلى Company time إن غاب.
UTCUTC.

الحدود​

  • تُقيّد كل فروع التأخير بـ30 يومًا كحد أقصى. يحفظ التأخير القيم التي يعرضها (7 أيام، والتاريخ واليوم والوقت الظاهرة على الشاشة). لا يمكن تفعيل تأخير تاريخ تقويمي بلا تاريخ؛ وأي تأخير ناقص آخر يُشغَّل فورًا بدل تعليق الرحلة، مع تسجيل تحذير منظم.

مثال: انتظر 24 ساعة قبل إرسال Email متابعة.

عُقد Branch​

توجّه عُقد Branch المستخدمين عبر مسارات مختلفة وفق السمات وسجل الأحداث وعضوية الشرائح وغير ذلك. تستوعب كتلة واحدة كلاً من Decision Split القديم، Yes / No، وAudience Path، مجموعات متعددة مرتبة، ويبدل مفتاح واحد في النافذة بينهما.

يبقى nodeType الأساسي للكتلة condition للتوافق مع بيانات الرحلات الحالية. تحفظ الرحلات الجديدة كـ branchMode: 'yesno' | 'multi'.

وضعان​

Yes / No: مسار مسمى واحد + Everyone else. استخدمه للسؤال الثنائي، مثل "did this user purchase yes/no".

Multi: حتى 10 مجموعات مسماة ومرتبة + Everyone else، أي 11 مسار توجيه إجمالًا. استخدمه لأكثر من مسارين، مثل VIP customers وfrequent visitors وone-time buyers وeveryone else. رقِّ فرع Yes/No إلى Multi عبر Add a new group في شريط النافذة. بسّطه بـ Simplify back to Yes / No عندما تبقى مجموعة مسماة واحدة مع Everyone else.

الحل حسب الأولوية​

في Multi، تُقيّم المجموعات بالترتيب. تفوز أول مجموعة مطابقة. يسلك غير المطابقين لأي مجموعة مسماة مسار Everyone else. اسحب الصفوف لترتيبها.

"Exit canvas" لكل مجموعة​

يمكن تعليم كل مجموعة مسماة، وEveryone else، بـ Exit canvas instead of routing: يكمل المستخدمون الذين يصلونها الرحلة عند خطوة الفرع مع exitReason: 'branch_exit:<group name>'. يفيد ذلك لـ "إن تحقّق الشرط، لا حاجة لإرسال شيء: اخرج من المسار".

صفوف الفلاتر​

يُضبط كل مسار/مجموعة بواحدة أو أكثر من مجموعات الفلاتر. تُوصل الفلاتر داخل مجموعة بواصل AND / OR داخلي، وتوصل المجموعات نفسها بـ groupOperator خارجي، غالبًا OR.

تستخدم نافذة Branch مكوّن <FilterRow> نفسه لمحرر الشرائح ومنتقي جمهور الحملة، ولذلك تدعم كل أنواع الفلاتر التي تدعمها تلك الواجهات:

النوعما يفحصهالعوامل
attributeuser.attributes[field]equals, not_equals, gt, gte, lt, lte, contains, not_contains, exists, not_exists, in, not_in
default_attributeحقول المستخدم العليا، email وphone وexternalId وfirstName وlastName وcountry ودرجات ML ومشتقات E-commerceمثل attribute
event / behavioralسجل الأحداث مع نافذة زمنية اختياريةperformed_event, not_performed_event, performed_event_in_last, not_performed_event_in_last, event_count_gte, event_count_lte
segmentعضوية الشريحة، تكرارية حتى عمق 5in, not_in
canvas_executionتنفيذات Canvas النشطة/المكتملة/الخارجةin_canvas, not_in_canvas, in_any_canvas, not_in_any_canvas, completed_canvas, exited_canvas
channel_subscriptionuser.subscriptions[channel].statussubscribed_to_channel, not_subscribed_to_channel, opted_in_to_channel
list_membershipسجل اشتراك قائمة مختارةmember_of_list, not_member_of_list
bounce_statusصلاحية Email أو ارتداد دائم/مؤقتemail_valid, email_bounced, email_hard_bounced
ecommerceشريحة RFM وعدد الطلبات والإنفاق وحالة السلةrfm_segment_equals, rfm_segment_in, has_purchased, never_purchased, total_orders_*, total_spent_*, average_order_value_*, days_since_last_order_*, has_active_cart, no_active_cart, cart_value_*, cart_abandoned
entityuser.entityRecords[entity]exists, not_exists
appuser.appIdshas_app, not_has_app

تشارك الأنواع الإحدى عشرة مقيّمًا واحدًا، FilterEvaluator، يستخدمه Worker Branch في Canvas ومقيّم حملات In-app؛ فأي أنواع جديدة مضافة هناك تظهر في كل مكان تلقائيًا.

خيارات النافذة الزمنية، فلاتر الأحداث​

  • withinMinutes: دقائق، مثل 30.
  • withinHours: ساعات، مثل 1 أو 24.
  • withinDays: أيام، مثل 7 أو 30.
  • eventTimeWindow: ثوانٍ، ويستخدمه مقيّم In-app.

تدعم شروط الخصائص كذلك: مثل "performed Order Completed in last 30 days with value ≥ 100":

{
"type": "event",
"eventName": "Order Completed",
"operator": "performed_event_in_last",
"withinDays": 30,
"eventProperties": { "value": "100" }
}

قيم الحدث المُشغِّل​

داخل الرحلة، يمكن لشرط على خاصية حدث أن يقارن بالقيمة التي حملها الحدث المُشغِّل بدلًا من قيمة ثابتة. بجوار مربع القيمة اختر استخدم قيمة الحدث المُشغِّل؛ يُقرأ الصف حينها «hotel يساوي hotel الخاص بالحدث المُشغِّل». على السلك تكون القيمة هي القالب {{ trigger.properties.hotel }} (وتُقبل الصيغة المختصرة {{ trigger.hotel }} أيضًا)، ويُحلّ من حدث المُشغِّل للتنفيذ قبل تقييم الشرط مباشرة.

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

الشرائح لا مُشغِّل لها، لذا يظهر الخيار في شروط الرحلة فقط.

عدّ نفس الشيء​

يقبل مُعاملا العدّ (performed_count_gte وperformed_count_lte) بنفس قيم - من خاصية حدث واحدة إلى خمس. يُحسب العدّ حينها لكل تركيبة مختلفة من تلك القيم، ويتحقق الشرط عندما تصل أي تركيبة إلى العدد.

{
"type": "event",
"eventName": "hotel_viewed",
"operator": "performed_count_gte",
"value": 2,
"withinDays": 2,
"sameProperties": ["hotel", "check_in"],
"propertyConditions": [
{ "property": "hotel", "operator": "equals", "value": "{{ trigger.properties.hotel }}" },
{ "property": "check_in", "operator": "equals", "value": "{{ trigger.properties.check_in }}" }
]
}

بالكلمات: «نفّذ hotel_viewed مرتين على الأقل خلال آخر يومين بنفس hotel وcheck_in، حيث hotel يساوي hotel الخاص بالحدث المُشغِّل وcheck_in يساوي check_in الخاص بالحدث المُشغِّل». بدون شرطَي الخاصية يكون المعنى «شاهد أي فندق واحد مرتين لنفس التواريخ» - وهي صيغة الشريحة. للرحلة التي يجب أن تبدأ عند النظرة الثانية، استخدم فحص التكرار على المشغّل وليس هذا الشرط في منتصف الرحلة.

في ClickHouse تكون الصيغة المجمّعة GROUP BY على الخصائص المستخرجة مع HAVING count(DISTINCT event_id) >= N LIMIT 1؛ وتُمرَّر أسماء الخصائص كمعاملات للاستعلام، لذا يعمل أي اسم مُتتبَّع (مسافات، شرطات، أي نظام كتابة؛ والاسم الذي يحتوي على نقطة يقرأ المفتاح المطابق تمامًا أولًا ثم المسار المتداخل)، والاسم الفارغ يُفشِل الشرط (خاطئ).

بطاقة عُقدة Canvas​

تتكيف البطاقة مع الوضع:

  • Yes / No: منفذا مصدر في أسفلها، أخضر yes وأحمر no.
  • Multi: منفذ مصدر لكل مجموعة في الحافة اليمنى للبطاقة مع تسمية اسم المجموعة في الصف. تطول البطاقة عموديًا عند إضافة مجموعات.

تطابق تسميات الحواف اسم المجموعة بالضبط، إذ يقرأ Worker الحواف بالاسم عند التوجيه. إذا أعدت تسمية مجموعة، تبقى الحافة المتصلة مرتبطة لأننا نستخدم React Flow handle id؛ rename ثم save دون كسر.

مثال: مسار سلة متروكة​

  1. Trigger: Event = "Product Added".
  2. Delay: انتظر ساعة.
  3. Branch (Yes / No): not_performed_event_in_last "Order Completed" في الساعة الأخيرة.
    • Yes: أرسل Email استعادة.
    • No (Everyone else): اخرج من المسار.

مثال: توجيه RFM متعدد المسارات​

  1. Branch (Multi) بثلاث مجموعات مسماة + Everyone else:
    • VIP customers، ecommerce.rfm_segment_equals: champions، أرسل عرضًا حصريًا.
    • Frequent visitors، event Page Viewed في آخر 7 أيام وevent_count_gte: 10، أرسل إعادة تفاعل.
    • At risk، ecommerce.days_since_last_order_gte: 60، أرسل استعادة.
    • Everyone else: Exit canvas.

عُقد Behavior Split​

يوجه Behavior Split المستخدمين حسب ما يفعلونه داخل نافذة زمنية. بينما يقرأ Branch الحالة لحظة التقييم، يوقف Behavior Split المستخدم ويراقب المستقبل: أول حدث مطابق أو نهاية النافذة يحدد المسار.

يستوعب Action Path القديم، حدث واحد وشرط واحد، وكتل event-keyed Audience Path. مفهوم واحد بحالتين.

وضعان​

الوضعمتى تستخدمه
Did / Didn'tمسار "did" مسمى واحد + بديل "No event in window" ضمني. مكافئ Action Path القديم للحدث الواحد.
Multiحتى 10 مجموعات مسماة ومرتبة + "No event in window". رقِّ عبر Add a new group وبسّط بـ Simplify back to Did / Didn't عندما تبقى مجموعة مسماة واحدة.

نافذة الانتظار​

الإعدادالسلوك
Wait up to N unitsمهلة ثابتة، minutes / hours / days / weeks.
Personalizeنافذة مسحوبة من {{canvas.x}}، متغير السياق، أو {{user.x}}، سمة المستخدم. يجب أن تُحل القيمة إلى رقم بالوحدة المختارة.

النافذة على مستوى الكتلة: تشترك كل المجموعات في Behavior Split نفسه في المهلة. أُزيلت النوافذ لكل مجموعة عند إعادة تصميم العُقدة لأن إعدادات المسارات المتعددة تصبح غير متماسكة ونادرًا ما استُخدمت.

وضع التقدم​

الوضعالسلوك
As soon as an event fires، الافتراضييفوز أول حدث يطابق أي صف مشغّل، ويوجّه المستخدم فورًا. تظل الأولوية فاصلاً للمطابقات المتزامنة في tick حدث واحد.
At end of windowتنتظر الكتلة النافذة كاملة. إن طابق المستخدم مجموعات متعددة، تفوز الأعلى ترتيبًا. استخدمه عندما تكون الأولوية أهم من السرعة.

منتقي المشغّل​

تقع قائمة مشغلات كل مجموعة في بطاقة بمنتقي trigger kind مميز أعلى كل صف. تتصل الأنواع الجديدة بالمنتقي نفسه من دون إعادة تشكيل الإعداد المحفوظ.

النوعحالة وقت التشغيل
Perform Custom Eventموصل بالكامل. اختر أي حدث من سجل أحداثك، وتضيّق فلاتر الخصائص، AND، المطابقة.
Place Order / Start Session / Make Purchase (Legacy)أحداث محددة مسبقًا بتسميات سهلة. موصلة وتحل لأسماء أحداث معيارية: place_order, start_session, make_purchase_legacy.
Perform Conversion Eventمحفوظ لكنه غير موصل بعد؛ بانتظار hook وقت تشغيل conversion-events.
Add an Email Addressمحفوظ لكنه غير موصل بعد؛ بانتظار مسار أحداث ضبط السمات.
Change Custom Attribute Valueمحفوظ لكنه غير موصل بعد؛ بانتظار مسار أحداث تغير السمات.

تعرض الأنواع غير الموصلة تنبيهًا كهرمانيًا ضمن صفها كي لا يفاجأ المؤلفون وقت التشغيل.

داخل مجموعة، صفوف المشغلات موصولة بـ OR؛ مطابقة أي منها تكفي للتوجيه. داخل مشغّل واحد، فلاتر الخصائص المتعددة موصولة بـ AND.

"Exit canvas" لكل مجموعة​

ينهي مربع اختيار لكل مجموعة الرحلة عند اختيار ذلك المسار بدل التوجيه إلى عُقدة متصلة. يغلق التنفيذ مع exitReason = "behavior_split_exit:<group_name>".

بطاقة عُقدة Canvas​

تحتوي بطاقة Behavior Split شريط رأس بنفسجي، "BEHAVIOR SPLIT"، وشارة ساعة بنافذة الانتظار، مثل "3 days" أو "{{canvas.evaluation_window}} hours".

  • Did / Didn't: منفذا أسفل ثابتان: did، بنفسجي، وtimed_out، رمادي. لا تؤدي إعادة تسمية المسار في النافذة إلى يتم الحواف.
  • Multi: صفوف مكدسة، واحد لكل مجموعة مسماة + صف رمادي "No event in window". يملك كل صف source handle في الحافة اليمنى، بـ id = group-name-slug، ويستخدم صف انتهاء المهلة timed_out.

عندما تكون قائمة مشغلات المجموعة فارغة، يعرض الصف شارة تحذير صغيرة: لا يمكن للمجموعة المطابقة، فلا تعمل الكتلة صحيحًا حتى تضيف مشغّلًا أو تضبط Exit canvas.

أمثلة عملية​

المثال 1: سلة متروكة: وضع Did / Didn't. المشغّل = purchase_completed. النافذة = 24 ساعة. التقدم = As soon as an event fires. صل حافة timed_out برسالة Email تذكير وحافة did برسالة شكر. يخرج المشترون بوضوح، ومن لا يشترون يحصلون على تذكير بعد يوم.

المثال 2: إعادة تفاعل متعددة القنوات: وضع Multi. ثلاث مجموعات مرتبة: 1. Made Purchase، event=purchase_completed، و2. Visited Pricing، event=page_view مع property page=/pricing، و3. Opened Email، event=email_opened. التقدم = At end of window. النافذة = 7 أيام. صل كل مجموعة بتسلسل متابعة مختلف؛ وتذهب حافة No event in window إلى مسار رعاية أطول. تهم الأولوية: من اشترى وزار pricing يسلك مسار Made Purchase.

عُقد Experiment​

لاختبار A/B/n وتثبيت الفائز وتحسين multi-armed bandit أو التخصيص لكل مستخدم القائم على ML، استخدم عُقدة Experiment. راجع دليل عُقدة Experiment المخصص للتغطية الكاملة.

أزيلت عُقدة A/B Split المستقلة؛ فـ Experiment في وضع مسار "Standard" يغطي حالة الاستخدام نفسها بمرونة أكبر، مجموعات تحكم ومجموعات تأخير واختيار فائز اختياري.

عُقد AI-Decision​

توجه عُقدة AI-Decision كل مستخدم في المسار الذي يتنبأ AI بأنه الأفضل لذلك الفرد: قرار "ملاءمة العرض" لكل مستخدم داخل رحلة. بينما يعثر Experiment على المسار الفائز عالميًا، يختار AI-Decision مسارًا مختلفًا لكل مستخدم من سماته وسلوكه.

اضبط:

  • Paths: المسارات التي يختار بينها AI، ويتابع كل مسار إلى فرعه اللاحق.
  • Goal: Engagement، فتحات/نقرات، أو Conversion، حدث محدد، أو Revenue، قيمة الشراء. يحدد ما يحسن النموذج تجاهه.
  • Conversion Event: يظهر عندما يكون الهدف Conversion؛ وهو الحدث الذي يعد نجاحًا، ويمكن أن يكون حدثًا مخصصًا مثل signup.

طريقة اتخاذ القرار لكل مستخدم: يختار النموذج المسار الأفضل، exploit، وتستكشف شريحة صغيرة مسارات غير مؤكدة لمواصلة التعلم، استكشاف ذكي لا عشوائي. قبل أن يتعلم النموذج المسارات، يوجه المستخدمين بعدل، cold start. تُنسب النتائج للخلف ويعاد تدريب النموذج يوميًا.

ما يُعد "فوزًا" وما الذي يتعلم منه: يتبع النجاح هدفك. يحتسب Engagement الفتحات والنقرات، وConversion حدث التحويل، وRevenue المشتريات. يُنسب الفوز إلى المسار الذي سلكه الشخص، فيتعلم AI الرسالة/العرض الذي يقود النتيجة فعليًا لا ما يفتح فقط. في هدف Conversion أو Revenue، ليس الفتح أو النقر "فوزًا" بمفرده؛ فذلك سيحسن للرسائل الطُعمية. تظل الفتحات والنقرات مدخلات. ينظر AI إلى:

  • Engagement: مقدار الفتح والنقر في Email/Push/In-app، وحداثة النشاط وتكرار الزيارة، sessions وpage views وردود WhatsApp ووقت اليوم/الأسبوع المعتاد للنشاط.
  • Value: المشتريات، الطلبات وإجمالي ومتوسط الإنفاق وRFM، الحداثة/التكرار/القيمة النقدية.
  • Profile: البلد ومدة كون الشخص عميلًا والقنوات القادرة على الوصول إليه، Email/phone.

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

إرسال مجدول لمرة واحدة: "Warm up before full send": لا تستطيع رحلة مجدولة مرة واحدة لجمهور ثابت التسخين ذاتيًا؛ يدخل الجميع اللحظة نفسها قبل أن يرى AI أي نتيجة. لهذه الحالة تملك AI-Decision مفتاح Warm up before full send: ترسل الرحلة إلى seed صغير من الجمهور أولًا، وتُبقي الباقي، ثم تطلق المتبقي بتوجيه مخصص تلقائيًا بعد أن يتعلم النموذج المسارات، أو بعد max-hold تضبطه. لا تحتاج الرحلات المستمرة المشغّلة ذلك، فهي تسخن تلقائيًا.

تقاسم الفضل، multi-touch: عندما يمر المستخدم عبر عدة عُقد AI-Decision في رحلة ثم يتحول، يُقسَّم الفضل على القرارات بدل إعطائه كله للأخير؛ فاختيارات التوجيه الأقدم ساعدت أيضًا. تحصل القرارات الحديثة على الحصة الأكبر وتبهت الأقدم تدريجيًا، نموذج time-decay. وتنسب الرحلة ذات القرار الواحد الفضل لذلك القرار كاملًا. يختلف ذلك عن حملة AI-Optimized، إرسال واحد، تنسب قرارها الأخير الوحيد last-touch.

عُقد أفضل رسالة تالية​

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

الإعداد:

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

كيف تقيّم (لكل شخص): يقيّم النموذج المشترك من الإعدادات، نماذج ML كل قالب حسب سلوك الشخص وتسميات محتوى القالب (فيحصل القالب الجديد تمامًا على تقييم حقيقي)، وتحتفظ قناة الشخص المفضلة بتقييمها بينما تُخفَّض القنوات الأخرى، ويفوز التقييم الأعلى. قبل تدريب نموذج مشترك تحصل كل القوالب على التقييم نفسه ويكون الاختيار قرعة عادلة، وهذا ما يقوله السجل.

وضع الإرسال. حوّلوا وضع العقدة إلى إرسال عندما تبدو مقارنة الظل صحيحة. تحتفظ حصة مجموعة ضبط تختارونها (20% افتراضيًا) بسلوك اليوم وتخرج عبر مخرج مجموعة الضبط الذي تربطونه برسالتكم؛ ويحصل الباقون على الاختيار المرسل من العقدة نفسها (قالب بريد أو إشعار، تحت قواعد الموافقة وساعات الهدوء والتكرار نفسها كأي عقدة رسالة) ويخرجون عبر مخرج أُرسل. تُقارن الذراعان في الإعدادات، نماذج ML بنطاق مرجح لكل منهما وحكم "لا خسارة في التحويلات"، وهو معيار إبقاء العقدة في وضع الإرسال. قوالب داخل التطبيق تُقيَّم ولا ترسلها العقدة.

عُقد Update User​

لدى عُقد Update User نوعا صفوف؛ اختر لكل صف.

تحديث سمة​

اضبط أو زد أو أنقص أو ألحق أو أزل قيمة سمة مستخدم. تأتي السمات من سجل مساحة العمل؛ ابدأ الكتابة للفلترة ولا يوجد نص حر، عرّف السمات الجديدة في Settings ← Attributes أولًا. تُصفى العمليات المتاحة تلقائيًا وفق نوع السمة: inc / dec للأرقام وappend / remove للمصفوفات وهكذا.

تتبع حدث​

أطلق حدثًا متتبعًا للمستخدم من داخل Canvas. يفيد لتعليم معالم الرحلة، مثل completed_onboarding أو abandoned_checkout، التي تستطيع رحلات/شرائح أخرى الاستماع إليها. يكمل حقل اسم الحدث تلقائيًا من أحداث مساحة العمل المتتبعة لكنه يقبل نصًا حرًا لأسماء أحداث جديدة.

يمكن إضافة صفوف متعددة إلى عُقدة Update User، وتطبق بالترتيب. اسحب المقبض لإعادة ترتيبها.

حالات الاستخدام​

  • وسم من أكملوا مسارًا: engagement_tag = 'onboarded'.
  • تحديث الدرجات: engagement_score += 10.
  • تتبع أحداث رحلة للاستهداف اللاحق: Track event: onboarding_completed.
  • ضبط أعلام للاستهداف المستقبلي: feature_eligibility = true.

JSON مخصص​

إلى جانب الصفوف أعلاه، لعُقدة Update User وضع ثانٍ: بدّل حقول إلى JSON مخصص أعلى العُقدة. تبقى العُقد التي أُنشئت قبل إضافة هذا الوضع في وضع الحقول.

في وضع JSON المخصص تكتب كائن JSON واحدًا بنفس شكل الحقول attributes وsubscriptions وevents في جسم طلب واجهة POST /users. استخدام نموذجي: صفحة هبوط على موقعك ترسل حدثًا عبر الواجهة البرمجية، فيبدأ الحدث هذه الرحلة، وتضيف هذه الخطوة الشخص إلى قائمة وتضبط سمات وتسجّل حدث متابعة.

{
"attributes": { "firstName": "Dana" },
"subscriptions": [
{ "listId": "<list id>", "channel": "email", "status": "subscribed" }
],
"events": [
{ "name": "Free Gift Requested", "properties": { "source": "landing-page" } }
]
}
المفتاحما يفعله
attributesيضبط كل سمة لدى الشخص، مثل دمج السمات في الواجهة البرمجية.
subscriptionsيضيف الشخص إلى قوائم الاشتراك أو يزيله منها. listId مطلوب؛ channel هو email (افتراضي) أو sms أو whatsapp أو push أو viber؛ status هو subscribed (افتراضي) أو unsubscribed.
eventsيسجّل أحداثًا للشخص. name مطلوب؛ properties وtimestamp (تاريخ ISO أو ميلي ثانية epoch) اختياريان. تُسجَّل الأحداث بالطريقة نفسها مثل صفوف Track an event.

استخدم إدراج مثال للبدء من المثال أعلاه، ومنتقي القوائم لإدراج إحدى قوائمك.

تحدّث الخطوة دائمًا الشخص الذي دخلها. لا يمكن تعيين المعرّفات أو تغييرها: تُرفض email وphone وexternalId وuserId وanonymousId و_id وid وaliases وبقية مفاتيح الهوية، سواء كمفاتيح في المستوى الأعلى أو كأسماء سمات، بأي حالة أحرف ومع _ أو - أو بدونهما. وتُرفض أيضًا السمات التي تديرها المنصة مثل lastEventName، تمامًا كما في الواجهة البرمجية. لا يُسمح في المستوى الأعلى إلا بـ attributes وsubscriptions وevents.

يُحتفظ بإلغاء الاشتراك. إذا ألغى الشخص اشتراكه في قائمة على هذه القناة، يُتخطّى عنصر subscribed لها ويُبلَّغ عنه ("opt-out kept") - لا تعيد الرحلة اشتراك أحد أبدًا. يُطبَّق "status": "unsubscribed" الصريح دائمًا. يجب أن تنتمي كل قائمة إلى مساحة العمل هذه؛ ويُتخطّى أي معرّف قائمة آخر.

قوائم التأكيد المزدوج تُعامل بالطريقة نفسها كما عبر الواجهة البرمجية: يُسجَّل الشخص مشتركًا (المصدر journey) ولا ترسل هذه الخطوة رسالة تأكيد.

الحدود هي حدود الواجهة البرمجية: 100 اشتراك و25 حدثًا كحد أقصى، وحدود الحجم الخاصة بقيم السمات وخصائص الأحداث. يمكن أن يصل JSON نفسه إلى 50,000 حرف و10 مستويات تداخل و5,000 قيمة؛ ويمكن أن تُعرض كل قيمة مخصصة في 50,000 حرف كحد أقصى (500,000 إجمالًا).

Liquid في JSON المخصص​

استخدم Liquid داخل القيم النصية - الحدث المُطلِق وملف الشخص ومتغيرات الرحلة متاحة، كما في أي حقل مخصص آخر:

{
"attributes": {
"firstName": "{{ event.properties.first_name }}",
"giftSource": "{{ event.properties.source | default: 'landing-page' }}"
},
"subscriptions": [
{ "listId": "{{ event.properties.list_id }}", "channel": "email" }
],
"events": [
{ "name": "Free Gift Requested", "properties": { "plan": "{{ user.plan }}" } }
]
}

يجب أن يكون JSON صالحًا كما هو مكتوب: يوضع Liquid داخل القيم المقتبسة فقط، وليس في المفاتيح أبدًا ولا كقيمة مجردة. تُعرض كل قيمة على حدة وتبقى قيمة نصية، لذا لا يمكن لبيانات الحدث أبدًا تغيير بنية JSON أو الوصول إلى معرّف. ولأن القيمة المعروضة نصية دائمًا، اكتب الأرقام وtrue / false حرفيًا.

متى يتم الفحص​

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

عُقد Issue coupon​

تمنح عقدة Issue coupon الشخص رمزاً من برنامج قسائم - يُنشأ في تلك اللحظة في المتجر المتصل - وتحتفظ به معه. كل رسالة لاحقة في الرحلة تستخدم {{ coupons.<slug>.code }} تعرض الرمز نفسه، في كل قناة.

  • Program - اختر برنامجاً نشطاً. لا تفعل العقدة شيئاً آخر: ضع الرمز في الرسائل التالية.
  • مخرجان: Issued (لدى الشخص رمز) وCould not issue (لم يستطع المتجر إنشاء رمز، أو البرنامج موقوف مؤقتاً). وجّه المخرج الثاني إلى رسالة بلا قسيمة، أو أنهِ الرحلة هناك.
  • إعادة تشغيل العقدة لا تُنشئ رمزاً ثانياً أبداً، ومع تفعيل "إعادة استخدام رمز الشخص المفتوح" في البرنامج، فإن الشخص الذي يدخل الرحلة مجدداً ورمزه لا يزال مفتوحاً يحصل على الرمز نفسه.

عُقد Webhook​

تنفذ عُقد Webhook طلبات HTTP إلى خدمات خارجية.

الإعداد​

الإعدادالوصف
Method + URLGET / POST / PUT / PATCH / DELETE مع URL نقطة النهاية. تدعم Liquid في URL.
AuthenticationNone / Bearer / Basic / API key / Signed (HMAC). تُترجم Bearer / Basic / API-key إلى الرأس الصحيح عند الحفظ، مثل Authorization: Bearer <token>. يضيف Signed (HMAC) الرأس X-Joryio-Signature، SHA-256 HMAC لنص الطلب، كي يتحقق المستلم أن الطلب من Joryio. يستخدم Signed (HMAC) سر التوقيع الذي تدخله. تُشفَّر الأسرار عند الحفظ وتظهر كحقل مخفي: اتركه للاحتفاظ بالسر، أو امسحه لإزالته، أو اكتب قيمة جديدة لاستبداله. يُحتفظ بالسر المحفوظ فقط للعنوان الذي حُفظ له: إذا غيّرت البروتوكول أو المضيف أو المنفذ في URL، فأعد إدخال السر قبل الحفظ. يحتاج السر إلى عنوان حرفي: بلا Liquid أو اسم مستخدم أو كلمة مرور في البروتوكول أو المضيف أو المنفذ (Liquid في المسار أو الاستعلام مسموح). عند الإرسال يُرفق السر فقط إذا كان URL بعد المعالجة لا يزال يشير إلى ذلك العنوان؛ وإلا يُرسل الطلب بدونه ويوضح عرض التشغيل ذلك. تُخفى بالطريقة نفسها الرؤوس المخصصة التي تبدو كبيانات اعتماد (Authorization، أو رأس يدل اسمه على token أو secret أو API key). في Journey Runs، تعرض خطوة Webhook لكل شخص رمز HTTP والنجاح أو الفشل والمدة وحقول الاستجابة المحفوظة في متغيرات الرحلة. وتعرض الاستدعاءات الفاشلة أيضًا كتلة الاستجابة أسفل الحالة (انظر سلوك Webhook أدناه)؛ ولا يُخزَّن نص الاستجابة الناجحة أبدًا.
Custom headersصفوف key/value. تدعم القيم Liquid. يُضاف Content-Type عندما يحتوي الطلب على نص ويمكن تجاوزه؛ ويُرسل دائمًا Content-Type الذي تضبطه بنفسك.
Request bodyJSON أو Form-encoded، application/x-www-form-urlencoded، أو None (بلا نص وبلا Content-Type - مناسب لـ GET/DELETE). يتحقق نص JSON ضمنيًا أثناء الكتابة؛ والنص الذي يتكون من وسم Liquid فقط (مثل {{ user.id }}) يظهر بجانبه "لا يُضمن أن يكون JSON بعد العرض".
Response handlingاختياري: استخرج قيمة من نص الاستجابة، مسار $.a.b مثل $.user.crm_id، إلى متغير رحلة مثل crm_id، كي يفرع أو يقالب بها خطوة لاحقة. للحفظ على المستخدم أضف Update User يقرأ المتغير.
Retry & timeoutالحد الأقصى لإعادة المحاولة والمهلة لكل عُقدة. يبقى التراجع أسيًا وتعمل المحاولات لـ5xx وأخطاء الشبكة؛ راجع Webhook Behavior.
System call - skip quiet hours & frequency capsمتوقف افتراضيًا: تنتظر Webhooks نوافذ الهدوء وتحترم حدود التكرار كأي رسالة. فعله فقط لاستدعاءات نظام-لنظام لا ينبغي تأخيرها بوقت هدوء شخص. تطبق قوائم الحظر في كلتا الحالتين، ومستلمو Webhook ملفات متفاعلة قابلة للفوترة دائمًا.

النص يُرسل كما هو​

يُرسل النص الذي تضبطه كما هو إلى المستلم، ولا يوجد غلاف Joryio يلف النص.

لإضافة بيانات Canvas أو التنفيذ أو المستخدم إلى الطلب، أضفها بنفسك عبر Liquid:

{
"event": "user_signup",
"user_id": "{{ user.id }}",
"email": "{{ user.email }}",
"canvas_id": "{{ canvas.id }}",
"execution_id": "{{ execution.id }}",
"node_id": "{{ node.id }}"
}

يرسل Joryio ثلاثة رؤوس بيانات وصفية تلقائيًا، فيلتقطها المستلم دون تغيير شكل النص:

X-Joryio-Canvas-Id: <canvas id>
X-Joryio-Execution-Id: <execution id>
X-Joryio-Node-Id: <node id>

يُرسل النص بايتًا بايتًا تمامًا كما عُرض: النص الذي يُعرض فارغًا لا يُرسل إطلاقًا (وليس "" فارغًا أبدًا)، والنص غير JSON - مثل معرّف مجرد من {{ user.id }} - يُرسل كما هو دون علامات اقتباس. ويغطي توقيع HMAC هذه البايتات بالضبط. يعرض Send test الطلب المُرسل وينبّه عندما لا يكون نص JSON صالحًا بعد العرض؛ ولا يتغير الإرسال الفعلي أبدًا.

نطاقات Liquid​

متاحة في URL وقيم الرؤوس ونص JSON:

النطاقيحتوي
user.*حقول المستخدم العليا، user.id وuser.email وuser.phone، وكل السمات المخصصة، user.firstName وuser.plan…
event.* / trigger.*حمولة حدث المشغّل التي بدأت التنفيذ.
canvas.*canvas.id, canvas.name.
execution.*execution.id, execution.startedAt.
node.*node.id, node.type, node.label.

تظل المفاتيح القديمة المسطحة، {{ canvasId }} و{{ executionId }}، قابلة للحل.

سلوك Webhook​

تعمل عُقدة Webhook بأحد وضعين وفق تفعيل Response handling:

غير متزامن، الافتراضي بلا ربط استجابة

تتقدم Canvas فور وضع Webhook في الطابور، من دون انتظار استجابة HTTP. الأفضل لاستدعاءات fire-and-forget، مثل إعلام CRM أو بدء مهمة تابعة.

متزامن، Response handling مفعّل

عند ربط حقل استجابة بمتغير رحلة، تعمل العُقدة بصورة متزامنة: تتوقف الرحلة عند Webhook حتى وصول الاستجابة، أو مهلة 15 ثانية، فيكون المتغير جاهزًا للخطوة التالية. وهي fail-open: عند المهلة أو الخطأ تستمر الرحلة والمتغير غير مضبوط؛ وإن وصلت on-error output فشل الطلب يذهب إليها. يكون التنفيذ موقوفًا ولا يحتجز Worker، فيتوسع لجماهير كبيرة.

في الوضعين:

  • لا توقف إخفاقات Webhook مسار Canvas، fail-open.
  • تعيد Webhooks غير المتزامنة المحاولة عند 5xx وأخطاء الشبكة بتراجع أسي حتى max-attempts للعُقدة. تفشل 4xx فورًا دون إعادة، وتحترم 429 رأس Retry-After.
  • تُحفظ الاستجابات الفاشلة لتسهيل تصحيح الأخطاء. عندما يفشل استدعاء بإجابة ليست 2xx، يخزّن Joryio رمز الحالة ونوع المحتوى وأول 2 KB من نص الاستجابة، مع إخفاء القيم التي تبدو كأسرار (رموز Bearer / Basic، و JWT، وحقول token / secret / password / api_key / authorization، وسلاسل hex أو base64 الطويلة) قبل التخزين. وتُزال أيضًا أي بيانات اعتماد أرسلها الطلب نفسه (الرمز أو كلمة المرور أو مفتاح API أو التوقيع) أينما كررتها الاستجابة، بما في ذلك صيغ base64 و URL-encoded و JSON-escaped و hex. لا تُخزَّن ترويسات الطلب أبدًا. عند انتهاء المهلة أو خطأ الشبكة تُخزَّن رسالة الخطأ فقط. افتح كتلة الاستجابة في خطوة Webhook ضمن Journey Runs (أو في حدث الفشل في الخط الزمني للمستلم في حملة Webhook) لقراءتها. لا يُعرض النص إلا لمن لديه صلاحية الوصول إلى البيانات الشخصية (صلاحية pii:view)، لأن الاستجابة قد تتضمن بيانات جهة اتصال؛ ويرى الآخرون الحالة والخطأ مع ملاحظة بأن الاستجابة مخفية. تُحذف الاستجابات المخزنة تلقائيًا بعد 30 يومًا. لا يُخزَّن نص الاستجابة الناجحة (2xx) أبدًا. يمكن لفريق Joryio إيقاف تخزين نصوص الاستجابات لمؤسستك عند الطلب؛ وتبقى الحالة والمدة والخطأ مسجلة.
  • لا تُحسب كتسليم إلا استجابة 2xx. الاستجابة 3xx أو 4xx (مثل 401 أو 404) فشل: تظهر فاشلة في تشغيل الرحلة وفي outbox، ويأخذ webhook المتزامن مخرج الخطأ، ولا يسلك مسار النجاح أبدًا.
  • تفشل Webhooks المتزامنة بسرعة دون حلقة محاولات ليبقى التنفيذ الموقوف متحركًا؛ تنتهي نقطة أبطأ من 15s وتستمر الرحلة. تستأنف شبكة أمان كل رحلة تضيع استجابتها كي لا تبقى جهة اتصال موقوفة للأبد.
  • يعمل circuit breaker لكل host بعد إخفاقات صحة متكررة، مهلة/شبكة/5xx، لنفس المضيف ويقصر الطلبات التالية أثناء cooldown قصير. أثناء تعطل نقطة نهاية، تفشل الطلبات المتزامنة fail-open فورًا بدل انتظار المهلة كاملة، ولا يُقصف مضيف ميت. يتعافى تلقائيًا عند استجابة المضيف؛ ولا تشغله 4xx/429 لأنهما يعنيان أن المضيف حي.

عُقد Connector​

تزامن عُقد Connector المستخدمين مع جماهير منصات الإعلانات الخارجية أثناء تنفيذ Canvas.

الإعداد​

الإعدادالوصف
Integrationاختر تكامل مزامنة جمهور متصل.
ActionAdd to Audience أو Remove from Audience أو Sync Audience.
Audienceالجمهور المستهدف في المنصة الخارجية.

المنصات المدعومة​

  • Meta Ads، Custom Audiences.
  • Google Ads، Customer Match.
  • TikTok Ads، Custom Audiences.
  • LinkedIn Ads، Matched Audiences.
  • Criteo Ads، Contact Lists.

سلوك Connector​

معالجة غير متزامنة

توضع إجراءات Connector في طابور وتعالج بصورة غير متزامنة. تتقدم Canvas فور وضع الإجراء في الطابور. تعاد الإجراءات الفاشلة حتى 3 مرات بتراجع أسي.

تُجزأ بيانات المستخدم، Email والهاتف وexternal ID، بحسب متطلبات كل منصة قبل الإرسال.

عُقد Exit​

تنهي عُقد Exit مسار Canvas للمستخدم.

أسباب الخروج​

السببالوصف
Goal Achievedأكمل المستخدم الإجراء المطلوب.
Unsubscribedألغى المستخدم الاشتراك.
No Longer Eligibleلم يعد المستخدم يطابق المعايير.
Manual Exitإنهاء صريح للمسار.

ترتيب المعالجة​

عندما يدخل مستخدمون متعددون Canvas في وقت واحد:

  1. يعالج Canvas workers المستخدمين بالتوازي.
  2. مسار كل مستخدم مستقل.
  3. يتوزع إرسال الرسائل على طوابير خاصة بكل قناة.
  4. تُعالج سيناريوهات الحجم العالي، مليون مستخدم فأكثر، بكفاءة.

متغيرات قالب E-Commerce​

عند إرسال رسائل من Canvas، تتاح بيانات التجارة الإلكترونية تلقائيًا للتخصيص.

بيانات السلة​

المتغيرالوصف
{{ cart.items }}مصفوفة عناصر السلة.
{{ cart.itemCount }}العدد الإجمالي للعناصر.
{{ cart.value }}القيمة الإجمالية للسلة.
{{ cart.subtotal }}المجموع الفرعي للعناصر، قبل الشحن والضريبة (cart.value هو الإجمالي الذي أرسله المتجر، وقد يشمل الشحن).
{{ cart.currency }}رمز العملة، USD أو EUR…
{{ cart.checkoutUrl }}URL لاستئناف إتمام الشراء.
{{ cart.abandoned }}ما إذا كانت السلة متروكة.

مثال: Email سلة متروكة​

<h2>You left items in your cart!</h2>

{% for item in cart.items %}
<div style="margin: 10px 0;">
<img src="{{ item.imageUrl }}" width="80" />
<strong>{{ item.name }}</strong>
<span>${{ item.price }} x {{ item.quantity }}</span>
</div>
{% endfor %}

<p><strong>Total: ${{ cart.value }}</strong></p>

<a href="{{ cart.checkoutUrl }}" style="background: #007bff; color: white; padding: 12px 24px;">
Complete Your Purchase
</a>

حقول عنصر السلة​

يحمل كل عنصر في cart.items:

الحقلالوصف
productIdمعرّف المنتج.
nameاسم المنتج.
priceسعر الوحدة.
quantityالكمية في السلة.
totalprice × quantity.
imageUrlURL صورة المنتج.
skuSKU المنتج.
variantIdمعرّف النسخة.

ذو صلة​

عُقد وكيل الذكاء الاصطناعي​

تشغّل عقدة وكيل الذكاء الاصطناعي أحد وكلاء الذكاء الاصطناعي لديك للشخص في الرحلة وتحفظ الإجابة في متغير رحلة (انظر مخرجات الوكيل).

  • لوكيل الكتابة فرعان: نجاح وخطأ.
  • لوكيل التصنيف فرع لكل وسم، بالإضافة إلى غير متأكد لإجابة لا يثق بها الوكيل، بالإضافة إلى خطأ.

الخطأ فرع واحد عمدًا. يُكتب سبب فشل التشغيل (مهلة، حد معدل، مفتاح مضبوط خطأ، ميزانية منتهية، خطأ مزود) في agent.<variable>_outcome وagent.<variable>_error، فتستطيع عقدة تفرّع بعد الوكيل التوجيه حسبه عندما تحتاج الرحلة ذلك. الفرع غير الموصول ينتقل إلى الخطوة التالية الافتراضية بقيمة احتياط الوكيل، فلا تتوقف الرحلة أبدًا عند فشل وكيل. تعرض العقدة تكلفة التشغيل، نحو X لكل 1,000 تشغيل، بجانب منتقي الوكيل.