ווידג'ט לאתר
הווידג'ט הוא הצ'אט של הבוט ישירות באתר שלכם: כפתור עגול בפינת העמוד שממנו נפתחת שיחה. עבור המבקר זו עוד דרך לפנות אליכם; עבור הבוט זה ערוץ רגיל לגמרי — אותן ריאקציות ואותם דיאלוגים של נציגים כמו במסנג'רים. סקירה של ריבוי הערוצים בעמוד ערוצים.
ההתקנה היא הדבקה של קטע קוד אחד לתבנית האתר. כל השאר מוגדר בממשק ונכנס לתוקף בלי לגעת באתר שוב.
היכן מקבלים את קוד ההטמעה
בממשק פתחו ווידג'ט ← בלוק התקנה באתר ← שדה קוד להטמעה. כפתור העתקה מעביר את כל הקטע ללוח.
הקוד נראה כך, עם המפתח שלכם במקום שלוש הנקודות:
<script>
window.mybot = { key: "eu-1a2b3c4d-..." };
</script>
<script async src="https://getmybot.dev/loader.js"></script>
אם במקום הקוד מופיעה הודעה שעדיין לא הונפק מפתח התקנה לבוט הזה, סימן שערוץ הווידג'ט אינו מחובר. פנו לתמיכה: המפתח מונפק בעת חיבור הערוץ.
מתחת לקוד מופיע רמז לאיזה מארח הווידג'ט יפנה. אם באתר שלכם מוגדר CSP (מדיניות אבטחת תוכן), אפשרו למארח הזה לטעון סקריפטים ולקבל בקשות רשת, אחרת הדפדפן יחסום את הווידג'ט בשקט.
היכן ממקמים את הקוד
הקטע נכנס ל־HTML של כל עמוד שבו הווידג'ט אמור להופיע. בפועל זה אומר פעם אחת בתבנית המשותפת של האתר: הפוטר, שדה «קוד לפני </body>» במערכת הניהול, או קונטיינר במנהל התגיות.
הכללים קצרים:
- המקום הטוב ביותר הוא מיד לפני
</body>הסוגר. גם ב־<head>זה עובד, אבל אז הדפדפן משקיע זמן בווידג'ט לפני התוכן שלכם. - הסדר של שני התגים חשוב: הראשון קובע את המפתח, השני טוען את הווידג'ט. אל תחליפו ביניהם ואל תפזרו אותם בעמוד.
- לתג השני יש
asyncוהוא אינו חוסם את הרינדור. אל תסירו את המאפיין הזה. - קטע אחד לכל עמוד. שני עותקים פירושם שני ניסיונות הפעלה.
משם הטוען מזהה בעצמו מאיזה מרכז נתונים מנוהל הבוט שלכם, ומושך משם את גוף הווידג'ט. מכם לא נדרש דבר.
מפתח ההתקנה הוא ציבורי
המפתח בתג הראשון הוא מזהה ציבורי של הבוט, לא סיסמה. הוא נמצא בקוד המקור של העמוד: כל מבקר יכול לפתוח «הצגת מקור העמוד» ולראות אותו. כך עובד כל ווידג'ט צ'אט, וזה תקין.
מה שחשוב להבין:
- באמצעות המפתח אי אפשר להיכנס לממשק, לקרוא דיאלוגים של אחרים, לייצא את מאגר הנרשמים או לשנות משהו בבוט. הוא פותח בדיוק אפשרות אחת: לפתוח שיחה חדשה עם הבוט הזה.
- אל תתייחסו למפתח כאל סוד: להסתיר או לערפל אותו לא נותן דבר.
- אם צריך להחליף את המפתח (למשל אחרי פרידה מספק חיצוני), התמיכה מטפלת בכך. לאחר ההחלפה הקוד הישן באתר מפסיק לעבוד ויש לעדכן אותו.
רשימת הדומיינים המורשים
לווידג'ט יש רשימת דומיינים מורשים (origin allowlist) — כתובות האתרים שמהם מותר לו לפעול. הרשימה נקבעת בעת חיבור הערוץ ומשתנה אחר כך בלי הנפקה מחדש של המפתח: הקוד באתר שלכם נשאר כפי שהוא.
כל רשומה היא origin: סכימה, מארח, ואם הפורט אינו סטנדרטי — גם הוא.
https://example.com
https://www.example.com
https://shop.example.com
http://localhost:3000
ההשוואה היא מדויקת, תו אחר תו:
- אין תווים כלליים.
https://*.example.comלא יעבוד — פרטו את תתי־הדומיינים אחד אחד. example.comו־www.example.comהן רשומות שונות. אם האתר נפתח בשתי הכתובות, הוסיפו את שתיהן.- גם
http://ו־https://הן רשומות שונות. בדרך כלל דרוש רקhttps://, אבל סביבת בדיקות עלhttp://צריכה תוספת מפורשת. - ללא נתיב:
https://example.com/shopיידחה, origin הוא כתובת האתר בלבד.
אם הדומיין האמיתי שלכם אינו ברשימה, הווידג'ט לא ייפתח. הדפדפן של המבקר יקבל סירוב «origin not allowed» והצ'אט פשוט לא ייפתח. זה קורה בדרך כלל אחרי מעבר לדומיין חדש, הוספת תת־דומיין או השקת גרסת שפה שנייה בכתובת נפרדת — כל אחת מהן דורשת רשומה משלה.
אם הרשימה ריקה אין שום הגבלה והווידג'ט פועל מכל אתר. התייחסו לכך כאל «עוד לא הוגדר» ולא כאל פתיחות מכוונת: ברגע שאתם יודעים מהם הדומיינים שלכם, הזינו אותם.
מה ההגבלה הזו מונעת ומה לא
מונעת: אתר זר לא יוכל להטמיע אצלו את הווידג'ט שלכם. אחרת מישהו היה יכול להעתיק את הקוד לעמוד שלו, והדפדפנים של מבקרים אמיתיים היו מוסרים לאותו אתר את תוכן השיחות עם הבוט שלכם. הרשימה סוגרת בדיוק את זה.
לא מונעת: זו אינה הגנה מפני מי שהעתיק את המפתח ופונה לפלטפורמה ישירות — לא מדפדפן אלא, למשל, מסקריפט. הכותרת עם כתובת האתר נוספת על ידי הדפדפן; תוכנה שרצה מחוץ לדפדפן יכולה לא לשלוח אותה או לשלוח כל ערך. לכן ראו ברשימה הגבלת הטמעה ולא גבול אבטחה. מפני שימוש לרעה מגינים מגבלות הקצב וניהול הדיאלוגים בצד הפלטפורמה, לא הרשימה הזו.
מראה
בווידג'ט ← מראה מגדירים:
- מיקום — הכפתור בפינה השמאלית או הימנית התחתונה.
- צבע הדגשה — צבע הכפתור ורכיבי הצ'אט. השתמשו בצבע המותג כדי שהווידג'ט לא ייראה זר.
- שם הצ'אט — הכיתוב על כפתור ההפעלה וכותרת חלונית הצ'אט. לרוב שם החברה או השם שבו הבוט מציג את עצמו.
לצדם יש תצוגה מקדימה — ווידג'ט חי שמראה את התוצאה עוד לפני השמירה.
הודעת פתיחה עדיין אין בווידג'ט: אלה שלוש ההגדרות היחידות. את ההודעה הראשונה שולח הבוט בתגובה למבקר, לפי כללי הריאקציות הרגילים שלכם.
השינויים מגיעים לאתר מעצמם: הווידג'ט קורא את ההגדרות בעת טעינת העמוד, ואת הקוד המודבק אין צורך לערוך אף פעם.
המבקרים אנונימיים
המבקר אינו ממלא דבר כדי לכתוב. בהפעלה הראשונה הווידג'ט מקבל מהפלטפורמה מזהה מבקר אנונימי ושומר אותו בדפדפן, כדי שבחזרה לאתר האדם יראה את השיחה הקודמת שלו ולא צ'אט ריק.
מכאן נובע:
- בדיאלוגים מבקר כזה מוצג כאנונימי: בלי שם, טלפון ודוא"ל, כל עוד לא כתב אותם בעצמו.
- המזהה חי בדפדפן מסוים. דפדפן אחר, מכשיר אחר או נתוני אתר שנמחקו — כל אלה מבקר חדש עם היסטוריה ריקה.
- מבקר אנונימי אפשר לקשר ללקוח שכבר מוכר לכם — למשל משתמש מחובר באזור האישי שלכם. כיצד — בפרק הבא.
קישור מבקר למשתמש שלכם
אם המבקר כבר מחובר באתר שלכם, אתם יכולים לומר לפלטפורמה מי הוא. לאחר הקישור השיחה מפסיקה להיות אנונימית: היא מתמזגת עם הפרופיל של אותו אדם, וההודעות האנונימיות הקודמות שלו אינן אובדות.
די בקריאה אחת, עם פונקציה שמייצרת את ההוכחה:
mybot.identify(async (visitorId) => {
const res = await fetch("/mybot-sign", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ userId: currentUser.id, visitorId }),
});
return res.json(); // { userId, signature, expiresAt }
});
הוידג'ט קורא לפונקציה שלכם עם visitorId — מזהה המבקר האנונימי הנוכחי לדפדפן הזה, הערך היחיד שרק הוידג'ט מכיר — וממתין שהיא תחזיר, או תתממש ל-, { userId, signature, expiresAt }. המשימה היחידה של הפונקציה שלכם היא למסור את visitorId לשרת שלכם, יחד עם מזהה המשתמש המחובר (currentUser.id למעלה הוא מה שזה אצלכם), ולהחזיר בדיוק את מה שהשרת שלכם עונה. החתימה עצמה מתבצעת בשרת שלכם, לא בפונקציה הזו — ראו בהמשך.
קולבק, לא ערך מוכן מראש ולא דרך לקרוא את visitorId ישירות, משתי סיבות:
- התזמון. הוידג'ט יוצר את
visitorIdבאופן א-סינכרוני תוך כדי עלייתו — הוא לא קיים ברגע שסקריפט הטעינה רץ, ו-mybot.identifyעצמו מותקן רק לאחר שזה מסתיים (פרטים בהמשך). כך שברגע שהעמוד שלכם בכלל יכול לקרוא ל-mybot.identify, המזהה שהפונקציה שלכם מקבלת מובטח כאמיתי. getter רגיל לא היה נותן ערבות כזו: שום דבר לא היה מונע מעמוד לקרוא אותו שורה אחת מוקדם מדי ולא לקבל כלום, ובשקט לייצר חתימה שלעולם לא תואמת, בלי שום רמז לסיבה. - ההיקף. קוד העמוד שלכם בעצמו לעולם לא צריך להחזיק, לשמור או להעביר את
visitorIdידנית — הוא קיים רק בתוך הפונקציה הזו, לקריאה היחידה שהיא צריכה לבצע.
מהרגע שהוא עוזב את הוידג'ט, visitorId הוא יכולת נשאית (bearer capability): מי שמצליח להשיג עבורו חתימה יכול להתמזג עם ההפעלה של אותו מבקר. שלחו אותו רק לשרת שלכם, בבקשה המאומתת שלכם, ולשום מקום אחר — אל תלוגו אותו, אל תעבירו אותו לצד שלישי ואל תשימו אותו בקריאת אנליטיקה בצד הלקוח.
החתימה מחושבת רק בשרת שלכם עצמו
בתוך הפונקציה שלכם למעלה, השרת שלכם עצמו — לעולם לא הדפדפן — מחשב את החתימה: HMAC-SHA256, עם סוד הווידג'ט כמפתח, בייצוג הקסדצימלי, 32 התווים הראשונים, משלושה ערכים המאוחדים להודעה אחת. אותה נוסחה מוצגת בממשק לצד הסוד, תחת הכותרת «Signing algorithm»:
signature = hex(HMAC-SHA256(key: secret, message: userId + "\n" + visitorId + "\n" + expiresAt)).slice(0, 32)
כל + "\n" + למעלה הוא תו ירידת שורה אמיתי בין החלקים, לא שני התווים לוכסן הפוך ו-n. אם פונקציית ה-HMAC שלכם מקבלת את ההודעה כמחרוזת אחת, חברו את שלושת החלקים בירידת שורה אמיתית — שלוש קריאות .update() נפרדות בלי ירידת שורה ביניהן מחשבות גיבוב של הודעה אחרת ושגויה.
שלושת החלקים:
userId— מזהה המשתמש המחובר, אותו ערך שהשרת שלכם מקבל מהפונקציה למעלה ומחזיר בתשובתו.visitorId— מזהה המבקר האנונימי שהפונקציה שלכם קיבלה כארגומנט והעבירה ללא שינוי לשרת שלכם.expiresAt— חותמת זמן יוניקס בשניות (לא במילישניות), שהשרת שלכם מנפיק ברגע החתימה ושעד אליה חתימה ספציפית זו נשארת תקפה. הפלטפורמה דוחה קריאה שה-expiresAtשלה כבר בעבר, וכן קריאה שהיא יותר מ-24 שעות קדימה — חתמו רגע לפני שהיא מוחזרת מהפונקציה שלכם, לא פעם אחת לשימוש חוזר בבקשות עתידיות.
תוקף זה הוא עיקר השינוי, לא פרט משני. הנוסחה הקודמת כיסתה רק את מזהה המשתמש, כך שחתימה שנתפסה פעם אחת — נרשמה איפשהו, נלכדה מהתעבורה, לא משנה איך — נשארה תקפה לנצח והתאימה לכל מבקר, לא רק לזה שלמענו הונפקה. מי שהשיג אותה יכול היה לשחזר אותה בדפדפן שונה לגמרי, והפלטפורמה הייתה ממזגת את הגלישה האנונימית של זר עם הפרופיל של לקוח אמיתי. קשירת החתימה ל-visitorId מסוים ומתן אורך חיים קצר סוגרים את שני קצות הפרצה הזאת: החתימה מאומתת רק עבור הסשן שלמענו הונפקה, ובשום מקום אחר, ומפסיקה להתאמת לחלוטין ברגע שה-expiresAt חולף — כך שאפילו חתימה שדלפה נשארת סיכון קצר, מוגבל לסשן אחד, לא סיכון קבוע.
חשבו את שלושת הערכים בשרת שלכם והחזירו אותם מהפונקציה שלכם מוכנים. זו אינה פורמליות: כדי לחשב חתימה בדפדפן היה צריך לשלוח לשם את הסוד עצמו, כלומר למסור אותו לכל מבקר בעמוד. מרגע זה כל אחד היה יכול להתחזות לכל לקוח שלכם ולקרוא את שיחתו. להחזיר לדפדפן את החתימה (ואת ה-visitorId/expiresAt שעבורם היא חושבה) בטוח, את הסוד לא.
הקריאה עצמה אינה מציגה דבר על המסך: הקישור מתבצע בצד השרת ובשקט. אם הפונקציה שלכם זורקת שגיאה או שה-promise שלה נדחה, או שהפלטפורמה דוחה את החתימה שהתקבלה — לא תואמת, או שה-expiresAt חסר, כבר בעבר, או יותר מ-24 שעות קדימה — לא קורה כלום מעבר לכך: המבקר לא מבחין בדבר וממשיך לכתוב כאנונימי.
mybot.identify אינו קיים מיד — הוא מופיע לאחר שנטענה החבילה הראשית של הווידג'ט, יחד עם visitorId אמיתי (ראו «התזמון» למעלה). קראו לו ממטפל טעינת העמוד, ולא בשורה הראשונה ב־<head>.
היכן נמצא הסוד וכיצד מחליפים אותו
סוד הווידג'ט הוא המפתח שבו אתם חותמים. הוא נמצא בהגדרות הווידג'ט, בקטע «identify() secret». אם הקטע מודיע שהווידג'ט עדיין לא מחובר, חברו קודם את ערוץ הווב — הסוד יופיע יחד איתו.
הצגה. הכפתור «Reveal secret» מושך את הערך. הוא אינו מופיע כטקסט גלוי: תחילה תראו נקודות, ואת התווים חושף מתג נפרד «Show» (ובחזרה «Mask»). לצדו יש «Clear from screen», שמסיר את הערך מהמסך.
אפשר להציג כמה פעמים שרוצים, וההצגה אינה מבטלת דבר: הסוד נשאר בתוקף גם אחרי סגירת המסך. כך זה מפני שהוא נשמר מוצפן ולא מגובב — הפלטפורמה זקוקה לערכו האמיתי כדי לאמת כל חתימה. אז אם בעוד חצי שנה תעלו שרת חדש, פשוט היכנסו והציגו אותו שוב.
אחרי שהעתקתם, נקו אחריכם בעצמכם. את הלוח הפלטפורמה אינה יכולה לרוקן: מהדפדפן אין דרך אמינה לעשות זאת, ולכן איננו מבטיחים. הסירו את הערך מהמסך ורוקנו את הלוח ידנית כשסיימתם, במיוחד במחשב משותף.
החלפה. הכפתור «Rotate secret», עם שלב אישור. זו פעולה ששוברת מיד: ברגע שהסוד החדש קיים, הישן מפסיק לעבור אימות. אין חלון חפיפה — אין רגע שבו שני המפתחות עובדים.
מה שנשבר הוא בדיוק קישור המבקרים למשתמשים שלכם. השיחות אינן נקטעות — מבקרים ממשיכים לכתוב ולקבל תשובות, פשוט כאנונימיים — עד שהשרת שלכם יתחיל לחתום בסוד החדש. קוד ההטמעה ורשימת הדומיינים המורשים אינם מושפעים, ובאתר אין מה לשנות.
לכן החליפו במודע: הכינו תחילה את פריסת השרת עם הערך החדש, ורק אז לחצו «Rotate secret». ללחוץ כדי לראות מה יקרה — רעיון גרוע. הערך החדש מוצג על המסך מיד לאחר ההחלפה, כך שאפשר להעתיק אותו במקום.
איך הווידג'ט מתנהג בעמוד
הווידג'ט בנוי בכוונה כך שלא יתנגש עם האתר שלכם:
- הוא חי בקונטיינר מבודד (Shadow DOM סגור). הסגנונות שלכם לא נכנסים פנימה, והסגנונות שלו לא דולפים החוצה. תופעת לוואי: אי אפשר לעצב אותו מחדש ב־CSS משלכם — השתמשו בהגדרות המראה.
- הקונטיינר פרוש על כל המסך אך אינו חוטף קליקים: הם עוברים לעמוד, ורק הכפתור וחלונית הצ'אט מגיבים.
- הווידג'ט תמיד מעל התוכן שלכם; שכבות משלכם לא יסתירו אותו.
- כל שגיאה בתוך הווידג'ט נשארת בתוכו: במקרה הגרוע כפתור הצ'אט לא יעבוד, והאתר ימשיך לפעול. אם הווידג'ט לא הופיע, בדקו את קונסולת הדפדפן — כמעט תמיד מדובר ב־CSP או בדומיין שלא נוסף לרשימה.
אם הווידג'ט לא הופיע
עברו לפי הסדר:
- פתחו את מקור העמוד וודאו ששני התגים במקומם ושהמפתח אינו ריק.
- ודאו שכתובת האתר זהה בדיוק לזו שברשימה, כולל
https://ו־www. - הביטו בקונסולת הדפדפן: הודעה על Content Security Policy פירושה שיש לאשר את מארח הפלטפורמה ב־CSP של האתר.
- ודאו שחוסם פרסומות אינו מסיר את הווידג'ט — בדקו בחלון פרטי בלי תוספים.
מה הלאה
- ערוצים — ריבוי ערוצים ויכולות הערוצים.
- ריאקציות: יסודות — מה הבוט יענה למבקר.
- צ'אטים ואופרטורים — איך נציג עונה בשיחה.