> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ukrgsm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Додавання на сайт

> Додайте вашого голосового агента на будь-який сайт, щоб відвідувачі могли з ним поговорити.

### Як додати

Додайте голосового агента на будь-який сайт через діалог «Configure Widget» у налаштуваннях агента.

Крок 1: Відкрийте налаштування агента, натиснувши іконку шестерні у верхньому правому куті редактора агента.

<img src="https://mintcdn.com/ukr-gsm/pisYMZLRPGIEw4_r/images/open-settings.png?fit=max&auto=format&n=pisYMZLRPGIEw4_r&q=85&s=3e922cc0fab1fa4238d6ada9969a2e45" alt="Відкрийте налаштування агента" width="2880" height="1557" data-path="images/open-settings.png" />

Крок 2: Прокрутіть до розділу **Add to Website** і натисніть **Configure Widget**.

<img src="https://mintcdn.com/ukr-gsm/pisYMZLRPGIEw4_r/images/add-to-website.png?fit=max&auto=format&n=pisYMZLRPGIEw4_r&q=85&s=4ff6e7f3cf095809025bc79c905ff8ce" alt="Перейдіть до Add to Website" width="2850" height="1558" data-path="images/add-to-website.png" />

Крок 3: Увімкніть вбудовування, додайте домен вашого сайту в **Allowed Domains**, оберіть **Floating Widget**, **Inline Component** або **Headless (Bring Your Own UI)**, за потреби налаштуйте кнопку (позицію, колір, текст) і натисніть **Save Configurations**.

<img src="https://mintcdn.com/ukr-gsm/pisYMZLRPGIEw4_r/images/save-configurations.png?fit=max&auto=format&n=pisYMZLRPGIEw4_r&q=85&s=4e8bfd9db8b1f270d17ed074c8a8b882" alt="Збережіть налаштування" width="1974" height="1534" data-path="images/save-configurations.png" />

Крок 4: Скопіюйте згенерований код і вставте його на вашу сторінку, щоб протестувати агента.

<img src="https://mintcdn.com/ukr-gsm/pisYMZLRPGIEw4_r/images/copy-deployment-code.png?fit=max&auto=format&n=pisYMZLRPGIEw4_r&q=85&s=9d017336d496d40f2c91aac55d1b8b3c" alt="Скопіюйте код вбудовування" width="2880" height="1537" data-path="images/copy-deployment-code.png" />

## Режими вбудовування

| Режим                | Що відображає                                                                                         | Коли використовувати                                                                                 |
| -------------------- | ----------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| **Floating Widget**  | Кнопку-пігулку у формі CTA, закріплену в кутку сторінки.                                              | Потрібен готовий досвід у стилі чат-бабла, що не порушує наявну верстку.                             |
| **Inline Component** | Панель, що рендериться всередині `<div id="dograh-inline-container">`, яку ви розміщуєте на сторінці. | Потрібно вбудувати агента в конкретний розділ (герой на лендингу, вкладка підтримки тощо).           |
| **Headless**         | Без інтерфейсу. Лише аудіопотік і JavaScript API на `window.DograhWidget`.                            | Потрібен повний контроль над інтерфейсом — власні кнопки, дизайн-система, стан фреймворку, анімації. |

## Передумови

Стосуються всіх трьох режимів:

* Обслуговуйте сторінку через **HTTPS** або з `http://localhost`. Браузери відмовляють у доступі до мікрофона на звичайних HTTP-джерелах чи `file://`.
* Якщо в кабінеті задано **Allowed Domains**, додайте туди й ваш тестовий домен (наприклад, `localhost`) — інакше запити конфігурації й сигналізації віджета будуть відхилені. Залиште список порожнім, щоб дозволити всі домени.
* Код вбудовування, який ви копіюєте з кабінету, — це один тег `<script>`, що завантажує `dograh-widget.js` **асинхронно**. Віджет автоматично ініціалізується після завантаження й надає `window.DograhWidget`. Код, що реєструє колбеки, має дочекатись доступності віджета.

## Floating Widget

<img src="https://mintcdn.com/ukr-gsm/pisYMZLRPGIEw4_r/images/floating-widget-example.png?fit=max&auto=format&n=pisYMZLRPGIEw4_r&q=85&s=78502542df6bf78773e2657f35bcfd24" alt="Floating widget показано в кутку сторінки" width="2880" height="1555" data-path="images/floating-widget-example.png" />

Рендерить кнопку-пігулку (іконка мікрофона + текст), закріплену в кутку сторінки. Клік починає дзвінок; повторний клік — завершує. Кнопка автоматично оновлює підпис і колір упродовж дзвінка: налаштований текст → «Connecting…» → «End Call» → «Retry» у разі помилки.

Налаштуйте **Button Text**, **Button Color** і **Position** (верх/низ + ліворуч/праворуч) у кабінеті.

Сторінка не потребує жодного власного JavaScript — вставка коду вбудовування і є всією інтеграцією. Якщо потрібно підписатись на події життєвого циклу дзвінка (наприклад, для аналітики), дивіться [Колбеки життєвого циклу](#lifecycle-callbacks-all-modes) нижче.

## Inline Component

<img src="https://mintcdn.com/ukr-gsm/pisYMZLRPGIEw4_r/images/inline-widget-example.png?fit=max&auto=format&n=pisYMZLRPGIEw4_r&q=85&s=c62f513e78403ea49bb56aa432db360d" alt="Inline widget, вбудований у розділ сторінки" width="2844" height="1555" data-path="images/inline-widget-example.png" />

Рендерить панель (іконка статусу + текст статусу + кнопка CTA) всередині `<div>`, який ви розміщуєте на сторінці. Зміни статусу оновлюють панель на місці.

Налаштуйте **Button Text**, **Button Color** і **Call to Action Text** у кабінеті.

### Звичайний HTML

Розмістіть контейнер `<div>` там, де має рендеритись віджет. Віджет автоматично приєднається до нього.

```html theme={null}
<!-- Вставте код вбудовування десь на сторінці -->
<div id="dograh-inline-container"></div>
```

### React

Оскільки React монтується вже після того, як скрипт віджета міг завантажитись, інтегруйте через `initInline` при першому монтуванні та `refresh` при повторному. Опитуйте наявність `window.DograhWidget`, щоб урахувати асинхронне завантаження скрипта.

```tsx theme={null}
import { useEffect } from 'react';

declare global {
  interface Window {
    DograhWidget?: {
      initInline: (options: { container: HTMLElement }) => void;
      refresh: () => void;
      getState: () => { isInitialized: boolean };
    };
  }
}

export function Assistant() {
  useEffect(() => {
    let retries = 0;
    const tryInit = () => {
      const container = document.getElementById('dograh-inline-container');
      if (window.DograhWidget && container) {
        const { isInitialized } = window.DograhWidget.getState();
        if (isInitialized) window.DograhWidget.refresh();
        else window.DograhWidget.initInline({ container });
      } else if (retries++ < 50) {
        setTimeout(tryInit, 100);
      }
    };
    tryInit();
  }, []);

  return <div id="dograh-inline-container" />;
}
```

## Headless Mode

<img src="https://mintcdn.com/ukr-gsm/pisYMZLRPGIEw4_r/images/headless-widget-example.png?fit=max&auto=format&n=pisYMZLRPGIEw4_r&q=85&s=8a9e91b5f76145c2147b9779eab359ac" alt="Headless widget, кероване інтерфейсом сторінки" width="2842" height="1548" data-path="images/headless-widget-example.png" />

У режимі Headless віджет не додає жодного власного інтерфейсу. Ви самі рендерите будь-які кнопки, банери чи індикатори дзвінка й викликаєте JavaScript API, щоб почати й завершити дзвінок.

### JavaScript API

| Метод / колбек                               | Опис                                                                                                                                          |
| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `window.DograhWidget.start()`                | Почати голосовий дзвінок. Має викликатись зсередини обробника користувацької дії (наприклад, `click`), щоб браузер надав доступ до мікрофона. |
| `window.DograhWidget.end()`                  | Завершити активний дзвінок.                                                                                                                   |
| `window.DograhWidget.onCallStart(cb)`        | Спрацьовує при виклику `start()` (статус `connecting`). Без корисного навантаження.                                                           |
| `window.DograhWidget.onCallConnected(cb)`    | Спрацьовує, коли встановлено WebRTC-з'єднання. Навантаження: `{ agentId, workflowRunId, token }`.                                             |
| `window.DograhWidget.onCallDisconnected(cb)` | Спрацьовує лише якщо дзвінок був встановлений, у момент завершення. Навантаження: `{ agentId, workflowRunId, token, durationSeconds }`.       |
| `window.DograhWidget.onCallEnd(cb)`          | Спрацьовує щоразу, коли сесія дзвінка завершується (зокрема при невдалих спробах з'єднання). Без корисного навантаження.                      |
| `window.DograhWidget.onStatusChange(cb)`     | Спрацьовує при кожній зміні статусу. Колбек отримує `(status, text, subtext)`. Значення статусу: `idle`, `connecting`, `connected`, `failed`. |
| `window.DograhWidget.onError(cb)`            | Спрацьовує при помилках (відмова в доступі до мікрофона, помилка сервера тощо). Колбек отримує об'єкт `Error`.                                |

Усі сетери `on*` — одноразові (single-listener): повторний виклик того самого замінює попередній обробник.

<Note>
  **Про час завантаження.** Скрипт віджета завантажується асинхронно, тож `window.DograhWidget` може бути ще недоступний у момент першого виконання вашого вбудованого `<script>`. Приклади нижче припускають, що `window.DograhWidget` уже доступний у момент реєстрації. Щоб це гарантувати:

  * **Звичайний JS:** обгорніть код реєстрації в `window.addEventListener('load', () => { /* реєстрація тут */ })`.
  * **React:** всередині `useEffect` реєструйтесь одразу, якщо `document.readyState === 'complete'`, інакше додайте одноразовий слухач `window.load`, що реєструє при спрацюванні.
  * **Обробники кліків**, що викликають `start()` / `end()`, не потребують захисту — на момент кліку користувача віджет уже давно завантажений.
</Note>

### Vanilla JS

```html theme={null}
<button id="talk-btn">Поговорити зі ШІ</button>

<script>
  let callStatus = 'idle';
  const btn = document.getElementById('talk-btn');

  function render() {
    btn.textContent =
      callStatus === 'connected' ? 'End Call'
      : callStatus === 'connecting' ? 'Connecting…'
      : callStatus === 'failed' ? 'Retry'
      : 'Поговорити зі ШІ';
  }

  window.DograhWidget.onStatusChange((status) => {
    callStatus = status;
    render();
  });

  window.DograhWidget.onError((err) => {
    console.error('Помилка віджета:', err.message);
  });

  btn.addEventListener('click', () => {
    if (callStatus === 'connected' || callStatus === 'connecting') {
      window.DograhWidget.end();
    } else {
      window.DograhWidget.start();
    }
  });
</script>
```

### React + TypeScript

```tsx theme={null}
import { useEffect, useState } from 'react';

type CallStatus = 'idle' | 'connecting' | 'connected' | 'failed';

declare global {
  interface Window {
    DograhWidget: {
      start: () => void;
      end: () => void;
      onStatusChange: (cb: (status: CallStatus, text?: string, subtext?: string) => void) => void;
      onError: (cb: (err: Error) => void) => void;
    };
  }
}

export function TalkButton() {
  const [status, setStatus] = useState<CallStatus>('idle');

  useEffect(() => {
    window.DograhWidget.onStatusChange((s) => setStatus(s));
    window.DograhWidget.onError((err) => console.error('Помилка віджета:', err.message));
  }, []);

  const isLive = status === 'connected' || status === 'connecting';
  const label = { idle: 'Поговорити зі ШІ', connecting: 'Connecting…', connected: 'End Call', failed: 'Retry' }[status];

  return (
    <button onClick={() => (isLive ? window.DograhWidget.end() : window.DograhWidget.start())}>
      {label}
    </button>
  );
}
```

<Note>
  `start()` має виконуватись усередині справжнього обробника користувацької дії (`click`, `touchend` тощо). Браузери відмовляються надавати доступ до мікрофона скриптам, що запитують його поза таким обробником — виклик `start()` з `setTimeout` чи при завантаженні сторінки завершиться помилкою дозволу.
</Note>

## Колбеки життєвого циклу (усі режими)

Колбеки `on*` з [Headless JavaScript API](#javascript-api) працюють у **всіх трьох режимах вбудовування**, а не лише в Headless. Використовуйте їх для аналітики або запуску інтерфейсу на сторінці навіть тоді, коли віджет рендерить власний інтерфейс (Floating чи Inline).

```js theme={null}
window.DograhWidget.onCallConnected(({ agentId, workflowRunId }) => {
  analytics.track('voice_call_started', { agentId, workflowRunId });
});

window.DograhWidget.onCallDisconnected(({ workflowRunId, durationSeconds }) => {
  analytics.track('voice_call_ended', { workflowRunId, durationSeconds });
});
```

`onCallConnected` і `onCallDisconnected` спрацьовують лише тоді, коли дзвінок дійсно встановлює медіа-з'єднання — невдалі спроби з'єднання (наприклад, відмова в доступі до мікрофона, збій мережі) їх не запускають, тож аналітика лишається чистою.
