Віджет на сайті
Віджет — це чат вашого бота просто на сайті: кругла кнопка в кутку сторінки, з якої відкривається листування. Для відвідувача це ще один спосіб написати вам, для бота — звичайний канал: ті самі реакції та ті самі діалоги операторів, що й у месенджерах. Огляд мультиканальності — на сторінці Канали.
Встановлення — це одна вставка коду в шаблон сайту. Усе інше налаштовується в кабінеті й підхоплюється без правок на сайті.
Де взяти код для вставлення
Відкрийте в кабінеті розділ «Віджет» → блок «Встановлення на сайт» → поле «Код для вставлення». Кнопка «Скопіювати» кладе весь фрагмент у буфер обміну.
Код виглядає так — з вашим власним ключем замість трьох крапок:
<script>
window.mybot = { key: "eu-1a2b3c4d-..." };
</script>
<script async src="https://getmybot.dev/loader.js"></script>
Якщо замість коду ви бачите напис, що ключ встановлення для цього бота ще не видано, канал віджета боту не підключено. Зверніться до підтримки: ключ видається під час підключення каналу.
Під полем із кодом показано підказку, до якого хоста звертатиметься віджет. Якщо на вашому сайті налаштовано CSP (Content Security Policy), дозвольте цій адресі завантаження скриптів і мережеві запити, інакше браузер заблокує віджет мовчки.
Куди вставляти код
Фрагмент вставляється в HTML кожної сторінки, де віджет має з'являтися. На практиці це означає — один раз у спільний шаблон сайту: підвал, «код перед </body>», footer-скрипти в CMS або контейнер у диспетчері тегів.
Правила прості:
- Найкраще місце — перед закривальним
</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, ідентифікатор, який отримує ваша функція, гарантовано справжній. Звичайний геттер не давав би такої гарантії: ніщо не заважало б сторінці прочитати його на рядок раніше й отримати порожнечу — мовчки отримавши підпис, який ніколи не збігається, без жодної підказки чому. - Область дії. Коду вашої власної сторінки взагалі не потрібно зберігати, запам'ятовувати чи вручну передавати
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— unix-час у секундах (не в мілісекундах), до якого саме цей підпис лишається дійсним; його видає ваш сервер у момент підпису. Платформа відхиляє виклик, якщоexpiresAtуже в минулому, а також якщо він більш ніж на 24 години в майбутньому — підписуйте прямо перед тим, як повернути значення з вашої функції, а не один раз про запас для наступних запитів.
Цей термін дії — не другорядна деталь, а головна причина зміни формули. Попередня формула охоплювала лише ідентифікатор користувача, тож одного разу перехоплений підпис — десь залогований, знятий із трафіку, байдуже як — лишався дійсним назавжди й підходив для будь-якого відвідувача, а не лише того, кому був виданий. Хто завгодно, отримавши такий підпис, міг відтворити його в зовсім іншому браузері — і платформа об'єднала б анонімне листування стороннього з профілем реального клієнта. Прив'язка підпису до конкретного visitorId і короткий термін життя закривають обидва кінці цієї діри: підпис проходить перевірку лише для тієї сесії, для якої виданий, і ніде більше, а після настання expiresAt перестає проходити перевірку взагалі — тож навіть підпис, що витік, лишається короткочасною загрозою для однієї сесії, а не постійною.
Рахуйте всі три значення на своєму сервері й повертайте їх із функції вже готовими. Це не формальність: щоб порахувати підпис у браузері, туди довелося б віддати сам секрет — тобто видати його кожному відвідувачеві сторінки. Після цього будь-хто зміг би представитися будь-яким вашим клієнтом і прочитати його листування. Підпис (і visitorId/expiresAt, для яких він порахований) віддавати назад у браузер безпечно, секрет — ні.
Сам виклик нічого не показує на екрані: зв'язування відбувається на сервері й мовчки. Якщо ваша функція викине помилку або її проміс буде відхилено, або платформа відмовить в отриманому підписі — не зійдеться, або 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 сайту.
- Переконайтеся, що віджет не ріже блокувальник реклами — перевірте в приватному вікні без розширень.
Що далі
- Канали — мультиканальність і можливості каналів.
- Реакції: основи — що бот відповість відвідувачеві сайту.
- Чати і оператори — як оператор відповідає в листуванні.