# Control the widget with JavaScript

> Open the chat, ask a question for the visitor, read its state and react to events from your own code.

Use the JavaScript API when buttons with attributes aren't enough: open the chat from your own logic, ask a question for the visitor, or react to what happens in the widget.

## Where the API lives

| How you installed | Call it on |
| --- | --- |
| **Quick install** script tag | `HelpAI`, the global the script adds |
| `<web-ai-chat>` element | The element itself |
| NPM package | The widget `init()` returns |
| React kit | `useHelpAI()`, see [Add the widget to a React or Next.js app](https://docs.help.ai/customize-and-extend-the-widget/add-the-widget-to-a-react-app) |

The calls are the same on each, with one difference: on the script tag, `await HelpAI.ready()` gives you the widget; on the element and the `init()` handle, `await chat.ready` (no brackets) waits for it. The `HelpAI` global doesn't control a `<web-ai-chat>` element. None of this reaches a deployment set to **Embed in an iframe**, where the chat runs on the hosted page.

The examples use `await`, so run them in an `async` function or a `<script type="module">`.

## Wait until the widget is ready

The **Quick install** snippet loads with `defer`, so `HelpAI` exists once the page has been read. Run your code after that, and `await HelpAI.ready()` before you use the widget: it resolves once the widget has finished connecting. If it couldn't connect, the `error` event fires first.

```js
document.addEventListener('DOMContentLoaded', async () => {
  const chat = await HelpAI.ready();
  console.log(chat.state);
  // { open: false, ready: true, unread: 0, … }
});
```

### Code that runs before the widget's script

Inline code above the widget's script tag runs before `HelpAI` exists, so a call throws `HelpAI is not defined`. Add this line first. It holds your calls until the widget loads:

```html
<script>
  window.HelpAI = window.HelpAI || function () { (HelpAI.q = HelpAI.q || []).push(arguments); };

  HelpAI('ready', (chat) => {
    chat.on('open', () => console.log('Chat opened'));
  });
</script>
```

`ready`, `login`, `track` and `hook` work from the start: they wait for the widget. Calls that act on the chat, such as `open`, `ask` and `reset`, do nothing until it has loaded, so make them from a click.

### On the element

If your code can run before the element's script, wait for the element first:

```js
await customElements.whenDefined('web-ai-chat');
const chat = document.querySelector('web-ai-chat');
await chat.ready;
chat.open({ to: 'help' });
```

## Open, close and ask

| Call | What it does |
| --- | --- |
| `HelpAI.open()` | Opens the chat |
| `HelpAI.open({ to: 'help' })` | Opens a tab: `home`, `chats`, `help` or `news` |
| `HelpAI.open({ to: 'help', id: '<article id>' })` | Opens one Help article. Use `to: 'news'` for a News post |
| `HelpAI.close()` | Closes the chat |
| `HelpAI.expand()` | Switches the chat between its normal and larger size |
| `HelpAI.ask('Can I change my plan?')` | Opens the chat with the question in the message box, for the visitor to send or edit |
| `HelpAI.ask('Can I change my plan?', { send: true })` | Opens the chat and sends the question for the visitor |
| `chat.openForm('<form id>')` | Shows a form whose **When** is **Manual (open via code)** |

`openForm` isn't a `HelpAI` shortcut: call it on the widget, `(await HelpAI.ready()).openForm(id)`.

`ask()` waits until the chat can take the question, for example after a form that must be filled in first, so you can call it as soon as the visitor clicks.

- A newer `ask()` replaces one that's still waiting.
- Empty text is ignored.
- If a send is turned down, the text stays in the message box for the visitor to send.
- Send only from something the visitor did, such as a click, never when the page loads.

```js
const button = document.querySelector('#plan-help');
button.addEventListener('click', () => {
  HelpAI.ask('Which plan fits a team of 10?');
});
```

## Change options while it runs

`HelpAI.update()` changes options on the running widget, such as its theme, without reloading it:

```js
HelpAI.update({ theme: 'dark' });
```

On `<web-ai-chat>`, change its attributes instead.

## Read the widget's state

`chat.state` says where the widget is right now:

| Field | Meaning |
| --- | --- |
| `open` | The chat is showing. Always `true` for an inline chat or a full page |
| `ready` | The widget has connected, so calls act at once |
| `unread` | Conversations with replies the visitor hasn't read |
| `conversationId` | The visitor's current conversation |

## Listen for events

`chat.on(event, callback)` calls you back each time, and returns a function that stops listening.

```js
const chat = await HelpAI.ready();
chat.on('open', () => analytics.track('Chat opened'));
chat.on('message', ({ role, text }) => {
  console.log(role, text);
});
const stopWatching = chat.on('state', (state) => {
  console.log(state);
});
```

| Event | Fires when |
| --- | --- |
| `open`, `close` | The chat opens or closes |
| `message` | The visitor sends a message, or a reply from the AI agent or your team finishes. `role` is `user`, `assistant` or `operator` |
| `state` | Anything in `chat.state` changes |
| `unread` | The number of conversations with unread replies changes |
| `expand`, `fullscreen` | The chat changes size: `true` when it's now larger or full screen |
| `formSubmit` | The visitor submits or skips a form: `{ formId, values, skipped }` |
| `messageFeedback` | The visitor rates a reply: `{ messageId, value }`, where `value` is `up`, `down` or `null` |
| `localeChange` | The visitor picks another language |
| `error` | The widget can't load or send |

A callback that throws an error can't break the widget. With the NPM package, `init()` also takes `onOpen`, `onClose`, `onMessage` and `onError`. To forward events to Google Analytics or another tracker, see [Send chat activity to your analytics](https://docs.help.ai/customize-and-extend-the-widget/send-chat-events-to-your-analytics).

## Start over when someone signs out

The widget remembers each visitor in their browser. On a shared computer, call `reset()` when someone signs out of your site. It forgets their conversation, preferences, and the user details and sign-in your page passed, then reconnects as a new visitor. Your `on()` listeners keep working.

```js
const signOut = document.querySelector('#sign-out');
signOut.addEventListener('click', () => HelpAI.reset());
```

On `<web-ai-chat>` it's `chat.reset()`. For signed-in users, see [Verify signed-in users](https://docs.help.ai/customize-and-extend-the-widget/verify-signed-in-users).

<Tip>
Every option, call and event is in the [API reference](https://cdn.help.ai/sdk/js/elements/latest/docs/api-reference.md).
</Tip>
