Блог
Руководства

Встраивание чат-виджета на базе знаний с захватом лидов

Практическое руководство по встраиванию Simmetric Chat на ваш сайт: sandboxed iframe-loader, model pin, разрешаемый на сервере, захват лидов и настройка CORS.

Simmetric Team8 мин чтения15/09/2026

Превратите документацию в ассистента на входе

В вашей базе знаний уже есть ответы, которые ищут посетители. Встроенный чат-виджет выводит эти ответы на ваш сайт как разговорную входную дверь: посетители задают вопросы, виджет выполняет тот же гибридный RAG-конвейер и ту же агентную инфраструктуру, которой пользуются ваши внутренние команды, а ответы приходят с цитатами из тех workspaces, которые вы решили открыть. Это руководство проходит по встраиванию виджета, контролю над тем, что он отвечает, захвату лидов и правильной настройке CORS - от админ-панели до работающего сниппета за несколько минут.

Двухшаговый embed: loader и sandboxed iframe

Виджет построен вокруг ориентированного на безопасность embed-паттерна. Вместо инъекции markup и стилей в вашу страницу виджет приходит в два шага:

  1. Скрипт-loader. Добавьте на сайт один тег script, указывающий на ваш widget-сервис с ID виджета. Loader - небольшой JavaScript-файл, создающий iframe на хост-странице.
  2. Панель iframe. Iframe загружает автономное приложение Preact - собранное как IIFE-бандл с инлайн-CSS, - которое рисует плавающую кнопку, панель чата и всё взаимодействие внутри собственного документа.
html
<script src="https://ваш-simmetric-chat.com/widget/loader.js?widgetId=WIDGET_ID"></script>

Почему iframe? Потому что интерполяция строк недоверенного контента в хост-страницу - классический путь XSS. Запуск интерфейса виджета в sandboxed iframe с opaque origin полностью устраняет этот класс риска: содержимое чата никогда не выполняется в контексте вашей страницы. Старые embed-пути через интерполяцию строк были удалены из продукта именно поэтому, так что двухшаговый паттерн не опция среди прочих - это сам embed.

Связь между iframe и страницей идёт через небольшой версионированный протокол postMessage (типы сообщений simmetric:*), который обслуживает открытие/закрытие FAB, перекраску FAB и handshake'и хранилища сессий. Обе стороны валидируют каждое входящее сообщение против точного ожидаемого contentWindow, так что поддельные сообщения между разными iframe'ами игнорируются.

Создать виджет и направить его на знания

Всё начинается в админ-панели:

  1. Создайте виджет в Настройки → Виджеты. Создание привязано к лицензии (widget_enabled) и соблюдает числовой лимит виджетов тарифа.
  2. Привяжите виджет к одному или нескольким workspaces. Whitelist workspaces атомарно заменяет все предыдущие привязки, поэтому расслоение доступа к базе знаний - это вопрос того, какие workspaces прикрепить.
  3. Настройте брендинг: основной цвет, имя бота, логотипы, позиция (справа внизу или слева внизу). Развёртывания уровня Community получают разумные значения по умолчанию при пустых полях; полная кастомизация и white-labeling - enterprise-флаги.
  4. Скопируйте embed-сниппет в HTML вашего сайта.

Поскольку виджеты определены на workspace, знание, из которого виджет может черпать, - ровно объединение баз знаний привязанных workspaces. Support-виджет может видеть публичный документационный workspace, никогда не касаясь данных внутренних проектов.

Model pin ответов: разрешается на сервере

Недавнее добавление важно для контроля качества: конфигурация каждого виджета может выбирать конкретный LLM-провайдер и модель, обслуживающие чат-ответы этого виджета. Pin хранится в строке виджета и разрешается на сервере при каждом запросе чата - он никогда не приходит от клиента, прокси виджета или браузера посетителя. Модель с pin имеет приоритет над значением по умолчанию workspace, а виджеты без pin сохраняют стандартную цепочку разрешения. На практике: ваш маркетинговый виджет может работать на той самой модели, которую вы проверили для публичных ответов, независимо от того, что кто-то подменит на стороне клиента.

Захват лидов, уважающий посетителей

Захват лидов в виджете спроектирован под реальность публичной формы: абьюз концентрируется там, где собираются данные, поэтому lead-эндпоинт намеренно ограничен 3 запросами в час на источник (лимит виден пользователю). Поток:

  • Посетитель видит барьер согласия на персональные данные до чата - явное признание того, как обрабатываются данные, а не спрятанная внизу ссылка на политику.
  • Lead-карточка собирает контактные данные во время или после разговора, и отправки попадают в почтовый ящик лидов виджета в админ-панели, с CSV-экспортом для вашего конвейера.
  • Сессии анонимны по решению дизайна: сервер создаёт сессию с 256-битным токеном и сроком 24 часа, и каждый последующий запрос валидируется против неё. Лимиты на сессию (20 сообщений в час, 5 разговоров в день) при превышении возвращают 429 с подсказкой retryAfter, и интерфейс показывает предупреждение о лимите вместо молчаливого отказа.

Rate limit'ы - часть истории доверия, а не запоздалая мысль: публичная чат-поверхность должна изящно деградировать под нагрузкой или абьюзом, и lead-лимитер - самый узкий из трёх лимитеров на стороне виджета.

CORS: закрыт по умолчанию by design

Widget-трафик пересекает источники по определению, поэтому CORS - часть поверхности безопасности, а не запоздалая мысль. Каждый виджет несёт собственный список allowedOrigins, редактируемый из админ-панели. В рантайме динамический CORS-middleware валидирует заголовок Origin каждого запроса против списка этого виджета: запросы с неразрешённых источников отклоняются уже на preflight, а middleware падает fail-closed: если проверка источника не может обратиться к базе, доступ запрещается, а не разрешается.

Настройте в один проход:

  • Добавьте источники вашего сайта (схема и хост, без игр с завершающим слэшем) в разрешённые источники виджета.
  • Помните, что варианты поддомена считаются отдельными источниками: example.com и www.example.com - две записи.
  • Используйте https://-источники в продакшене; widget-сервис говорит по тем же URL-правилам, что и остальной стек.

Всё остальное - URL loader'а, iframe, bootstrap сессии, SSE-поток чата - использует тот же хост, на котором вы разворачиваете widget-сервис, поэтому есть ровно одно место, где решается доверие к источнику: разрешённый список виджета.

Что где работает

Быстрая карта ориентации, потому что виджет затрагивает три процесса:

  • Основной сервер - CRUD и брендинг виджетов, привязка workspaces, внутренний API, который widget-сервис вызывает своим API-ключом, и lead/analytics-эндпоинты для администраторов. Весь внутренний роутер возвращает 402, когда фича виджетов выключена.
  • Widget-сервис - публичная embed-поверхность: JS-loader, HTML iframe, создание сессий, выдача кэшированной конфигурации, SSE-прокси чата к основному серверу и lead-эндпоинт. Он аутентифицируется на основном сервере WIDGET_API_KEY и несёт собственные лимитеры частоты.
  • Iframe - IIFE-клиент Preact с жизненным циклом чата: создание сессии, SSE-стриминг токен за токеном, отображение цитат, предложенные вопросы и барьеры согласия.

Прокси чата пересылает тот же формат событий, что и внутренний streaming API - статусные сообщения, анонсы плана, потоковые токены, цитаты и терминальные события done/error, - так что всё, что ваша команда видит в workspace-чате, посетители испытывают в виджете.

Чек-лист запуска

  • Виджет создан, лицензионная фича активна, workspaces привязаны
  • Брендинг настроен; white-label-флаг, если виджет не должен нести марку продукта
  • Model pin ответов задан в строке виджета (разрешается на сервере)
  • Разрешённые источники покрывают каждый сайт и поддомен, который будет его встраивать
  • Захват лидов проверен end-to-end: барьер согласия, отправка, админ-ящик, CSV-экспорт
  • Rate limit'ы поняты: 3 лида в час, 20 сообщений в час на сессию, 5 разговоров в день

Оттуда виджет - это drop-in: один тег script, один разрешённый список, одна база знаний, которой вы уже доверяете. Когда посетители задают вопросы, они получают ответы, опирающиеся ровно на выбранные вами workspaces, - с конвейером захвата лидов, вежливым к людям и строгим к ботам.

Читайте полное руководство в документации →

Похожие статьи