Виджет для сайта
Виджет — это чат, который посетители видят на вашем сайте. Он загружает опубликованного вами бота и ведёт весь диалог в браузере. Без языковой модели, без запросов к сторонним сервисам, размер после сжатия — около 22 КБ. Чат с оператором загружается из отдельного файла, только когда вы его включаете.
Установка
Вставьте эту строку перед </body> на каждой странице, где должен появляться бот. В панели управления на странице Установка эта строка уже содержит ваш ключ.
<script src="https://cdn.kavchat.com/v1/kavchat.js" data-key="pk_live_..." async></script>Публичный ключ (pk_live_...) можно размещать на странице. Секретный ключ (sk_live_...) нельзя размещать на странице ни в коем случае.
Атрибуты
| Атрибут | По умолчанию | Описание |
|---|---|---|
data-key | Обязательный | Ваш публичный ключ. |
data-api | https://api.kavchat.com | Адрес API. |
data-locale | Язык браузера | Язык интерфейса виджета (кнопок, формы, уведомлений): he, en, ar, ru, es, fr, de, pt, it, tr. Если перевода на этот язык нет, используется язык бота. Содержимое сценария всегда отображается так, как вы его написали. Для he и ar используется направление справа налево. |
data-user-token | Нет | Токен идентификации пользователя, вошедшего в систему. См. Идентификация пользователей. |
data-user-name | Нет | Отображается в приветствии ({name}) и заранее подставляется в форму обращения. |
data-open | false | При значении "true" чат открывается сразу после загрузки. |
<script
src="https://cdn.kavchat.com/v1/kavchat.js"
data-key="pk_live_..."
data-locale="he"
data-user-token="<identity JWT>"
data-user-name="Dana"
data-open="false"
async></script>JavaScript API
Скрипт создаёт window.Kavchat:
Kavchat.init({
publicKey: 'pk_live_...',
apiBase: 'https://api.kavchat.com', // optional
locale: 'he', // optional
userToken: '<identity JWT>', // optional
userName: 'Dana', // optional
open: false, // optional
onScreen(screen, targetId) {}, // optional: "screen" buttons in your scripts
onEvent(event) {}, // optional: ready, unavailable, open, close, effect, ticket
});
Kavchat.open();
Kavchat.close();
Kavchat.toggle();
Kavchat.setUser({ token: '<identity JWT>', name: 'Dana' }); // on login; setUser(null) on logout
Kavchat.offset({ bottom: 80 }); // lift the launcher, e.g. above a cookie banner; offset(null) resets
Kavchat.destroy();Вызывать init не нужно, если в теге скрипта указан data-key. Повторный вызов init заменяет работающий виджет.
Вызов API до загрузки скрипта
У тега скрипта указан async, поэтому ваш код может выполниться раньше. Создайте очередь и добавляйте в неё вызовы. После загрузки виджет выполнит их по порядку. init всегда выполняется первым, а его настройки имеют приоритет над атрибутами тега.
<script>
window.Kavchat = window.Kavchat || { q: [] };
Kavchat.q.push(['init', { publicKey: 'pk_live_...', onScreen: function (s, id) { location.href = '/' + s + '/' + id; } }]);
Kavchat.q.push(['setUser', { token: '<identity JWT>', name: 'Dana' }]);
</script>
<script src="https://cdn.kavchat.com/v1/kavchat.js" async></script>Каждый элемент очереди имеет вид [methodName, ...args]. После загрузки скрипта Kavchat.q.push(...) продолжает работать и выполняет вызов сразу, поэтому один и тот же код подходит для обоих случаев.
Место для cookie-баннера
Если на сайте есть элемент, закреплённый внизу экрана, например cookie-баннер, вы можете поднять над ним кнопку, окно и облачка. Для этого есть два способа: CSS-переменная --kavchat-bottom или команда Kavchat.offset, которая принимает число в пикселях или значение длины, например 5rem. Смещение прибавляется к высоте, заданной в панели управления. Когда баннер закроется, удалите переменную или вызовите offset(null). Оба способа работают и на сайте со строгой политикой CSP. На телефоне окно открывается на весь экран и не смещается.
/* while your cookie banner is shown */
body.cookie-banner-open { --kavchat-bottom: 80px; }// works before or after the widget script loads
window.Kavchat = window.Kavchat || { q: [] };
Kavchat.q.push(['offset', { bottom: banner.offsetHeight + 12 }]);
// after the visitor makes a choice
Kavchat.q.push(['offset', null]);События
Функция onEvent получает одно из следующих событий:
type | Поля | Когда происходит |
|---|---|---|
ready | version, offline | Бот загружен из сети или из сохранённой копии, если сети нет. |
unavailable | reason? ('quota') | Бот выключен, доступен только тестовым пользователям или квота исчерпана. Ничего не отображается. |
open, close | Окно открылось или закрылось. | |
effect | effect | Кнопка запросила открытие формы обращения, ссылки или экрана. |
ticket | id, number | Создано обращение. |
live | state, id | Изменилось состояние чата с оператором: queued, active, closed или ticket. |
Kavchat.init({
publicKey: 'pk_live_...',
onEvent(event) {
if (event.type === 'ready') console.log('Bot version', event.version, event.offline ? '(offline copy)' : '');
if (event.type === 'ticket') console.log('Request opened', event.number);
},
});Действия в сценарии
- Обращение: открывает форму обращения внутри чата. К обращению прикладывается переписка.
- Ссылка: открывает ссылки
https:иtel:в новой вкладке (rel="noopener noreferrer"). Ссылки других типов не открываются. - Экран: вызывает вашу функцию
onScreen(screen, targetId). Без неё кнопка на сайте ничего не делает.
Список экранов в редакторе
Один раз укажите экраны, которые умеет открывать приложение, в параметре screens метода Kavchat.init. SDK сам отправит список в Kavchat, и редактор сценариев предложит эти экраны по названиям в выпадающем списке вместо поля для свободного ввода. Редактор также запросит идентификатор элемента, если он нужен экрану, и предупредит о кнопке, ведущей на экран, которого нет в списке. Вводить список экранов вручную в панели управления не нужно.
Kavchat.init({
publicKey: 'pk_live_...',
screens: [
{ id: 'orders', label: 'My orders' },
{ id: 'product', label: 'Product page', needsTarget: true }, // the button also carries a product id
],
onScreen(screen, targetId) {
location.href = targetId ? `/${screen}/${targetId}` : `/${screen}`;
},
});id— значение, которое получаетonScreen: латинские буквы, цифры,_,.и-, до 40 символов.label— название, которое видит администратор, до 60 символов. Можно указать до 100 экранов. Некорректные записи и повторяющиеся идентификаторы пропускаются.needsTarget: кнопка также передаёт идентификатор элемента (например, товара), который поступает вonScreenкакtargetId.- Список отправляется в фоновом режиме после загрузки версии, только если он изменился или раз в неделю. Ошибка отправки не отображается, повторная попытка выполняется при следующем запуске. Пользователь ничего не видит.
- Зарегистрированные экраны отображаются в панели управления в разделе «Бот», «Настройки», «Экраны приложения». Для каждого экрана указаны платформы, которые о нём сообщили. Экран, удалённый из приложения, можно удалить и там.
Идентификация ваших пользователей
Чтобы привязать диалоги и обращения к идентификатору пользователя в вашей системе или показывать бота только тестовым пользователям, подпишите JWT на сервере и передайте его через data-user-token или userToken. Когда пользователь входит в систему или выходит из неё, вызывайте Kavchat.setUser(...). Виджет отправляет токен в заголовке Authorization: Bearer <token> при каждом запросе. Пользователь, вошедший в систему, может создать обращение, не оставляя email или телефон. Как создать токен: Идентификация пользователей.
Политика CSP
Виджет работает на сайте со строгой CSP без 'unsafe-inline' и 'unsafe-eval'. Достаточно разрешить два наших источника:
script-src https://cdn.kavchat.com;
connect-src https://api.kavchat.com;Стили загружаются в виде constructable stylesheets внутри Shadow DOM, поэтому менять style-src не нужно. Если у бота есть собственное изображение или в сценариях используются изображения, добавьте в img-src сервер, с которого они загружаются. Виджет ничего не загружает из других источников и не открывает iframe.
Чат с оператором
На сайте ничего настраивать не нужно. Когда вы включаете чат с операторами в панели управления, виджет загружает дополнительный файл kavchat-live.js из той же папки и той же версии, что и kavchat.js. На сайтах без чата с операторами этот файл вообще не загружается.
- Выбор: рядом с «Обратиться в поддержку» появляется вариант «Чат с оператором», но только после того, как сервер подтвердит наличие свободного оператора. В нерабочее время или когда все операторы заняты, отображается только форма обращения. Рядом указана краткая причина и время возвращения команды, если оно известно. Когда месячная квота исчерпана, форма отображается без пояснения.
- Запрос: гости оставляют email или телефон на случай, если ни один оператор не освободится вовремя. Можно также добавить имя и первое сообщение. Если открыто несколько отделов, нужно выбрать один. Идентифицированным пользователям (
userToken) не нужно указывать контактные данные. Если ни один оператор не может принять чат, открывается форма обращения с уже введёнными данными. - Ожидание: отображается надпись «Ожидаем оператора» с обратным отсчётом заданного вами времени ожидания, а также кнопки «Оставить сообщение вместо чата» и «Завершить чат». Писать можно уже во время ожидания. Когда время истекает, чат автоматически превращается в обращение. Посетитель видит номер обращения и пояснение, что ни один оператор не освободился вовремя.
- Диалог: имя оператора, сообщения, индикатор набора текста, перевод на другого оператора и завершение чата. Всё, что приходит с сервера, отображается как обычный текст, без HTML и ссылок. Программы чтения с экрана озвучивают новые сообщения, а если окно закрыто, на плавающей кнопке появляется точка.
- В реальном времени: соединение устанавливается через Server-Sent Events. При обрыве связи виджет пытается подключиться снова с постепенно растущими интервалами и получает всё пропущенное. Поэтому сообщения не теряются и не отображаются дважды. В сетях, блокирующих такое соединение, виджет переходит на повторные запросы (long-poll). У каждого сообщения есть идентификатор, поэтому повторная попытка не создаёт дубликат. Неотправленное сообщение помечается, и его можно отправить повторно нажатием.
- Перезагрузка: токен доступа к чату хранится в
localStorageс привязкой к публичному ключу и диалогу, но никогда не попадает в адрес страницы. Он действует до 12 часов или до завершения чата. Поэтому после перезагрузки или перехода на другую страницу восстанавливается весь диалог: сначала часть с ботом, затем часть с оператором. - Без preflight: запросы отправляются без специальных заголовков, а тело запроса содержит JSON, передаваемый как
text/plain.
Ответы ИИ (Premium)
На сайте ничего настраивать не нужно. Когда вы включаете ответы ИИ в панели управления (со своим ключом провайдера ИИ), вопрос, на который нет ответа ни в одном сценарии, отправляется в Kavchat. Во время ожидания, до 20 секунд, чат показывает, что бот печатает. Ответ отображается как обычный текст с небольшой меткой «Ответ ИИ» на языке интерфейса. Под ним появляются кнопка связанной темы, если она есть, и кнопка «Обратиться в поддержку».
Если ответа нет, запрос завершился ошибкой, занял слишком много времени или превысил лимит (10 ответов на диалог каждые 15 минут), чат показывает обычное сообщение «Не удалось найти ответ». Вопрос по-прежнему попадает в отчёт о вопросах без ответа, а ответы ИИ сохраняются в истории диалога, как и любые другие сообщения.
Как работает виджет
- Изоляция: всё отображается внутри Shadow DOM. Ваш CSS не влияет на виджет, а CSS виджета не влияет на страницу.
- Кэш: опубликованный бот сохраняется в
localStorageс привязкой к публичному ключу вместе со своим ETag. При каждой загрузке отправляется заголовокIf-None-Match. Если ничего не изменилось, сервер отвечает кодом 304. Когда сети нет, виджет использует сохранённую копию и показывает уведомление об этом. - Диалоги: случайный идентификатор диалога хранится в
sessionStorage, поэтому при переходе между страницами продолжается тот же диалог. - Чат с оператором: открытый чат сохраняется в
localStorageи восстанавливается на следующей странице. - Данные: сведения о ходе диалога отправляются примерно через 2 секунды после каждого действия, а также когда страница становится скрытой.
- Значок Kavchat: отображается на всех тарифах. На Premium его можно скрыть в настройках бота.
- Доступность: окно представляет собой диалог с меткой. Фокус переходит в него и возвращается обратно, Esc закрывает окно. Кнопки реализованы как настоящие кнопки, новые сообщения бота озвучиваются, а анимация сокращается, если посетитель выбрал такую настройку.
Установка из npm
В одностраничном приложении можно включить виджет в сборку вместе с вашим кодом вместо загрузки через тег скрипта:
yarn add @kavchat/widget
# or: npm install @kavchat/widgetimport { createWidget } from '@kavchat/widget';
const widget = createWidget({ publicKey: 'pk_live_...' });
await widget.ready;
widget.open();