عُقد Canvas
تُبنى مسارات Canvas بأنواع مختلفة من العُقد تحدد طريقة تقدم المستخدمين في الأتمتة. يغطي هذا الدليل كل العُقد المتاحة وسلوكها.
عُقد المشغّل
تحدد عُقد المشغّل كيفية دخول المستخدمين إلى Canvas.
المشغلات المتاحة
| نوع المشغّل | الوصف |
|---|---|
| Event | يدخل المستخدم عند تنفيذه حدثًا محددًا |
| Segment Entry | يدخل المستخدم عند انضمامه إلى شريحة |
| Entity Change | يدخل المستخدم عند تغير سجل كيان ذي صلة |
| API | يدخل المستخدم عبر استدعاء API |
| Schedule | يدخل المستخدمون وفق جدول متكرر |
| WhatsApp Message | يدخل المستخدم عند إرسال رسالة WhatsApp |
| Inbound SMS | تدخل جهة اتصال معروفة عند إرسال SMS؛ صفِّ حسب حساب SMS ونوع الرسالة وشروط Message Text / Message Type |
عُقد الرسائل
ترسل عُقد الرسائل اتصالات إلى المستخدمين عبر قنوات متعددة.
القنوات المدعومة
- Email: أرسل Emails مخصصة.
- SMS: أرسل رسائل نصية.
- Push Notifications: أرسل إشعارات Push للجوال.
- WhatsApp: أرسل قوالب WhatsApp أو ردودًا.
- Webhook: استدع API خارجيًا بنص مبني بقوالب Liquid.
الرسائل داخل التطبيق ليست قناة ضمن عقدة الرسالة. لأنها تُعرض عند فتح المستخدم لتطبيقك في المرة التالية (بدلاً من إرسالها إليه)، لها عقدة خاصة بها هي رسالة داخل التطبيق - راجع عقد رسالة داخل التطبيق.
تختار القناة من عُقدة Message نفسها. يوجد Webhook في منتقي القنوات نفسه مع Email وSMS، وله منشئ طلب خاص: الطريقة والرؤوس والنص والمصادقة وإعادة المحاولة وانتظار اختياري لربط الاستجابة. استخدم Send test لتشغيل استدعاء عينة، ثم انقر أي حقل في الاستجابة لربطه بمتغير رحلة، أو الصق استجابة عينة لتأليف الربط دون استدعاء حي. عند تفعيل ربط الاستجابة، تستطيع أيضًا تفعيل on-error output: منفذ ثانٍ تتبعه الرحلة عند فشل الطلب أو انتهاء مهلته. اتركه بلا توصيل للمتابعة على المخرج العادي، fail-open.
تستدعي قناة 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":
- تُخصص الرسالة ببيانات المستخدم.
- تُضاف إلى طابور الإرسال.
- يتقدم المستخدم إلى خطوة Canvas التالية.
- يعالج 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 بالطريقة نفسها، فما تتلقاه في الاختبار هو ما سيتلقاه جمهورك بالضبط.
عُقد رسالة داخل التطبيق
تعمل الرسائل داخل التطبيق بطريقة مختلفة عن كل القنوات الأخرى، لذلك لها عقدة خاصة بها. البريد الإلكتروني والرسائل النصية والإشعارات وWhatsApp تُرسل إلى الشخص. أما الرسالة داخل التطبيق فتُعرض عند فتح الشخص لتطبيقك في المرة التالية - لذا فإن هذه العقدة لا "ترسل" شيئًا. إنها تضع الرسالة في قائمة انتظار لذلك المستخدم، ويعرضها تطبيقك في الجلسة المؤهلة التالية.
أضِفها من مربّع رسالة داخل التطبيق في لوحة عناصر المُنشئ.
ما الذي تضبطه
- حملة داخل التطبيق (مطلوبة) - الحملة التي توفّر المحتوى والتخطيط والمتغيّرات. تعيد العقدة استخدام الحملة التي أنشأتها بالفعل، فتبدو الرسالة متطابقة أينما سُلّمت.
- الأولوية - عاجلة / عالية / عادية / منخفضة. عندما تكون عدة رسائل مؤهلة في اللحظة نفسها، تُعرض الأعلى أولوية أولًا، ويُحسم التعادل بالأقدم أولًا حتى لا تُدفن رسالة منتظرة تحت رسائل أحدث. رسائل الرحلة وحملات التطبيق تتنافس في الترتيب نفسه.
- عدد مرات العرض - العرض مرة واحدة (افتراضي)، أو العرض حتى 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". |
Duration
| الإعداد | الوصف |
|---|---|
| Wait for | رقم ووحدة: Minutes / Hours / Days / Weeks. |
| Then wait until a specific time of day | اختياري. بعد انتهاء المدة، استمر في الانتظار حتى وقت اليوم المختار في المنطقة الزمنية المختارة. |
| Timezone | Company / User local / UTC؛ يستخدمه خيار وقت اليوم. |
Calendar date
| الإعداد | الوصف |
|---|---|
| Date | تاريخ ISO مستهدف. قابل للاختيار من التقويم المضمن؛ انقر يومًا للاختيار واستخدم الأسهم للتنقل بين الأشهر. |
| Time | منتقيا الساعة والدقيقة. |
| Timezone | Company / User local / UTC. |
Day of week
| الإعداد | الوصف |
|---|---|
| Day & time | يوم الأسبوع مع الساعة والدقيقة. صف المعاينة ذي 7 خلايا أعلى النافذة قابل للنقر أيضًا. |
| Timezone | Company / User local / UTC. |
| If a user arrives after the cutoff | Wait، الافتراضي، ينقله إلى وقوع الأسبوع التالي. Advance يشغل فورًا كي لا يخسر أسبوعًا. |
تخصيص التأخير
مفتاح في كل نوع. عند تفعيله يقرأ التأخير متغيرًا لكل مستخدم بدل قيمة ثابتة:
| المصدر | يقرأ من |
|---|---|
| Context variables | execution.context[varName]، سياق الدخول للرحلة، الافتراضي القديم. |
| User custom attribute | user.attributes.<varName> وحقول المستخدم العليا. |
| Event property | execution.context.event.<varName> وحمولة المشغّل. |
في Calendar date / Day of week مع متغير مخصص، تستطيع ضبط offset، زائد أو ناقص بالساعات/الأيام/الأسابيع، مثل "send 3 days before the renewal date".
حل المنطقة الزمنية
| الوضع | يحل إلى |
|---|---|
| Company time | workspace.settings.timezone، مخزنة مؤقتًا لكل Worker لـ60 ثانية. |
| User local time | user.attributes.timezone، تضبطه SDK. يعود إلى Company time إن غاب. |
| UTC | UTC. |
الحدود
- تُقيّد كل فروع التأخير بـ30 يومًا كحد أقصى. تُشغّل العُقدة المضبوطة خطأً فورًا بدل تعليق الرحلة، مع تسجيل تحذير منظم.
مثال: انتظر 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> نفسه لمحرر الشرائح ومنتقي جمهور الحملة، ولذلك تدعم كل أنواع الفلاتر التي تدعمها تلك الواجهات:
| النوع | ما يفحصه | العوامل |
|---|---|---|
attribute | user.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 | عضوية الشريحة، تكرارية حتى عمق 5 | in, not_in |
canvas_execution | تنفيذات Canvas النشطة/المكتملة/الخارجة | in_canvas, not_in_canvas, in_any_canvas, not_in_any_canvas, completed_canvas, exited_canvas |
channel_subscription | user.subscriptions[channel].status | subscribed_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 |
entity | user.entityRecords[entity] | exists, not_exists |
app | user.appIds | has_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" }
}
بطاقة عُقدة Canvas
تتكيف البطاقة مع الوضع:
- Yes / No: منفذا مصدر في أسفلها، أخضر yes وأحمر no.
- Multi: منفذ مصدر لكل مجموعة في الحافة اليمنى للبطاقة مع تسمية اسم المجموعة في الصف. تطول البطاقة عموديًا عند إضافة مجموعات.
تطابق تسميات الحواف اسم المجموعة بالضبط، إذ يقرأ Worker الحواف بالاسم عند التوجيه. إذا أعدت تسمية مجموعة، تبقى الحافة المتصلة مرتبطة لأننا نستخدم React Flow handle id؛ rename ثم save دون كسر.
مثال: مسار سلة متروكة
- Trigger: Event = "Product Added".
- Delay: انتظر ساعة.
- Branch (Yes / No):
not_performed_event_in_last"Order Completed" في الساعة الأخيرة.- Yes: أرسل Email استعادة.
- No (Everyone else): اخرج من المسار.
مثال: توجيه RFM متعدد المسارات
- 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.
- VIP customers،
عُقد 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.
عُقد 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.
عُقد Webhook
تنفذ عُقد Webhook طلبات HTTP إلى خدمات خارجية.
الإعداد
| الإعداد | الوصف |
|---|---|
| Method + URL | GET / POST / PUT / PATCH / DELETE مع URL نقطة النهاية. تدعم Liquid في URL. |
| Authentication | None / Bearer / Basic / API key / Signed (HMAC). تُترجم Bearer / Basic / API-key إلى الرأس الصحيح عند الحفظ، مثل Authorization: Bearer <token>. يضيف Signed (HMAC) الرأس X-Joryio-Signature، SHA-256 HMAC لنص الطلب، كي يتحقق المستلم أن الطلب من Joryio. |
| Custom headers | صفوف key/value. تدعم القيم Liquid. يُضاف Content-Type افتراضيًا ويمكن تجاوزه. |
| Request body | JSON أو Form-encoded، application/x-www-form-urlencoded، أو None. يتحقق نص 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>
نطاقات 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 أو بدء مهمة تابعة.
عند ربط حقل استجابة بمتغير رحلة، تعمل العُقدة بصورة متزامنة: تتوقف الرحلة عند Webhook حتى وصول الاستجابة، أو مهلة 15 ثانية، فيكون المتغير جاهزًا للخطوة التالية. وهي fail-open: عند المهلة أو الخطأ تستمر الرحلة والمتغير غير مضبوط؛ وإن وصلت on-error output فشل الطلب يذهب إليها. يكون التنفيذ موقوفًا ولا يحتجز Worker، فيتوسع لجماهير كبيرة.
في الوضعين:
- لا توقف إخفاقات Webhook مسار Canvas، fail-open.
- تعيد Webhooks غير المتزامنة المحاولة عند 5xx وأخطاء الشبكة بتراجع أسي حتى max-attempts للعُقدة. تفشل 4xx فورًا دون إعادة، وتحترم 429 رأس
Retry-After. - تفشل Webhooks المتزامنة بسرعة دون حلقة محاولات ليبقى التنفيذ الموقوف متحركًا؛ تنتهي نقطة أبطأ من 15s وتستمر الرحلة. تستأنف شبكة أمان كل رحلة تضيع استجابتها كي لا تبقى جهة اتصال موقوفة للأبد.
- يعمل circuit breaker لكل host بعد إخفاقات صحة متكررة، مهلة/شبكة/5xx، لنفس المضيف ويقصر الطلبات التالية أثناء cooldown قصير. أثناء تعطل نقطة نهاية، تفشل الطلبات المتزامنة fail-open فورًا بدل انتظار المهلة كاملة، ولا يُقصف مضيف ميت. يتعافى تلقائيًا عند استجابة المضيف؛ ولا تشغله 4xx/429 لأنهما يعنيان أن المضيف حي.
عُقد Connector
تزامن عُقد Connector المستخدمين مع جماهير منصات الإعلانات الخارجية أثناء تنفيذ Canvas.
الإعداد
| الإعداد | الوصف |
|---|---|
| Integration | اختر تكامل مزامنة جمهور متصل. |
| Action | Add 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 في وقت واحد:
- يعالج Canvas workers المستخدمين بالتوازي.
- مسار كل مستخدم مستقل.
- يتوزع إرسال الرسائل على طوابير خاصة بكل قناة.
- تُعالج سيناريوهات الحجم العالي، مليون مستخدم فأكثر، بكفاءة.
متغيرات قالب E-Commerce
عند إرسال رسائل من Canvas، تتاح بيانات التجارة الإلكترونية تلقائيًا للتخصيص.
بيانات السلة
| المتغير | الوصف |
|---|---|
{{ cart.items }} | مصفوفة عناصر السلة. |
{{ cart.itemCount }} | العدد الإجمالي للعناصر. |
{{ 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 | الكمية في السلة. |
total | price × quantity. |
imageUrl | URL صورة المنتج. |
sku | SKU المنتج. |
variantId | معرّف النسخة. |