# Установка на сайт

> Куда вставить две строки и как проверить, что чат работает.

Чат — это веб-компонент. Вы добавляете две строки в общий шаблон всех страниц. Всё остальное
приходит с сервера Tolkly.

## Две строки
```html
<script type="module" src="https://api.tolkly.io/widget.js"></script>
<tolkly-chat project="your-project"></tolkly-chat>
```

Замените `your-project` на id проекта. Готовые строки с вашим id есть в приложении: раздел проекта
«Установка», блок «Установка на сайт». Там же кнопка «Скопировать код».

- `widget.js` весит около килобайта: он загружает чат с `https://api.tolkly.io`, а если чат за 2,5 с не
  поднялся — с нашего следующего адреса ([посетители из России](#russia)).
- Атрибут `endpoint` тегу не нужен: чат ходит туда, откуда загружен его скрипт.
- Загружайте скрипт с `https://api.tolkly.io`. Не копируйте его в репозиторий и не включайте в сборку. Так
  новые версии будут приходить на сайт сами.
- Других атрибутов не добавляйте. Название чата, приветствие, цвета и то, кто отвечает (ИИ или
  только люди), приходят с сервера. Элемент берёт их из `GET https://api.tolkly.io/v1/projects/<project>/widget`
  при подключении. Атрибуты нужны в редких случаях, когда сайту нужны свои значения
  ([атрибуты](https://tolkly.io/docs/ru/widget-attributes.md)).

## Куда их вставить
Вставьте обе строки один раз, прямо перед `</body>`, в шаблон, общий для всех страниц: корневой
layout, базовый шаблон или подвал темы. Не вставляйте их на каждую страницу отдельно. Как это
сделать в вашем стеке — в разделе [Фреймворки](https://tolkly.io/docs/ru/frameworks.md).

### Одностраничные приложения
В React, Vue, Angular, Next.js и Nuxt чат не должен пропадать при смене маршрута:

- Выводите `<tolkly-chat>` один раз, вне router outlet: в `index.html` или корневом layout.
  Внутри компонента страницы элемент удаляется и создаётся заново при каждом переходе.
- Загружайте скрипт один раз, а не на каждой странице.
- В TypeScript JSX объявите элемент, а не приводите его к `any`
  ([TypeScript и JSX](https://tolkly.io/docs/ru/frameworks.md#typescript-and-jsx)).

## Что загружается на каждой странице
Большинство посетителей чат не открывают. Поэтому на обычной странице загружается только кнопка:

| Запрос | Когда | Кэширование |
|---|---|---|
| `https://api.tolkly.io/widget.js` | на каждой странице | `no-cache` с ETag: при повторном просмотре приходит `304` без тела |
| `GET …/v1/projects/<project>/widget` | на каждой странице | браузер хранит ответ `WIDGET_SETTINGS_MAX_AGE_SECONDS` (по умолчанию 60 с) |
| `POST …/v1/projects/<project>/identify` | на каждой странице с `data-identity` и при `identify()` | `POST`, не кэшируется ([подпись посетителя](https://tolkly.io/docs/ru/identity.md)) |
| `https://api.tolkly.io/widget/chat-<hash>.js` | когда посетитель впервые тянется к чату | имя зависит от содержимого, хранится год |

Окно чата загружается в трёх случаях:

- посетитель тянется к кнопке: наводит курсор, ставит на неё фокус или нажимает;
- страница сама открывает чат;
- у посетителя уже идёт разговор (тогда окно загружается сразу).

Скрипты приходят сжатыми — brotli или gzip, смотря что принимает браузер. Код окна лежит там же,
где `widget.js`, в `/widget/`.

## Посетители из России
С июня 2025 года российские провайдеры обрывают соединения с Cloudflare после первых ~16 КБ,
поэтому у посетителя из России без VPN чат с `https://api.tolkly.io` может так и не загрузиться.
`widget.js` настолько мал, что доходит целиком; он ждёт, пока поднимется сам чат, а не событие
`load` скрипта (зависшая загрузка не даёт ни `load`, ни `error`), и тогда загружает чат с нашего
адреса в России. Рабочий
адрес запоминается в `localStorage` сайта на сутки, и следующая страница начинает с него; если
браузер не даёт хранилище, теряется только эта память. Дальше чат отправляет все запросы туда,
откуда загружен: `https://api.tolkly.io https://ru.tolkly.io` отдают один и тот же чат и одни и те же разговоры.

## Проверьте, что всё работает
1. Откройте две разные страницы сайта. На обеих в правом нижнем углу видна кнопка чата.
2. Во вкладке сети браузера `GET https://api.tolkly.io/v1/projects/<project>/widget` отвечает `200`.
   В его JSON нет поля `refused`. Проверяйте в браузере на своём сайте, а не через `curl`. Сервер
   смотрит на заголовок `Origin` страницы, а запрос без него не отклоняет никогда.
3. Через несколько минут после выкладки в разделе проекта «Установка» появится «Чат работает на
   example.com · 2 мин назад». До этого там написано «Ещё не установлен».

Как сервер запоминает сайт:

- Сайт берётся из заголовка `Origin` запроса настроек.
- Время последнего визита обновляется не чаще раза в `WIDGET_ORIGIN_TOUCH_SECONDS` (по умолчанию
  300 с).
- Страница на том же хосте, что и `https://api.tolkly.io`, не отправляет `Origin`, поэтому не учитывается.
- Сайт, который заблокировал владелец, там не показывается.

## Если чат не виден
| Что вы видите | Почему и что делать |
|---|---|
| Во вкладке сети нет запроса к `https://api.tolkly.io` | В странице, которую получил браузер, нет этих строк. Проверьте исходный код страницы, шаблон, который сайт использует на самом деле, и кэш страниц. |
| `/widget` отвечает `{"refused": "origin_blocked"}` | Владелец заблокировал этот домен. Разблокировать его можно в разделе проекта «Установка», блок «Домены» ([Домены и зеркала](https://tolkly.io/docs/ru/domains.md)). |
| `/widget` отвечает `{"refused": "origin_not_allowed"}` | Проект в строгом режиме, а этого домена нет в списке. Владелец может его разрешить ([Домены и зеркала](https://tolkly.io/docs/ru/domains.md)). |
| `/widget` отвечает `404` | В атрибуте `project` указан проект, которого нет на этом сервере. |
| В консоли ошибка Content-Security-Policy | Политика сайта блокирует виджет. Что делать — в разделе [Content-Security-Policy](https://tolkly.io/docs/ru/csp.md). |
| В консоли `tolkly: the identity token was refused (…)` | Чат работает, но анонимно. Подробнее — [Подпись посетителя](https://tolkly.io/docs/ru/identity.md#rejected). |

Отклонённый сайт получает `200`, а не `403`. Поэтому в консоли страницы пусто, а виджет просто
ничего не показывает.

Как поручить установку ИИ-агенту для кода — в разделе [Для ИИ-агентов](https://tolkly.io/docs/ru/agents.md).
