# Widget JavaScript API

> The tag, the window.SupportFast object, the options, the events, the CSS variables and the technical limits of the widget, for whoever develops the website.

Page: https://supportfast.ai/en/guide/developers/widget-api/ · Section: Developers · Updated on 30 October 2026

To install the widget without writing code, start from [Installing the widget](https://supportfast.ai/en/guide/website/install-widget.md).

## What stays stable across versions

These elements don't change name or meaning from one version to the next:

- The `chatbot.js` file, included as a classic script, with `id="supportfast-script"` (or `id="chatbot-script"`) and the `data-chatbot-id` attribute.
- The `window.SupportFast` object, with `init()` and `version`.
- `window.ChatbotConfig.lang` and `window.chatbotUserData`.
- The `chatbot_open` event in the `dataLayer`.
- The `#chat-widget-container` container, which the CSS variables apply to.
- The CSS variables `--sf-offset-bottom`, `--sf-offset-side` and `--sf-z-index`.

Everything else, including the widget's internal classes, can change: don't use it in your website's code.

## The tag

**HTML · the widget tag (sample agent code)**

```
<script defer id="supportfast-script" src="https://cdn.supportfast.ai/chatbot.js" data-chatbot-id="bot-a1b2c3d4e5"></script>
```

| Attribute | Value | Notes |
| --- | --- | --- |
| `id` | `supportfast-script` or `chatbot-script` | Required. Keep the one in the code the console gives you. |
| `src` | The address of `chatbot.js` | Required. Don't host the file on your own server: the widget loads its parts from the same folder. |
| `data-chatbot-id` | The agent's code | Required. Without it, the widget doesn't start. |
| `defer` | — | Recommended, and already in the console's code. The widget also works with `async` or with neither, but your code must wait for it as explained [further down](https://supportfast.ai/en/guide/developers/widget-api.md#making-your-code-wait). |

- The tag must stay a classic script: don't add `type="module"`.
- Include it once per page. A second inclusion does nothing.
- The widget mounts when the document is ready. If the tag arrives later, for example from Google Tag Manager, it mounts right away.

## The window.SupportFast object

The widget creates `window.SupportFast` as soon as `chatbot.js` runs, before the chat is ready.

| Member | What it does |
| --- | --- |
| `version` | The version of the widget running on the page. |
| `init()` | Mounts the widget, if it isn't mounted already. It runs on its own when the document is ready; calling it again doesn't create duplicates. If your framework removed the container, it mounts it again. |
| `open()`, `close()`, `toggle()` | Open, close or toggle the chat. |
| `identify(data)` | Replaces the signed-in customer's data. Without arguments, it reads `window.chatbotUserData` again. |
| `on(event, handler)`, `off(event, handler)` | Start or stop listening to the `ready`, `open` and `close` events. |

- Calls made after `chatbot.js` runs, but before the chat is ready, are queued and run in the order they arrive.
- `ready` fires when the agent is loaded and active; a handler registered later runs right away. If the agent isn't available, it doesn't fire.

**HTML · a website button that opens the chat**

```
<button type="button" onclick="window.SupportFast && window.SupportFast.open()">Contact us</button>
```

### Making your code wait

Before `chatbot.js` runs, `window.SupportFast` doesn't exist and there's no queue to leave calls in. So your code must wait for the object.

- **With the tag in `defer`**, as in the console's code, the `DOMContentLoaded` event is enough: it fires after `defer` scripts have run.
- **With `async`, with Google Tag Manager or with a plugin that delays scripts**, `chatbot.js` can arrive after `DOMContentLoaded`. Use the function below, which works in every case.

**JavaScript · waiting for the widget, however it's loaded**

```
function conSupportFast(azione) {
  var tentativi = 0;
  (function prova() {
    if (window.SupportFast && typeof window.SupportFast.on === "function") {
      azione(window.SupportFast);
    } else if (tentativi < 100) {
      tentativi += 1;
      setTimeout(prova, 100); // retries every tenth of a second, for 10 seconds
    }
  })();
}

conSupportFast(function (chat) {
  chat.on("ready", function () {
    // the chat is loaded and the agent is active
  });
});
```

If `chatbot.js` can arrive later, for example because a plugin waits for the visitor's first interaction, raise the number of attempts.

## Forcing the language: window.ChatbotConfig.lang

Normally the widget picks the language from the visitor's browser, among the workspace languages. To force it, set `window.ChatbotConfig` before the widget code.

**HTML · chat always in English**

```
<script>window.ChatbotConfig = { lang: "en" };</script>
<script defer id="supportfast-script" src="https://cdn.supportfast.ai/chatbot.js" data-chatbot-id="bot-a1b2c3d4e5"></script>
```

- Possible codes, in lowercase: `it`, `en`, `de`, `fr`, `es`, `nl`, `pl`, `tr`, `pt`, `pt-br`, `sr`. `it-IT` or `IT` aren't valid.
- The language must be one of the workspace languages. Otherwise the widget ignores it and picks as usual.
- The language is set at startup: to change it, the page must be reloaded.
- It applies only to the widget installed with the code on the website, not to the link and the iframe.

## The signed-in customer's data: window.chatbotUserData

With `window.chatbotUserData` you pass the widget the data of a customer signed in to your website. The fields are `firstName`, `lastName`, `fullName`, `company`, `email`, `phone` and `metadata`, for the workspace variables. Limits and examples are in [Passing user data](https://supportfast.ai/en/guide/developers/user-data.md).

## Events for Google Analytics and Tag Manager

Every time the chat opens, the widget runs `window.dataLayer.push({ event: "chatbot_open" })`. If `dataLayer` doesn't exist, it creates it. The event has no other parameters.

**With Google Tag Manager**, create a trigger of type Custom Event, with event name `chatbot_open`. Connect it to a Google Analytics 4 event tag, for example with the same name. Publish the container, open the chat and look for the event in the Analytics Realtime report.

**With gtag.js, without Tag Manager**, an entry in the `dataLayer` doesn't become an Analytics event. Use the widget's `open` event:

**JavaScript · GA4 event when the chat opens**

```
// conSupportFast is the function from "Making your code wait", above
conSupportFast(function (chat) {
  chat.on("open", function () {
    gtag("event", "chatbot_open");
  });
});
```

The chat inside an iframe communicates with the page that contains it through `postMessage` messages, listed in [Passing user data](https://supportfast.ai/en/guide/developers/user-data.md#with-the-iframe).

## Moving the button: the CSS variables

The widget container reads three CSS variables, which you can set from the website's stylesheet:

| Variable | Default | What it changes |
| --- | --- | --- |
| `--sf-offset-bottom` | `30px` | The button's distance from the bottom of the screen. |
| `--sf-offset-side` | `25px` | The distance from the side, right or left depending on the Button position. |
| `--sf-z-index` | `2147483647` | The stacking level: the default value is the highest possible. |

**CSS · button higher up, so it doesn't cover a cookie banner**

```
#chat-widget-container {
  --sf-offset-bottom: 100px; /* the button moves above the banner, about 80 pixels tall */
  --sf-offset-side: 20px;
  --sf-z-index: 1000; /* lower than the default: the banner, if it has a higher level, stays above the chat */
}
```

- You can set them on `#chat-widget-container` or on an element that contains it, such as `:root`.
- The open window and the bubble move with the button. Below 600 pixels wide, the open window fills the whole screen anyway.
- Lower `--sf-z-index` if an element of the website, such as a menu or the cookie banner, must stay above the chat: every element with a level higher than the value you choose goes on top.
- To hide the widget on a page, apply the rule `#chat-widget-container { display: none; }` on that page only. You need it, for example, on the page where you put the chat with the [iframe](https://supportfast.ai/en/guide/website/full-page-and-iframe.md#the-iframe).

## Isolation from the website's CSS

The chat is isolated from the rest of the page: the website's CSS doesn't get into the chat and the chat's CSS doesn't get out. From the website you control only the container and the three CSS variables.

## Content Security Policy

If the website sends a Content Security Policy (CSP), the policy must allow the addresses the widget loads its parts from and communicates with. Otherwise the button doesn't appear, or the chat opens but doesn't answer. Add these origins to the directives the website already uses:

| Directive | Origins to add | What it's for |
| --- | --- | --- |
| `script-src` | `https://cdn.supportfast.ai` | `chatbot.js` and the widget's parts, which come from the same folder. |
| `font-src` | `https://cdn.supportfast.ai` | The chat's font. |
| `connect-src` | `https://server.supportfast.ai` and `wss://server.supportfast.ai` | The agent, the messages, attachment uploads and real-time updates, for example operators' replies. |
| `img-src` | `https:` and `blob:` | The agent's photo or logo, images in answers, attachments and the preview of a photo before it's sent. Images come from several addresses, temporary ones too: that's why `https:` is needed. |
| `media-src` | `https:` | Playing voice messages in the chat. |
| `frame-src` | `https://app.supportfast.ai` | Only if you put the chat on a page with the [iframe](https://supportfast.ai/en/guide/website/full-page-and-iframe.md#the-iframe): it's the address you find in the iframe code. |

**HTTP · example header with only the widget's directives**

```
Content-Security-Policy:
  script-src 'self' https://cdn.supportfast.ai;
  font-src 'self' https://cdn.supportfast.ai;
  connect-src 'self' https://server.supportfast.ai wss://server.supportfast.ai;
  img-src 'self' https: blob:;
  media-src 'self' https:;
  frame-src 'self' https://app.supportfast.ai
```

- The widget needs neither `'unsafe-inline'` nor `'unsafe-eval'`. The scripts you write in the page yourself, such as `window.chatbotUserData` or `window.ChatbotConfig`, are inline scripts instead: with a policy without `'unsafe-inline'`, give them a `nonce` or move them to a file.
- For voice messages, the browser must grant the page access to the microphone. If the website sends the `Permissions-Policy` header, it must contain `microphone=(self)`. In the iframe, the console's code already has `allow="microphone"`.
- On a reseller's portal the addresses can be different: for `script-src`, `font-src` and `frame-src`, use the domains you find in the code copied from the console.

**How to check.** Open the website, then the browser console (`F12`), and open the chat. If the policy blocks something, the console shows an error naming the directive and the blocked address: add it and try again.

## What it saves in the browser

The widget uses only `localStorage`: no cookies, no `sessionStorage` or IndexedDB. With the button, the data is stored on your website's domain; with the link and the iframe, on the chat's domain.

- The privacy consent given by the visitor is valid until the same day of the following month. A conversation idle for more than 31 days doesn't reopen on its own.
- The widget's keys start with `sf:`. If a cookie manager clears `localStorage`, exclude them: otherwise the chat starts from scratch at every visit.
- If the browser denies `localStorage`, the widget works without memory.

## Messages in the browser console

During normal operation the widget doesn't write to the console. When something goes wrong, it writes a message in English that starts with `[SupportFast]`:

| Message | What it means |
| --- | --- |
| `script tag not found: it needs id="supportfast-script" or id="chatbot-script" and a src.` | The tag doesn't have the right `id` or the `src`. Also check that a plugin hasn't removed the `id`. |
| `data-chatbot-id is missing on the script tag.` | The agent's code is missing. |
| `the widget could not be loaded.` | The widget's parts didn't arrive: network, [Content Security Policy](https://supportfast.ai/en/guide/developers/widget-api.md#content-security-policy), or `chatbot.js` copied to your own server. |

Some cases produce no message: agent paused, code that doesn't exist, domain not authorized, browser too old. The causes and fixes are in [Website widget](https://supportfast.ai/en/guide/help/widget-issues.md).

## Supported browsers

The widget works on Chrome and Edge from version 85, on Firefox from 101 and on Safari from 16.4. On iPhone and iPad it needs iOS or iPadOS 16.4 or later. On older browsers the button doesn't appear, with no effect on the rest of the page.

Voice messages also need a browser that can record audio, and access to the microphone. Where they're missing, the microphone doesn't appear.

## Versions and updates

The tag always points to the same `chatbot.js`: new versions arrive on their own, without touching the website. To find out which version is running, type `window.SupportFast.version` in the browser console.

## See also

- [Installing the widget](https://supportfast.ai/en/guide/website/install-widget.md): The code, the publishing domain and the check.

- [HTML and other sites](https://supportfast.ai/en/guide/website/other-sites.md): HTML, Google Tag Manager, website builders, Joomla and PrestaShop.

- [Website widget](https://supportfast.ai/en/guide/help/widget-issues.md): The most common problems, by symptom.
