Управляйте виджетом со своей страницы и поддерживайте каждую беседу устойчивой — автоматическое переподключение, повтор сообщений, обнаружение оффлайна, тайм-ауты и дружелюбная обработка ошибок.
После загрузки скрипта виджета Companin регистрирует мост хоста в window.CompaninWidgetHost. Он дает вашей странице небольшой, не имеющий зависимостей API для открытия и закрытия виджета, отправки сообщений, чтения состояния и подписки на события жизненного цикла — без связывания вашего кода с внутренностями виджета.
Мост также добавляет уровень надежности поверх виджета: сообщения ставятся в очередь, пока нет подключения, автоматически повторяются, когда соединение восстанавливается, тайм-аут, если ответ не приходит, и виджет автоматически переподключается после временных ошибок. Каждое изменение состояния отображается как событие DOM, так что вы можете реагировать в своем собственном интерфейсе.
Вызывайте эти методы на window.CompaninWidgetHost после загрузки виджета. Они безопасны и не выполняются, когда виджет еще не готов, так что вам никогда не нужно защищать каждый вызов.
open() / close() / toggle() — Показать, скрыть или перевернуть панель виджета.sendText(text) — Отправить текстовое сообщение как посетитель.sendPayload(payload) — Отправить структурированное сообщение или объект команды.sendSafe(payload) — Отправить через уровень надежности — ставится в очередь при оффлайне и проходит через любые перехватчики.sendWithTimeout(payload, ms) — Отправить и вызвать событие тайм-аута, если ответ не приходит в течение ms (по умолчанию 10000).intercept(fn) — Зарегистрировать функцию, которая может переписывать или отменять исходящие сообщения; возвращает функцию отписки.getState() — Прочитать текущее состояние хоста: статус открытия, последнее отправленное и полученное сообщение, флаг онлайн и историю команд.getIsOnline() — Считает ли хост в данный момент соединение онлайн?drainRetryQueue() — Вручную очистить любые сообщения, поставленные в очередь во время оффлайна.cleanup() — Отписаться от каждого слушателя — вызов перед удалением виджета.<script> window.addEventListener('load', function () { var host = window.CompaninWidgetHost; if (!host) return; host.open(); host.sendText('Hi! I have a question about pricing.'); console.log(host.getState()); });</script>Позвольте виджету распознавать ваших вошедших пользователей, чтобы разговоры были персонализированы и восстанавливались на их устройствах. Ваш сервер подписывает краткосрочный токен, который виджет передает Companin; Companin проверяет его и связывает сессию с этим пользователем.
1. Получите ваш секрет подписи. В панели управления откройте Установка → Вошедшие пользователи → Генерировать секрет, затем скопируйте его в окружение вашего сервера. Никогда не раскрывайте его в коде браузера.
2. Подпишите токен на вашем сервере — краткосрочный HS256 JWT, содержащий идентификатор пользователя (sub), электронную почту и имя:
const jwt = require('jsonwebtoken'); // npm i jsonwebtokenfunction signUserToken(user) { return jwt.sign( { sub: String(user.id), email: user.email, name: user.name }, process.env.COMPANIN_EMBED_SECRET, { algorithm: 'HS256', expiresIn: '5m' } );}3. Передайте токен виджету. На странице, рендеренной на сервере, добавьте его в тег скрипта как data-user-token; в одностраничном приложении вызовите identify() после входа пользователя:
<!-- Option A: server-rendered page — put the signed token on the script tag --><script src="https://YOUR_WIDGET_HOST/widget.js" data-widget-key="wgt_your_key" data-user-token="SERVER_SIGNED_JWT"></script><!-- Option B: after login — fetch a fresh token and call identify() --><script> fetch('/api/widget-user-token') .then(function (r) { return r.json(); }) .then(function (data) { if (data.token) window.CompaninWidget.identify({ token: data.token }); });</script>Плохой или просроченный токен игнорируется — виджет просто остается анонимным, так что безопасно всегда пытаться идентифицировать.
Используйте sendSafe вместо sendText, когда важна доставка. Хост отслеживает события онлайн и оффлайн браузера; во время оффлайна сообщения добавляются в очередь повторов, и срабатывает событие companin:widget:offline. Как только соединение восстанавливается, очередь автоматически очищается в порядке, и срабатывает companin:widget:online.
window.CompaninWidgetHost.sendSafe('Track my order #1234');window.addEventListener('companin:widget:offline', function () { showBanner('You are offline — your message will send automatically.');});window.addEventListener('companin:widget:online', function () { showBanner('Back online.');});window.addEventListener('companin:widget:retryDrained', function (e) { showBanner(e.detail.count + ' queued message(s) sent.');});Оборачивайте отправку в sendWithTimeout, чтобы защититься от ответа, который никогда не приходит. Если ответ не получен в течение тайм-аута (по умолчанию 10 секунд), срабатывает событие companin:widget:timeout, чтобы вы могли показать дружелюбный запрос на повтор вместо того, чтобы оставлять пользователя в ожидании.
window.CompaninWidgetHost.sendWithTimeout('Are you there?', 8000);window.addEventListener('companin:widget:timeout', function () { showRetryPrompt('That took longer than expected. Try again?');});Когда виджет сообщает об ошибке, хост пытается переподключиться до трех раз с увеличением времени ожидания (1.5с, 3с, затем 4.5с), излучая companin:widget:reconnecting при каждой попытке. Успешный ответ сбрасывает счетчик; если все попытки не удались, срабатывает companin:widget:reconnectFailed, чтобы вы могли плавно вернуться к предыдущему состоянию.
window.addEventListener('companin:widget:reconnecting', function (e) { console.log('Reconnecting — attempt', e.detail.attempt, 'in', e.detail.delay, 'ms');});window.addEventListener('companin:widget:reconnectFailed', function () { showBanner('We could not reconnect. Please refresh the page.');});Зарегистрируйте перехватчик с помощью intercept(fn), чтобы проверить, переписать или отменить каждое исходящее сообщение. Верните измененный полезный груз, чтобы изменить его, верните false, чтобы отменить отправку, или ничего не возвращайте, чтобы пропустить его без изменений. intercept возвращает функцию отписки.
const stop = window.CompaninWidgetHost.intercept(function (payload) { if (typeof payload === 'string') { if (!payload.trim()) return false; // cancel the send return payload.replace(/[\w.+-]+@[\w-]+\.[\w.-]+/g, '[email]'); } return payload;});// Later, to remove the interceptor:stop();Хост повторно излучает каждое изменение жизненного цикла виджета как событие DOM CustomEvent в окне, так что вы можете реагировать, не удерживая ссылку на виджет. Соответствующие данные находятся в event.detail.
companin:widget:open / close — Панель виджета была открыта или закрыта.companin:widget:message / response — Посетитель отправил сообщение или агент ответил.companin:widget:authFailure — Аутентификация с бэкендом не удалась.companin:widget:error — Виджет сообщил об ошибке.companin:widget:offline / online — Браузер потерял или восстановил соединение.companin:widget:queued / retryDrained — Сообщение было поставлено в очередь во время оффлайна или очередь была очищена.companin:widget:reconnecting / reconnectFailed — Попытка автоматического переподключения началась или все попытки были исчерпаны.companin:widget:timeout — Сообщение не получило ответ в течение своего тайм-аута.window.addEventListener('companin:widget:message', function (e) { console.log('Visitor sent:', e.detail.message);});window.addEventListener('companin:widget:response', function (e) { console.log('Agent replied:', e.detail.response);});window.addEventListener('companin:widget:authFailure', function (e) { console.warn('Widget auth failed:', e.detail.error);});Декуплированный код может управлять виджетом, отправляя событие companin:widget:command вместо прямого вызова API. Отправьте строку, чтобы доставить сообщение, или объект детали, такой как { action: 'open' } или { text: 'Hello' }. Это удобно для аналитических тегов, GTM или других скриптов, которые не должны импортировать виджет.
// Open the widget from anywhere — no widget reference needed.window.dispatchEvent(new CustomEvent('companin:widget:command', { detail: { action: 'open' }}));// Or send a message.window.dispatchEvent(new CustomEvent('companin:widget:command', { detail: { text: 'I need help with billing' }}));Установите window.__COMPANIN_WIDGET_WEBHOOK_URL на конечную точку коллектора, и хост пересылает события открытия, закрытия, сообщения и ответа на него в формате JSON через navigator.sendBeacon (падение обратно на keepalive fetch). Это легкий, клиентский дополнение к серверным вебхукам — полезно для аналитики первой стороны.
// Point the host at your collector before the widget loads.window.__COMPANIN_WIDGET_WEBHOOK_URL = 'https://example.com/collect/widget';