דלג לתוכן הראשי

שילוב Web SDK

Joryio Web SDK מאפשר לעקוב אחרי התנהגות משתמשים, לשלוח אירועים ולנהל פרופילי משתמשים באתר שלכם.

התקנה​

דרך npm/yarn​

npm install @joryio/web-sdk
# or
yarn add @joryio/web-sdk

דרך CDN​

קובצי ה־SDK מוגשים משרת גלובלי אחד, https://sdk.joryio.com, בלי קשר לאזור שבו נמצאת סביבת העבודה שלכם. אירועים וקריאות API ממשיכים לעבור לשרת ה־API של האזור שלכם (ההגדרה apiEndpoint) - רק מיקום הקובץ גלובלי.

<!-- מומלץ: הגרסה החדשה ביותר של 1.x. מקבלת תיקונים, לעולם לא שינוי שובר. -->
<script src="https://sdk.joryio.com/web/1/joryio.min.js"></script>

<!-- מקובעת: גרסה מדויקת אחת שלא משתנה. משדרגים על ידי שינוי ה־URL. -->
<script src="https://sdk.joryio.com/web/1.3.3/joryio.min.js"></script>
נתיבמה מוגש בו
/web/1/<file>הגרסה החדשה ביותר של 1.x (מומלץ)
/web/<version>/<file>גרסה מדויקת אחת, למשל /web/1.3.3/ - התוכן שלה לא משתנה לעולם

קבצים: joryio.min.js (ה־SDK), joryio-sw.js (ה־service worker של Web Push) ו־joryio.umd.js (בניית UMD לא מכווצת).

מתי להשתמש בכל אחד
  • /web/1/ - רוב האתרים. תיקוני באגים ויכולות חדשות של 1.x מגיעים אוטומטית, ושינוי שובר (2.0) לעולם לא מגיע בנתיב הזה.
  • מקובעת (/web/1.3.3/) - אתרים שרוצים שליטה דטרמיניסטית על מתי ה־SDK משודרג. הקובץ לא משתנה לעולם, ולכן הדפדפן שומר אותו במטמון לזמן רב.

שדרוג אינטגרציה מקובעת. כאשר Joryio משחררת גרסת SDK חדשה, העלו את המספר ב־snippet:

<!-- לפני -->
<script src="https://sdk.joryio.com/web/1.3.3/joryio.min.js"></script>
<!-- אחרי -->
<script src="https://sdk.joryio.com/web/1.4.0/joryio.min.js"></script>

הדפדפן מתייחס ל־URL החדש כקובץ חדש ומריץ את ה־SDK החדש.

עבר משרת ה־API

עד אוקטובר 2026 קובץ ה־SDK הוגש משרת ה־API, בכתובת https://api-eu1.joryio.com/sdk/web/.... הנתיב הזה כבר לא קיים - החליפו אותו ב־https://sdk.joryio.com/web/1/.

Snippet אסינכרוני​

הדביקו את הקוד הזה ב־<head>. הוא טוען את ה־SDK בלי לחסום את העמוד, וקריאות שנעשות לפני שהקובץ נטען נכנסות לתור ומורצות לפי הסדר. אפשר לקרוא כך לכל מתודה ציבורית, וגם init עצמו יכול להגיע מאוחר יותר - למשל מה־callback של באנר ההסכמה.

<script>
!function(){var e=window.joryio=window.joryio||[];if(!e.initialize)if(e.invoked)window.console&&console.error&&console.error("Joryio snippet included twice.");else{e.invoked=!0,e.methods=["init","track","identify","addAlias","setAttributes","setAttribute","incrementAttribute","unsetAttribute","addToArray","removeFromArray","reset","flush","optOut","optIn","updateConsent","getTrackingConsent","isUserOptedOut","setSdkAuthenticationToken","setSdkAuthenticationErrorCallback","getAnonymousId","getUserId","ready","getIdentity","getSessionInfo","getUTMData","updateUTM","syncInAppCampaigns","getInAppCampaigns","displayInAppCampaign","dismissInAppMessage","trackInAppConversion","ecommerce","wipeData","destroy"],e.keep=["init","optOut","optIn","updateConsent","wipeData"],e.factory=function(t){return function(){var n=Array.prototype.slice.call(arguments);if(n.unshift(t),e.length>=1e3)for(var i=0;i<e.length;i++)if(e.keep.indexOf(e[i][0])<0){e.splice(i,1);break}return e.push(n),/^(get|is)[A-Z]/.test(t)?void 0:e}};for(var t=0;t<e.methods.length;t++){var n=e.methods[t];e[n]=e.factory(n)}e.load=function(e){var t=document.createElement("script");t.type="text/javascript",t.async=!0,t.src="https://sdk.joryio.com/web/1/joryio.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n)},e.load()}}();
joryio.init({ sdkKey: 'jry_sdk_web_YOUR_KEY' });
</script>
  • התור מחזיק עד 1,000 קריאות. מעבר לזה הוותיקות ביותר נמחקות - אף פעם לא init, optOut(), optIn(), updateConsent() או wipeData().
  • קריאה בתור לא יכולה להחזיר ערך. getter כמו getUserId() או isUserOptedOut() מחזיר undefined עד שה־SDK נטען. כדי לקרוא מזהה, או להשתמש ב־user, ב־push או ב־tracker ש־ecommerce() מחזיר, השתמשו ב־ready: joryio.ready(function (sdk) { sdk.getAnonymousId(); }).
  • init שנכשל לא מאבד דבר. אם init נכשל (מפתח SDK חסר או שגוי - הסיבה נרשמת בקונסול), window.joryio נשאר התור. קראו שוב ל־joryio.init({...}) עם המפתח הנכון וה־SDK מתחיל עם כל הקריאות שנעשו עד אז - החלטות פרטיות קודם, ואחריהן כל השאר לפי הסדר, כולל ביטול מינוי.
  • קריאות שנעשו בזמן שהמעקב כבוי נזרקות. track(), כתיבת מאפיין, addAlias() או trackInAppConversion() שנכנסו לתור בזמן שהמבקר ביטל מעקב או שההסכמה נדחתה - לפי הבחירה השמורה, הגדרות ה־init או החלטה שנכנסה לתור לפניהם - נזרקים, ו־optIn() או updateConsent('granted') מאוחרים יותר בתור לא מחזירים אותם. identify() וביטולי מינוי נשמרים. כך גם קריאה כזו שנכנסה לתור לפני optOut() או updateConsent('denied') שבתור, או לפני wipeData() שנכנס לתור לפני ה־init. callback של ready() שנכנס לתור בזמן שהמעקב היה כבוי, או לפני optOut() או updateConsent('denied') שבתור, עדיין רץ, אבל קריאות track(), כתיבות מאפיינים, כינויים, המרות והרשמות שהוא מבצע בזמן הריצה נזרקות גם הן - אלא אם ה־callback עצמו מבטל את מה שכיבה את המעקב, להמשך הריצה שלו: optIn() שלו מבטל ביטול מעקב, updateConsent('granted') שלו מבטל דחיית הסכמה, אף אחד מהם לא מבטל את השני, ושום דבר בתוכו לא מבטל optOut() או דחייה שנכנסו לתור אחריו. wipeData() שנכנס לתור לפני ה־init לא חוסם callback של ready() שנכנס לתור לפניו (ה־callback רץ עבור המבקר החדש). קריאת ערכים וביטולי מינוי עובדים, ומופע ה־SDK שהוא קיבל מתנהג כרגיל לאחר מכן.
  • החלטות פרטיות רצות קודם. optOut(), optIn() או updateConsent() שבתור, ו־wipeData() שנכנס לתור לפני init, מוחלים בתוך init לפני שהוא שולח משהו - כך ששום Session Start, סנכרון In-App או רישום Push לא יוצאים במצב שהם מחליפים:
<script>
/* the snippet above, then: */
joryio.updateConsent('denied'); // applied inside init, before anything is sent
joryio.init({ sdkKey: 'jry_sdk_web_YOUR_KEY' });
</script>

התחלה מהירה​

1. אתחול ה־SDK​

אתחלו את ה־SDK באמצעות מפתח ה־SDK שלכם. תוכלו למצוא את המפתח בלוח הבקרה של Joryio תחת Settings → Apps.

import JoryioSDK from '@joryio/web-sdk';

// Initialize the SDK
const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_your_sdk_key_here',
enableDebug: false, // Enable debug logging in development
});

לחבילה יש מפת exports: גרסת ES module ל־import וגרסת CommonJS ל־require. ה־bundlers (webpack, esbuild, Rollup, Vite) משתמשים בגרסת ה־ES module לשניהם, כך שאפליקציה שמייבאת את ה־SDK בקובץ אחד ועושה לו require בקובץ אחר עדיין מריצה SDK אחד. ייבוא ברירת המחדל הוא המחלקה גם ב־bundlers וגם ב־Node ESM (SSR, Vitest, סקריפטים .mjs), גם import { JoryioSDK } from '@joryio/web-sdk' עובד, ו־TypeScript נותן לו את אותו טיפוס עם moduleResolution מסוג node16, nodenext או bundler.

בטעינה מה־CDN במקום npm, אותה מחלקה זמינה כ־window.Joryio:

const joryio = new Joryio({
sdkKey: 'jry_sdk_web_your_sdk_key_here',
});

2. זיהוי משתמשים​

שלחו מספרי טלפון עם + וקידומת מדינה

שלחו תמיד מספרי טלפון בפורמט בינלאומי מלא (E.164): +, קידומת המדינה ואז המספר - למשל +972501234567. מספר בלי + נקרא לפי מדינת ברירת המחדל למספרי טלפון של סביבת העבודה; אם לא הוגדרה, או שאפשר לקרוא את הספרות בשתי דרכים, הוא נשמר כלא מאומת ולא משמש להודעות. איך מטופלים מספרי טלפון

זהו משתמשים כשהם נרשמים או מתחברים:

// Identify a user
joryio.identify('user_123');

// Set profile attributes separately
joryio.setAttributes({
firstName: 'John',
lastName: 'Doe',
plan: 'premium',
signupDate: '2024-01-15',
});

3. מעקב אירועים​

עקבו אחרי פעולות משתמשים:

// Track a custom event
joryio.track('Product Viewed', {
product_id: 'prod_123',
product_name: 'Premium Plan',
price: 99.99,
currency: 'USD',
});

// Track page views
joryio.track('Page Viewed', {
page: '/pricing',
title: 'Pricing Page',
category: 'Marketing',
});

אפשרויות תצורה​

אפשרותסוגברירת מחדלתיאור
sdkKeystringנדרשמפתח ה־SDK מלוח הבקרה של Joryio
apiEndpointstringhttps://api-eu1.joryio.com/apiשרת ה־API של האזור שלכם. אפשר גם שם שרת בלבד; /api מתווסף
userIdstring-התחלה עם מזהה משתמש ידוע
anonymousIdstringנוצר אוטומטיתשימוש במזהה אנונימי משלכם
enableDebugbooleanfalseהפעלת יומני ניפוי שגיאות במסוף (logLevel: 'debug'). logLevel שהוגדר במפורש גובר
batchFlushIntervalnumber5000תדירות שליחת אירועים באצווה (מילישניות). אירועים מתווספים לתור ונשלחים כל 5 שניות כדי לצמצם בקשות רשת. ערכים מתחת ל־1000 מועלים ל־1000.
batchSizenumber50מספר האירועים בכל בקשה, וגודל התור שמפעיל שליחה לפני הטיימר. לעולם לא יותר מ־500 בבקשה (המגבלה של ה־API)
sendImmediatelybooleanfalseשליחת כל אירוע מיד ללא אצווה (לא מומלץ לסביבת ייצור)
sessionTimeoutnumber1800000פסק זמן סשן במילישניות (ברירת מחדל: 30 דקות). סשן חדש מתחיל לאחר תקופת חוסר פעילות זו - נבדק בכל track() וכשהלשונית חוזרת להיות גלויה.
trackSessionStartbooleantrueאירוע "Session Start" אחד לכל סשן חדש. טעינה מחדש שממשיכה את הסשן לא שולחת אירוע כזה.
trackPageViewsbooleanfalseמעקב אוטומטי אחרי "Page Viewed" בטעינת עמוד
captureUTMbooleantrueלכידה אוטומטית של פרמטרי UTM מה־URL לשיוך קמפיינים
resetSessionOnNewCampaignbooleanfalseפתיחת סשן חדש כאשר פרמטרי UTM משתנים (שימושי לאנליטיקה ברמת קמפיין)
trackDevicePropertiesbooleantrueהוספת מידע מכשיר לאירוע Session Start
persistQueuebooleantrueשמירת תור האירועים ב־localStorage כדי לשרוד רענונים
maxQueueSizenumber1000מספר האירועים המרבי שהתור המקומי מחזיק בזמן ששליחות נכשלות; מעבר לכך הישנים ביותר נמחקים (עם אזהרה ביומן כשהרישום פעיל)
maxRetriesnumber3ניסיונות חוזרים מיידיים של בקשה אחת (5xx, 429, שגיאת רשת). אצווה שעדיין נכשלת נשמרת ונשלחת שוב מאוחר יותר
retryBackoffMsnumber1000ההשהיה הראשונה לפני ניסיון חוזר, במילישניות; מוכפלת בכל כישלון, עד 5 דקות
requestTimeoutnumber10000זמן קצוב במילישניות לכל בקשת API (אירועים, מאפיינים, In-App, Push)
trackPagePropertiesbooleantrueהוספת ה־referrer ועמוד הנחיתה לאירועי "Page Viewed"
respectDoNotTrackbooleantrueהתייחסות להגדרת Do Not Track של הדפדפן כביטול מעקב
logLevelstring-'error', 'warn', 'info' או 'debug'. שום דבר לא נרשם לקונסול אלא אם הוגדר זה או enableDebug
trackingConsentstringלא מוגדר'granted', 'denied' או 'pending'. השאירו לא מוגדר אם אין באתר באנר הסכמה. ראו פרטיות והסכמה
optOutbooleanfalsetrue מבטל את המעקב אחרי המבקר ונשמר בין טעינות עמוד, כמו optOut(). false לא מבטל ביטול מעקב שמור - רק optIn() עושה זאת
enableSdkAuthenticationbooleanfalseצירוף ורענון של JWT שהשרת שלכם מנפיק. ראו אימות SDK
sdkAuthenticationTokenstring-ה־JWT הראשון, בשימוש כש־enableSdkAuthentication מופעל
pluginsarray[]תוספים עם beforeTrack / afterTrack (Web בלבד)
inApp.enabledbooleantrueהפעלה או כיבוי של הודעות In-App
inApp.evaluationModestring'differential-sync'מתי נטענים קמפייני In-App: 'differential-sync' (בטעינה, ב־identify(), ב־reset(), בסשן חדש, בשינוי מאפיין במעקב ובכל inApp.syncInterval) או 'session-start-only' (בטעינה, ב־identify(), ב־reset() ובסשן חדש בלבד)
inApp.syncIntervalnumber0 (כבוי)טעינה מחדש של קמפייני In-App כל N מילישניות במצב 'differential-sync'. ערך מתחת ל־30000 מועלה ל־30000; מושהה כשהלשונית מוסתרת
inApp.allowHtmlJsInAppMessagesbooleanfalseמאפשר הודעות In-App ב-HTML. ההודעה מוצגת ב-iframe מבודד תחת Content-Security-Policy מחמירה: רק סקריפט הגשר של ה-SDK רץ - ה-<script> שלכם, מטפלי on* בתוך התגית ו-<iframe> לא - ולכן כפתורים וטפסים עובדים דרך data-joryio-action / data-jry-form. כבוי כברירת מחדל כי הוא מציג HTML שנכתב ידנית. ההודעה אף פעם לא מנווטת את ה-iframe שלה: קישורים והפניות עוברים דרך ה-SDK, שפותח אותם בעמוד שלכם (רק קישורי http(s) וקישורים יחסיים לשורש); אם ה-iframe מנווט בכל זאת, ההודעה נסגרת. הודעות נייטיב מוצגות בכל מקרה. הודעות In-App
inApp.displayOptions.defaultPositionstring'center''top', 'center' או 'bottom': היכן מוצגת הודעה מסוג Custom. הודעות Modal, Banner, Slide-Up ו־Full-Screen שומרות על המיקום שלהן
inApp.displayOptions.defaultAnimationstring'fade''fade', 'slide' או 'none': איך ההודעות נכנסות. מדולג כשמערכת המבקר מבקשת פחות תנועה
inApp.displayOptions.backdropColorstring'rgba(0, 0, 0, 0.5)'צבע שכבת ההאפלה מאחורי הודעות Modal ו־Full-Screen
inApp.displayOptions.closeButtonColorstringצבע הטקסט של ההודעהצבע כפתור הסגירה
inApp.displayOptions.zIndexnumber999999סדר השכבות של ההודעות (שכבת ההאפלה נמצאת אחת מתחת)
inApp.onMessageDisplay / onMessageClick / onMessageDismissfunction-פונקציות לכל שלב - ראו Callbacks

אצווה ושליחה​

אירועים מקובצים מקומית לאצוות ונשלחים בקבוצות כדי לייעל את השימוש ברשת:

  • שליחה אוטומטית: כל batchFlushInterval מילישניות (ברירת מחדל 5 שניות)
  • שליחה לפי גודל: שליחה מידית כאשר מצטברים batchSize אירועים (ברירת מחדל 50)
  • שליחה ידנית: joryio.flush() שולחת אירועים בתור מיידית
  • בעת יציאה מהעמוד: האירועים בתור נמסרים לדפדפן עם fetch(..., { keepalive: true }) - בלי עוגיות, ועם כותרת האימות של ה־SDK. רק מה שנכנס במגבלת ה־keepalive של הדפדפן (64KB) נמסר - תקציב אחד לכל העמוד, לא משנה כמה אירועי יציאה נורים; השאר נשאר בתור לצפייה הבאה בעמוד. כשהדפדפן לא מחובר, או אחרי שהשליחה האחרונה נכשלה, שום דבר לא נמסר: האירועים נשארים בתור במקום לצאת בבקשה שכנראה תיכשל
  • שליחה שנכשלה לא חוסמת את התור: כל בקשה נושאת לכל היותר batchSize אירועים (ואף פעם לא יותר מ־500 או כ־900KB). בקשה שה־API דוחה כפגומה (400, 413, 422) מפוצלת עד שהאירוע הפגום היחיד נמחק; שגיאות רשת, 429 ו־5xx שומרות את כל האירועים ומנסות שוב בהשהיה הולכת וגדלה; 402 (קליטת האירועים מושהית ב־workspace שלכם), 403 או מפתח לא תקין עוצרים את שליחת האירועים עד סוף הצפייה בעמוד ושומרים אותם. אחרי 402 גם כתיבות לפרופיל ממתינות - חוץ מביטולים, שה־API עדיין מקבל ושעדיין נשלחים
  • חותמות זמן: אירועים נושאים חותמת זמן ISO 8601 ב־UTC עם מילישניות (2026-10-07T09:30:00.123Z), כמו בכל SDK של Joryio
  • success: false הוא כישלון: תשובת 2xx שגופה אומר success: false - לאצווה, ל־identify, למאפיינים, לכינוי, לשינוי מינוי או לרישום Push - נשלחת שוב ואף פעם לא נחשבת כבוצעה. באצווה נשמרים רק האירועים שה־API מפרט ב־failedIndices
  • נדחה סופית פירושו נמחק: אירועים שה־API מפרט ב־rejectedIndices נמחקים ולא נשלחים שוב. track() מוחק אירוע לפני שהוא נכנס לתור (עם שורת לוג) כשהשם שלו אינו באורך 1-255 תווים או כשהמאפיינים שלו חורגים ממגבלות ה־API: יותר מ־50 KB בסריאליזציה, יותר מ־200 מפתחות, או קינון עמוק מ־5 רמות
  • משתמש אחד לכל בקשה: בקשה אף פעם לא מערבבת אירועים של שני משתמשים, כך שאירועים בתור של משתמש שהתנתק לא מעכבים את אלה של המשתמש הבא (ראו אימות SDK)
  • כתיבות לפרופיל עמידות ושומרות על הסדר: כתיבות מאפיינים, addAlias() ושינויי מינוי וקבוצות מינוי נשמרים ב־localStorage עד שה־API מאשר אותם, כך שמעבר עמוד או לשונית שנסגרה לא מאבדים אותם, וביציאה מהעמוד אלה שממתינים נמסרים גם ל־fetch(..., { keepalive: true }). שינוי חדש יותר לאותו ערוץ, קבוצה או מאפיין מחליף שינוי ישן יותר שעדיין ממתין, כך ששינוי ישן אף פעם לא מגיע אחרי שינוי חדש
  • כלל ניסיון חוזר אחד לכל כתיבה (כולל identify()): שגיאות רשת, זמן קצוב שפג, 429, 5xx ו־402 אף פעם לא נספרים מולו ונשלחים שוב בהשהיה הולכת וגדלה; 404 ("עדיין אין פרופיל") נשלח שוב לכל היותר 5 פעמים, וכל דחייה אחרת שאפשר לנסות שוב (success: false, 401 של אימות SDK עבור המשתמש הנוכחי) לכל היותר 10 פעמים; 400, 403, 409, 413 ו־422 מוחקים את הכתיבה עם שורת לוג
  • תקרת תור: התור המקומי מחזיק עד maxQueueSize אירועים (ברירת מחדל 1,000); מעבר לכך (למשל בתקופות ארוכות ללא חיבור) האירועים הישנים ביותר נמחקים מהתור (עם אזהרה ביומן כשהרישום פעיל)
// Send events immediately instead of batching
const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_...',
sendImmediately: true // Send each event immediately
});

// Or configure batching behavior
const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_...',
batchFlushInterval: 10000, // Flush every 10 seconds
batchSize: 20 // Or when 20 events accumulate
});

// Or manually flush at any time
joryio.track('Important Event', {...});
joryio.flush(); // Send now

ניהול סשנים​

סשנים עוקבים אחרי פעילות רציפה ומנוהלים אוטומטית:

  • פסק זמן סשן: ברירת מחדל 30 דקות ללא פעילות (sessionTimeout)
  • סשן חדש מתחיל כאשר:
    1. המשתמש טוען את העמוד לראשונה
    2. פסק זמן הסשן חלף ללא אירועים
    3. המשתמש קורא joryio.reset() (למשל, ביציאה)
    4. מזוהה קמפיין חדש (אם resetSessionOnNewCampaign מופעל)

הגדרת פסק זמן סשן:

const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_...',
sessionTimeout: 3600000 // 1 hour in milliseconds
});

// Or shorter session timeout
const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_...',
sessionTimeout: 600000 // 10 minutes
});
טיפ

סשנים מנוהלים אוטומטית לפי פעילות המשתמש. כל אירוע מאפס את הטיימר של חוסר פעילות.

מעקב Session Start​

ברירת מחדל: ה־SDK עוקב אוטומטית אחרי אירוע "Session Start" בכל פעם שמתחיל סשן חדש. האירוע הזה:

  • יכול לשמש כטריגר בקמפיינים ובמסעות
  • כולל הקשר סשן מלא (פרמטרי UTM, referrer, עמוד נחיתה, וכאשר trackDeviceProperties פעיל - נתוני מכשיר)
  • נשמר בפרופיל המשתמש כמו כל אירוע אחר, כך שסגמנטים ואנליטיקה יכולים לספור סשנים לכל משתמש

דוגמת אירוע Session Start:

// Automatically tracked when user visits your site
{
event: "Session Start",
properties: {
utm_source: "google", // If UTM parameters present
utm_medium: "cpc",
utm_campaign: "spring_sale",
referrer: "https://google.com",
landing_page: "https://example.com/..."
},
userId: "user_123", // If identified
anonymousId: "anon_456",
sessionId: "sess_789"
}

נתוני סשן אוטומטיים​

Web SDK מעשיר אירועי Session Start בנתוני מכשיר וסביבה:

  • $user_agent
  • $timezone
  • $screen_width / $screen_height
  • $viewport_width / $viewport_height
  • $language / $languages
  • $platform
  • $browser
  • $device_id
  • country (ISO-3166-1 alpha-2, נגזר מה־IP בתחילת סשן)

מקרי שימוש:

  1. מסעות קבלת פנים: השתמשו ב־Session Start כטריגר של מסע כדי להגיע למשתמשים כשהם מגיעים לאתר.

  2. סגמנטים מבוססי סשנים: אירועי Session Start נשמרים לכל משתמש, כך שתנאי סגמנט מבוססי אירועים יכולים לספור אותם - למשל, "ביצע Session Start לפחות 10 פעמים" (משתמשים כבדים) או "לא ביצע Session Start ב־7 הימים האחרונים" (חידוש מעורבות).

  3. שיוך קמפיינים: סננו באנליטיקה על Session Start וקבצו לפי utm_campaign כדי לראות אילו קמפיינים מייצרים הכי הרבה סשנים.

כיבוי מעקב Session Start:

const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_...',
trackSessionStart: false // Disable automatic session start events
});

הודעות In-App​

ה־SDK מציג עבורכם הודעות In-App. קמפיינים מתאימים מופיעים מעצמם, וחשיפות, קליקים וסגירות נמדדים אוטומטית.

אסימוני שליחה (delivery tokens)​

כאשר השרת מגיש קמפיין מתאים, הוא מנפיק עבורו גם אסימון שליחה חתום וקצר-מועד. ה-SDK מחזיר את האסימון כשהוא מדווח על הצגה, קליק או סגירה, והשרת מאמת את החתימה לפני שהוא רושם משהו.

אינך צריך לעשות דבר - ה-SDK מטפל בזה עבורך. התיעוד כאן קיים כי ניתן להגדיר את השרת לדרוש את האסימון. כברירת מחדל דיווח ללא אסימון עדיין מתקבל - השרת רושם אותו ביומן כלקוח מגרסה שקדמה לאסימונים - ורק כאשר השרת רץ עם IN_APP_REQUIRE_DELIVERY_TOKEN=true אותו דיווח נדחה:

POST /v1/in-app/track (no deliveryToken)
{ "success": false, "error": "A delivery token is required" }

אסימון שנשלח אך אינו עובר אימות - מזויף, שונה או שפג תוקפו - נדחה תמיד, ללא קשר להגדרה.

האסימון הוא מה שהופך דיווח הצגה לאמין: בלעדיו, כל מי שמחזיק במפתח ה-SDK - שנשלח בתוך כל אפליקציה ובכל עמוד - היה יכול לדווח על הצגות וקליקים לקמפיין שמעולם לא הוצג, והדוחות שלך היו סופרים אותם.

אתרים שטוענים את החבילה המתארחת מ-https://sdk.joryio.com/web/1/joryio.min.js מקבלים זאת אוטומטית.

שני סוגי תוכן​

תוכןמה זהאיך זה מוצג
Nativeנתונים מובנים - כותרת, טקסט, תמונה, כפתוריםאלמנטים רגילים ב־DOM, שנכנסים כטקסט. ללא iframe וללא הרצת סקריפט.
HTMLקוד HTML ו־CSS שנכתב על ידי המחבר. נשמר כפי שנכתב (רק <base> ו־<meta http-equiv="refresh"> מוסרים)iframe מבודד בדף שלכם, תחת Content-Security-Policy חדשה לכל הודעה, שבו רץ רק סקריפט הגשר של ה־SDK.

הפעלת הודעות HTML​

הודעות HTML כבויות כברירת מחדל. הסקריפטים שלכם לא רצים בהן: Joryio שומר את הקוד כפי שנכתב, אבל כל הודעה מקבלת Content-Security-Policy חדשה עם nonce חדש, כך שרק סקריפט הגשר של ה־SDK רץ - בלוקי <script> ומטפלי on* של המחבר לא פועלים, וה־iframe לא יכול לבצע קריאות רשת (connect-src 'none') או לשלוח טפסים (form-action 'none'). אבל ה־iframe הזה יכול להריץ סקריפט במקור (origin) של הדף שלכם, ולכן הסיכון שנותר הוא פרצה במדיניות הזו, למשל דפדפן שלא אוכף אותה - ומשום כך ההפעלה היא החלטה של הצוות שלכם, לא משהו שמפעילים ממערכת השיווק:

const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_YOUR_KEY',
inApp: {
allowHtmlJsInAppMessages: true, // ברירת מחדל: false
},
});

השארת ההגדרה כבויה אינה מבטלת הודעות In-App. הודעות Native ימשיכו להופיע, כי הן נתונים שנכתבים כטקסט ב־DOM - ללא מפרש כלשהו. קמפייני HTML מדולגים (עם אזהרה ביומן כשהרישום פעיל). קמפיין שדולג לא צורך חשיפה ונשאר זמין.

אם ה־Content Security Policy שלכם אוסר סקריפטים מוטבעים או תוכן ב־iframe, השאירו את ההגדרה כבויה וכתבו את הקמפיינים כהודעות Native.

עיצוב הודעות Native מה-CSS שלכם​

הודעת Native היא DOM אמיתי בעמוד שלכם, לא iframe, ולכן אפשר לעצב אותה כמו כל רכיב אחר שלכם. הרנדרר מייצר נקודות אחיזה יציבות:

.joryio-inapp-native /* הכרטיס */
.joryio-inapp-native h2 /* כותרת */
.joryio-inapp-native p /* גוף ההודעה */
.joryio-inapp-native img /* תמונה */
.joryio-inapp-native button.primary /* הכפתור הראשון */
.joryio-inapp-native button.secondary /* השאר */
.joryio-inapp-close /* כפתור הסגירה */
.joryio-inapp-backdrop /* שכבת ההכהיה */
.joryio-inapp-modal / -banner / -slideup / -fullscreen /* לפי סוג */

עדיף להשתמש במשתנים ולא בסלקטורים. כל מה שקמפיין יכול להגדיר נקרא ממשתנה CSS, ולכן הגדרה על :root נותנת סגנון בית שקמפיין עדיין יכול לדרוס להודעה מסוימת:

:root {
--joryio-inapp-bg: #0A1240;
--joryio-inapp-fg: #FFFFFF;
--joryio-inapp-primary: #00C8B7;
--joryio-inapp-primary-fg: #041028;
--joryio-inapp-radius: 18px;
--joryio-inapp-font: 'Inter', system-ui, sans-serif;
--joryio-inapp-size: 15px;
--joryio-inapp-align: start; /* start | center | end */
--joryio-inapp-title-weight: 700;
}

סדר הקדימות, מהגבוה לנמוך:

  1. מה שהקמפיין הגדיר ב-Style (optional) - נכתב inline על הכרטיס
  2. הערכים שלכם ב-‎--joryio-inapp-*
  3. ברירות המחדל של ה-SDK, שהן צבעי מערכת

כך קמפיין שלא הגדיר דבר יורש את סגנון הבית שלכם, וקמפיין שהגדיר רקע מנצח להודעה הזו בלבד. בלי !important בשום מקום.

אם בכל זאת תשתמשו בסלקטורים, שימו לב שגיליון הסגנון של ה-SDK מוזרק בזמן ההצגה ולכן מגיע אחרי שלכם בסדר המסמך, ומנצח בתיקו. הוסיפו ספציפיות - ‏.joryio-inapp .joryio-inapp-native {…} - במקום כלל של מחלקה בודדת.

כיווניות מטופלת עבורכם: הכרטיס נושא dir="auto", ולכן הודעה בעברית או בערבית מיושרת לימין ומציבה את הכפתור הראשי בימין, גם בתוך עמוד שכולו משמאל לימין.

סוגי הודעות​

  1. Modal - במרכז המסך עם רקע מוצל
  2. Banner - בראש הדף
  3. Slide-Up - התראה קטנה מלמטה
  4. Full-Screen - הודעה שתופסת את כל המסך
  5. Custom - הדף שלכם קובע את המיקום

אפשרויות תצוגה​

const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_YOUR_KEY',
inApp: {
displayOptions: {
defaultPosition: 'bottom', // Custom-type messages only
defaultAnimation: 'slide', // 'fade' (default), 'slide' or 'none'
backdropColor: 'rgba(10, 18, 64, 0.6)',
closeButtonColor: '#ffffff',
zIndex: 2147483000,
},
},
});

Callbacks​

כל פונקציה מקבלת את ההודעה; הקמפיין שלה הוא message.campaign (message.campaign.id, message.campaign.name).

const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_YOUR_KEY',
inApp: {
onMessageDisplay: (message) => console.log('shown', message.campaign.id),
onMessageClick: (message, action) => console.log('clicked', message.campaign.id, action), // action: the button id
onMessageDismiss: (message, action) => console.log('dismissed', message.campaign.id, action), // e.g. 'close_button'
},
});

הפונקציות האלה הן התראות בלבד: ה־SDK עדיין מצייר את ההודעה.

callback שזורק שגיאה נרשם בלוג ומתעלמים ממנו: ה־SDK עדיין מתעד את החשיפה, ההקלקה או הסגירה, ומנקה אחריו.

כששני טריגרים מופעלים יחד (אותו אירוע פעמיים, למשל), ההודעה מוצגת - ונספרת - פעם אחת.

שליטה ידנית​

await joryio.syncInAppCampaigns(); // fetch campaigns now
const campaigns = joryio.getInAppCampaigns(); // what is currently eligible
await joryio.displayInAppCampaign(campaignId); // show one now
joryio.dismissInAppMessage(campaignId); // close it
await joryio.trackInAppConversion(campaignId, eventName); // record a conversion
מתודהתיאור
syncInAppCampaigns(attributeChanges?)בקשה מהשרת של הקמפיינים של המבקר עכשיו. לא עושה דבר כשהמעקב כבוי או כשההסכמה ממתינה
getInAppCampaigns()הקמפיינים הזמינים כרגע, כפי שסונכרנו
displayInAppCampaign(campaignId)הצגת אחד מהקמפיינים האלה עכשיו (מגבלת התדירות שלו עדיין חלה)
dismissInAppMessage(campaignId)סגירת הודעה מוצגת (נרשמת כ־dismissed)
trackInAppConversion(campaignId, eventName)רישום המרה לקמפיין

מתי הודעה נחשבת כמוצגת​

הודעה נחשבת כמוצגת - כלומר in_app.displayed מדווח ומגבלת התדירות של הקמפיין נצרכת - רק כשהאדם יכול היה לראות אותה. משך הזמן שעליה להיות על המסך הוא IN_APP_DISPLAY_DWELL_MS (1000 מילישניות), אותו קבוע בכל ה-SDK של Joryio.

  • הודעה מופיעה רק אחרי שהעמוד סיים להיטען ונרגע, ולעולם לא בזמן שהעמוד נפרק (הפניה, מעבר בקישור, סגירת הלשונית).
  • היא נחשבת כמוצגת אחרי שהייתה על המסך שנייה אחת כשהלשונית גלויה. אם הלשונית מוסתרת לפני כן, השנייה מתחילה מחדש כשהיא גלויה שוב.
  • אם העמוד נפרק לפני כן - הפניה אחרי התחברות, קישור התנתקות - שום דבר לא מדווח, המגבלה לא נצרכת, וההודעה מוצגת שוב בעמוד הבא.
  • לחיצה או סגירה לפני כן נחשבות כצפייה: קודם מדווח displayed, ואחריו הלחיצה או הסגירה. הסרת ההודעה מהקוד (dismissInAppMessage, reset()) לפני כן לא מדווחת דבר.
  • onDisplay נקרא כשההודעה נחשבת כמוצגת, יחד עם הדיווח - לא כשהיא עולה למסך. החבילה מייצאת את IN_APP_DISPLAY_DWELL_MS.

שני מתגים בלתי תלויים קובעים אם נאסף משהו: הסכמה (התשובה לבאנר העוגיות שלכם) וביטול המעקב של המבקר עצמו. ה־SDK אוסף רק כשההסכמה ניתנה וגם המבקר לא ביטל מעקב - כל "לא" גובר.

joryio.updateConsent('granted'); // or 'denied' or 'pending'
joryio.optOut(); // remembered across page loads until optIn()
joryio.optIn();

joryio.ready(function (sdk) {
sdk.getTrackingConsent(); // 'granted' | 'denied' | 'pending'
sdk.isUserOptedOut(); // the opt-out switch only
});
מצבמה ה־SDK עושה
הסכמה granted (או שלא הוגדרה, ואין סירוב שמור)אוסף ושולח כרגיל
הסכמה pendingאוסף מקומית ולא שולח דבר - בלי Session Start, בלי סנכרון In-App, בלי רישום Push - עד ש־updateConsent('granted') משחרר הכול. updateConsent('denied') מוחק את זה. מה שמוחזק נשמר ב־localStorage, כך שטעינה מחדש לא מאבדת אותו: אירועים ו־identify() (עד maxQueueSize אירועים), כתיבות מאפיינים (עד 500) ושינויי כינוי ומינוי (עד 200). ביטולי מינוי הם החריג: הם נשלחים בכל מקרה. ה־Service Worker של Web Push לא מדווח בינתיים על מסירות והקלקות
הסכמה deniedלא אוסף דבר ומוחק את כל מה שבתור. ה־Service Worker מפסיק לדווח על מסירות והקלקות
optOut()לא אוסף דבר, מוחק אירועים בתור וכתיבות ממתינות של מאפיינים, כינויים והרשמות למינוי (ביטולי מינוי עדיין נמסרים), ונשמר כך שהוא שורד טעינה מחדש. ה־Service Worker של Web Push עדיין מציג התראות אבל מפסיק לדווח על מסירות והקלקות
Do Not Trackנחשב כביטול מעקב כל עוד respectDoNotTrack הוא true (ברירת המחדל)

איך שני המתגים מתנהגים:

  • denied נשמר. הוא נשאר בתוקף בצפיות הבאות עד updateConsent('granted') או trackingConsent: 'granted' מפורש בקונפיגורציית ה־init. השארת trackingConsent לא מוגדר שומרת סירוב שמור - ולכן לאפשרות אין ברירת מחדל.
  • pending הוא לצפייה אחת. הוא אף פעם לא נשמר, ואף פעם לא גובר על סירוב שמור.
  • הסכמה אף פעם לא מבטלת ביטול מעקב. updateConsent('granted') לא מבטל את optOut(); רק optIn() עושה זאת. optOut() ו־optIn() אף פעם לא משנים את ההסכמה השמורה.
  • הפרופיל מתעד את ביטול המעקב. כשמתג ביטול המעקב משתנה - כולל optOut: true ב־init - ה־SDK כותב tracking_opted_out (true או false) לפרופיל, עם המזהים של המבקר שעשה את הבחירה, ומנסה שוב לפי כלל הניסיון החוזר. שום דבר לא נשלח כשהמתג לא השתנה. true נשלח גם כשההסכמה denied או pending; false ממתין עד שהמעקב מותר.
  • ביטולים נמסרים תמיד. ביטול מינוי (SubscriptionStatus.UNSUBSCRIBED, removeFromSubscriptionGroup()), הסימון tracking_opted_out וביטול רישום Push נשלחים גם כשהמבקר ביטל מעקב, כשההסכמה denied או pending, ואחרי wipeData(). כל כתיבה אחרת נעצרת יחד איתם.
  • סשן שהתחיל כשהמעקב היה כבוי מקבל את ה־Session Start היחיד שלו כשההסכמה ניתנת או כשהמבקר חוזר למעקב.
  • identify() כשהמעקב כבוי (הסכמה נדחתה, או ביטול מעקב) לא שולח דבר ולא כותב דבר לפרופיל. מזהה המשתמש נשמר במכשיר הזה בלבד, כדי שביטול מינוי או ביטול מעקב מאוחר יותר יגיעו לאותו אדם ולא לפרופיל אנונימי; ה־identify() הרגיל רץ כשהמעקב מותר שוב. reset() ו־wipeData() שוכחים אותו. בהסכמה או בחזרה למעקב, ה־identify() שנשמר רץ לפני ה־Session Start של סשן שהתחיל בינתיים, כך שהסשן הזה שייך למשתמש החדש. המזהה השמור משמש לכל ביטול: ביטול מינוי, ביטול מינוי לקבוצה, הסמן tracking_opted_out ו־push.unsubscribe(). identify() אחרי שהמעקב מותר מחליף אותו, ו־userId מפורש בהגדרות האתחול גובר עליו.
  • כל הלשוניות הפתוחות מתעדכנות. ביטול מעקב, שינוי הסכמה, reset() או identify() שנעשו בלשונית אחת של האתר חלים מיד על הלשוניות הפתוחות האחרות, ולא רק בטעינה הבאה שלהן. התנתקות בלשונית אחת היא reset() מלא באחרות: הן עוברות למבקר החדש ולסשן החדש, וכתיבות שעשו עבור המשתמש היוצא נשארות שלו. הסכמה בלשונית אחת משחררת גם לשונית שממתינה ב־pending. לשונית או סקריפט אחר שקוראים ל־localStorage.clear() לעולם לא מבטלים ביטול מעקב או דחייה - הלשונית שומרת את ההחלטה ורושמת אותה מחדש. כתיבות הפרופיל והאסימונים של משתמשים שהתנתקו, שכל לשונית שומרת ב־localStorage, ממוזגים, ואף לשונית לא דורסת אותם. גם המשתמש ש־identify() שומר לביטולים בזמן שהמעקב כבוי מתעדכן בכל הלשוניות. updateConsent('granted') או optIn() מפורשים שנעשים מיד אחרי localStorage.clear() כזה חדשים יותר מההחלטה השמורה וגוברים בכל הלשוניות. כתיבת פרופיל שלשונית אחרת כבר מסרה, או החליפה בכתיבה חדשה יותר, לעולם לא נשלחת מהלשונית הזו, ו־wipeData() בלשונית אחת מוחק גם את הכתיבות הממתינות של הלשוניות האחרות (מלבד ביטולים).
  • עם ה־snippet האסינכרוני, הקריאות האלה נכנסות לתוקף לפני ש־init שולח משהו - ראו Snippet אסינכרוני.

מחיקת הנתונים המקומיים​

await joryio.wipeData();

מוחק את כל מה שה־SDK שומר על המבקר בדפדפן הזה: הזהות (מזהה אנונימי חדש, בלי מזהה משתמש), אירועים בתור ו־identify() ממתין, כתיבות מאפיינים, כינויים ומינויים ממתינות, מצב In-App והיסטוריית חשיפות, הסשן, נתוני UTM, מזהה המכשיר ומינוי ה־Push (שמבוטל גם מול Joryio; הוא נשאר מבוטל עד שקוראים שוב ל־push.subscribe()). ביטולים שעדיין ממתינים - ביטול מינוי, סימון ביטול המעקב, ביטול רישום ה־Push - עדיין נמסרים, עם המזהים שאיתם נעשו. הוא שומר את ביטול המעקב ואת הסירוב להסכמה, ולא מבטל מעקב לאף אחד - בשביל זה יש optOut(). המעקב ממשיך כמבקר אנונימי חדש, בסשן חדש עם Session Start משלו.

תיעוד API​

Initialize​

const joryio = new JoryioSDK(config)

אתחול ה־SDK עם ההגדרות שלכם. הבנאי מחזיר מופע יחיד - בנייה שנייה מחזירה את המופע הקיים, שגם JoryioSDK.getInstance() מחזיר (או null לפני האתחול).

ה־SDK אף פעם לא זורק שגיאה אל הדף שלכם. sdkKey חסר או שגוי נרשם פעם אחת, בכל רמת רישום, והמופע הזה מתעלם מכל קריאה; ארגומנט null במקום שבו הוא נדרש נרשם ביומן ונדחה.

Identify​

joryio.identify(userId)

שיוך מזהה משתמש לסשן הנוכחי.

פרמטרים:

  • userId (string): מזהה ייחודי למשתמש

דוגמה:

joryio.identify('user_123');
joryio.setAttributes({
name: 'John Doe',
plan: 'premium',
});

Track​

joryio.track(eventName, properties?)

מעקב אחרי אירוע מותאם עם מאפיינים לפי הצורך.

פרמטרים:

  • eventName (string): שם האירוע
  • properties (object, optional): מאפייני אירוע

דוגמה:

joryio.track('Plan Upgraded', {
from_plan: 'basic',
to_plan: 'premium',
});

לרכישות השתמשו בכלי ה־E-Commerce, ששולח את המפתחות שדוחות ההכנסות קוראים (orderId ו־total באירוע Order Completed):

joryio.ecommerce({ currency: 'USD' }).purchase({
orderId: 'order_789',
items: [{ productId: 'SKU123', name: 'Blue Shirt', price: 49.99, quantity: 3 }],
value: 149.99, // sent as `total`
});

כל המתודות של הכלי מתוארות ב־מעקב E-Commerce. כל מתודה בודקת את הארגומנטים הנדרשים שלה - productId, orderId, value סופי של ההזמנה, מערך items - וכשאחד מהם חסר היא רושמת אזהרה ביומן ולא שולחת דבר (אף פעם לא הזמנה ריקה או בערך אפס). היא אף פעם לא זורקת שגיאה אל הדף שלכם. ecommerce() מקבל אפשרות אחת, currency (ברירת מחדל 'USD').

מעקב צפיות עמוד

אפשר להפעיל מעקב אוטומטי אחר צפיות עמוד:

const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_...',
trackPageViews: true
});

Add Alias​

joryio.addAlias(aliasLabel, aliasName)

הוספת כינוי עם תווית למבקר הזה. עובד גם לפני identify(): הבקשה נושאת את המזהה האנונימי (ואת מזהה המשתמש אחרי זיהוי), והכינוי מוצמד לפרופיל שאליו הם מובילים.

כדי לקשר מבקר אנונימי למזהה המשתמש שלו, קראו ל־identify(). בהתחברות ראשונה הפרופיל האנונימי הופך לפרופיל המשתמש, עם כל ההיסטוריה; אם כבר יש למשתמש פרופיל, הפרופיל האנונימי ממוזג אליו. alias() ללא תווית הוסר בגרסה 1.3.0.

דוגמה:

joryio.addAlias('crm', 'crm_98765');

Reset​

joryio.reset()

התנתקות המשתמש הנוכחי. המבקר מקבל מזהה אנונימי חדש וסשן חדש; הודעות ה־In-App של המשתמש הקודם מנוקות ואסימון אימות ה־SDK שלו נשכח; כתיבות המאפיינים, הכינויים והמינויים שלו שעדיין לא אושרו עדיין נשלחות, עם המזהים שלו - אף פעם לא עם אלה של המבקר הבא; נתוני ה־UTM (כולל attribution ראשון ואחרון) מנוקים; קמפייני In-App נטענים עבור המבקר החדש; ומינוי Push קיים נרשם מחדש תחת המזהה האנונימי החדש, כך שהתראות המשתמש הקודם מפסיקות להגיע לדפדפן הזה.

הזהות החדשה קיימת ברגע ש־reset() חוזר. ה־Promise שהוא מחזיר מכסה רק את שליחת מה שכבר היה בתור (כל אירוע בתור שומר את המזהים שאיתם נרשם), ולכן reset(); identify(nextUser) בטוח גם בלי await.

דוגמה:

// On user logout
function handleLogout() {
joryio.reset();
// ... other logout logic
}

קבלת מזהה אנונימי​

joryio.getAnonymousId()

מחזיר את המזהה האנונימי הנוכחי - המזהה ש־Joryio מקצה לכל מבקר לפני שהוא מזוהה. הוא נוצר באתחול הראשון, נשמר ב־localStorage, ויציב לאורך טעינות עמודים למשך כל חיי המבקר האנונימי (reset() יוצר אותו מחדש בעת התנתקות). זהו בדיוק ה־anonymousId המצורף לכל אירוע ש־track() שולח, כך שאפשר להשתמש בו כדי לקשר אירוע צד־שרת או רשומת הסכמה לאותו פרופיל.

מחזיר:

  • string - המזהה האנונימי (תמיד קיים)
קראו אותו לאחר שה־SDK נטען

עם ה־snippet האסינכרוני, window.joryio הוא תור פקודות עד שה־SDK מסיים להיטען, וקריאה בתור אינה יכולה להחזיר ערך. קראו את המזהה על המופע המזוהה לאחר הטעינה, או מתוך ready() (למטה).

דוגמה:

joryio.ready(function (sdk) {
const anonId = sdk.getAnonymousId();
fetch('/consent', { method: 'POST', body: JSON.stringify({ anonymousId: anonId }) });
});

קבלת מזהה משתמש​

joryio.getUserId()

מחזיר את מזהה המשתמש המזוהה הנוכחי, או null אם המבקר עדיין אנונימי (כלומר identify() לא נקרא).

מחזיר:

  • string | null

דוגמה:

joryio.ready(function (sdk) {
const userId = sdk.getUserId(); // null עד שתקראו ל־joryio.identify(...)
});

Ready​

joryio.ready(callback)

מריץ את callback(sdk) לאחר שה־SDK נטען ואותחל. זו הדרך הבטוחה לקרוא ערך (כגון getAnonymousId() / getUserId()) שקריאת stub בתור אינה יכולה להחזיר לפני הטעינה. ה־callback מקבל את מופע ה־SDK; אם ה־SDK כבר נטען, הוא רץ מיד.

דוגמה:

joryio.ready(function (sdk) {
console.log('anon:', sdk.getAnonymousId(), 'user:', sdk.getUserId());
});

Get UTM Data​

joryio.getUTMData()

קבלת פרמטרי UTM נוכחיים, first touch ו־last touch.

החזרה:

  • אובייקט עם current, firstTouch, ו־lastTouch

דוגמה:

const utmData = joryio.getUTMData();
console.log(utmData.current?.utm_source); // "google"
console.log(utmData.firstTouch?.utm_campaign); // "awareness_campaign"
console.log(utmData.lastTouch?.utm_campaign); // "conversion_campaign"

Update UTM​

joryio.updateUTM()

עדכון ידני של פרמטרי UTM מה־URL הנוכחי. שימושי עבור SPA שמשנות URL ללא רענון.

דוגמה:

// React Router
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

function App() {
const location = useLocation();

useEffect(() => {
joryio.updateUTM();
}, [location]);
}

// Vue Router
router.afterEach(() => {
joryio.updateUTM();
});

מאפיינים​

joryio.setAttributes(attributes)
joryio.setAttribute(key, value)
joryio.incrementAttribute(key, by?)
joryio.unsetAttribute(key)
  • setAttributes({ plan: 'pro', city: 'Athens' }) מגדיר כמה מאפיינים יחד; setAttribute('plan', 'pro') מגדיר אחד.
  • ערך null או undefined מוחק את המאפיין, בדיוק כמו unsetAttribute(key).
  • ערך ש־JSON לא יכול לשאת - NaN, Infinity, BigInt, פונקציה, אובייקט שמפנה לעצמו - נזרק עם אזהרה ביומן: המפתח הזה נשמט ושאר הקריאה ממשיכה. אותו דבר לגבי מאפייני אירוע. ערך פגום אחד אף פעם לא מעכב כתיבות אחרות.
  • incrementAttribute('logins', 1) מוסיף למספר בשרת (ברירת מחדל 1), כך ששתי לשוניות לעולם לא דורסות זו את הספירה של זו.
  • כתיבות סמוכות נשלחות בבקשה אחת. הן ממתינות ש־identify() ממתין יגיע לשרת קודם, נשמרות ב־localStorage עד שהן מאושרות, וכתיבה שנכשלה נשלחת שוב לפי כלל הניסיון החוזר.
  • כתיבה שומרת את הזהות שתחתיה נעשתה: כתיבה שנעשתה רגע לפני identify() נשלחת עם מזהה המשתמש הזה ברגע שה־identify הגיע לשרת; כתיבה של משתמש A שעדיין ממתינה כשנקראים identify('B') או reset() עדיין הולכת ל־A.

מאפייני מערך​

joryio.addToArray(key, value)
joryio.removeFromArray(key, value)

ניהול מאפייני מערך בצורה יעילה.

פרמטרים:

  • key (string): שם המאפיין
  • value (any): ערך להוספה או להסרה

דוגמה:

// Add tags to user
joryio.addToArray('tags', 'vip');
joryio.addToArray('tags', 'premium');
// Result: tags = ['vip', 'premium']

// Add duplicate (no-op, prevents duplicates)
joryio.addToArray('tags', 'vip');
// Result: tags = ['vip', 'premium'] (unchanged)

// Remove tag
joryio.removeFromArray('tags', 'vip');
// Result: tags = ['premium']

// Common use cases
joryio.addToArray('interests', 'technology');
joryio.addToArray('purchasedProducts', 'prod_123');
joryio.addToArray('featureFlags', 'beta-access');

התנהגות:

  • addToArray() מוסיף ערך רק אם אינו קיים (מונע כפילויות)
  • addToArray() יוצר מערך חדש אם המאפיין לא קיים
  • removeFromArray() מסיר את כל המופעים של הערך
  • השינויים מסתנכרנים אוטומטית לצד השרת, גם למשתמשים מזוהים וגם לאנונימיים

קריאות על אותו מאפיין שומרות על הסדר שלהן: שתי קריאות addToArray() על אותו מפתח מגיעות שתיהן לשרת, ו־addToArray() ואחריו removeFromArray() של אותו מפתח נשלחים בזה אחר זה, אף פעם לא באותה בקשה.

Flush​

await joryio.flush()

שליחת מה שבתור עכשיו במקום לחכות לאצווה הבאה. ממתין גם לשליחה שכבר מתבצעת.

flush() מדלג על ה־backoff של ה־SDK עצמו, אבל אף פעם לא על Retry-After שה־API ביקש.

פרטי זהות וסשן​

joryio.getIdentity() // { userId, anonymousId, attributes }
joryio.getSessionInfo() // { sessionId, sessionStart, lastActivity, isNewSession }

attributes מכיל את מה שהדף הזה הגדיר (הוא לא נקרא מהשרת).

joryio.getTrackingConsent() // 'granted' | 'denied' | 'pending'
joryio.isUserOptedOut() // true after optOut(), until optIn()

isUserOptedOut() משקף רק את ביטול המעקב של המבקר עצמו - לא את ההסכמה ולא את Do Not Track. ראו פרטיות והסכמה. עם ה־snippet האסינכרוני, קראו להן בתוך ready().

Destroy​

await joryio.destroy()

שליחת מה שבתור, עצירת כל הטיימרים, הסרת המאזינים מהדף ופריקת התוספים. new JoryioSDK(config) מאוחר יותר יוצר מופע חדש.

Web Push​

Web Push דורש service worker במקור (origin) שלכם (הדפדפנים מחייבים זאת). אחסנו בשורש האתר קובץ בשם joryio-sw.js עם שורה אחת:

importScripts('https://sdk.joryio.com/web/1/joryio-sw.js');

לאחר מכן בקשו הרשאה מתוך פעולת משתמש, כמו לחיצה על כפתור:

if (joryio.push.isSupported() && joryio.push.getPermissionState() === 'notDetermined') {
button.onclick = () => joryio.push.subscribe();
}
מתודהתיאור
push.isSupported()האם הדפדפן הזה תומך ב־Web Push בכלל (נדרשים HTTPS, service worker ו־Push API)
push.getPermissionState()'granted', 'denied', 'notDetermined' או 'unavailable' - אותם שמות בכל SDK של Joryio
push.prepare(options?)רישום ה־service worker ושליפת המפתח מראש, כך ש־subscribe() מאוחר יותר מציג את הבקשה מיד. אף פעם לא מציג בקשת הרשאה
push.subscribe(options?)בקשת הרשאה (אם צריך), הרשמה, ורישום הדפדפן ב־Joryio. מחזיר את המינוי, או null
push.getExistingSubscription(options?)המינוי הנוכחי, בלי בקשת הרשאה
push.unsubscribe(options?)הסרת המינוי של הדפדפן וביטול הרישום שלו ב־Joryio. הוא נשאר מבוטל בביקורים הבאים עד שקוראים שוב ל־subscribe(). אף פעם לא נדחה; מחזיר false כשלא היה מה להסיר

options מקבל swPath (ברירת מחדל '/joryio-sw.js') ו־scope (ברירת מחדל '/') אם ה־worker מאוחסן במקום אחר.

אין צורך לקרוא שוב ל־subscribe() בביקורים הבאים. כשההרשאה כבר ניתנה, ה־SDK בודק את המינוי של הדפדפן בטעינה ורושם אותו מחדש אם הדפדפן החליף אותו, אם המפתח של ה־workspace השתנה (הוא נרשם מחדש בלי בקשת הרשאה), או אחרי reset() - אלא אם נקרא unsubscribe(). כל רישום נושא את מזהה המכשיר הקבוע של ה־SDK. שום דבר לא נרשם כשהמעקב בוטל או כשההסכמה ממתינה. ביטול הרישום של unsubscribe() הוא ביטול: הוא נשלח גם אז, נשמר עד שה־API עונה, ונשלח שוב לפי כלל הניסיון החוזר. רישום מחדש של אותו דפדפן מבטל ביטול רישום שעוד לא נשלח.

ה־service worker מציג כל Push עם הכותרת, הגוף, האייקון, התמונה, ה־badge, הפעולות, ה־tag (Push חדש עם אותו tag מחליף את זה שעל המסך) ו־requireInteraction (נשאר עד שסוגרים אותו), מדווח על המסירה ורושם את הלחיצה. הוא קורא את המפתחות האלה מה־data של ה־Push, אותם שמות שה־SDK של Android ו־iOS קוראים:

מפתחהשפעה
trackingIdמשמש לאישור המסירה ולמעקב הלחיצה. חסר בשליחות בדיקה, שלא נספרות
jry_deep_linkהעמוד שלחיצה פותחת (שורש האתר כשהוא חסר)
jry_image_urlתמונה גדולה, בדפדפנים שמציגים אותה
jry_api_originלאן ה־worker שולח את אישור המסירה ואת הלחיצה
jry_campaign_idמזהה הקמפיין, או מזהה המסע בשליחה ממסע. לידיעה בלבד

אימות SDK​

אופציונלי. כשהוא מופעל, כל בקשה נושאת JWT שהשרת שלכם מנפיק, בכותרת X-Joryio-Auth, וה־SDK מרענן אותו כשה־API דוחה אותו. האסימון מוכיח מי הוא מבקר מזוהה: מבקרים אנונימיים ממשיכים לעבוד בלעדיו.

השרת שלכם חותם על ה־JWT במפתח שאתם רושמים ב־Joryio, עם sub שתואם את מזהה המשתמש שאתם מעבירים ל־identify(). אסימון שגוי, שפג תוקפו או חסר נענה ב־401 { error: 'sdk_authentication_error', reason: 'missing' | 'invalid' | 'expired' | 'sub_mismatch' }.

const joryio = new JoryioSDK({
sdkKey: 'jry_sdk_web_YOUR_KEY',
enableSdkAuthentication: true,
sdkAuthenticationToken: await mintJoryioJwt(),
});

// Fires on a 401 sdk_authentication_error. Return a fresh token (or call
// setSdkAuthenticationToken); the failed request is then retried once.
joryio.setSdkAuthenticationErrorCallback(async (info) => {
// info = { reason, endpoint, userId }
return await mintJoryioJwt();
});

// Replace the token at any time, e.g. before it expires
joryio.setSdkAuthenticationToken(await mintJoryioJwt());
מתודהתיאור
setSdkAuthenticationToken(token)הגדרה או החלפה של ה־JWT. מתעלם (עם אזהרה) אלא אם enableSdkAuthentication מופעל
setSdkAuthenticationErrorCallback(callback)callback(info) רץ כשאסימון נדחה; החזירו אסימון חדש, או Promise של אסימון
  • ה־callback מופעל ב־401 של אימות SDK לבקשה של המשתמש הנוכחי כל עוד enableSdkAuthentication פעיל - גם לפני שהוגדר אסימון כלשהו (reason: 'missing'). הוא אף פעם לא מופעל לבקשה של משתמש שכבר התנתק, ולכן הוא לא יכול לגרום לאפליקציה שלכם לנתק את מי שמשתמש בה עכשיו.
  • ניסיון חוזר מיידי אחד. הבקשה שנכשלה נשלחת שוב פעם אחת עם האסימון החדש. אם אין callback, הוא לא מחזיר אסימון, או שגם הניסיון החוזר נכשל, שום דבר לא נמחק: האירועים נשארים בתור ונשלחים שוב עם ה־backoff הרגיל, עם האסימון שמוגדר באותו רגע. כתיבה לפרופיל נשלחת שוב לכל היותר 10 פעמים.
  • האסימון של משתמש שהתנתק נשמר בשביל מה שהשאיר. ב־reset() - או ב־identify() של משתמש אחר - האסימון מפסיק להיות של הסשן אבל נשאר קשור לאירועים ולכתיבות של המשתמש היוצא שבתור, נשמר איתם ב־localStorage כך שטעינה מחדש לא מאבדת אותו, ונמחק כשהאחרון שבהם נמסר או נזרק. אסימון שהגדרתם למשתמש הנכנס לפני הקריאה ל־identify() מזוהה לפי ה־sub שלו ונשאר שלו. הגדרת אסימון שה־sub שלו הוא משתמש אחר שומרת בצד באותו אופן את האסימון שהוא מחליף, כך שהסדר לא משנה: מה שהמשתמש היוצא השאיר ממשיך לשאת את האסימון שלו. רענון האסימון של אותו משתמש לא שומר דבר בצד. אסימון שנשמר בצד נשמר לפחות דקה ולכל היותר 30 ימים. אסימון שה־sub שלו אינו המשתמש הנוכחי נשמר כך עבור אותו משתמש גם כשאף אחד לא מחובר, עד ש־identify() הופך אותו לאסימון של הסשן; wipeData() מוחק אסימון כזה.
  • משתמש אחד לכל בקשה. אירועים אף פעם לא נאספים לאצווה אחת מעבר להחלפת משתמש. reset() מוציא את האסימון מהסשן; הוא נשאר צמוד לעבודה שהמשתמש היוצא הכניס לתור. אירועים וכתיבות שהמשתמש היוצא כבר הכניס לתור עדיין נשלחים עם הטוקן שלו, כך שהתנתקות רגילה לא מאבדת דבר. אירועים, identify() וכתיבות לפרופיל של משתמש שכבר אינו הנוכחי, שנדחו עם 401 כלשהו של אימות SDK (missing, sub_mismatch, expired או invalid), נמחקים - לא יוגדר עוד אסימון למשתמש הזה - כך שהם אף פעם לא מעכבים את אלה של המשתמש הבא. בקשה נושאת רק טוקן שה־sub שלו הוא המשתמש של אותה בקשה: הטוקן הנוכחי כשהוא שלו, אחרת הטוקן ששמור בצד עבורו, אחרת אף טוקן - כך שטוקן שהגדרתם למשתמש הבא לפני identify() לעולם לא יוצא בבקשות של המשתמש הנוכחי. בקשות אנונימיות לא נושאות טוקן.

העדפות מינוי​

האובייקט user, שמיועד לכתיבה בלבד, מעדכן את המינויים השיווקיים של המבקר. השינויים ממתינים ש־identify() ממתין יגיע לשרת, נושאים גם את מזהה המשתמש וגם את המזהה האנונימי, ונשלחים שוב אם איש הקשר עדיין לא קיים. שינוי שנעשה לפני identify() נשלח עם מזהה המשתמש ברגע שה־identify הגיע לשרת, כך שאימות ה־SDK מקבל אותו. השינויים נשמרים ב־localStorage עד שהם מאושרים ונמסרים לפי הסדר: שינוי חדש יותר לערוץ או לקבוצה מחליף שינוי ישן יותר שעדיין ממתין. ביטול מינוי נמסר גם כשהמבקר ביטל מעקב או כשההסכמה denied.

import { SubscriptionStatus } from '@joryio/web-sdk';

joryio.user.setSubscription('email', SubscriptionStatus.OPTED_IN);
joryio.user.setSubscriptions({
email: SubscriptionStatus.OPTED_IN,
sms: SubscriptionStatus.UNSUBSCRIBED,
});

joryio.user.addToSubscriptionGroup('newsletter-list-id', 'email');
joryio.user.removeFromSubscriptionGroup('newsletter-list-id', 'email');
מתודהתיאור
user.setSubscription(channel, status)ערוץ אחד
user.setSubscriptions(preferences)כמה ערוצים, בצורה { channel: status }
user.addToSubscriptionGroup(groupId, channel?)הצטרפות לקבוצת מינוי (רשימה); channel ברירת מחדל 'email'
user.removeFromSubscriptionGroup(groupId, channel?)יציאה מקבוצת מינוי

ערוצים: email, sms, whatsapp, push, viber. סטטוסים: SubscriptionStatus.OPTED_IN (הסכמה מפורשת, למשל double opt-in שאושר), SubscriptionStatus.SUBSCRIBED (הסכמה פשוטה) ו־SubscriptionStatus.UNSUBSCRIBED. בגרסת ה־CDN העבירו את המחרוזות 'optedIn', 'subscribed' או 'unsubscribed'.

ייצוא החבילה​

ייצואמה זה
default / JoryioSDKמחלקת ה־SDK (window.Joryio בגרסת ה־CDN)
SubscriptionStatusסטטוסי המינוי שלמעלה
User, PushManager, EcommerceTrackerהמחלקות שמאחורי joryio.user, joryio.push ו־joryio.ecommerce() - לטיפוסים; לא יוצרים אותן בעצמכם
createEcommerceTracker(sdk, config?)זהה ל־sdk.ecommerce(config)
SDK_VERSIONמחרוזת הגרסה של ה־SDK, למשל '1.3.3'
טיפוסיםInitConfig, InAppOptions, InAppDisplayOptions, InAppCampaign, InAppMessage, InAppTrigger, Plugin, TrackingConsent, PushPermissionState, PushSubscribeOptions, SubscriptionChannel, SubscriptionPreferences, UTMParameters, UTMData, EcommerceProduct, EcommerceCartItem, EcommerceOrder, EcommerceConfig, SdkAuthFailureInfo, SdkAuthFailureReason, SdkAuthFailureCallback

installSnippetQueue מיוצא לבדיקות של ה־SDK עצמו; אל תקראו לו.

נתוני סשן אוטומטיים​

ה-Web SDK מעשיר באופן אוטומטי אירועי Session Start בנתוני מכשיר וסביבה. הערכים נשמרים בפרופיל המשתמש וברשומות המכשיר:

  • $user_agent
  • $timezone
  • $screen_width / $screen_height
  • $viewport_width / $viewport_height
  • $language / $languages
  • $platform
  • $browser
  • $device_id
  • country (ISO-3166-1 alpha-2, נגזר מה־IP בתחילת סשן)

מאפייני אירוע​

מאפיינים סטנדרטיים​

כל אירוע שנשמר נושא את המאפיינים הבאים - $device_id מצורף על ידי ה־SDK, והשאר מתווספים על ידי צינור הקליטה של Joryio בעת קבלת האירוע:

  • $device_id: מזהה מכשיר יציב לכל דפדפן (מצורף על ידי ה־SDK)
  • $session_id: מזהה סשן נוכחי
  • $anonymous_id: מזהה משתמש אנונימי (לפני זיהוי)
  • $app_id: מזהה האפליקציה שלכם
  • $app_name: שם האפליקציה שלכם
  • $platform: תמיד 'web' עבור Web SDK
  • $is_identified: האם המשתמש מזוהה

הקידומת $ שמורה - אל תשתמשו בה למאפיינים משלכם.

מאפיינים מותאמים​

אפשר להוסיף כל מאפיין מותאם לאירועים:

joryio.track('Video Played', {
video_id: 'vid_123',
video_title: 'Product Demo',
duration: 120,
autoplay: false,
// Any other custom data
});

שיטות עבודה מומלצות​

1. אתחול מוקדם​

אתחלו את ה־SDK מוקדם ככל האפשר באפליקציה:

// In your main app file
import JoryioSDK from '@joryio/web-sdk';

const joryio = new JoryioSDK({
sdkKey: process.env.JORYIO_SDK_KEY,
enableDebug: process.env.NODE_ENV === 'development',
});

2. מעקב אחרי אירועים משמעותיים​

התמקדו באירועים חשובים לעסק:

// Good: Specific, actionable events
joryio.track('Trial Started', { plan: 'premium' });
joryio.track('Feature Used', { feature: 'export', format: 'csv' });

// Avoid: Overly generic events
joryio.track('Button Clicked'); // Too generic

3. שימוש בשמות עקביים​

השתמשו במוסכמת שמות עקבית לאירועים ולמאפיינים:

// Good: Clear, consistent naming
joryio.track('Subscription Upgraded', {
from_plan: 'basic',
to_plan: 'premium',
billing_cycle: 'monthly',
});

// Avoid: Inconsistent naming
joryio.track('upgraded_subscription', {
FromPlan: 'basic',
'to-plan': 'premium',
});

4. ניהול מחזור חיי משתמש​

טפלו נכון בזיהוי משתמשים וניהול סשנים:

// On login
function handleLogin(userId, userInfo) {
joryio.identify(userId);
joryio.setAttributes({
email: userInfo.email,
name: userInfo.name,
});
}

// On logout
function handleLogout() {
joryio.reset();
}

// On signup
function handleSignup(userId, userInfo) {
joryio.identify(userId);
joryio.setAttributes(userInfo);
}

פתרון תקלות​

אירועים לא מופיעים​

  1. בדקו את מפתח ה־SDK - ודאו שהוא מתחיל ב־jry_sdk_web_ (גם מפתח של אינטגרציית חנות עובד). מפתח של אפליקציית מובייל (jry_sdk_ios_, jry_sdk_android_) נדחה: ה־SDK רושם ביומן למה ונשאר לא פעיל
  2. בדקו את המסוף - הפעילו מצב debug כדי לראות יומנים מפורטים
  3. בדקו שהאתחול הושלם - ודאו ש־new JoryioSDK(config) רץ לפני קריאה לשיטות אחרות

שגיאות CORS​

נקודות הקצה של ה־SDK מחזירות Access-Control-Allow-Origin: *, כך שלא נדרש אישור דומיין. אם אתם עדיין רואים שגיאות CORS, בדקו ש־apiEndpoint מצביע על כתובת הבסיס הנכונה (https://api-eu1.joryio.com/api) ושהבקשה לא נחסמת על ידי תוסף דפדפן או פרוקסי שמסיר כותרות CORS.

בעיות מעקב סשן​

ה־SDK משתמש ב־localStorage לשמירת סשן. ודאו:

  • האתר שלכם מוגש ב־HTTPS (נדרש להקשרים מאובטחים)
  • המשתמשים לא השביתו localStorage
  • אתם לא קוראים ל־reset() בטעות

צעדים הבאים​