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

# Web SDK

> Embed the chat widget and control it from your site with JavaScript

The Web SDK lets you embed the Totebot chat widget on your site and control it from JavaScript: identify signed-in users, show or hide the widget, and react to chat events.

## Embed the widget

### Chat bubble

Add the snippet from **Channels → Web** before the closing `</body>` tag. It loads the widget and shows a floating chat bubble:

```html theme={null}
<script>
  (function () {
    const onLoad = function () {
      const script = document.createElement('script');
      script.src = 'https://totebot.ai/embed.min.js';
      script.id = 'YOUR_AGENT_ID';
      script.domain = 'totebot.ai';
      document.body.appendChild(script);
    };
    if (document.readyState === 'complete') onLoad();
    else window.addEventListener('load', onLoad);
  })();
</script>
```

The `id` attribute is your agent ID. Copy the ready-made snippet from the dashboard so it's filled in for you.

### Inline iframe

To place the full chat inside a page instead of a floating bubble:

```html theme={null}
<iframe
  src="https://totebot.ai/embed-agent/YOUR_AGENT_ID"
  width="100%"
  style="height: 100%; min-height: 700px"
  allow="microphone"
  frameborder="0">
</iframe>
```

## JavaScript API

Once the script loads, it exposes a global `window.totebot` object.

| Method                                 | Description                                                                           |
| -------------------------------------- | ------------------------------------------------------------------------------------- |
| `window.totebot.identifyUser(payload)` | Attach a verified identity to the conversation (see below).                           |
| `window.totebot.show()`                | Show the chat bubble.                                                                 |
| `window.totebot.hide()`                | Hide the chat bubble, window, and initial messages.                                   |
| `window.totebot.refresh()`             | Re-send the current page context (URL, title) and re-evaluate page-specific messages. |

Calls made before the widget finishes loading are queued and replayed once it's ready, so you can call them at any time.

## Identify a user

For signed-in users, pass a `userId` together with a `userHash` so the agent can trust the identity and recognize the person across sessions and channels. Generate the hash on your **server** (never expose your agent secret in the browser): it's an HMAC-SHA256 of the `userId`, keyed with your agent secret.

Find your agent secret in **Channels → Web** under the identity section.

<CodeGroup>
  ```javascript Node.js theme={null}
  const crypto = require('crypto');

  const userId = 'user_123';
  const agentSecret = 'your_agent_secret';

  const userHash = crypto
    .createHmac('sha256', agentSecret)
    .update(userId)
    .digest('hex');
  ```

  ```python Python theme={null}
  import hmac
  import hashlib

  user_id = 'user_123'
  agent_secret = 'your_agent_secret'

  user_hash = hmac.new(
      agent_secret.encode('utf-8'),
      user_id.encode('utf-8'),
      hashlib.sha256,
  ).hexdigest()
  ```
</CodeGroup>

Then pass the id, hash, and any metadata to the widget in the browser:

```javascript theme={null}
window.totebot.identifyUser({
  userId: 'user_123',
  userHash: userHash, // generated on your server
  metadata: {
    name: 'John Doe',
    email: 'john@example.com',
    // any additional fields
  },
});
```

<Note>Identity verification requires the Personalization feature, available on the **Basic**, **Pro**, and **Scale** plans.</Note>

## Listen for events

The widget posts messages to the host page so you can react to what happens in the chat:

```javascript theme={null}
window.addEventListener('message', (event) => {
  switch (event.data?.type) {
    case 'close':
      // the chat window was closed
      break;
    case 'conversation_id_changed':
      console.log('Conversation:', event.data.conversationId);
      break;
    case 'anon_user_id_changed':
      console.log('Anonymous user:', event.data.anonUserId);
      break;
  }
});
```

| Event                     | Payload              | When                                 |
| ------------------------- | -------------------- | ------------------------------------ |
| `close`                   | (none)               | The customer closes the chat window. |
| `conversation_id_changed` | `{ conversationId }` | A conversation starts or switches.   |
| `anon_user_id_changed`    | `{ anonUserId }`     | An anonymous ID is assigned.         |

## E-commerce and voice

On Shopify and WooCommerce, the widget syncs the live cart automatically, so the agent can read and update it. Voice input (the iframe's `allow="microphone"`) and attachments are controlled from **Settings → Chat Interface**. For server-to-server access to conversations, analytics, and more, use the [Public API](/api/public-api).
