Skip to main content

Add the Widget to Any Website

One <script> tag puts your widget on any site that lets you add HTML — this page is the full reference for that snippet: every data-* attribute, plus notes for plain HTML sites, single-page apps, and Google Tag Manager.

If you haven't created a widget yet, start with Website Widgets. For the platform-specific walkthroughs, see WordPress, Wix, and Shopify.

The snippet

The widget's Install screen generates a ready-to-paste snippet with your branding baked in. In its simplest form it is:

<script src="https://api.bess-ai.com/embed.js"
data-widget-id="bess_pk_live_XXXXXXXXXXXX"
async></script>

Paste it just before the closing </body> tag of every page where the widget should appear. A fully-dressed example:

<script src="https://api.bess-ai.com/embed.js"
data-widget-id="bess_pk_live_XXXXXXXXXXXX"
data-locale="en"
data-position="bl"
data-accent="#0EA5E9"
data-label="Talk to our agent"
data-waves="0"
async></script>

How it works: the script is a tiny loader that draws only the floating launcher button. The panel itself — and the microphone permission, the audio connection, and the session — loads lazily inside an iframe the first time a visitor clicks, so the snippet adds almost nothing to your page weight. One snippet per page is enough; a second copy on the same page is ignored.

note

The publishable key in the snippet is safe to expose publicly — like a Stripe pk_ key, it can only start sessions for this widget's agent and is bounded by your allowed domains, rate limits, daily caps, and credit balance. If you rotate the key in the dashboard, update the snippet — the old key stops working immediately.

Every data-* attribute

AttributeValuesDefaultWhat it does
data-widget-idbess_pk_live_…— (required)The widget's publishable key from the Install screen. Without it the widget does not load.
data-localetr, entrLanguage of the widget UI (button labels, status text, default titles).
data-positionbr, blbrCorner for the launcher bubble: bottom-right or bottom-left.
data-accenthex color, e.g. #0EA5E9#C2A14ELauncher and panel accent color — the Install screen bakes your dashboard accent in here. Hex only (3–8 digits, # optional); any other format is ignored.
data-labelfree textnoneText pill next to the launcher (e.g. "Talk to our agent"). Omit for the bare button.
data-waves1, 01The pulsing attention ring around the launcher. Set 0 to disable.
data-modevoice, chat, hybridwidget's modePins a hybrid widget to one surface for this embed. It never unlocks a mode the widget doesn't allow — the platform enforces the widget's configuration.
data-titlefree textwidget brandingOverrides the panel title for this embed only.
data-subtitlefree textwidget brandingOverrides the panel subtitle for this embed only.
data-transcript1, 01Set 0 to hide the live transcript in the voice panel.
data-page-tools1, 00Lets the agent use tools your page registers — see Page Tools (Beta). Also requires the widget's Allow page tools setting in the dashboard.

Attributes only change the embed they are on — useful when the same widget lives on several sites with different branding. Everything you configure in the dashboard (allowed domains, caps, rate limits, mode, badge) is enforced server-side no matter what the attributes say.

Platform notes

  • WordPress — the official plugin is the no-code path: Install on WordPress. Without the plugin, paste the snippet site-wide with a header/footer code plugin (e.g. WPCode) or into your child theme just before </body>.
  • WixSettings → Custom Code, applied to All pages, placement Body - end: Install on Wix. Requires a Premium site with a connected domain.
  • Shopify — paste into layout/theme.liquid just before </body>: Install on Shopify. Don't use Custom pixels — they are sandboxed and can't render the widget.
  • Google Tag Manager — on any platform with GTM: create a Custom HTML tag containing the snippet, trigger it on All Pages, and publish the container. The widget's Install screen has the click-by-click version.
  • Plain HTML sites — paste the snippet before </body> in your shared footer include or page template so it ships on every page.
  • Other site builders — the widget's Install screen (Where is your site?) has step-by-step instructions for more platforms. Anywhere you can add an HTML/script block that runs on your public pages, the same snippet works.

Single-page apps (React, Vue, Next.js, …)

Load the snippet once at the app shell — in index.html, or your root layout/document component — not inside a routed page component:

  • Mounted at the shell, the widget survives client-side navigation: a visitor can keep talking or chatting while they move between routes.
  • Mounted inside a route, the launcher would only exist on that route, and remounting on every navigation is wasted work (the loader ignores duplicate injections, but there's no reason to create them).

This is how we run it on our own site — the widget on bess-ai.com is mounted once at the shell precisely so sessions survive navigation.

If you inject the tag programmatically, make sure to copy the data-* attributes onto the created element:

const s = document.createElement("script");
s.src = "https://api.bess-ai.com/embed.js";
s.async = true;
s.setAttribute("data-widget-id", "bess_pk_live_XXXXXXXXXXXX");
document.body.appendChild(s);

Nothing shows up?

  1. The page's domain is listed in the widget's Allowed domains in the dashboard — a widget with no matching domain renders nowhere.
  2. The widget is Active (not disabled) in the dashboard.
  3. The data-widget-id matches the current key — a rotated key invalidates old snippets instantly.
  4. The snippet actually ships on the page (view the page source and search for embed.js) — some builders only apply code changes after you re-publish the site.

Once any page carrying the snippet loads, the widget's Install screen in the dashboard flips to "widget detected" on your domain automatically.