Методы виджета

После подключения скрипта виджет публикует глобальный объект window.apxChat для управления чатом из кода страницы. Метод init() доступен сразу, остальные — после монтирования React-компонента.

Подключение

XML
<script src="https://cdn.apx.chat/static/widget.js" async></script>
<script>
  window.addEventListener('load', function () {
    window.apxChat.init('ВАШ_ТОКЕН');
  });
</script>

Два разных токена

Часто путают токен в init() и токен в setToken() — это разные вещи с разным назначением:

МетодЧто за токенДля чего
init(token)Токен виджетаИдентифицирует, какой виджет загружать (его настройки, операторы, дизайн)
setToken(token)Токен вашего пользователяДаёт AI-оператору доступ к вашему API от имени этого пользователя

init(token, client?, options?)

Первичная инициализация виджета. Делает HTTP-запрос на сервер, получает конфиг (тема, дизайн, аналитика, операторы), создаёт DOM-контейнер #apx-chat-root и монтирует в него React-приложение.

ПараметрТипОбяз.Описание
tokenstringдаТокен виджета из админ-панели. Идентифицирует, какой именно виджет загружать
clientstringнетВаш внутренний ID пользователя сайта. Значение приходит со страницы и ничем не подтверждено, поэтому для авторизации не используется — если нужен идентификатор, которому можно доверять, см. подписанную личность
options.proxyApiUrlstringнетПодмена MAIN_URL / API_URL / SOCKET_URL. См. Proxy виджета
options.proxyWidgetUrlstringнетПодмена WIDGET_URL
JS
window.apxChat.init(
  '1430a564bc7ccfeb0093d2302548a0fb',
  'user-42',
  {
    proxyApiUrl: 'https://yourdomain.com/chat-api',
    proxyWidgetUrl: 'https://yourdomain.com/chat-widget',
  },
);

open()

Открывает окно чата. Полезно, когда нужно открыть чат по своей кнопке на сайте (например, «Связаться с нами» в шапке), а не только по дефолтной круглой кнопке виджета.

JS
document.getElementById('support-btn').onclick = () => window.apxChat.open();

close()

Закрывает окно чата.

JS
window.apxChat.close();

toggle()

Переключает состояние чата (открыт ↔ закрыт).

JS
window.apxChat.toggle();

changeTheme(theme)

Переключает тему оформления виджета. Полезно для синхронизации с темой вашего сайта. Невалидное значение игнорируется с предупреждением в консоли. Вызывать можно и до init(), и сразу после него: тема применится, как только виджет загрузится.

Надолго выбор сохраняется, только если в настройках канала тема не задана. Выбор записывается в localStorage, но тема канала главнее: если она задана, при следующей загрузке страницы виджет снова откроется в ней. Новые веб-каналы создаются со светлой темой. Поэтому, чтобы тема виджета совпадала с темой сайта, вызывайте changeTheme при каждой загрузке страницы и при переключении темы на сайте.

ПараметрТипОписание
theme'light' | 'dark'Целевая тема
JS
// у вас на сайте переключили тёмную тему — синхронизируем виджет
window.apxChat.changeTheme('dark');

setToken(token)

Передаёт токен вашего пользователя AI-оператору, чтобы тот мог дёргать ваше API от его имени. Не путать с init(token) — здесь токен идентифицирует клиента на вашем сайте, а не виджет.

Зачем это нужно

В админ-панели для AI-оператора можно настроить API-интеграции — список endpoint'ов вашего бэкенда (заказы, профиль, баланс и т.д.), которые AI вызывает как tools во время диалога. У каждого endpoint есть флаг useUserToken:

  • useUserToken: false — AI вызывает endpoint без авторизации (публичные данные).
  • useUserToken: true — сервер берёт токен, сохранённый через setToken(), и подставляет его в заголовок Authorization при вызове.

Так AI «понимает», от чьего имени делать запросы:

Клиент: «Где мой заказ?» AI вызывает GET https://yourshop.com/api/orders с Authorization: Bearer <user_jwt> Ваш бэкенд возвращает заказы конкретно этого пользователя AI отвечает: «Заказ #1234 в пути, прибудет завтра»

Сервер подставляет токен в заголовок Authorization: <prefix> <token> при вызове ручки — префикс настраивается в интеграции, по умолчанию Bearer.

Без setToken() AI имеет доступ только к публичным/анонимным endpoint'ам и не может работать с персональными данными.

ПараметрТипОписание
tokenstringJWT или любой токен вашего бэкенда, по которому он умеет авторизовать пользователя

Метод можно вызывать в любой момент, в том числе до того, как виджет закончил загрузку — вызов не потеряется.

JS
// после логина у вас на сайте
window.apxChat.setToken(myJwtFromBackend);

Жизненный цикл токена

Что происходитЧто с токеном
вызвали setToken(token)сохраняется на сервере в зашифрованном виде
закрылась последняя вкладка с чатомудаляется сразу
закрылась одна из нескольких вкладоксохраняется, пока открыта хотя бы одна
вызвали clearToken()удаляется сразу
ничего из перечисленного (например, обрыв связи)удаляется автоматически не позже чем через 24 часа
виджет переподключилсяпереотправляется автоматически, вызывать setToken заново не нужно

Что гарантируется

  • Токен хранится только в оперативной памяти браузера и в зашифрованном виде на нашем сервере. В localStorage он не попадает.
  • Его не видит ни оператор в чате, ни AI-модель: заголовок Authorization формируется на сервере в момент вызова, модель не может его прочитать или переслать.
  • Он уходит только на те адреса, которые вы сами прописали в API-интеграции. Переадресации при вызове ваших ручек запрещены — токен не может «уехать» на сторонний домен по редиректу.

Не передавайте основной JWT вашего пользователя. Выпускайте для чата отдельный токен с коротким сроком жизни и доступом только к тем ручкам, которые нужны AI. Если авторизация на сайте построена на httpOnly-куках, setToken вам не подойдёт в принципе — JS не может прочитать такую куку; используйте подписанную личность.

clearToken()

Отзывает токен пользователя. Вызывайте при выходе из аккаунта на вашем сайте — иначе AI сможет обращаться к вашему API от имени этого пользователя, пока открыта вкладка.

JS
// пользователь разлогинился у вас на сайте
window.apxChat.clearToken();

setIdentity(identity) / clearIdentity()

Альтернатива setToken() для тех, кто не хочет отдавать токены пользователей. Ваш бэкенд подписывает идентификатор пользователя, а мы передаём его в ваше API вместе с подписью запроса — самого токена у нас не существует. Работает при авторизации через httpOnly-куки.

Полное описание, включая формат подписи и проверку на вашей стороне — Подписанная личность.

JS
window.apxChat.setIdentity(identityJwtFromBackend);
window.apxChat.clearIdentity(); // при выходе из аккаунта

popup.toggle(uuid?)

Открывает и закрывает попап — маркетинговое всплывающее окно с формой, ссылкой, товарами или игрой (не путать с чатом). Попапы настраиваются в кабинете в разделе «Маркетинг → Попап» и показываются сами по условиям показа, а метод управляет ими из кода сайта.

ПараметрТипОписание
uuidstring (опц.)UUID попапа. Если этот попап на экране — закрывает его, если на экране другой — показывает этот вместо него. Без аргумента закрывает показанный попап, а если на экране ничего нет — открывает первый подходящий попап сайта: сначала с триггером «Вручную (через JS API)», затем по приоритету

Готовый вызов с UUID и кнопкой копирования есть в редакторе попапа на шаге «Условия показа», если выбрать «Вручную (через JS API)».

Вызывать метод можно сразу после init(), не дожидаясь загрузки виджета: пока виджет загружает попапы, вызовы ждут и потом выполняются по порядку — до 10 вызовов popup.toggle() и stories.open() вместе.

Метод учитывает частоту, условия показа, расписание и сроки публикации: если попап сейчас показывать нельзя, вызов ничего не делает. Пауза между автопоказами на вызов из кода не действует. Истории без uuid метод не открывает — для них есть stories.open().

Внутри просто диспатчит CustomEvent('apx-popup-toggle') — можно делать то же самое напрямую без обёртки.

JS
window.apxChat.popup.toggle();
window.apxChat.popup.toggle('a3f7c2e1-...');

Событие apx-popup-toggle

Кастомное событие на window. Виджет слушает его и переключает попап. Можно диспатчить вручную — без обёртки popup.toggle().

JS
window.dispatchEvent(
  new CustomEvent('apx-popup-toggle', {
    detail: { uuid: 'a3f7c2e1-...' },
  }),
);
Поле detailТипОписание
uuidstring (опц.)UUID попапа — работает так же, как аргумент popup.toggle(uuid)

stories.open(popupId?, storyId?)

Открывает плеер интерактивных историй — так же, как если бы посетитель нажал на кружок или карточку историй. Нужен, когда у историй выбран вход «Без лаунчера» или вы хотите открывать их своей кнопкой на сайте.

ПараметрТипОписание
popupIdstring (опц.)UUID попапа историй — виден в адресе его редактора в кабинете, после /dashboard/popup/. Без аргумента открываются первые по приоритету истории сайта
storyIdstring (опц.)ID истории (кружка) в этом попапе, с которой начать показ. Без него — с первой истории, а если включено «Начинать с того, что посетитель ещё не видел» — с первой непросмотренной. Неизвестный ID — показ с первой истории

Готовый вызов с UUID и кнопкой копирования есть у сохранённых историй в редакторе: на шаге «Условия показа», в блоке «Открыть истории из кода сайта», а при входе «Без лаунчера» — ещё и на вкладке «Вход в истории». Выбирать «Вручную (через JS API)» и включать автопоказ для вызова не нужно. ID истории с кнопкой копирования указан под её заголовком на вкладке «Истории и слайды».

Вызывать метод можно сразу после init(), как и popup.toggle(): пока виджет загружает истории, вызов ждёт и выполняется, как только они загрузятся.

Это действие посетителя: частота, условия показа и расписание не проверяются, учитываются только сроки публикации. Если на экране уже есть попап или другие истории, они закроются — одновременно показывается только одно окно.

Если открыть истории нельзя, вызов ничего не делает и не пишет ошибок в консоль. Так бывает, когда:

  • в UUID опечатка;
  • истории выключены или для них не выбран этот сайт;
  • срок публикации ещё не начался или уже закончился;
  • ни один слайд ещё не готов к показу — фото и видео обрабатываются;
  • истории недоступны вашей организации.

Без popupId вызов ничего не делает, если на сайте нет ни одних историй.

JS
document
  .getElementById('stories-btn')
  .addEventListener('click', () => window.apxChat.stories.open('b91d4c7a-...'));

// сразу с нужной истории
window.apxChat.stories.open('b91d4c7a-...', 'ID_ИСТОРИИ');

booking.open(options?)

Открывает онлайн-запись в окне виджета — на вкладке «Запись», поверх любого экрана: стартового, FAQ, формы или звонка. Нужен, чтобы записывать клиентов своей кнопкой на сайте, например «Записаться» в карточке услуги. Работает на сайтах с виджетом канала, у которого включена онлайн-запись.

Поле optionsТипОписание
branchIdstring (опц.)ID филиала, с которого начать запись
serviceIdstring (опц.)ID услуги
specialistIdstring (опц.)ID специалиста

Без аргументов запись открывается с начала: предвыбор предыдущего вызова сбрасывается. С options клиент начинает запись с заданного выбора — можно передать одно поле или несколько. Поля, которые вы не передали, берутся из значений по умолчанию в настройках канала, если они там заданы. Если филиал, услуга или специалист не найдены или не связаны между собой (специалист не работает в этом филиале, услугу там не оказывают), виджет пишет в консоль ApxChat: booking.open — филиал, услуга или специалист не найдены и оставляет только ту часть выбора, которая подходит.

Готовый вызов с кнопкой копирования есть в кабинете: в настройках канала сайта, в блоке «Онлайн-запись» → «Открыть запись своей кнопкой» (там же можно выбрать филиал, услугу и специалиста из каталога), и в «Онлайн-запись → Настройки» рядом со ссылкой на публичную страницу.

Вызывать метод можно сразу после init(), не дожидаясь загрузки виджета: вызов подождёт и выполнится, когда виджет загрузится.

Если запись на канале выключена, вызов ничего не открывает и пишет в консоль предупреждение ApxChat: онлайн-запись выключена на канале. Так же — пока запись не опубликована в кабинете («Онлайн-запись → Настройки»).

В режиме «только запись» — когда в канале выключен чат, а запись включена, — кнопка виджета открывает запись, а open() и toggle() ничего не делают и пишут ApxChat: чат выключен на канале. Открывать окно из кода в этом режиме нужно через booking.open().

Во время диалога вызов работает как стрелка «Назад»: окно переходит на стартовый экран с вкладкой «Запись», а переписка не теряется — клиент может вернуться в диалог после записи.

Каждый вызов начинает новую запись. Если клиент уже записался и видит подтверждение, кнопка виджета и вкладка «Запись» показывают это подтверждение, а booking.open() — новую запись.

JS
// запись с начала
window.apxChat.booking.open();

// сразу с нужной услуги в нужном филиале
window.apxChat.booking.open({
  branchId: 'ID_ФИЛИАЛА',
  serviceId: 'ID_УСЛУГИ',
});

Если скрипт виджета загружается позже кнопок, можно ставить вызовы в очередь через глобальную функцию APX — вызовы booking.open из неё выполнятся, когда загрузится виджет канала с записью:

XML
<script>
  window.APX = window.APX || function () { (APX.q = APX.q || []).push(arguments); };
</script>
<button onclick="APX('booking.open', { serviceId: 'ID_УСЛУГИ' })">Записаться</button>

Примеры

Кнопка «Записаться» на странице услуги

XML
<button id="book-haircut" type="button">Записаться</button>
<script>
  document.getElementById('book-haircut').addEventListener('click', () => {
    window.apxChat.booking.open({ serviceId: 'ID_УСЛУГИ' });
  });
</script>

Открыть чат по клику на свою кнопку

JS
document
  .getElementById('support-btn')
  .addEventListener('click', () => window.apxChat.open());

Дать AI-оператору доступ к данным залогиненного пользователя

JS
window.apxChat.init('ВАШ_ТОКЕН', 'user-42');

// JWT вашего пользователя — AI будет ходить с ним в API-интеграции,
// у которых в админке включён флаг useUserToken
window.apxChat.setToken(jwt);

Синхронизация темы с сайтом

JS
const syncTheme = () => {
  const theme = document.documentElement.dataset.theme; // 'light' | 'dark'
  window.apxChat.changeTheme(theme);
};

// При каждой загрузке страницы: иначе после перезагрузки вернётся тема из настроек канала
syncTheme();

// И при каждом переключении темы на сайте
new MutationObserver(syncTheme).observe(document.documentElement, {
  attributes: true,
  attributeFilter: ['data-theme'],
});