> 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 Embed & SDK

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" %}

{% endtab %}

{% tab title="sidebar" %}

{% endtab %}

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

{% 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
  },
}
```

**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 same goes for `auth.sourceId`: use unguessable values (such as UUIDs), not sequential numbers, emails, or phone numbers—identity sync is a public endpoint, and a guessable `sourceId` equals an impersonatable identity.
{% endhint %}

### 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`. 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.
