Installation Guides
The hosted widget.js integration is the no-build path when you want ChattyBox to maintain the interface and transport. If your app should initialize the same UI from npm code, use mountWidget(). To own the UI, use the headless SDK.
Before Installing
Complete the Getting Started flow first: configure and scrape the source, review indexed pages, and verify representative answers in Test chatbot.
In Install, prepare an installation for your website or manage a browser-safe key under Keys & domains. Check the key's origin settings: a key prepared for a website domain can already be restricted to that origin, while keys created without restrictions work across origins. Under Edit origins, you can enable optional restrictions or add the production, preview, staging, and localhost origins you need. When enabled, matching includes scheme, hostname, and port: https://example.com, https://preview.example.com, and http://localhost:3000 are separate entries. In Website installation, enter an HTTP(S) website URL; the snippet selector offers unexpired keys that are unrestricted or allowed for that URL's origin. Choose a suitable key and copy the generated snippet. If the installation form is unavailable, complete the dashboard setup step shown first. The snippet includes the public key and API URL for your project:
<script
src="https://chattybox.ai/widget.js"
data-api-key="YOUR_API_KEY"
data-api-url="YOUR_WIDGET_API_URL"
async
></script>
For docs-oriented platforms, see the MkDocs AI chatbot, VitePress AI chatbot, and GitBook AI chatbot guides.
Replace YOUR_API_KEY with the public widget key from your dashboard. Keep the data-api-url value exactly as shown in the dashboard. In production, this is a stable https://...convex.site/chat URL for the public widget API.
What Belongs in the Script
Use script attributes for values that must be available before the widget can start:
| Attribute | Required | Use it for |
|---|---|---|
src | Yes | Loading the ChattyBox widget JavaScript. |
data-api-key | Yes | Identifying the public widget key for your project. |
data-api-url | Yes | Sending widget requests to the ChattyBox API. |
data-locale | No | Requesting a UI language at initialization, only when project script overrides are allowed. |
data-chattybox-widget="true" | No | Lets dynamic loaders and the SDK find an existing script. Recommended when injecting from application code. |
data-debug="true" | No | Enabling browser diagnostics; off by default. |
data-color | No | Explicit accent-color override after a successful config fetch; use a six-digit hex color. Prefer the dashboard. |
data-position | No | Explicit position override after a successful config fetch: bottom-right, bottom-left, top-right, or top-left. Prefer the dashboard. |
Use dashboard settings for everything that should be managed without redeploying your site:
- Widget colors, position, icon, title, and welcome message.
- Default language mode and whether
data-localeoverrides are allowed. - Public key creation, deletion, and optional per-key origin restrictions. Open Install → Keys & domains and use Edit origins to add or remove production, staging, preview, or localhost origins.
- Scraping, re-scraping, test chat, analytics, and content gaps.
If you enable the config-as-code lock, assistant, source, runtime, and supported widget settings come from the deployed config instead of dashboard forms. Public keys and optional origin restrictions remain project setup settings, not config-file values.
The API URL can be the HTTP deployment root or end in /chat; the loader strips trailing slashes and a trailing /chat before deriving its endpoints. It does not convert a Convex .cloud URL into .site. Keep query strings and fragments out of this value.
Install one loader only. The SDK recognizes the marker attribute above, not every manual script with the same src. Published SDK 0.1.4 reference-counts only identical mount options and rejects a changed key, endpoint, script URL, locale, or debug setting until all handles are removed. The widget does not subscribe to dashboard configuration changes; reinitialize it to pick up saved settings. In current-source hosted widget.js v16, changes to <html lang> or the loader's data-locale can refresh widget labels when the resolved locale changes, subject to the project's locale policy. Verify the deployed loader version before relying on live updates; this behavior is separate from the published npm SDK version. Origin restrictions, when enabled, use Origin or a fallback Referer origin; absent or disallowed origins produce 401 Invalid API key. They are not authentication.
Plain HTML
Paste the snippet once near the end of body, just before </body>. This works for static HTML, hand-coded sites, and templates that expose a global footer.
<!doctype html>
<html lang="en">
<head>
<title>Example Site</title>
</head>
<body>
<main>
<!-- Page content -->
</main>
<script
src="https://chattybox.ai/widget.js"
data-api-key="YOUR_API_KEY"
data-api-url="YOUR_WIDGET_API_URL"
async
></script>
</body>
</html>
Next.js / React App Shell
For a Next.js App Router site, add the widget to app/layout.tsx with next/script so it loads once for the whole app.
import Script from "next/script";
import type { ReactNode } from "react";
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://chattybox.ai/widget.js"
data-api-key="YOUR_API_KEY"
data-api-url="YOUR_WIDGET_API_URL"
data-chattybox-widget="true"
strategy="afterInteractive"
/>
</body>
</html>
);
}
For a React single-page app, add the script once in your top-level app shell or HTML template. Do not inject it from every route component.
Keep the loader in a persistent shell during ordinary navigation. For route-scoped removal or consent revocation, remove every SDK 0.1.4 handle: the final matching handle signals hosted widget.js v15 to destroy its owned UI/styles and cancel pending initialization, retries (up to 10 attempts within 30 seconds), and in-flight chat; window.ChattyBox.destroy() is available after v15 initialization. Cleanup cannot undo a server-processed request. The hosted widget floats under document.body; it does not render inside the component that loads it.
import { useEffect } from "react";
export function ChattyBoxWidget() {
useEffect(() => {
if (document.getElementById("chattybox-widget-script")) return;
const script = document.createElement("script");
script.id = "chattybox-widget-script";
script.src = "https://chattybox.ai/widget.js";
script.async = true;
script.setAttribute("data-api-key", "YOUR_API_KEY");
script.setAttribute("data-api-url", "YOUR_WIDGET_API_URL");
script.setAttribute("data-chattybox-widget", "true");
document.body.appendChild(script);
}, []);
return null;
}
Docusaurus
For Docusaurus, create or update src/theme/Root.tsx so the widget is available across docs pages.
import React, { useEffect } from "react";
export default function Root({ children }: { children: React.ReactNode }) {
useEffect(() => {
if (document.getElementById("chattybox-widget-script")) return;
const script = document.createElement("script");
script.id = "chattybox-widget-script";
script.src = "https://chattybox.ai/widget.js";
script.async = true;
script.setAttribute("data-api-key", "YOUR_API_KEY");
script.setAttribute("data-api-url", "YOUR_WIDGET_API_URL");
script.setAttribute("data-chattybox-widget", "true");
document.body.appendChild(script);
}, []);
return <>{children}</>;
}
If your Docusaurus site has translated routes, set data-locale before loading (when overrides are allowed), or use auto mode and the page's <html lang>. Fixed mode uses the project's default locale unless an allowed script override is present. Current-source hosted widget.js v16 can refresh product-owned labels when either attribute changes the resolved locale; verify your deployed loader's behavior before relying on client-side updates. Custom title and welcome text and generated answers are not automatically translated.
Keep the loader in your persistent application shell. Do not recreate it during normal client-side route changes; use the hosted widget's destruction API when you intentionally need teardown, or remove all SDK mount handles if you used the SDK.
Custom Interface
The hosted widget is optional. If you want full control over rendering, message state, and interaction design, use the JavaScript SDK with the same public widget API key and widget API URL.
Generic CMS/Custom HTML
Most CMS platforms have a global custom code, footer, or theme template area. Add the script there so every public page can load the widget.
Use this path for Webflow, Framer, Squarespace, Wix custom code areas, Shopify themes, HubSpot templates, and custom CMS platforms that let you edit global HTML.
<script
src="https://chattybox.ai/widget.js"
data-api-key="YOUR_API_KEY"
data-api-url="YOUR_WIDGET_API_URL"
async
></script>
Before publishing, confirm the CMS does not strip data-api-key, data-api-url, or async from custom scripts.
Google Tag Manager
Use Google Tag Manager when your team already manages third-party scripts through GTM.
- Open your GTM container.
- Create a new Custom HTML tag.
- Paste the ChattyBox snippet.
- Use an All Pages trigger, or a narrower trigger for only the pages that should show the widget.
- Preview the container, verify the widget loads, then publish.
<script
src="https://chattybox.ai/widget.js"
data-api-key="YOUR_API_KEY"
data-api-url="YOUR_WIDGET_API_URL"
async
></script>
If your site uses consent mode or a tag consent policy, ensure the widget is allowed to load on the pages where visitors need help.
On SPAs, a narrower GTM trigger prevents the initial load on excluded routes but does not remove a widget already loaded on another route. Do not repeatedly fire the loader on history changes.
Content Security Policy
For the default hosted loader, permit https://chattybox.ai in script-src and your widget API origin in connect-src. The widget injects a stylesheet and inline style attributes; it currently has no nonce option, so a policy forbidding inline styles will block parts of its UI. If your policy permits it, allow 'unsafe-inline' for these styles, or use a custom UI compatible with your policy. Loading Inter on launcher interaction also requires https://fonts.googleapis.com in style-src and https://fonts.gstatic.com in font-src. Allow any configured icon image origin in img-src. Review consent and security requirements before relaxing CSP.
WordPress plugin guide
For a no-code WordPress installation, use the ChattyBox WordPress plugin. Follow the WordPress plugin guide to install, configure, exclude routes, and verify it. The production API endpoint is configured automatically.
The plugin loads the hosted widget on public frontend requests without editing your theme. It intentionally does not load in wp-admin, feeds, REST requests, or AJAX requests.
This is not a privacy/access check for every frontend page. Where needed, implement and test exclusions for checkout, account, password-protected, or membership pages using the plugin's filter, or use a suitably scoped manual installation. The plugin's loader URL setting does not change its built-in production API endpoint; use the manual snippet for a different API deployment.
If you prefer a manual script install, use one of the script locations your WordPress setup already supports:
- Theme settings that provide header or footer scripts.
- A child theme that controls the footer template.
- A header/footer script plugin.
- Google Tag Manager if your WordPress site already uses it.
Paste the snippet in a global footer location so it appears on published pages, posts, docs, and knowledge base articles where the chatbot should be available.
<script
src="https://chattybox.ai/widget.js"
data-api-key="YOUR_API_KEY"
data-api-url="YOUR_WIDGET_API_URL"
async
></script>
Avoid adding the widget to wp-admin, checkout, account, or private membership pages unless those pages are intentionally public and supported.
Drupal module
For Drupal 10 or 11, Composer is the recommended installation path. Add the public GitHub VCS repository to the consuming Drupal project's root composer.json:
{
"repositories": {
"chattybox-drupal": {
"type": "vcs",
"url": "https://github.com/OpenStaticFish/chattybox-drupal.git"
}
}
}
Then install the tagged module and enable it:
composer require openstaticfish/chattybox-drupal:^0.1
drush en chattybox
Open Configuration > Web services > ChattyBox, paste the public widget API key from the website installation snippet, and enable the chatbot. The locally audited module version uses a hard-coded API endpoint. Compare it with your snippet; use the manual integration for a different API deployment. See the Drupal chatbot module guide for route exclusions, caching, and consent guidance.
The module starts disabled. It skips administrative and non-HTML requests, not all private frontend content. Changing its script URL does not change the built-in production API endpoint. Use a manual widget snippet instead of the module for a different API deployment.
Verification
After installing, run the launch checklist before announcing the chatbot:
- Open a public page in an incognito window.
- Confirm the widget launcher appears.
- Open the widget and ask a real customer question.
- Verify a supported answer includes relevant source citations, then ask an unsupported question and check the fallback (which can have no sources).
- Check the browser console for missing
data-api-key, missingdata-api-url, or key errors. Check whether the key has origin restrictions enabled and, if so, whether the intended origin is allowed.