# Embed & JavaScript SDK

> Install the widget with one script tag, then control it from your own code: open/close/toggle/reset, a call queue for early calls, events, and identity.

## Install

Paste before `</body>`, with the agent's public key from the chat service's **Embed** page:

```html
<script src="https://app.openagent.work/widget/embed" data-agent-id="bk_your_agent_key"></script>
```

| Attribute | Description |
| --- | --- |
| `data-agent-id` | Required. The agent to load (public key, or a legacy numeric ID). |
| `data-color` | Optional. Override the launcher color, e.g. `#16a34a`. |
| `data-position` | Optional. `right` (default) or `left`. |

For an inline panel instead of the floating bubble, use the iframe form inside a sized container: `https://app.openagent.work/widget/frame?agentId=…`.

## The window.bookbag global

The embed exposes one global, callable as a function (`bookbag('open')`) or via methods (`bookbag.open()`):

| Call | Does |
| --- | --- |
| `bookbag('open')` | Opens the chat panel. |
| `bookbag('close')` | Closes it. |
| `bookbag('toggle')` | Opens if closed, closes if open. |
| `bookbag('resetChat')` | Clears the conversation and starts fresh; config is preserved. |
| `bookbag('identify', {...})` | Passes verified identity — see [Identity verification](/docs/developers/identity-verification). |
| `bookbag.addEventListener(...)` | React to widget events — messages, opens, tool calls. |

## Calling before the widget loads

Define this stub first and calls are queued and replayed once ready:

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

> **ONE GLOBAL PER PAGE:** If you embed more than one agent on a page, the control methods act on the most recently initialized widget.
