שילוב 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 החדש.
עד אוקטובר 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',
});
אפשרויות תצורה
| אפשרות | סוג | ברירת מחדל | תיאור |
|---|---|---|---|
sdkKey | string | נדרש | מפתח ה־SDK מלוח הבקרה של Joryio |
apiEndpoint | string | https://api-eu1.joryio.com/api | שרת ה־API של האזור שלכם. אפשר גם שם שרת בלבד; /api מתווסף |
userId | string | - | התחלה עם מזהה משתמש ידוע |
anonymousId | string | נוצר אוטומטית | שימוש במזהה אנונימי משלכם |
enableDebug | boolean | false | הפעלת יומני ניפוי שגיאות במסוף (logLevel: 'debug'). logLevel שהוגדר במפורש גובר |
batchFlushInterval | number | 5000 | תדירות שליחת אירועים באצווה (מילישניות). אירועים מתווספים לתור ונשלחים כל 5 שניות כדי לצמצם בקשות רשת. ערכים מתחת ל־1000 מועלים ל־1000. |
batchSize | number | 50 | מספר האירועים בכל בקשה, וגודל התור שמפעיל שליחה לפני הטיימר. לעולם לא יותר מ־500 בבקשה (המגבלה של ה־API) |
sendImmediately | boolean | false | שליחת כל אירוע מיד ללא אצווה (לא מומלץ לסביבת ייצור) |
sessionTimeout | number | 1800000 | פסק זמן סשן במילישניות (ברירת מחדל: 30 דקות). סשן חדש מתחיל לאחר תקופת חוסר פעילות זו - נבדק בכל track() וכשהלשונית חוזרת להיות גלויה. |
trackSessionStart | boolean | true | אירוע "Session Start" אחד לכל סשן חדש. טעינה מחדש שממשיכה את הסשן לא שולחת אירוע כזה. |
trackPageViews | boolean | false | מעקב אוטומטי אחרי "Page Viewed" בטעינת עמוד |
captureUTM | boolean | true | לכידה אוטומטית של פרמטרי UTM מה־URL לשיוך קמפיינים |
resetSessionOnNewCampaign | boolean | false | פתיחת סשן חדש כאשר פרמטרי UTM משתנים (שימושי לאנליטיקה ברמת קמפיין) |
trackDeviceProperties | boolean | true | הוספת מידע מכשיר לאירוע Session Start |
persistQueue | boolean | true | שמירת תור האירועים ב־localStorage כדי לשרוד רענונים |
maxQueueSize | number | 1000 | מספר האירועים המרבי שהתור המקומי מחזיק בזמן ששליחות נכשלות; מעבר לכך הישנים ביותר נמחקים (עם אזהרה ביומן כשהרישום פעיל) |
maxRetries | number | 3 | ניסיונות חוזרים מיידיים של בקשה אחת (5xx, 429, שגיאת רשת). אצווה שעדיין נכשלת נשמרת ונשלחת שוב מאוחר יותר |
retryBackoffMs | number | 1000 | ההשהיה הראשונה לפני ניסיון חוזר, במילישניות; מוכפלת בכל כישלון, עד 5 דקות |
requestTimeout | number | 10000 | זמן קצוב במילישניות לכל בקשת API (אירועים, מאפיינים, In-App, Push) |
trackPageProperties | boolean | true | הוספת ה־referrer ועמוד הנחיתה לאירועי "Page Viewed" |
respectDoNotTrack | boolean | true | התייחסות להגדרת Do Not Track של הדפדפן כביטול מעקב |
logLevel | string | - | 'error', 'warn', 'info' או 'debug'. שום דבר לא נרשם לקונסול אלא אם הוגדר זה או enableDebug |
trackingConsent | string | לא מוגדר | 'granted', 'denied' או 'pending'. השאירו לא מוגדר אם אין באתר באנר הסכמה. ראו פרטיות והסכמה |
optOut | boolean | false | true מבטל את המעקב אחרי המבקר ונשמר בין טעינות עמוד, כמו optOut(). false לא מבטל ביטול מעקב שמור - רק optIn() עושה זאת |
enableSdkAuthentication | boolean | false | צירוף ורענון של JWT שהשרת שלכם מנפיק. ראו אימות SDK |
sdkAuthenticationToken | string | - | ה־JWT הראשון, בשימוש כש־enableSdkAuthentication מופעל |
plugins | array | [] | תוספים עם beforeTrack / afterTrack (Web בלבד) |
inApp.enabled | boolean | true | הפעלה או כיבוי של הודעות In-App |
inApp.evaluationMode | string | 'differential-sync' | מתי נטענים קמפייני In-App: 'differential-sync' (בטעינה, ב־identify(), ב־reset(), בסשן חדש, בשינוי מאפיין במעקב ובכל inApp.syncInterval) או 'session-start-only' (בטעינה, ב־identify(), ב־reset() ובסשן חדש בלבד) |
inApp.syncInterval | number | 0 (כבוי) | טעינה מחדש של קמפייני In-App כל N מילישניות במצב 'differential-sync'. ערך מתחת ל־30000 מועלה ל־30000; מושהה כשהלשונית מוסתרת |
inApp.allowHtmlJsInAppMessages | boolean | false | מאפשר הודעות 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.defaultPosition | string | 'center' | 'top', 'center' או 'bottom': היכן מוצגת הודעה מסוג Custom. הודעות Modal, Banner, Slide-Up ו־Full-Screen שומרות על המיקום שלהן |
inApp.displayOptions.defaultAnimation | string | 'fade' | 'fade', 'slide' או 'none': איך ההודעות נכנסות. מדולג כשמערכת המבקר מבקשת פחות תנועה |
inApp.displayOptions.backdropColor | string | 'rgba(0, 0, 0, 0.5)' | צבע שכבת ההאפלה מאחורי הודעות Modal ו־Full-Screen |
inApp.displayOptions.closeButtonColor | string | צבע הטקסט של ההודעה | צבע כפתור הסגירה |
inApp.displayOptions.zIndex | number | 999999 | סדר השכבות של ההודעות (שכבת ההאפלה נמצאת אחת מתחת) |
inApp.onMessageDisplay / onMessageClick / onMessageDismiss | function | - | פונקציות לכל שלב - ראו 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) - סשן חדש מתחיל כאשר:
- המשתמש טוען את העמוד לראשונה
- פסק זמן הסשן חלף ללא אירועים
- המשתמש קורא
joryio.reset()(למשל, ביציאה) - מזוהה קמפיין חדש (אם
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_idcountry(ISO-3166-1 alpha-2, נגזר מה־IP בתחילת סשן)
מקרי שימוש:
-
מסעות קבלת פנים: השתמשו ב־
Session Startכטריגר של מסע כדי להגיע למשתמשים כשהם מגיעים לאתר. -
סגמנטים מבוססי סשנים: אירועי Session Start נשמרים לכל משתמש, כך שתנאי סגמנט מבוססי אירועים יכולים לספור אותם - למשל, "ביצע
Session Startלפחות 10 פעמים" (משתמשים כבדים) או "לא ביצעSession Startב־7 הימים האחרונים" (חידוש מעורבות). -
שיוך קמפיינים: סננו באנליטיקה על
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;
}
סדר הקדימות, מהגבוה לנמוך:
- מה שהקמפיין הגדיר ב-Style (optional) - נכתב inline על הכרטיס
- הערכים שלכם ב-
--joryio-inapp-* - ברירות המחדל של ה-SDK, שהן צבעי מערכת
כך קמפיין שלא הגדיר דבר יורש את סגנון הבית שלכם, וקמפיין שהגדיר רקע מנצח
להודעה הזו בלבד. בלי !important בשום מקום.
אם בכל זאת תשתמשו בסלקטורים, שימו לב שגיליון הסגנון של ה-SDK מוזרק בזמן ההצגה
ולכן מגיע אחרי שלכם בסדר המסמך, ומנצח בתיקו. הוסיפו ספציפיות -
.joryio-inapp .joryio-inapp-native {…} - במקום כלל של מחלקה בודדת.
כיווניות מטופלת עבורכם: הכרטיס נושא dir="auto", ולכן הודעה בעברית או בערבית
מיושרת לימין ומציבה את הכפתור הראשי בימין, גם בתוך עמוד שכולו משמאל לימין.
סוגי הודעות
- Modal - במרכז המסך עם רקע מוצל
- Banner - בראש הדף
- Slide-Up - התראה קטנה מלמטה
- Full-Screen - הודעה שתופסת את כל המסך
- 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- המזהה האנונימי (תמיד קיים)
עם ה־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_idcountry(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);
}
פתרון תקלות
אירועים לא מופיעים
- בדקו את מפתח ה־SDK - ודאו שהוא מתחיל ב־
jry_sdk_web_(גם מפתח של אינטגרציית חנות עובד). מפתח של אפליקציית מובייל (jry_sdk_ios_,jry_sdk_android_) נדחה: ה־SDK רושם ביומן למה ונשאר לא פעיל - בדקו את המסוף - הפעילו מצב debug כדי לראות יומנים מפורטים
- בדקו שהאתחול הושלם - ודאו ש־
new JoryioSDK(config)רץ לפני קריאה לשיטות אחרות
שגיאות CORS
נקודות הקצה של ה־SDK מחזירות Access-Control-Allow-Origin: *, כך שלא נדרש אישור דומיין. אם אתם עדיין רואים שגיאות CORS, בדקו ש־apiEndpoint מצביע על כתובת הבסיס הנכונה (https://api-eu1.joryio.com/api) ושהבקשה לא נחסמת על ידי תוסף דפדפן או פרוקסי שמסיר כותרות CORS.
בעיות מעקב סשן
ה־SDK משתמש ב־localStorage לשמירת סשן. ודאו:
- האתר שלכם מוגש ב־HTTPS (נדרש להקשרים מאובטחים)
- המשתמשים לא השביתו localStorage
- אתם לא קוראים ל־
reset()בטעות
צעדים הבאים
- Web SDK: מעקב UTM ושיוך קמפיינים - שיוך קמפיינים, first/last touch ולכידת UTM
- מעקב מסחר אלקטרוני - אירועי מוצרים, עגלה, תשלום והזמנות
- מעקב אירועים מותאמים
- הגדרת מאפייני משתמש
- יצירת סגמנטים
- בניית קמפיינים
- E-Commerce API