> For the complete documentation index, see [llms.txt](https://docs.maiagent.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.maiagent.ai/tech/en/api-integration/web-chat-sdk.md).

# Web Chat Embedding and SDK

Embed MaiAgent Web Chat into any website: embed code, window modes, user identification, full configuration reference, and the JavaScript SDK API

Add a snippet of embed code to your web page to put MaiAgent's AI assistant on your website. Once the embed code loads `embed.min.js` (hereafter "the SDK"), the SDK creates a chat button and an iframe chat window on the page, and exposes a global `MaiAgent` JavaScript API for programmatic control.

This page is the complete technical reference for Web Chat embedding. Related topics:

* [Web Chat MaiGPT Mode Embedding](/tech/en/api-integration/web-chat-sdk/web-chat-maigpt-mode.md) — a ChatGPT-like, full-featured conversation interface
* [WebChat Page Context Injection](/tech/en/api-integration/web-chat-sdk/web-chat-context-data.md) — inject page information into the LLM System Prompt
* [Contact Identity Sync and Token Refresh](/tech/en/authorization-integration/contact-credentials-sync.md) — create contacts and credentials from the backend
* [Software Vendor Integration Guide (End-to-End)](/tech/en/authorization-integration/vendor-integration-guide.md) — the complete journey of embedding plus permission integration (batch backfill, login sync, logout revocation)

## 1. Quick Start <a href="#quickstart" id="quickstart"></a>

Add the following before `</body>` on your page:

```html
<script>
  window.maiagentChatbotConfig = {
    webChatId: 'your-web-chat-id',
    baseUrl: 'https://chat.maiagent.ai/web-chats',
    primaryColor: '#1890ff',
  }
</script>
<script src="https://chat.maiagent.ai/js/embed.min.js" defer></script>
```

* Get `webChatId` from the Web Chat settings page in the admin console (see [Connecting Chat Platforms: Website](https://docs.maiagent.ai/release/website); the embed code generated by the console fills it in automatically)
* The `baseUrl` and SDK URL above use the SaaS environment (`chat.maiagent.ai`) as an example; for private cloud / on-premises deployments, replace them with your environment's domain
* `window.maiagentChatbotConfig` **must be defined before the SDK script loads**

Default behavior: a chat button appears at the bottom-right of the page. Clicking it opens a floating chat window, and the user can switch between the floating and sidebar window modes.

### Initialization Timing <a href="#init-timing" id="init-timing"></a>

After loading, the SDK registers a `document.body.onload` handler to run initialization; normally no manual intervention is needed. When you need to control the initialization timing (for example, waiting for an SPA container to mount, or deferring rendering):

1. **Lazy-load the script**: dynamically insert the `embed.min.js` `<script>` tag only when appropriate
2. **Trigger manually**: set up `window.maiagentChatbotConfig` first, then call `document.body.onload()`

The SDK initializes only once per page; duplicate loads are ignored.

## 2. Window Modes <a href="#window-modes" id="window-modes"></a>

The `enabledWindowModes` array determines which window modes are available to the user; **the first element is the default mode**. When unset, it is equivalent to `['floating', 'sidebar']`.

| Mode       | Form                                                                                                                                    | Suitable for                                                                                                                          |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `floating` | A floating window overlaid at the bottom-right of the page; the button is draggable and the window is resizable (320×400 to 900×900 px) | General customer service, consultations                                                                                               |
| `sidebar`  | A sidebar docked to the right edge of the viewport (width 320–800 px, drag to resize); page content automatically shrinks to make room  | Work scenarios where users chat while viewing the page                                                                                |
| `maigpt`   | A ChatGPT-like full interface (conversation history sidebar, search, settings) that fills the specified container or the whole screen   | Main page feature areas, a site-wide AI entry point; see [MaiGPT Mode](/tech/en/api-integration/web-chat-sdk/web-chat-maigpt-mode.md) |

```javascript
// Allow sidebar mode only
window.maiagentChatbotConfig = {
  webChatId: 'your-web-chat-id',
  baseUrl: 'https://chat.maiagent.ai/web-chats',
  enabledWindowModes: ['sidebar'],
}
```

* When the array contains two or more modes, a mode-switch button appears in the chat window; `allowWindowModeSwitch: false` hides it
* When `maigpt` is the first element, MaiGPT mode is used and the remaining elements are ignored (that mode does not offer switching)
* The legacy `defaultWindowMode` field is deprecated: it still works (treated as `enabledWindowModes: [value]`), but a deprecation warning is shown in the console

### What the Three Modes Look Like <a href="#window-modes-gallery" id="window-modes-gallery"></a>

{% tabs %}
{% tab title="floating window" %}

<figure><img src="https://3415477754-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNBTi475lqozGpB7xObpE%2Fuploads%2Fgit-blob-56a6936e787340e6429586677d8be3bacc08b308%2Fwebchat-mode-floating.png?alt=media" alt="floating mode: the chat window is overlaid at the bottom-right of the page"><figcaption><p>floating: the chat window is overlaid at the bottom-right of the page without affecting the page layout; the button can be dragged to reposition it</p></figcaption></figure>
{% endtab %}

{% tab title="sidebar" %}

<figure><img src="https://3415477754-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNBTi475lqozGpB7xObpE%2Fuploads%2Fgit-blob-4d989af74c4a47e70c3d61a6f6f4b496a31f6a09%2Fwebchat-mode-sidebar.png?alt=media" alt="sidebar mode: the chat window docks to the right edge and page content automatically shrinks"><figcaption><p>sidebar: the chat window docks to the right edge of the viewport and page content automatically shrinks to make room, ideal for chatting while viewing the page</p></figcaption></figure>
{% endtab %}

{% tab title="maigpt full interface" %}

<figure><img src="https://3415477754-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FNBTi475lqozGpB7xObpE%2Fuploads%2Fgit-blob-aab515bf01f9122d1b558aeaefcd1e59079466a0%2Fwebchat-maigpt-mode-a-container.png?alt=media" alt="maigpt mode: a ChatGPT-like full conversation interface"><figcaption><p>maigpt: a ChatGPT-like full interface (with conversation history sidebar); see <a href="/tech/en/api-integration/web-chat-sdk/web-chat-maigpt-mode.md">MaiGPT Mode Embedding</a></p></figcaption></figure>
{% endtab %}
{% endtabs %}

## 3. Identifying Users <a href="#identify-users" id="identify-users"></a>

Web Chat has three identity levels, based on whether a Contact is bound:

| Level               | Setup                                                                                                                                                  | Conversation history                      | AI personalization / calling tools with the user's permissions |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------- | -------------------------------------------------------------- |
| Anonymous           | Set nothing                                                                                                                                            | Kept per browser                          | ✖                                                              |
| Frontend auth       | Config carries `auth: { sourceId, ... }`; the SDK automatically creates or matches a contact                                                           | Follows the contact, works across devices | ✔                                                              |
| Backend integration | Backend calls the [identity sync API](/tech/en/authorization-integration/contact-credentials-sync.md) to get a `contactId`; config carries `contactId` | Follows the contact, works across devices | ✔                                                              |

**Frontend auth**: After the SDK finishes initializing, it automatically calls MaiAgent's identity sync API (`setup-contact-credentials`) with the contents of `auth`, creating or matching a contact by `sourceId`:

```javascript
window.maiagentChatbotConfig = {
  webChatId: 'your-web-chat-id',
  baseUrl: 'https://chat.maiagent.ai/web-chats',
  auth: {
    sourceId: 'user-12345',   // Required: the user's unique identifier in your system
    name: 'John Wang',        // Optional: contact display name (only takes effect on first creation)
    contextData: { ... },     // Optional: injected into the LLM System Prompt, see the contextData page
    ts: 1785500000,           // Required when signature verification is enabled: Unix seconds (UTC), generated by your backend
    sig: '9f2c...',           // Required when signature verification is enabled: HMAC-SHA256 signature, see "Signature Verification" below
  },
}
```

If this Web Chat's login settings enable "Allow embedded clients to chat without logging in using Source ID" and signature mode is selected, `ts` and `sig` are required. If either is missing or verification fails, the user is redirected to the login page. These two fields are also accepted when calling `MaiAgent.auth.setup()` manually.

**Backend integration**: Your backend calls the same API when the user logs in (it can bind MCP tool credentials at the same time), stores the returned `contactId` in the member record, and the frontend passes only `contactId`.

How to choose between the two:

* If you only need to "recognize the user and keep conversations across devices" → **frontend auth** is the simplest
* If you need to bind the user's Access Token into MCP tool credentials (so the AI calls your APIs with the user's permissions) and don't want the token to appear in the frontend page source → **backend integration**
* Both use the same underlying contact mechanism; the same `sourceId` is treated as the same contact, and they can be mixed

{% hint style="info" %}
You can also use `queryMetadata` to control the user's knowledge base retrieval scope (RAG permission filtering); see the [Knowledge Management Permissions (Query Metadata) Overview](/tech/en/authorization-integration/zhi-shi-guan-li-quan-xian-query-metadata-cha-xun-yuan-zi-liao-zong-lan.md). `queryMetadata` does not enter the LLM prompt; to make the AI "know" a value, use [contextData](/tech/en/api-integration/web-chat-sdk/web-chat-context-data.md).
{% endhint %}

### Security Notes <a href="#identity-security" id="identity-security"></a>

{% hint style="danger" %}
**`contactId` is an identity credential**: anyone who has it can chat as that user and see their conversation history. Only output `contactId` to the user themselves on **post-login** pages, and never put it in the source of public pages.

The requirements for `auth.sourceId` depend on whether signature verification is enabled:

* **Signature verification disabled**: Identity sync is a public endpoint, so a guessable `sourceId` is equivalent to an impersonatable identity. Use an unguessable value (such as a UUID), not a sequential number, email address, or phone number.
* **Signature verification enabled**: Security comes from the signature rather than the `sourceId` itself, so readable values such as student IDs, employee IDs, and registered email addresses can be used directly. The secret exists only on your server; without it, knowing the `sourceId` is not enough to calculate a valid signature.
  {% endhint %}

### Signature Verification <a href="#source-id-signature" id="source-id-signature"></a>

In Web Chat's login settings, you can enable "Allow embedded clients to chat without logging in using Source ID" so users already logged in to your website do not need to log in again in the chat window. The switch and secret are on the Login Settings tab in the admin console. For instructions, see [Chat Without Login Using a Contact Source ID](https://docs.maiagent.ai/conversations/web-chat/source-id-access) in the user manual.

Two verification methods are available; signature mode is recommended:

| Verification method            | Behavior                                                                                                                                |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| Require signature verification | `ts` and `sig` must be provided, and access is granted only after the signature passes verification                                     |
| Source ID only                 | No signature verification; access is granted whenever `sourceId` is provided. Suitable only for testing or closed intranet environments |

**Signature algorithm**

```
HMAC-SHA256(secret, "{webChatId}.{sourceId}.{ts}")
```

Send the result as a lowercase hex string. `ts` is Unix time in seconds (UTC). The platform generates the secret in the admin console. Store it only in your server's environment variables; never include it in frontend code.

{% tabs %}
{% tab title="PHP" %}

```php
$ts  = time();
$sig = hash_hmac('sha256', "{$webChatId}.{$sourceId}.{$ts}", $SIGNING_SECRET);
```

{% endtab %}

{% tab title="Node" %}

```javascript
const ts = Math.floor(Date.now() / 1000);
const sig = crypto.createHmac('sha256', SIGNING_SECRET)
  .update(`${webChatId}.${sourceId}.${ts}`).digest('hex');
```

{% endtab %}

{% tab title="Python" %}

```python
ts = int(time.time())
sig = hmac.new(SIGNING_SECRET.encode(),
  f"{web_chat_id}.{source_id}.{ts}".encode(), hashlib.sha256).hexdigest()
```

{% endtab %}
{% endtabs %}

**Verification rules**

| Rule               | Description                                                                                                       |
| ------------------ | ----------------------------------------------------------------------------------------------------------------- |
| Validity period    | Configurable to 1, 5, or 15 minutes in the admin console; the default is 5 minutes                                |
| Clock tolerance    | Allows a 60-second offset; timestamps more than 60 seconds in the future are always rejected                      |
| One-time use       | The same signature can be used successfully only once; the signature itself serves as the anti-replay nonce       |
| Web Chat binding   | The signature includes `webChatId`, so a signature for another Web Chat in the same organization cannot be reused |
| Rejection response | All failures return the same external response, revealing neither the reason nor whether the `sourceId` exists    |

{% hint style="warning" %}
A signature is valid for one use only. **Recalculate it every time the user enters; never cache it**. The validity period limits how long the signature can be exchanged for a contact identity, not how long the conversation lasts. After the identity is obtained, the conversation is not interrupted when the signature expires.
{% endhint %}

**Relationship between expiration and logout**

The resulting `contactId` does not expire, and the platform currently has no endpoint for invalidating it. After a user logs out of your website, you can stop issuing new signatures. The frontend can call `MaiAgent.auth.signOut()` to return the chat window to anonymous mode. To revoke tool credentials, see [Logout and Credential Revocation](/tech/en/authorization-integration/contact-credentials-sync.md#logout-revoke).

**Troubleshooting signature verification failures**

"View Signature Verification Failure Logs" in the admin login settings lists recent failures and their causes for troubleshooting:

| Reason                                     | Common cause                                                                                                  |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| Signature expired                          | The server clock is offset, or the frontend cached the signature                                              |
| Timestamp exceeds the allowed future range | The server clock is more than 60 seconds fast                                                                 |
| Signature mismatch                         | The secrets differ, or the signature string was assembled incorrectly (the separator must be an ASCII period) |
| Missing timestamp or signature             | `ts` or `sig` was not provided                                                                                |
| Signature already used                     | The same signature was submitted a second time                                                                |
| Source ID maps to multiple contacts        | This Web Chat contains duplicate contact records with the same `sourceId`                                     |

### Allowed Embedding Domains <a href="#embed-origin-allowlist" id="embed-origin-allowlist"></a>

Web Chat's "allowed embedding domains" list restricts which websites can complete **identity sync** (both `auth` and the backend's setup-contact-credentials are subject to it). This list is currently configured for you by the MaiAgent team: please provide the list of domains to allow to your integration contact.

| List state                           | Behavior                                                                              |
| ------------------------------------ | ------------------------------------------------------------------------------------- |
| Empty list (default)                 | No origin restriction                                                                 |
| Lists `https://example.com`          | Exact match on scheme + host (+ port)                                                 |
| Lists `*.example.com`                | Covers `example.com` and all its subdomains (any scheme / port)                       |
| List has entries but all are invalid | **Rejects all origins** (fail closed); it does not silently fall back to unrestricted |

For any Web Chat embedded externally that uses identity features, we recommend always configuring this list to narrow down where `contactId` can be obtained.

## 4. Configuration Reference <a href="#config-reference" id="config-reference"></a>

All fields supported by `window.maiagentChatbotConfig`. Setting unknown fields does not raise errors, but the console shows a `[maiagent] Unknown config options: ...` warning to help catch typos.

### Basic <a href="#config-basic" id="config-basic"></a>

| Field           | Type                 | Required | Description                                                                                                                                                                                                                                                                       |
| --------------- | -------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `webChatId`     | `string`             | ✅        | The Web Chat's unique identifier                                                                                                                                                                                                                                                  |
| `baseUrl`       | `string`             | ✅        | The Web Chat service URL; for SaaS it is `https://chat.maiagent.ai/web-chats`                                                                                                                                                                                                     |
| `contactId`     | `string`             |          | Contact ID (used with backend integration; see [Identifying Users](#identify-users))                                                                                                                                                                                              |
| `auth`          | `object`             |          | Frontend identity settings: `sourceId` (required), `name`, `contextData`, `mcpCredentials`, plus `ts` and `sig` (required when signature verification is enabled; see [Signature Verification](#source-id-signature)). The SDK automatically runs `auth.setup()` once it is ready |
| `queryMetadata` | `object` or `string` |          | Knowledge base retrieval scope filter (does not enter the LLM prompt)                                                                                                                                                                                                             |
| `locale`        | `string`             |          | Interface language (such as `zh-TW`, `en`); for the supported list see [MaiGPT Mode, Section 5](/tech/en/api-integration/web-chat-sdk/web-chat-maigpt-mode.md#locale). Priority: config > user's last selection > browser language > `zh-TW`                                      |

{% hint style="warning" %}
In the current version, passing `auth` causes the console to incorrectly report `Unknown config options: auth`. Functionality is unaffected; you can ignore that warning.
{% endhint %}

### Window Modes and Behavior <a href="#config-behavior" id="config-behavior"></a>

| Field                   | Type                      | Default                   | Description                                                                                                                 |
| ----------------------- | ------------------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `enabledWindowModes`    | `string[]`                | `['floating', 'sidebar']` | Available window modes; the first entry is the default. See [Window Modes](#window-modes)                                   |
| `allowWindowModeSwitch` | `boolean`                 | `true`                    | Whether to show the window mode switch button (only meaningful when two or more modes are enabled)                          |
| `showButton`            | `boolean`                 | `true`                    | Whether to show the chat button. When `false`, open the chat programmatically via `MaiAgent.control.open()`                 |
| `showChatNotification`  | `boolean`                 | `false`                   | Whether to show a notification next to the button when a reply arrives while the window is closed                           |
| `chatNotificationTitle` | `string`                  |                           | Title text of the notification                                                                                              |
| `preventIosInputZoom`   | `boolean`                 |                           | Prevent iOS Safari from auto-zooming the page when the input field is focused                                               |
| `targetElement`         | `string` or `HTMLElement` |                           | MaiGPT mode only: the embedding container, see [MaiGPT Mode](/tech/en/api-integration/web-chat-sdk/web-chat-maigpt-mode.md) |
| `maigptTitle`           | `string`                  |                           | MaiGPT mode only: the sidebar brand title, defaults to `MaiGPT`                                                             |

### Appearance <a href="#config-appearance" id="config-appearance"></a>

Size fields accept a number (treated as px), or an `'Npx'` or `'Nrem'` string.

| Field           | Type                 | Default                              | Description                                                          |
| --------------- | -------------------- | ------------------------------------ | -------------------------------------------------------------------- |
| `primaryColor`  | `string`             | `#1890ff`                            | Theme color (button and primary interface color)                     |
| `buttonSize`    | `string` or `number` | `3rem`                               | Chat button size                                                     |
| `buttonRadius`  | `string`             | `50%`                                | Chat button corner radius                                            |
| `buttonIcon`    | `string`             |                                      | Image URL for the button icon (takes precedence over `openIconHtml`) |
| `openIconHtml`  | `string`             | Built-in SVG                         | Custom HTML for the button's "open" state                            |
| `closeIconHtml` | `string`             | Built-in SVG                         | Custom HTML for the button's "closed" state                          |
| `windowWidth`   | `string` or `number` | `24rem`                              | Floating window width                                                |
| `windowHeight`  | `string` or `number` | `40rem`                              | Floating window height                                               |
| `windowRadius`  | `string`             | `0.75rem`                            | Floating window corner radius                                        |
| `boxShadow`     | `string`             | `0.125rem 0.125rem 0.5rem #00000044` | Button and window shadow                                             |

### Position <a href="#config-position" id="config-position"></a>

| Field                  | Type                 | Default   | Description                                     |
| ---------------------- | -------------------- | --------- | ----------------------------------------------- |
| `buttonPositionBottom` | `string` or `number` | `16` (px) | Button distance from the bottom of the viewport |
| `buttonPositionRight`  | `string` or `number` | `16` (px) | Button distance from the right of the viewport  |
| `windowPositionBottom` | `string`             | `5rem`    | Floating window distance from the bottom        |
| `windowPositionRight`  | `string`             | `1rem`    | Floating window distance from the right         |
| `windowPosition`       | `string`             |           | Set to `'center'` to center the floating window |

The chat button supports drag-and-drop repositioning, and the position is remembered in the browser. On the next load, if the remembered position falls outside the current viewport, it automatically returns to a safe position.

## 5. SDK API <a href="#sdk-api" id="sdk-api"></a>

After the SDK initializes, use the global `MaiAgent` object. All methods should be called after the SDK is ready (see the availability check in [Troubleshooting](#troubleshooting)).

### Window Control `MaiAgent.control` <a href="#api-control" id="api-control"></a>

| Method     | Description                                        |
| ---------- | -------------------------------------------------- |
| `open()`   | Open the chat window                               |
| `close()`  | Close the chat window                              |
| `isOpen()` | Return whether the chat window is open (`boolean`) |

Equivalent global shortcuts are also available: `window.maiagentOpenChat()` / `window.maiagentCloseChat()`.

### Messages `MaiAgent.chat` <a href="#api-chat" id="api-chat"></a>

| Method              | Description                                      |
| ------------------- | ------------------------------------------------ |
| `send(content)`     | Send a text message as the user                  |
| `clearHistory()`    | Clear the current conversation's message history |
| `newConversation()` | Start a new conversation                         |

```javascript
MaiAgent.chat.send('Hello, I would like to learn about your services')
MaiAgent.control.open()
```

### Events `MaiAgent.events` <a href="#api-events" id="api-events"></a>

| Method                     | Description                                                      |
| -------------------------- | ---------------------------------------------------------------- |
| `on(eventType, callback)`  | Register an event listener                                       |
| `off(eventType, callback)` | Remove an event listener (must pass the same callback reference) |

Available events:

| Event          | Fired when                                | Callback argument                                                                          |
| -------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------ |
| `messageReply` | A reply is received from the AI assistant | A parsed object: `{ content: string, sender?: { name, avatar }, timestamp?: number, ... }` |
| `sdkReady`     | SDK initialization completes              | —                                                                                          |
| `authReady`    | `auth.setup()` completes                  | —                                                                                          |
| `iframeReady`  | The chat window iframe is ready           | —                                                                                          |

```javascript
// Use the MaiAgent.EVENT_TYPES constants to avoid typos
MaiAgent.events.on(MaiAgent.EVENT_TYPES.MESSAGE_REPLY, (data) => {
  console.log('Reply received:', data.content)
})
```

### Locale and Speech <a href="#api-locale-speech" id="api-locale-speech"></a>

| Method                                 | Description                                                                                                                                                                                    |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `MaiAgent.locale.set(lang)`            | Switch the interface language, such as `'zh-TW'`, `'zh-CN'`, `'en'`; for the supported list see [MaiGPT Mode, Section 5](/tech/en/api-integration/web-chat-sdk/web-chat-maigpt-mode.md#locale) |
| `MaiAgent.speech.set(lang, provider?)` | Set the language for speech recognition and synthesis; `provider` can specify the speech service provider (such as `'azure'`)                                                                  |

`locale` only affects the interface text, not the language of the AI's answers; for configuring the AI's reply language, see [Multi-Language Support](https://docs.maiagent.ai/build/multi-language-support).

### Identity `MaiAgent.auth` <a href="#api-auth" id="api-auth"></a>

| Method              | Description                                                                                                                                                                                                                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `setup(authConfig)` | Create or match a contact and apply the identity; returns `Promise<string \| null>` (the `contactId` on success). `authConfig` has the same fields as the config's `auth`                                                                                                                     |
| `signOut()`         | Sign out of the current identity, return to anonymous, and clear `contextData`. Frontend only; tool credentials already bound on the backend must be revoked separately, see [Logout and Credential Revocation](/tech/en/authorization-integration/contact-credentials-sync.md#logout-revoke) |

When the config contains `auth`, the SDK calls `setup()` automatically—no manual call needed. Call it manually only when the user logs in / out in an SPA, or when you need to update `contextData`.

## 6. Complete Example <a href="#full-example" id="full-example"></a>

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>MaiAgent Web Chat Integration Example</title>
  </head>
  <body>
    <h1>My Website</h1>

    <button onclick="MaiAgent.control.open()">Open Support Chat</button>
    <button onclick="startNewChat()">New Conversation</button>

    <script>
      window.maiagentChatbotConfig = {
        webChatId: 'your-web-chat-id',
        baseUrl: 'https://chat.maiagent.ai/web-chats',
        primaryColor: '#007bff',
        enabledWindowModes: ['floating', 'sidebar'],
        locale: 'en',
        auth: {
          sourceId: 'user-12345',
          name: 'John Wang',
        },
      }
    </script>
    <script src="https://chat.maiagent.ai/js/embed.min.js" defer></script>

    <script>
      document.addEventListener('DOMContentLoaded', () => {
        MaiAgent.events.on(MaiAgent.EVENT_TYPES.MESSAGE_REPLY, (data) => {
          console.log('AI reply received:', data.content)
          // Hook up analytics tools here, e.g. GA4:
          // gtag('event', 'chat_interaction', { event_label: 'bot_reply' })
        })
      })

      function startNewChat() {
        MaiAgent.chat.newConversation()
        MaiAgent.control.open()
      }
    </script>
  </body>
</html>
```

## 7. Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

| Symptom                                                       | Check                                                                                                                                                                   |
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The button doesn't appear                                     | Whether `maiagentChatbotConfig` is defined before the SDK script; whether `webChatId` / `baseUrl` are correct; whether there are errors in the console                  |
| Console shows `Unknown config options: ...`                   | Check field spelling against the [Configuration Reference](#config-reference) (the false positive for `auth` can be ignored)                                            |
| `MaiAgent is not defined`                                     | The SDK has not finished loading; call after `DOMContentLoaded`, or first check `typeof MaiAgent !== 'undefined'`                                                       |
| Event listeners don't fire                                    | Confirm the event name is correct (use the `MaiAgent.EVENT_TYPES` constants); `off()` must receive the same function reference passed to `on()`                         |
| Conversations disappear on another device                     | Anonymous conversations are kept per browser; for cross-device continuity set `auth` or `contactId` (see [Identifying Users](#identify-users))                          |
| Identity doesn't take effect after setting `auth` (400 error) | If the Web Chat has "allowed embedding domains" configured, only pages on listed domains can complete identity sync; confirm the embedding page's domain is on the list |
| Button position is off                                        | Check whether page CSS conflicts with the button styles; whether position parameter formats are correct (number, `px`, or `rem`)                                        |

Calling the SDK safely:

```javascript
function safeOpenChat() {
  if (typeof MaiAgent !== 'undefined' && MaiAgent.control) {
    MaiAgent.control.open()
  }
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.maiagent.ai/tech/en/api-integration/web-chat-sdk.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
