# JavaScript embed

> Add the Bookbag chat widget to any website with a single script tag. Configure color and position with data attributes, and learn how the loader and iframe work.

The fastest way to put a Bookbag agent in front of customers is the embed script. It injects a chat bubble in the corner of your page; clicking it opens the agent in a sandboxed iframe. No build step, no API key.

> **LOOKING FOR THE NO-CODE PATH?:** The dashboard generates this exact snippet for you under Deploy. See [Website widget](/docs/deploy/web-widget) for the click-through setup.

## Install

Paste the script anywhere before the closing `</body>` tag, replacing `YOUR_AGENT_ID` with your agent's id:

```html
<script
  src="https://app.bookbag.ai/widget/embed"
  data-agent-id="YOUR_AGENT_ID"
  defer
></script>
```

> **CHECK:** Reload the page — a chat bubble appears in the corner and answers from your agent's knowledge.

## Configuration attributes

The loader reads optional `data-` attributes off its own `<script>` tag:

| Attribute | Required | Default | Description |
| --- | --- | --- | --- |
| data-agent-id | Yes | — | The numeric id of the agent to load. Without it the loader logs an error and does nothing. |
| data-color | No | #3b82f6 | The accent color of the launcher bubble (any CSS color). |
| data-position | No | right | `right` or `left` — which corner the bubble sits in. |

```html
<script
  src="https://app.bookbag.ai/widget/embed"
  data-agent-id="123"
  data-color="#0f766e"
  data-position="left"
  defer
></script>
```

> **BRAND COLORS AND WELCOME TEXT:** Most of the agent's appearance — avatar, welcome message, suggested prompts, and whether the "Powered by Bookbag" badge shows — is set in the dashboard and served from the agent's public config, not from the embed tag.

## How it works

1. **The loader runs** — The script at `/widget/embed` is a tiny loader. It finds its own tag, reads the data attributes, and creates a launcher button and a hidden iframe.
2. **The iframe holds the chat UI** — The iframe points at `/widget/frame?agentId=...`. Running the chat in an iframe isolates its styles and scripts from your page.
3. **Clicking toggles the panel** — The launcher button shows and hides the iframe. The chat UI inside talks to the public chat runtime to stream answers.

Because the chat lives in an iframe, it will not inherit or pollute your site's CSS. The launcher uses a very high `z-index` so it stays clickable above page content.

## Control the widget from your code

Once the script has loaded it exposes a global, `window.bookbag`, you can call to control the widget. Call it as a function (`bookbag('open')`) or use the equivalent methods (`bookbag.open()`).

| Call | Does |
| --- | --- |
| `bookbag('open')` | Opens the chat panel. |
| `bookbag('close')` | Closes the chat panel. |
| `bookbag('toggle')` | Opens if closed, closes if open. |
| `bookbag('resetChat')` | Clears the conversation and starts fresh. Your config is preserved. |

```javascript
document.getElementById("help-button").addEventListener("click", () => {
  window.bookbag("open");
});
// Method form is identical:
window.bookbag.open();
window.bookbag.close();
window.bookbag.toggle();
window.bookbag.resetChat();
```

### Calling before the widget is ready

If you call `window.bookbag(...)` before the embed finishes loading, define this stub first — calls are queued and replayed once the widget is ready, so you never miss one:

```html
<script>
  window.bookbag = window.bookbag || function () {
    (window.bookbag.q = window.bookbag.q || []).push(arguments);
  };
</script>
<script src="https://app.bookbag.ai/widget/embed" data-agent-id="123"></script>
```

See [Event listeners](/docs/developers/event-listeners) to react to messages and tool calls, and [Identity verification](/docs/developers/identity-verification) to identify signed-in users.

## Frameworks

In single-page apps, add the script once at the app shell level (e.g. in the document head/body template) rather than inside a component that mounts and unmounts. In Next.js, use the `next/script` component with the `afterInteractive` strategy and pass the data attributes through.

## Troubleshooting

**The bubble never appears.**

Open the console. If you see "[Bookbag] data-agent-id required", the `data-agent-id` attribute is missing or empty. Confirm the agent id is correct and the agent is not archived.

**It works locally but not in production.**

Check that your Content Security Policy allows loading the script from `app.bookbag.ai` and framing `app.bookbag.ai` (the chat runs in an iframe).

**Can I open or close the widget from my own code?**

Yes — call `window.bookbag('open')`, `('close')`, `('toggle')`, or `('resetChat')`. See "Control the widget from your code" above.

- [Website widget setup](/docs/deploy/web-widget) — The dashboard walkthrough and appearance settings.
- [Event listeners](/docs/developers/event-listeners) — React to the widget in the browser.
- [Identity verification](/docs/developers/identity-verification) — Personalize chat for logged-in users.
