# ChattyBox Full Documentation
> Full default-locale documentation and reviewed, citeable product facts for ChattyBox.
## Retrieval and Product Facts
### Supported public-content scope
- ChattyBox indexes selected public website pages, documentation, help articles, CMS content, and knowledge bases.
- Choose sitemap, same-site crawl, or manual URLs; review indexed pages and test representative answers before launch.
- The crawler extracts content from fetched HTML without executing page JavaScript. Client-rendered content may need a public server-rendered or static version.
Sources: [Content Scraping](https://chattybox.ai/docs/scraping/); [Getting Started](https://chattybox.ai/docs/getting-started/)
### Source-link behavior
- When relevant indexed pages are retrieved, an answer can include links to those source pages.
- Source cards use retrieved page URLs; fallback responses can have no sources. Inline answer links still require accuracy checks.
Sources: [Source citations and retrieval](https://chattybox.ai/docs/); [Troubleshooting citations](https://chattybox.ai/docs/troubleshooting/)
### Integration options
- Use the hosted widget script or Chattybox.mountWidget() for the maintained interface.
- Use the JavaScript SDK headless methods when your application owns the UI, conversation state, citations, and accessibility.
Sources: [Installation Guides](https://chattybox.ai/docs/installation/); [JavaScript SDK](https://chattybox.ai/docs/sdk/)
### Managed crawl and retrieval workflow
- Create a project, configure a source, run a scrape, review indexed pages, test cited answers and fallbacks, then integrate the widget or SDK.
- Re-scrape after source content changes.
Sources: [Getting Started](https://chattybox.ai/docs/getting-started/); [Content Scraping](https://chattybox.ai/docs/scraping/)
### Boundaries
- Crawls do not provide authenticated access to private pages. The current crawler does not enforce robots.txt rules; explicitly select or exclude URLs and use access controls for private content.
- It supports public-content self-service and should retain human escalation or help-desk workflows for private, sensitive, or unresolved issues.
- This file makes no enterprise-only or ecommerce workflow claim without public, indexed documentation.
Sources: [Content Scraping](https://chattybox.ai/docs/scraping/); [AI Customer Support Chatbot](https://chattybox.ai/ai-customer-support-chatbot/)
### Public plans (USD)
| Plan | Price | Sites | Pages included | Messages/month | Refresh cadence |
| --- | --- | ---: | ---: | ---: | --- |
| Free | $0/month | 1 | 10 | 100 | weekly |
| Starter | $19/month | 3 | 150 | 1,000 | daily |
| Pro | $49/month | 10 | 5,000 | 10,000 | daily |
| Business | $199/month | 25 | 25,000 | 50,000 | daily |
Source: [Pricing](https://chattybox.ai/pricing/). Pro and Business offer optional pay-as-you-go overages; see Pricing for current overage terms.
## Documentation Pages
### Welcome to ChattyBox
URL: https://chattybox.ai/docs/
Description: Learn how ChattyBox turns documentation into a source-cited AI chatbot that answers from your content and reveals content gaps.
# Welcome to ChattyBox
Turn your documentation into a source-cited AI chatbot that answers from your content. Choose a one-line hosted widget, mount that same widget from application code, build your own UI with the headless SDK, or manage the project with versioned configuration as code.
### Fast path
If you already have a docs site or help center, start with **Getting Started**, pick the right **Installation Guide**, and use **Analytics** to find unanswered questions.
- Create a ChattyBox project. Add your site URL or sitemap so the crawler can discover documentation pages.
- Test grounded answers. Ask real support questions and verify the cited source pages.
- Choose an integration. Paste the script, mount the hosted UI with the SDK, or use the headless SDK with your own components.
## Four ways to use ChattyBox
| Goal | Use | You own |
|---|---|---|
| Add the maintained chatbot UI from React or app code | [`Chattybox.mountWidget()`](/docs/sdk/) | App initialization |
| Use ChattyBox infrastructure with your own chatbot UI | [Headless SDK](/docs/sdk/) | Components, state, and interaction design |
| Manage project behavior from Git and CI instead of the dashboard | [CLI and config as code](/docs/cli/) | One config file and its deployment pipeline |
| Add the maintained UI without npm or a build step | [`widget.js` HTML snippet](/docs/installation/) | Where the script is installed |
The browser integrations use a **public widget API key**. Configuration deployment uses a separate secret **deployment token**; never put that token in browser code.
## Choose an implementation or evaluation path
- Compare verified framework guidance in the [platforms hub](/platforms/), including the [Docusaurus implementation](/docusaurus-ai-chatbot/) and [MkDocs implementation](/mkdocs-ai-chatbot/).
- For a visitor-facing public-content rollout, use the [AI chatbot for website guide](/ai-chatbot-for-website/) to choose source pages, test citations, and embed without building a custom RAG stack.
- Plan technical-docs evaluation with the [documentation chatbot guide](/ai-chatbot-for-documentation/) or narrow endpoint and authentication testing with the [API documentation guide](/chatbot-for-api-documentation/).
- Review retrieval, freshness, and fallback behavior in the [RAG architecture guide](/rag-chatbot-for-website/).
- Define answer-verification behavior with the [source-citation guide](/ai-chatbot-with-source-citations/).
- Browse support, trust, and content-discovery goals in the [use-cases hub](/use-cases/), or compare products through the [alternatives hub](/alternatives/).
## What ChattyBox Does
ChattyBox is an AI-powered chatbot platform that:
- **Scrapes your website** and indexes documentation, guides, help centers, or knowledge bases.
- **Answers from retrieved content** instead of generic model memory.
- **Shows source citations** so visitors can verify answers and continue reading.
- **Uses a fallback for detected content gaps** when there is insufficient source context. Test answer quality; grounding is not a guarantee that every generated answer is correct.
## Quick Start
Build and verify the chatbot before exposing it to visitors.
1. [Create an account](/docs/getting-started/) and make your first project.
2. [Configure and index your content](/docs/scraping/), then review the pages that were discovered.
3. Use **Test Chat** to verify representative answers, citations, and fallback behavior.
4. Tune the persona and hosted-widget appearance for the experience you want.
5. Create a public widget key, optionally restrict its browser origins, and [choose an integration](/docs/installation/).
6. [Run the launch checklist](/docs/launch-checklist/) before publishing broadly.
7. [Review analytics](/docs/analytics/) to see what visitors ask and what content is missing.
## Key Features
### Source-Grounded Answers
Unlike generic chatbots, ChattyBox is designed to answer only from your scraped content. If the information isn't in your documentation, the bot can say it doesn't know. Answers can include source citations for verification.
### Source Citations
When relevant source pages are retrieved, answers can include clickable links to your documentation. This builds trust and lets users verify information.
### Analytics Dashboard
Track what questions visitors are asking, identify content gaps, and improve your documentation based on real user needs.
**Analytics** and **Content Gaps** require Pro or Business. **Logs** and **Test Chat** are available on every plan. Test questions consume message quota and appear alongside public interactions. Use the [dashboard map](/docs/getting-started/#dashboard-map) to find each feature.
### Easy Customization
Match the chat widget to your brand with custom colors, icons, and welcome messages, all from the dashboard with no code required.
## How It Works
1. **Scraping** - Choose homepage, sitemap, crawl, or manual URLs. The crawler fetches public HTML without JavaScript rendering or `robots.txt` enforcement; source selection and plan budgets determine coverage.
2. **Vector Embeddings** - Content is converted to high-dimensional vectors for semantic search
3. **RAG Response** - When a user asks a question, we retrieve relevant chunks and generate an answer using only that context
## Recommended Reading Order
## Pricing
ChattyBox offers a permanent Free plan for one site, up to 10 indexed pages, and 100 messages per month, including dashboard test messages. Free refreshes are at most weekly; paid plans allow daily refreshes. Monthly page-refresh budgets are separate from stored-page limits. Paid plans increase site, page, and message limits; see [plans and budgets](/docs/getting-started/#plans-and-budgets) and the [pricing page](/pricing/) for details.
## Frequently Asked Questions
### What content can ChattyBox index?
ChattyBox can index public HTML pages from websites, documentation, help centers, CMS sites, and knowledge bases. It extracts readable text and headings; it does not log in or render JavaScript-only content. Long pages can be partially retained. Review [content extraction and limits](/docs/scraping/) before choosing sources.
### How do source citations work?
When a visitor asks a question, ChattyBox retrieves relevant passages from indexed pages and can include links to the source pages used for the response. Citations help visitors verify answers and continue reading the official documentation.
### What should I test before launch?
Ask real support and documentation questions, confirm the cited pages are correct, check fallback behavior when information is missing, and run through the [launch checklist](/docs/launch-checklist/) before publishing the widget broadly.
## Need Help?
- Email us at support@chattybox.ai
- Check the [documentation](/docs/getting-started/) for detailed guides
- Use [Troubleshooting](/docs/troubleshooting/) if the widget does not appear or answers look weak
### Getting Started
URL: https://chattybox.ai/docs/getting-started/
Description: Create a ChattyBox project, index your website, verify grounded answers, and prepare the right integration.
# Getting Started
Build a useful chatbot before putting it on your site. The core sequence is **create → add content → review → test → customize → integrate**.
## 1. Create an Account and Project
Sign in to the [ChattyBox dashboard](https://app.chattybox.ai/dashboard), select **New Chatbot**, and give the project a name and optional Website URL. After creation, open the chatbot from the project list. Its default tab is **Content**, where stored pages and scrape jobs will appear; creation alone does not start a scrape.
See [pricing](/pricing/) for current chatbot, account-page, and usage limits.
## 2. Configure Your Content Source
Open the chatbot's **Settings** tab. Under **General Settings**, add the public **Website URL** and select **Save Changes**. Under **Scraping Configuration**, choose a discovery mode, maximum pages, and optional refresh schedule, then select **Save Config**. These are separate forms. Include/exclude rules and crawl depth are available through [configuration as code](/docs/cli/), not dashboard controls.
Run **Scrape Now**. ChattyBox discovers the selected pages, extracts readable HTML content, and queues changed content for indexing. It does not render JavaScript or enforce `robots.txt`; use public pages you are authorized to index and deliberately select the launch scope. Timing depends on discovery, page count, and indexing work.
Use [Add and refresh content](/docs/scraping/) when you need sitemap, manual URL, crawl, multilingual, or re-scraping guidance.
## 3. Review Indexed Content
Return to **Content** and compare the actual pages with your expected sources. Open the scrape job to review counts and partial-content warnings, and check the separate embedding job before evaluating answers. A completed scrape does not guarantee that every requested page or every section was indexed. See [progress and partial indexing](/docs/scraping/#progress-and-partial-indexing).
## 4. Test Answer Quality
Open **Test Chat** and ask representative questions that real visitors will use. Check that answers:
- use the indexed documentation rather than unsupported assumptions;
- link to useful source pages;
- handle missing information with the intended fallback;
- work for important languages and terminology.
Improve the source content or source selection when an answer is weak, then scrape again when the plan's cooldown allows it. Free refreshes are at most weekly; paid refreshes are at most daily. **Test Chat uses your message allowance and contributes to the same conversation logs, analytics, and content gaps as public chat.** Do not install the chatbot merely because the first scrape completed.
## 5. Tune the Experience
Use **Persona** to choose Helpful Assistant, Sales Representative, Technical Support, Sarcastic Bot, or Custom Persona, edit the instructions, and select **Save Changes**. Editing a preset switches it to Custom. These instructions supplement ChattyBox's built-in grounding and formatting rules; retrieved content is appended automatically, so do not paste your knowledge base into the prompt.
Persona text does **not** replace the enforced no-context/content-gap fallback. The separate `assistant.fallbackMessage` setting is available through [configuration as code](/docs/cli/), not a Persona form field. Test both supported questions and fallback behavior after saving.
If you plan to use the hosted widget, use **Embed** to preview its title, welcome message, colors, icon, position, and language behavior, then **Save Widget Settings**. **Settings** also exposes the same project language settings. Fixed mode and script overrides affect widget UI language, not which language pages get indexed; see [language troubleshooting](/docs/troubleshooting/#wrong-language). Free includes styling but requires ChattyBox branding; Starter and higher can hide it.
These choices come after content testing so visual setup does not hide retrieval or documentation problems.
## 6. Choose an Integration
| Goal | Next step |
|---|---|
| Mount ChattyBox's maintained interface from application code | [JavaScript SDK](/docs/sdk/) |
| Build and maintain your own interface | [Headless JavaScript SDK](/docs/sdk/) |
| Let an AI coding assistant integrate the npm package | [AI-assisted integration](/docs/ai-builder-prompts/) |
| Manage project configuration from Git and CI | [CLI and configuration deployment](/docs/cli/) |
| Use the maintained interface without npm or a build step | [Hosted widget script](/docs/installation/) |
| Add the maintained widget to WordPress without theme edits | [WordPress plugin](/docs/wordpress-chatbot-plugin/) |
| Add the maintained widget to Drupal 10 or 11 with Composer | [Drupal module](/docs/drupal-chatbot-plugin/) |
Browser integrations need a public widget API key. Public keys work from production, previews, staging, and localhost by default. For optional defense-in-depth hardening, open **Public Keys** > **Edit origins**, enable **Restrict this key to specific origins**, and add each permitted browser origin. Restricted origins match exactly by scheme, hostname, and port (for example, `https://example.com` and `http://localhost:3000` are different origins). Return to **Embed** to select the key and copy the generated snippet and API URL.
Public widget keys are designed to appear in browser code. Config deployment tokens and other management credentials are private and must never be added to a website.
You can recover an existing public key by selecting it in **Embed** and copying the snippet. To rotate it, create a new key, update and test your installation, then delete the old key. Deletion immediately stops installations that still use it. A key belongs to one chatbot; naming it "staging" or "production" does not enforce an environment boundary. Origin restrictions are optional hardening, not visitor authentication.
## 7. Validate Before Launch
Install the selected integration on a preview or staging site first. Test the deployed origin, navigation between routes, citations, fallback behavior, mobile layout, and browser console before publishing broadly.
Complete the [launch checklist](/docs/launch-checklist/), then use **Logs** on any plan, or [Analytics and Content Gaps](/docs/analytics/) on Pro and Business, to improve the documentation after real questions arrive.
## Dashboard Map
Open a project at `/chatbot/`. Tabs use the `tab` query parameter, not separate subpages:
| Tab | Query value | What to do there |
|---|---|---|
| Content | `content` | Review pages and scrape jobs, delete content, rebuild embeddings |
| Test Chat | `test` | Ask questions and revisit saved conversations |
| Logs | `logs` | Read saved conversations and delete individual or all conversations |
| Analytics | `analytics` | Review the last 30 days of recorded interactions, capped at 5,000 records; Pro/Business |
| Content Gaps | `gaps` | Review and resolve detected unanswered questions; Pro/Business |
| Persona | `prompts` | Choose or edit assistant instructions |
| Public Keys | `keys` | Create/delete public widget keys and edit optional origin restrictions |
| Embed | `embed` | Save hosted-widget appearance/language and copy a key's snippet |
| Settings | `settings` | Save general/source settings, start scrapes, manage deployment tokens and config lock, delete the chatbot |
**All projects** returns to `/dashboard`. Workspace **Overview** is `/dashboard/overview`; **Account & Billing** is `/settings/account`, with profile, plan, message usage, billing portal, and PAYG controls. `/settings` and `/settings/billing` redirect there. `/settings/keys` provides a project selector for public key creation/deletion; optional origin editing is in the chatbot's **Public Keys** tab.
## Permissions and Config Lock
Dashboard project access is owner-only (or the owning user of a legacy workspace). A public widget key does not grant access to project settings or stored conversation history; organization membership alone does not grant these project permissions.
For Git/CI management, **Settings** > **Config deployment tokens** creates project-scoped secret tokens with development, preview, and/or production scopes, optional expiry, and revocation. Unlike public widget keys, a deployment token's full value is shown only at creation. The section also shows deployment history.
**Enable config lock** is irreversible. It blocks dashboard configuration writes and manual content operations, including Persona saves and Scrape Now, even where a control remains visible. Deploy configuration through the [CLI workflow](/docs/cli/) instead. Public-key management, conversation cleanup, and the plan-permitted branding preference remain separate from those locked configuration fields. Token environment scopes authorize deployments; they do not create separate chatbots or browser-key environments.
Configuration as code also exposes `widget.enabled`. Setting it to `false` disables public chat, including the headless SDK, not just the floating widget. There is no corresponding enable/disable switch in the current Embed form.
## Plans and Budgets
| Plan | Chatbots | Account pages | Messages per month |
|---|---|---|---|
| Free | 1 | 10 | 100 |
| Starter | 3 | 150 | 1,000 |
| Pro | 10 | 5,000 | 10,000 |
| Business | 25 | 25,000 | 50,000 |
Messages and included stored pages are owner-level allowances shared by the owner's chatbots, including Test Chat. Monthly page-refresh work and refresh cooldowns are distinct limits; review [refresh budgets](/docs/scraping/#page-limits) before a large import or rebuild. The owner-pooled page allowance is part of the forthcoming rollout; until it reaches the public dashboard, labels and enforcement there can still reflect the prior per-chatbot behavior.
PAYG for messages, pages, and sites is optional on Pro/Business and off by default. In **Account & Billing**, set monthly overage budgets per feature or explicitly choose **No spend cap**. A zero budget keeps that feature hard-capped; no spend cap permits uncapped usage charges. PAYG does not unlock features on Free/Starter or bypass crawler refresh cooldowns. Profile name is editable there; email is managed through your sign-in provider's account settings.
### Hosted Widget Customization
URL: https://chattybox.ai/docs/widget/
Description: Customize the ChattyBox AI chat widget, configure language behavior, manage dashboard settings, and troubleshoot multilingual setup.
# Hosted Widget Customization
Customize the ready-made interface loaded by `https://chattybox.ai/widget.js`. For canonical framework and platform installation examples, see [Installation Guides](/docs/installation/).
## Before You Customize
Create the project, index its content, and verify representative answers in **Test Chat** before spending time on presentation. See [Getting Started](/docs/getting-started/) for the complete sequence.
## Configure the Hosted Widget
1. Go to your [Dashboard](https://app.chattybox.ai/) and select your project.
2. Navigate to the **Embed** tab.
3. Preview and save the widget's appearance and language behavior.
The **Embed** tab controls presentation and generates installation code, but public keys are managed separately. When you are ready to install:
1. Open **Public Keys** and create a browser key.
2. Return to **Embed**, select the key, and copy the generated snippet. The key works across production, previews, staging, and localhost by default.
3. Optionally open **Public Keys** > **Edit origins** and enable an exact origin restriction for defense in depth.
4. Follow the [Installation Guides](/docs/installation/) for your platform.
[Widget embed snippet]
:::tip
Widget presentation changes saved in the dashboard apply on the next widget initialization without replacing the snippet. Already-open pages do not update live; reload to fetch the saved settings.
:::
---
## Visual Customization
The dashboard editor lets you adjust the supported widget colors, placement, icon, and text without editing your site's code. Verify the result in the hosted widget, since the preview and loader are not identical.
### Dashboard Controls
1. **Accent Color** - Pick your brand's primary color. This affects the launcher, key highlights, and user messages.
2. **Position** - Choose where the widget appears on the screen.
3. **Header Title** - Set the title shown at the top of the chat window.
4. **Welcome Message** - Customize the first message visitors see when they open the chat.
5. **ChattyBox Branding** - Starter and higher plans can turn off the “Powered by ChattyBox” footer. Branding remains enabled on Free.
The editor also has **Widget Background** and **Text Color** controls, plus a default robot, emoji, image URL, or uploaded image for the widget icon. Uploaded icons must be at most 512 KiB and use an accepted image MIME type (PNG, JPEG, WebP, SVG, GIF, or ICO). Although the editor stores an icon size, the current hosted loader does not read `iconSize`; do not expect small/medium/large to resize it.
:::note
Save changes, then reload the installed page to verify them. The dashboard preview is a mock, not the hosted widget itself. For config-locked projects, appearance and locale fields are managed by config-as-code; entitled projects can still save branding separately.
:::
### Configuration Defaults
These are the defaults returned by a successful public widget-config request when no custom value exists:
| Field | Default |
| --- | --- |
| `enabled` | `true`, unless disabled on the project |
| `themeColor` | `#3b82f6` |
| `chatBgColor` | `#0f172a` |
| `textColor` | `#f8fafc` |
| `position` | `bottom-right`; all four corners are supported |
| `iconType`, `iconSize` | `default`, `medium` (size is not consumed by the hosted loader) |
| `iconEmoji`, `iconUrl` | Speech-balloon emoji, `null` |
| `headerTitle` | `Chat with us` |
| `welcomeMessage` | `Hi! 👋 How can I help you today?` |
| `showBranding` | `true`; forced on for Free projects |
| `localeMode`, `defaultLocale`, `allowLocaleOverride` | `auto`, `en`, `true` |
If configuration cannot be fetched, the loader still renders a fallback UI with `ChattyBox AI` as the title and `Hi! How can I help you today?` as the welcome message. A visible launcher therefore does not prove the key or origin is valid. A successful config response with `enabled: false` prevents rendering; the chat API also rejects a disabled widget with HTTP 403, including SDK requests.
The standalone loader requests config with `Authorization: Bearer` and retries once using a query-string key only after HTTP 400. Published SDK `0.1.4` mirrors that config-only fallback when the page exposes `window.ChattyboxSDK`. Hosted v15 also retries only its startup config and translation GETs for retryable failures. Chat messages still use the hosted loader's own transport. For SDK mounting, published SDK `0.1.4` shares only identical options and rejects a changed key, endpoint, script URL, locale, or debug setting until all matching handles are removed.
## Advanced Options
### Dashboard Settings vs Script Attributes
Most widget behavior should be managed from the dashboard so you do not need to redeploy your website for simple changes.
Use the dashboard for colors, position, icon, header title, welcome message, language defaults, public key management, scraping, and analytics.
If you explicitly enable a public-key origin restriction, keep its exact origins in sync with the domains where the widget is installed. Origin is optional defense-in-depth, not authentication.
Use script attributes only for values the widget needs at page load:
- `data-api-key` identifies the public widget key.
- `data-api-url` tells the widget where to send requests. In production this is a stable `https://...convex.site/chat` URL from your dashboard.
- `data-locale` requests a specific widget UI language at initialization only if project overrides are allowed.
- `data-color` and `data-position` override saved accent color and position after a successful config fetch. Prefer dashboard values; these attributes can mask later dashboard changes.
- `data-debug="true"` enables console diagnostics; it is off by default.
The hosted widget sends the current public page's validated origin and path with each chat request for **Popular Pages** analytics. It removes query strings, fragments, and credentials. The widget also respects `prefers-reduced-motion`, provides a labelled message input and live announcements, and exposes citations through a keyboard-accessible **Sources** disclosure.
Page context is taken from the current HTTP(S) URL, not from a test of whether the page is public. Do not load it on sensitive routes solely because query strings are stripped. The loader may also send initialization/configuration/translation/chat errors to `/widget-error` using a beacon or fetch, including bounded error details, locale, version, and page origin/path. Debug mode is not required for these reports.
Chat uses complete JSON responses rather than token streaming. The hosted v15 loader creates an idempotency key per message and makes at most 10 total transport attempts within a 30-second automatic retry window for network errors, HTTP 429, HTTP 5xx, and 409 responses with a readable `Retry-After` header. Browser CORS can hide that header. This retry behavior is not provided by headless `sendMessage()`; the v15 startup GET retries and SDK `0.1.4` config-400 fallback are separate, limited behaviors. Conversation state stays in memory for that widget instance and is lost on reload or reinitialization. Sources are deduplicated and limited to three displayed entries; fallback answers can have no sources.
If the widget does not appear after installation, see [Troubleshooting](/docs/troubleshooting/).
For platform-specific examples, start with [Docusaurus](/docusaurus-ai-chatbot/), [MkDocs](/mkdocs-ai-chatbot/), [VitePress](/vitepress-ai-chatbot/), [WordPress](/wordpress-ai-chatbot/), or [GitBook](/gitbook-ai-chatbot/).
### Hide the Widget on Specific Pages
To visually hide the widget, apply the following CSS only on the selected pages (globally applying it hides the widget everywhere):
```css
.chattybox-widget {
display: none;
}
```
CSS hiding does not stop initialization, API requests, or error reporting and is not a consent or privacy control. To prevent loading, exclude the script on those page requests. For client-side route transitions or consent revocation, hosted `widget.js` v15 provides `window.ChattyBox.destroy()`. SDK `0.1.4` `remove()` sends the same teardown signal before removing the script, destroying owned UI/styles and cancelling pending initialization, retries, and in-flight chat.
### Browser Controls
After initialization completes, the hosted loader exposes `window.ChattyBox.open()`, `close()`, `toggle()`, `sendMessage(text)`, and (v15) `destroy()`. `destroy()` removes the owned widget and styles, aborts its lifetime work, and clears the global; it cannot undo a request already processed by the server. `close()` only closes the chat panel; it leaves the launcher present. `sendMessage(text)` opens the panel and starts sending but returns no answer promise, and sends while another message is pending are ignored. Check that `window.ChattyBox` exists before calling it; script load alone does not guarantee config and translations have finished. This global is distinct from the SDK constructors on `window.ChattyboxSDK`.
### Custom Integrations
Need a more tailored setup than the hosted widget? Build your own interface with the [JavaScript SDK](/docs/sdk/), or contact support@chattybox.ai for architecture help.
## Multilingual Support
The ChattyBox widget resolves a UI locale at initialization according to the project's fixed or auto mode. It does not watch locale attributes or client-side navigation for changes.
### Officially Supported Languages
The widget has translation catalogs for **14 languages**. All current catalogs use left-to-right layout. Catalog coverage does not mean every visible or accessible string is translated: the current loader retains English for some labels, including the send-message label and the chat-log label.
| Language | Code |
|----------|------|
| English | `en` |
| French | `fr` |
| German | `de` |
| Spanish | `es` |
| Italian | `it` |
| Dutch | `nl` |
| Portuguese | `pt` |
| Polish | `pl` |
| Swedish | `sv` |
| Indonesian | `id` |
| Estonian | `et` |
| Finnish | `fi` |
| Welsh | `cy` |
| Czech | `cs` |
:::note UI Language vs Answers
The UI locale is not sent as a chat-language parameter. The backend detects language from the question and attempts language-aware retrieval and generation. Answer quality and available languages depend on indexed content and the configured model; the UI catalogs are not a response-quality guarantee.
:::
### How Language Detection Works
The widget uses a cascading detection system:
1. **Allowed script override** - A nonempty `data-locale` wins only when `allowLocaleOverride` is not false, even in fixed mode.
2. **Fixed mode** - Without an allowed override, use `defaultLocale` and ignore page/browser language.
3. **Auto mode** - Use the first nonempty value from page ``, browser `navigator.language` (or legacy `userLanguage`), then `defaultLocale`.
4. **Normalization** - Recognized regional values such as `fr-CA` reduce to their supported base language. An unsupported value becomes English immediately; detection does not continue to the next candidate. Use lowercase base codes, since normalization is not fully case-insensitive. Defaults are auto mode, English, and script overrides allowed.
The header title and any nonblank configured welcome message are displayed verbatim, not translated automatically. The public config endpoint supplies an English welcome message even for an empty saved value; clearing that field in the dashboard does not currently select the localized `welcome.default` label. If translations fail to load, built-in English labels remain.
### Manual Language Override
To request a specific language regardless of browser settings, enable **Allow Script Override** and add `data-locale` before the loader runs:
[Widget embed snippet]
:::tip Use Case
This is particularly useful if you have a multilingual website where each language version has its own URL (e.g., `/de/`, `/fr/`). Set `data-locale` to match each page's language for consistent user experience.
:::
### Dashboard Language Settings
The app dashboard allows you to configure widget language preferences per project:
- **Auto-detect** - Uses the page language before the visitor's browser language
- **Fixed Language** - Uses the configured default language unless an allowed script override is present
- **Allow Script Override** - Enable/disable the `data-locale` attribute override
Access these settings in your [Dashboard](https://app.chattybox.ai/) → Project → **Embed** tab → **Widget Language** section.
### Content Language Matching
For the best multilingual experience, index useful content in the languages your visitors ask about:
1. **Scrape all language versions** of your documentation using the `sitemap.xml` file
2. The scraper attempts to detect page language; inspect extracted content and citations rather than assuming detection is always correct
3. Retrieval attempts to prefer the query's detected language but can fall back to other indexed content; test rather than assuming a language match
**Setup in App Dashboard:** When configuring scraping, use your `sitemap.xml` URL (e.g., `https://yourdocs.com/sitemap.xml`) to discover language versions, then verify the indexed pages. Sitemaps do not bypass crawl limits or exclusions.
### Troubleshooting
#### Widget Still Shows English
- **Hard refresh as a diagnostic** - Reload with Ctrl+F5 or Cmd+Shift+R, then check the browser network panel for widget and translation requests
- **Check `data-locale`** - Verify the attribute is set correctly with a supported language code
- **Check project mode and override permission** - Fixed mode and disabled overrides can intentionally ignore browser language or `data-locale`
- **Verify browser language** - Check that your browser's preferred language is set correctly
- **Check page HTML lang** - Ensure your page has `` (or appropriate code)
#### Sources Are in Wrong Language
- **Re-scrape your content** - Ensure all language versions are indexed
- **Use sitemap.xml** - Include the desired language URLs and confirm they were actually indexed; crawl limits and exclusions can omit pages
- **Check query language** - The AI attempts to match response language to query language
#### Missing Translations
- **Check supported languages and requests** - Only the 14 codes listed above have catalogs; missing keys use built-in fallbacks
### Best Practices
1. **Set `` on your pages** - Helps with accessibility and widget detection
2. **Test with `data-locale`** during development - Verify each language renders correctly
3. **Scrape all language versions** - Use `sitemap.xml` for comprehensive multilingual indexing
4. **Review real questions** - Inspect conversations for language-specific content gaps; the dashboard does not currently expose a widget-locale distribution report
### Content Scraping
URL: https://chattybox.ai/docs/scraping/
Description: Configure ChattyBox content scraping with sitemaps or manual URLs so your AI chatbot indexes the right pages for grounded answers.
# Content Scraping
Configure how ChattyBox crawls your website and indexes content for AI responses.
Open your chatbot's **Settings** tab. Save **Website URL** under **General Settings** with **Save Changes**, then choose a mode and **Maximum Pages** under **Scraping Configuration** and select **Save Config**. **Scrape Now** starts a job using the current scraping form values and opens its progress page. The dashboard requires a saved Website URL even for Manual URLs mode.
:::warning Public HTML only
The crawler fetches HTML; it does **not** run a browser or render JavaScript. It does **not** currently read or enforce `robots.txt`. Only submit content you are authorized to index, and use an explicit source selection rather than robots rules to keep unwanted pages out. Authentication, CAPTCHA solving, and private-network crawling are not supported.
:::
For a public-content rollout, see the [AI chatbot for website guide](/ai-chatbot-for-website/) for how to choose trustworthy docs, help articles, product pages, and FAQs before testing cited answers.
## Scraping Modes
ChattyBox supports four scraping modes:
### 1. Homepage Only
Scrapes only the saved Website URL, which can be a specific page rather than the site's root. Best for a landing page or a one-page evaluation.
### 2. Sitemap Mode (Recommended)
Provide a sitemap URL to discover pages, including pages in child sitemaps. Only page URLs on the Website URL's origin are retained, and filtering, page limits, and refresh budgets still apply. A sitemap is a discovery source, not a guarantee that every listed page will be indexed.
```
https://example.com/sitemap.xml
```
If **Sitemap URL** is empty, ChattyBox tries `/sitemap.xml`, then `/sitemap_index.xml`. If neither returns URLs, it falls back to the saved Website URL only. An explicitly supplied sitemap that returns no URLs fails the job instead of falling back. Nested sitemap discovery is depth-limited.
### 3. Crawl Mode
Start from a public URL and let ChattyBox discover pages on the same site. Crawl mode first tries the conventional `/sitemap.xml` and `/sitemap_index.xml` locations. If neither yields URLs, it follows same-origin links from the starting page up to the configured depth (default: `3`).
If a conventional sitemap returns URLs, crawl mode uses those URLs; it does not follow links to fill gaps in an incomplete sitemap. During link discovery, the crawler skips common account, login, checkout, search, and asset URLs. Review the actual indexed pages rather than treating those heuristics as a privacy boundary.
### 4. Manual URLs
Specify exact public URLs to scrape, one per line. Use this when you want precise control over which pages are indexed. These pages are not expanded by following links; page and refresh limits still apply.
```
https://example.com/pricing
https://example.com/features
https://example.com/about
https://example.com/faq
```
### Advanced URL Selection
The dashboard exposes mode, sitemap/manual URLs, maximum pages, and the refresh schedule. It does **not** expose include/exclude patterns or maximum crawl depth. [Configuration as code](/docs/cli/) supports these advanced settings. Include/exclude values are case-sensitive substrings of the URL, not glob patterns or regular expressions; an exclude match wins. During link crawling, filtered-out pages are not traversed, so a rule that excludes the starting page can prevent discovery entirely.
For multilingual sites, explicitly include the public language versions you need. Sitemap discovery and link crawling stay on the same origin, so another language on a subdomain needs its own source selection. Page language is detected from the page and URL; adding a widget locale does not translate or index missing content.
## Page Limits
Distinguish stored pages from monthly refresh work. In the forthcoming owner-pooled page rollout, **Maximum Pages** stores the requested value without clamping it to the base plan. Each run limits outbound discovery and selection to the smaller of that request and the larger of current provider page capacity or known existing project pages. At zero or denied capacity, only known existing pages may refresh; a project with none makes no unknown-page outbound discovery. When omitted, the request defaults to the plan's included account-page allowance. This does not add owner-pool or plan entitlements. Saving the source checks the owner's available page allowance, and a scrape separately rechecks it before saving pages. Existing indexed URLs are prioritized when they are in the discovered set. Changing your source or lowering the limit does not automatically delete older pages.
| Plan | Included account pages | Monthly page-refresh budget | Fastest refresh cadence |
|------|---------------------------|-----------------------------|-------------------------|
| Free | 10 | 500 | Weekly |
| Starter | 150 | 5,000 | Daily |
| Pro | 5,000 | 100,000 | Daily |
| Business | 25,000 | 250,000 | Daily |
Pro and Business can enable optional pay-as-you-go (PAYG) page overages in **Account & Billing**. Free and Starter remain hard-capped. PAYG page allowance does not currently raise the separate monthly refresh budget in the crawler. See [plans and limits](/pricing/) and your account's current allowance before increasing a run's size.
## Refreshing Content
- **Automatic Re-scraping** is opt-in. Free allows weekly or monthly runs; paid plans also allow daily runs. Monthly scheduling means a 30-day interval, not a particular calendar date.
- **Scrape Now** is not an unlimited retry button. The minimum interval after the latest scrape job was created is seven days on Free or 24 hours on paid plans, including after a failed job. A pending or running job also blocks another manual scrape.
- New pages and pages whose extracted text changes each consume one unit of the monthly refresh budget. An unchanged page updates its scrape metadata without consuming another unit or triggering a content-change embedding rebuild.
- The refresh budget is shared across the owner's projects (or the legacy workspace) and resets at the start of each UTC calendar month. It is not a separate allowance for every chatbot or every scrape.
- Successfully fetched updates replace stored page text. Failed fetches and rejected block/error pages leave previously stored content in place. Removing a URL from a sitemap or source selection does not remove it from the knowledge base; delete unwanted pages in **Content** and remove them from future discovery.
## Progress and Partial Indexing
Open a job in **Content** > **Scrape Jobs** to see status, page counts, timestamps, and an estimated rate/time remaining while pages are being saved. Discovery happens before the final selected-page total is known, so an early zero count does not necessarily mean a stalled job. Counts describe pages saved, including unchanged pages, not completed vector embeddings.
**Completed** means the run ended, not that every selected URL succeeded. A run may finish with fewer saved pages after fetch failures or a page/refresh limit, and an empty selection can complete with zero pages. Compare the saved count and actual Content list with your expected URLs. The job detail displays at most 200 saved pages; use the paginated **Content** list for larger collections. It is not a complete per-URL failure report.
**Partially indexed** means a page's extracted text exceeded the **512 KiB UTF-8** storage limit. Only the beginning is retained, and the UI shows retained versus extracted bytes. A completed job with such pages shows **Completed with warnings**. That warning is about truncated page text, not every possible failed or skipped URL. Split a long reference into smaller public pages if important sections were cut off.
The fetch layer separately rejects response bodies over **5 MiB** and redirect chains beyond five hops. Those fetch failures are different from successfully fetched pages whose extracted text is partially retained.
Changed content queues a separate embedding job. Review the index/rebuild status and test representative answers before launch; a scrape completion badge alone does not validate retrieval quality.
### Content Maintenance
**Content** supports deleting individual pages, **Clear All**, and **Rebuild Index**. Clearing pages removes their stored content and embeddings, not the saved source configuration. Later scrapes can add them again.
**Rebuild Index** rebuilds embeddings from already stored text; it does not fetch your site, restore deleted pages, or recover truncated text. Manual rebuilds have the plan's weekly/daily cooldown, measured from the latest embedding job, and consume the same monthly page-refresh budget for each page reserved for rebuilding. Embeddings automatically queued for changed scraped pages do not charge that work a second time. Config-locked projects reject dashboard scrape, content deletion, and manual rebuild operations; use the [configuration deployment workflow](/docs/cli/).
## Content Extraction
ChattyBox reads the page title and prefers text from ``, then ``, then an element with `role="main"`, falling back to body text. Within the selected content it retains:
- **Page title** - The `` tag
- **Headings** - `` through `` text
- **Paragraphs** - Readable paragraph text
- **Lists** - `` and `` items
- **Code and tables** - Text content, with preformatted code whitespace retained
A limited fallback can fetch a same-origin OpenAPI document referenced by a recognized `SwaggerUIBundle` configuration when the HTML has too little text. This is not general JavaScript rendering, file upload, or support for every API-reference viewer.
## Ignored Content
Extraction excludes common non-content elements, including:
- Navigation menus
- Footer content
- Scripts and styles
- Elements marked `hidden`, `aria-hidden="true"`, or with inline `display: none` / `visibility: hidden`
- Recognized cookie/consent banner markup and dialog/navigation roles
- Iframes, canvas, SVG, and embedded objects
These are HTML-based heuristics, not a computed browser layout. Do not assume every visually hidden element or every banner will be detected.
---
## Troubleshooting
### Pages not being scraped?
- Check that the URL is publicly accessible
- Check that the server allows ordinary HTML requests without a login, CAPTCHA, or bot challenge
- Verify the page isn't behind authentication
- Check the mode, origin, selected URLs, page allowance, and refresh budget; robots rules are not consulted
- For link-crawl fallback, confirm important links are reachable from the start URL within the depth limit
### Content missing from responses?
- Re-scrape after publishing changes, once the refresh cooldown allows it
- Serve important text in the initial HTML; content loaded only by JavaScript is not rendered
- Ensure the content is in the main body, not in iframes
- Check for partial-indexing warnings and wait for embedding work before retesting
### Need more control?
For unsupported sources or persistent extraction failures, contact support@chattybox.ai with a public example URL. Do not send login credentials or assume support can enable authenticated or JavaScript-rendered crawling.
For launch issues after scraping, use the [launch checklist](/docs/launch-checklist/) and [troubleshooting guide](/docs/troubleshooting/).
### Analytics
URL: https://chattybox.ai/docs/analytics/
Description: Use ChattyBox analytics to track visitor questions, find content gaps, improve answer quality, and measure self-service coverage.
# Analytics
Understand what your visitors are asking and improve your content based on real data.
:::info Plan access
The **Analytics** and **Content Gaps** tabs require Pro or Business. **Logs** and **Test Chat** are available on every plan. Open a chatbot from `/dashboard`; these are project tabs, not workspace Overview metrics.
:::
Use the [launch checklist](/docs/launch-checklist/) to validate your rollout, then compare [plans and limits](/pricing/) before choosing the right evaluation path.
## Dashboard Overview
Open **Analytics** (`/chatbot/?tab=analytics`). The dashboard uses the last **30 days**, with at most the **5,000 most recent recorded interactions** in that window. There is no date-range selector or full-history export in this tab. High-volume results can therefore be a capped view rather than all traffic in the period.
The dashboard shows:
- **Total Questions** - Recorded interactions in that window, subject to the cap
- **Answered** - Interactions not flagged by the content-gap detector
- **Unanswered** - Interactions flagged as content gaps, including missing-context fallbacks
- **Answer Rate** - Answered divided by total recorded interactions
These are automated classification metrics, not verified answer accuracy, customer satisfaction, unique visitors, or support tickets avoided. The detector checks source context, fallback-like wording, and some question-specific terms; it can misclassify responses. **Test Chat contributes to these metrics and consumes the owner's message allowance.** This is not a visitor-only report or the billing usage ledger, and failed requests need not produce an analytics record.
## Conversations and Logs
Open **Logs** (`?tab=logs`) to page through saved project conversations, expand a row to read messages and timestamps, or delete one conversation or all conversations after confirmation. Logs combines dashboard tests and public chat; it is not the internal API request/error log. Expanded conversations load the first 100 stored messages, so a row's total count can exceed the messages displayed.
**Test Chat** (`?tab=test`) also lets you select saved conversations, start a new chat, copy answers, and delete history. Its search filters conversation previews on the currently loaded page, not every message in the project. **New** / **Reset Chat** starts a fresh conversation without deleting existing history; **Clear** is a separate destructive action. Conversation IDs group stored messages, but previous turns are not currently passed to the answer generator. Include the necessary context in each question rather than relying on conversational memory.
Deleting conversations removes their messages, not analytics records, content-gap records, or already consumed message usage. Some early fallback responses are returned to the chat UI without being stored as assistant messages, so a saved conversation can show a question without that displayed fallback.
## Most Asked Questions
See the top 10 question texts within the analytics window/cap. Text is trimmed, lowercased, and truncated to 500 characters before grouping; this is not semantic clustering of differently worded questions. Use this to:
- Understand what visitors care about most
- Prioritize content improvements
- Identify FAQ opportunities
## Content Gap Detection
Open **Content Gaps** (`?tab=gaps`) to review questions flagged by the detector. A gap is not tied to one exact fallback sentence: missing source context, recognized refusal wording, and some overly general answers can all produce a gap. The tab shows:
- **Question** - What the visitor asked
- **Count** - How many times this was asked
- **Last Asked** - When it was most recently asked
Use these as candidates for review, not proof that a page is missing. Check the source selection, retrieval, wording, and the actual answer first. After adding content, re-scrape within your refresh allowance and test again, then select **Resolve**. Resolution is a manual tracking flag; it does not train the chatbot or verify the new answer. **Delete** removes the gap record.
The dashboard lists only unresolved gaps: resolving one removes it from the list, and there is no resolved-history/undo control in the current view. A later occurrence of the same normalized question increments its existing count but does not automatically reopen it. The list takes the newest 100 unresolved records and sorts that subset by count; the unresolved badge is capped at 500. These records are separate from the Analytics tab's 30-day window.
Use these gaps with the [ticket-reduction measurement guide](/reduce-support-tickets-with-ai-chatbot/) to test repeat-question coverage and compare any support impact with your own baseline rather than assuming an outcome.
## Peak Traffic Hours
See the five hour-of-day buckets with the highest counts in the same analytics window. Hours are recorded on the backend and displayed without conversion to the visitor's timezone; they do not identify your audience's timezone. Use them to:
- Schedule content updates during low-traffic times
- Compare busy and quiet hours on a consistent reporting basis
- Plan for capacity if you're approaching limits
## Popular Pages
The dashboard labels this panel **Popular Triggers**. It shows the top 10 page URLs where recorded questions originated, not the most-cited documentation pages or pageviews. The hosted `widget.js`, including the widget mounted by `Chattybox.mountWidget()`, automatically sends page context without query strings or fragments.
The headless SDK's `sendMessage()` currently accepts `message`, `conversationId`, and `idempotencyKey`; it does **not** accept or send `sourceUrl` or `sourcePath`. Do not add an unsupported SDK option expecting page attribution. Dashboard Test Chat likewise has no source-page URL, so questions can be counted even when Popular Triggers is empty.
For a custom direct HTTP integration, `POST /chat` accepts optional `sourceUrl` and/or `sourcePath`. Source context requires an HTTP(S) request origin, taken from `Origin` or the fallback `Referer` origin; `sourceUrl` must match it and must not contain credentials. A supplied path must start with `/` (not `//`), contain no query or fragment, and match the URL's pathname when both are sent. The server strips query strings/fragments and normalizes the URL before recording it. Never send private paths or sensitive visitor data as page context.
Page context is used for analytics, including interaction telemetry; it does not change which indexed sources the assistant retrieves.
## Source Citations
Answers can include clickable source links showing which pages the information came from. This:
- Builds trust with visitors
- Lets users verify information
- Drives traffic to relevant pages
The widget presents citations in a native disclosure. Visitors can expand **Sources** to review the cited links without interrupting the answer.
---
## Improving Your Answer Rate
Tips to get more questions answered:
1. **Review content gaps regularly** - Add missing information to your site
2. **Scrape more pages** - Include FAQ pages, help docs, and blog posts
3. **Use clear headings** - Well-structured content is easier to search
4. **Keep content updated** - Enable automatic re-scraping within your plan's cadence and [monthly refresh budget](/docs/scraping/#refreshing-content)
5. **Retest before resolving** - Confirm the answer and citations, rather than treating a higher Answer Rate as proof of accuracy
### Integrate with an AI Coding Assistant
URL: https://chattybox.ai/docs/ai-builder-prompts/
Description: Give an AI coding assistant a complete SDK-first prompt for integrating ChattyBox into your application.
# Integrate with an AI Coding Assistant
The recommended application-code integration is the [`@openstaticfish/chattybox` npm package](/docs/sdk/). It lets code configure the public key and API URL, load ChattyBox's maintained floating widget from a persistent browser layout, or use the headless client for a completely custom UI.
The standalone `widget.js` script is documented last as a no-build fallback for sites that cannot install npm packages.
## Before You Start
Complete the chatbot setup before asking an assistant to edit your application:
- Verify representative answers and citations in **Test Chat**.
- Create a browser key in **Public Keys**. It works across production, previews, staging, and localhost by default; optionally enable an exact origin restriction in **Edit origins** for defense in depth.
- Copy the public key and widget API URL shown in **Embed**.
- Decide whether a persistent floating widget fits the application or you need a custom UI with route-scoped placement and teardown.
These are public browser credentials, but you should still avoid committing environment-specific values. Never provide a config deployment token, admin credential, or unrelated environment file.
## Recommended: Mount the Maintained UI from npm
This is the default prompt for React, Next.js, Vite, and other package-based browser applications.
{`Integrate ChattyBox into this application using the @openstaticfish/chattybox npm package.
Public browser configuration:
- API key: [PASTE PUBLIC WIDGET KEY]
- API URL: [PASTE WIDGET API URL]
First inspect the framework, routing model, package manager, environment-variable conventions, and persistent application layout. Tell me which files you plan to change before editing. Ask me if the routes where ChattyBox should appear are unclear.
Requirements:
1. Install @openstaticfish/chattybox with the package manager already used by this repository.
2. Store the public API key and API URL using the framework's browser-exposed environment-variable convention. Add placeholder names to an example environment file, but do not commit real values.
3. Import Chattybox from @openstaticfish/chattybox and create one client with apiKey and baseUrl.
4. Call client.mountWidget() only in browser code after document.body exists, from a persistent application shell. It loads a floating widget under document.body, not inside the component.
5. Keep the loader across normal SPA navigation. SDK 0.1.4 reference-counts only identical mount options; call remove() on every returned handle, and the final handle plus hosted widget.js v15 destroys owned UI/styles and cancels pending initialization, retries, and in-flight chat. window.ChattyBox.destroy() is the hosted equivalent. Cleanup cannot undo a request the server already processed.
6. Do not inject widget.js manually, create a backend proxy, or introduce a second loader. mountWidget rejects changed key, API URL, script URL, locale, or debug options until every existing matching handle is removed; it never silently keeps old options.
7. Preserve existing navigation, rendering boundaries, localization, analytics, consent, and styling. Locale is resolved at initialization only; a locale option works only when project script overrides are allowed. Do not claim reactive locale updates or a ready promise. Hosted v15 retries transport up to 10 times total within 30 seconds; headless sendMessage() does not retry. SDK 0.1.4 validates baseUrl and wraps unreadable response bodies.
8. Make the smallest focused change and do not deploy it.
9. Run the repository's build, lint, type-check, and relevant tests.
10. Report changed files, environment variables I must set, where the UI mounts, and how to test it on the deployed site.`}
The resulting application code should follow this shape:
```ts
const client = new Chattybox({
apiKey: PUBLIC_CHATTYBOX_API_KEY,
baseUrl: PUBLIC_CHATTYBOX_API_URL,
});
const widget = client.mountWidget();
// Keep this loader for normal navigation; in SDK 0.1.4 + hosted v15, remove() is teardown.
```
## Build a Custom Interface
Choose this when your application should own the message list, input, loading states, errors, citations, and placement instead of mounting the maintained interface.
{`Build a custom chatbot interface using the @openstaticfish/chattybox npm package and its headless client.
Public browser configuration:
- API key: [PASTE PUBLIC WIDGET KEY]
- API URL: [PASTE WIDGET API URL]
First inspect the application's framework, component system, state patterns, styling, accessibility conventions, and test setup. Propose the component boundaries and files before editing.
Requirements:
1. Install @openstaticfish/chattybox with the repository's existing package manager.
2. Configure one Chattybox client with apiKey and baseUrl using browser-exposed environment variables; do not commit real values.
3. Use sendMessage() and retain conversationId in visitor-scoped state to group messages. The current public generation path does not pass previous turns to the model, so do not assume conversational memory.
4. Render answers safely as text or sanitized Markdown and render HTTP(S) sources as accessible links, preserving their order. Never insert untrusted raw HTML or unsafe link schemes.
5. Implement pending, empty, error, and retry states. Fallback answers can have empty sources; the public result has no separate wasAnswered or fallback-status field. Handle both ChattyboxError and unwrapped network errors; code is optional.
6. Reject blank or over-2,000-character trimmed messages, prevent duplicate submissions, and keep keyboard and screen-reader behavior usable. Headless sendMessage() does not retry automatically: use one unique idempotencyKey per logical message and reuse the exact input for retries; do not blindly retry every 409. SDK 0.1.4 only retries getWidgetConfig() once after HTTP 400; hosted v15 separately retries startup GETs.
7. Mount the interface only in the routes or layout I specify.
8. Follow existing components and styles instead of adding a new design system.
9. Do not load widget.js or call mountWidget().
10. Run build, lint, type-check, and relevant tests, then report changed files and a verification plan.`}
## Framework Notes
Give the assistant one additional sentence when needed:
- **Next.js App Router:** “Use a small Client Component in a persistent layout, and call `mountWidget()` from a browser-only effect, not during rendering.”
- **React SPA:** “Mount from the persistent app shell. If the component owns the final SDK-0.1.4 handle, return `remove()` for intentional teardown; otherwise retain the shared loader across route changes.”
- **Docusaurus:** “Initialize from `src/theme/Root` in browser code and keep the loader across docs navigation; verify full-page locale transitions because client-side language changes do not reconfigure it.”
- **Vue, Nuxt, Svelte, or another framework:** “Use the client-only mount lifecycle in a persistent layout; choose a headless UI if matching teardown is required.”
## Review an Existing SDK Integration
{`Review this ChattyBox integration without deploying or changing unrelated code.
Check that:
1. @openstaticfish/chattybox is installed and imported instead of duplicating its behavior.
2. One Chattybox client receives the intended public API key and API URL.
3. Browser environment variables follow this framework's public-variable naming rules without exposing private credentials.
4. A hosted widget uses a persistent shell and uses remove() only for intentional UI teardown, route exclusions after SPA navigation, or consent revocation. A custom interface has real component cleanup.
5. Client-side navigation and development remounts do not create duplicate instances.
6. Existing rendering boundaries, localization, analytics, consent, accessibility, and layout remain intact. Origin restrictions are optional; restricted keys need an allowed request origin, and Node fetch does not automatically supply browser headers.
7. The implementation has appropriate tests and no unrelated refactor.
Return findings by severity with file paths and line references. Propose only the smallest safe fixes and give me exact verification commands.`}
## No npm or Build Step?
Use the [`widget.js` installation guide](/docs/installation/) only when the site cannot use the npm package—for example, plain HTML, a CMS custom-code field, or Google Tag Manager.
{`Install the hosted ChattyBox widget on this site using the exact script generated by my ChattyBox Embed tab:
[PASTE COMPLETE WIDGET SCRIPT]
Inspect the site first and identify the safest global public-page insertion point. Load the unchanged script exactly once, exclude private/admin/checkout routes, preserve consent and CSP behavior, do not expose private credentials, do not deploy the change, and report the changed location plus a browser test plan.`}
## Test the Result
1. Review the diff and confirm no real credentials were committed.
2. Run the project's normal build, lint, type-check, and tests.
3. Deploy through the normal review process.
4. Verify the intended routes in a private browser window, including client-side navigation.
5. Ask a supported question, follow a citation, and test the fallback behavior.
6. Check mobile layout, keyboard use, and the browser console.
Continue with the [SDK reference](/docs/sdk/) and [launch checklist](/docs/launch-checklist/).
### CLI and Configuration Deployment
URL: https://chattybox.ai/docs/cli/
Description: Validate and remotely deploy versioned ChattyBox configuration from local development or CI.
# CLI and Configuration Deployment
The CLI creates, validates, deploys, promotes, and rolls back immutable ChattyBox configuration versions. Each deployment token is scoped to exactly one existing project and selected environments. Treat one config file plus one project-scoped token as one managed ChattyBox project.
## Release and Runtime Status
The public registry provides `@openstaticfish/chattybox-cli@0.3.1`, `@openstaticfish/chattybox-config@0.3.1`, and the separate JavaScript SDK `@openstaticfish/chattybox@0.1.4`. The published CLI/config packages implement the `0.3.0` backend/config contract; local and backend validation have parity and reject unknown keys. Package versions and `schemaVersion: "1"` are separate versioning systems.
The starter config and basic commands below exist in the published CLI. The expanded configuration reference is supported by the published `0.3.1` CLI/config packages and the matching `0.3.0` backend contract. The bundled validator covers `project`, discovery/scheduling fields, expanded locale controls, `widget.icon`, and `widget.showBranding`; local and backend validation reject unknown keys.
The CLI is an ESM command-line program declaring **Node.js 20 or newer**. `bunx` respects its Node shebang by default, so have Node installed, or explicitly select Bun with `bunx --bun @openstaticfish/chattybox-cli ...`. It is not browser tooling. Published-consumer CI covers Node 20, 22, and 24 on Linux, not a general OS or browser compatibility matrix. Pin a tested package version in production automation; the unversioned examples resolve the installed/cached or registry package, not this repository's source.
## What Config as Code Manages
The config controls the project's name and description, assistant persona and fallback behavior, website discovery and refresh policy, locale behavior, and hosted-widget presentation. A preview or production deployment applies those values and queues an in-place corpus refresh. With **Config-as-code lock** enabled, config-owned settings are changed through versioned deployments rather than dashboard forms, with a deliberate exception for the entitlement-controlled branding preference.
Initial project creation is currently a one-time dashboard step. Credentials and operational data stay outside configuration: public widget keys and optional origin restrictions, deployment-token lifecycle, analytics/conversations/content gaps, destructive actions, and uploaded icon files are not config fields. Use a URL or emoji for a declarative custom icon. The config intentionally contains no project ID: the secret deployment token selects the one project that receives it.
| Credential | Scope | Safe in browser code? |
|---|---|---|
| Public widget API key | Chat and widget configuration | Yes; works across browser origins by default. Optional exact origin restrictions are defense in depth. |
| Config deployment token | Config deploy/promote/rollback/status for one project and selected environment labels | No; keep in local/CI secrets |
## Create a Configuration
```bash
bunx @openstaticfish/chattybox-cli init
```
This creates `chattybox.config.json`:
```json
{
"schemaVersion": "1",
"assistant": {
"name": "Support"
},
"knowledge": {
"sources": [
{
"type": "website",
"url": "https://example.com"
}
]
},
"widget": {
"enabled": true
}
}
```
Use a custom path when the config belongs in a subdirectory:
```bash
bunx @openstaticfish/chattybox-cli init config/chattybox.config.json
```
## Validate Locally or in CI
```bash
bunx @openstaticfish/chattybox-cli validate
bunx @openstaticfish/chattybox-cli validate config/chattybox.config.json
```
Current-source validation checks object shapes, the required assistant name, enums, HTTP(S) URLs, integer limits, locale combinations, and six-digit hex colors. `knowledge` may be omitted for local validation or development, but when present must contain exactly one website source. Preview and production require that source. `widget.enabled` is required if `widget` is present.
Validation reads JSON only; it does not load TypeScript, JSONC, YAML, or a remote schema. It makes no network request, checks no token or plan entitlement, and does not apply defaults. Local and backend validation both reject unknown properties. A local success is not a deployment guarantee.
Schema v1 rejects unknown fields at every object level, including misspellings and arbitrary extensions. Include/exclude entries must be non-empty strings. `runtime.locale` is shorthand for fixed locale with overrides disabled and cannot be combined with `localeMode`, `defaultLocale`, or `allowLocaleOverride: true`. Local and management deployment validation share the same rules; plan entitlements and token scope are checked by the server.
## Create a Deployment Token
Open the project **Settings** tab, find **Config deployment tokens**, and create a token for the environments your workflow may change. Copy it immediately; ChattyBox stores only its hash and cannot show it again.
The form initially selects `development` only and no expiry. Choose `preview` or `production` explicitly when needed. The dashboard offers no expiry or 7, 30, 90, or 365 days; the authenticated creation API accepts an integer from 1 to 365 days, or omission for no expiry. A project may have at most 20 active, unexpired tokens. Rotate by creating a replacement, updating CI, and revoking the old token. There are no CLI login, token-create, token-list, or token-revoke commands.
Set the token and the widget API URL from the project's **Embed** tab:
```bash
export CHATTYBOX_DEPLOY_TOKEN='cb_cfg_v1_...'
export CHATTYBOX_API_URL='https://your-deployment.convex.site/chat'
```
Never commit the token. Store it in your CI provider's encrypted secret store.
Deployment tokens authenticate as `Authorization: Bearer ...`; public widget keys cannot replace them. Management routes do not use widget origin restrictions, do not require an `Origin` header, and do not provide browser CORS access. This is not an origin-bound secret: anyone holding it can call the API from a server. Missing, malformed, expired, revoked, wrong-environment, or otherwise invalid tokens all return HTTP 401 `INVALID_TOKEN`. Tokens also stop working when their project or owner is missing or being deleted.
Use the HTTP actions deployment root or its widget URL ending in `/chat`, not a `.convex.cloud` client URL or a full `/v1/config/deployments` endpoint. The CLI removes trailing slashes and a final `/chat`, then appends the management route. HTTPS is required except for `localhost`, `127.0.0.1`, or `[::1]`; credentials, query strings, and fragments in the API URL are rejected. Verify the destination before supplying a secret.
### Config Lock
After verifying the deployment workflow, optionally enable **Config-as-code lock** in the same settings section. **This is irreversible through the current dashboard, CLI, and public API: there is no supported unlock operation.** Enabling it does not create a token or deploy a version. Keep a tested token workflow before locking.
The lock blocks dashboard writes to config-owned project/widget settings, icon uploads, and manual corpus operations such as scraping, deleting pages, clearing content, and regenerating embeddings. It does not stop scheduled work or project deletion. Token creation/revocation, public-key management, and operational reads remain available.
**Branding is the exception:** the dashboard's branding-only control remains editable on locked projects. Hiding attribution requires Starter or higher, including through config deployment. Omitting `widget.showBranding` preserves the current stored preference (or defaults to `true` if none exists); an explicit value overwrites it on the next runtime promotion. Free-plan runtime output still enforces branding.
## Deploy Configuration
Deploying creates an immutable version and promotes it to the selected environment:
```bash
bunx @openstaticfish/chattybox-cli deploy --environment preview
bunx @openstaticfish/chattybox-cli deploy --environment production
```
**Environment labels do not isolate runtimes.** `development` only records a version/pointer (`applied: false`, `indexingStatus: "not_required"`). Both `preview` and `production` overwrite the same project's runtime settings and use the same corpus and public widget keys. The most recent runtime promotion wins, even if another label's status still points to an older version. A preview-scoped token can therefore change a project serving production traffic. Use separate projects and their respective tokens/keys for actual isolation.
Preview and production atomically apply configuration and queue a scrape job (`applied: true`, `indexingStatus: "pending"`). This does not wait for scraping or embeddings to finish. Refreshes update pages in place, request embeddings when content changes, and do not prune old URLs merely because a new source/filter omits them. The corpus is not a versioned snapshot: partial updates can remain if work fails, and failed refreshes do not revert the applied config. Jobs record a config version ID but also read mutable scrape settings; avoid overlapping deployments when indexing consistency matters.
### Replacement and Plan Limits
Deploy complete desired configuration, not a patch. Runtime promotion clears or resets omitted config-owned values, including previous dashboard settings:
| Omitted value | Runtime effect |
|---|---|
| `project.description`, assistant prompt/profile/fallback | Clears stored overrides; runtime fallback behavior applies. |
| `runtime` | Resets to automatic locale, default `en`, locale override allowed. |
| `widget` or optional widget copy/theme/position | Enables the widget; clears omitted presentation overrides so runtime defaults apply. |
| `widget.icon` | Resets to default icon, medium size; unlinks any uploaded icon. |
| Source mode/filters/schedule | Mode defaults to `crawl`; omitted filters clear; automatic refresh defaults to off. Mode-specific settings are only applied for their matching mode. |
| `widget.showBranding` | Exception: preserves the existing stored preference, otherwise `true`. |
`maxPages` stores the requested value without clamping it to the base plan. Each run limits outbound discovery and selection to the smaller of that request and available capacity. Existing indexed pages and available capacity are pooled at the owner/account level; this is not a per-project capacity contract or a promise that all requested pages will be indexed. At zero or denied capacity, only known existing pages may refresh; a project with none makes no unknown-page outbound discovery. Omission uses the plan's included account-page allowance as the request default: Free 10, Starter 150, Pro 5,000, and Business 25,000. This does not add owner-pool or plan entitlements. A scrape separately rechecks current page/PAYG allowance and monthly refresh limits.
Automatic daily refresh and explicit `showBranding: false` require Starter or higher. Free accepts weekly or monthly automatic refresh. These entitlement checks happen on preview/production promotion, including rollback, not during local validation or development recording. A previously valid version can fail promotion after a plan change.
Promotion resolves the plan from server-cached project/workspace data, not a live billing-provider request. Verify billing synchronization and actual scrape allowance separately when diagnosing a recent plan/PAYG change.
Use `--json` in automation to receive the API result, including `version._id`, the environment pointer, `applied`, `indexingStatus`, and the scrape job ID when one is queued. Keep `version._id` for later promotion or rollback; the human-readable sequential version number is not a usable `--version` argument.
## Status, Promotion, and Rollback
```bash
bunx @openstaticfish/chattybox-cli status --environment production
bunx @openstaticfish/chattybox-cli promote \
--version '' \
--environment production
bunx @openstaticfish/chattybox-cli rollback \
--version '' \
--environment production
```
`--version` takes the opaque config version ID from deploy/promote/rollback JSON (`version._id`) or status JSON (`activeVersion._id`), not the displayed number, a Git SHA, or a config hash. Quote placeholder IDs as shown, then replace them with real IDs belonging to the token's project.
Rollback uses the same backend operation as promote. It need not target an older version and has no automatic previous-version selection. It preserves immutable config version records but overwrites the selected environment pointer and its promotion metadata; there is no append-only promotion event history. Preview/production rollback reapplies config under current entitlements and queues another refresh, not an exact historical content restore. Repeated deploys create new versions even for identical config; repeated promotions can queue new jobs.
`status` prints the selected label's **Environment version** and pointer summary, not the effective runtime config, a dashboard-drift diff, or scrape/embedding progress. An undeployed label prints `Environment version: none` and returns `environment: null` and `activeVersion: null`. The separate `runtimeConfigVersionId` identifies the last configuration applied to the shared runtime and can differ after another label is promoted. Successful status calls also update the token's `lastUsedAt` and consume management rate limit capacity. Check indexing separately in the dashboard.
## Commands, Flags, and Errors
| Command | Arguments and effect |
|---|---|
| `init [path]` | Defaults to `chattybox.config.json`; creates parent directories; refuses to overwrite an existing file. |
| `validate [path]` | Same default path; reads and validates JSON without remote access. |
| `deploy` | Requires `--environment`; optional `--config `; validates then creates and promotes a version. |
| `promote`, `rollback` | Require `--environment` and `--version `; do not read a local config. |
| `status` | Requires `--environment`; does not read a local config. |
| No command, `help`, `--help`, `-h` | Top-level help. Use `chattybox --help`, not `chattybox deploy --help`. |
| `--version`, `-v` | Top-level CLI version; unrelated to promotion's `--version` flag. |
All four management commands accept `--token`, `--api-url`, and `--json`. Explicit credentials/URL flags take precedence over `CHATTYBOX_DEPLOY_TOKEN` and `CHATTYBOX_API_URL`. Prefer secret environment variables over tokens in shell history or process arguments. Value flags accept `--flag value` or `--flag=value`; `--json` is a bare switch. There is no default environment. Unknown, duplicate, empty, and command-inapplicable management options are rejected. Local commands accept only one positional path and reject flags/extra arguments.
There are no `--dry-run`, `--wait`, `--force`, `--project`, message, or optimistic-concurrency flags. The HTTP API supports expected-version fields, but the CLI does not send them. Serialize CI deployments to the same project.
Successful executable commands exit 0. File/JSON/validation, argument, transport, response-read, and HTTP failures exit 1 with a `ChattyBox: ...` message on stderr. `--json` formats successful results only; it does not produce JSON errors. API errors include their HTTP status and error code when supplied; successful non-JSON responses are rejected. The CLI has no automatic retry, polling, or configured request timeout. After a transport failure, check status before retrying because the server may already have committed the deployment.
Management routes are `POST /v1/config/deployments` (201), `POST /v1/config/deployments/promote` and `/rollback` (200), and `GET /v1/config/deployments/status?environment=...` (200). Success is wrapped in `{ "data": ... }` over HTTP; CLI JSON unwraps it. Errors normally use `{ "error": { "code": ..., "message": ... } }`: 401 `INVALID_TOKEN`, 404 `NOT_FOUND` for a missing/other-project version, 409 `CONFIG_CONFLICT`, 413 `BODY_TOO_LARGE`, 422 `INVALID_CONFIG`, or 500 `INTERNAL_ERROR`. Malformed typed IDs are 422, not necessarily 404. The request-body limit is 262,144 bytes. All management routes share a per-token limit of 20 requests per minute; 429 responses use the shared rate-limit format and `Retry-After` header. A completely absent POST body currently falls through to 500, unlike malformed JSON (422).
Status `activeVersion` is the selected environment label's last promoted version. The separate `runtimeConfigVersionId` is the last configuration applied to the shared project runtime and may differ after another label is promoted. A development promotion does not change that runtime pointer. If configuration is not locked, later dashboard edits can also change runtime fields without changing the last-applied configuration ID.
## CI/CD Workflows
Add `CHATTYBOX_DEPLOY_TOKEN` as an encrypted, production-scoped secret in your CI provider. Add `CHATTYBOX_API_URL` as a secret or variable using the widget API URL from the project's **Embed** tab. Run validation on pull requests, but restrict production deployment to your protected default branch or an approved deployment environment.
### GitHub Actions
```yaml
name: Deploy ChattyBox configuration
on:
pull_request:
push:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v6
with:
node-version: 24
- run: bunx @openstaticfish/chattybox-cli validate
deploy:
if: github.event_name == 'push'
needs: validate
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- uses: actions/setup-node@v6
with:
node-version: 24
- name: Validate and deploy
env:
CHATTYBOX_DEPLOY_TOKEN: ${{ secrets.CHATTYBOX_DEPLOY_TOKEN }}
CHATTYBOX_API_URL: ${{ vars.CHATTYBOX_API_URL }}
run: |
bunx @openstaticfish/chattybox-cli validate
bunx @openstaticfish/chattybox-cli deploy --environment production --json
```
Use an environment-scoped production secret and require deployment approval when your repository supports it. The CLI records common CI commit and branch variables with the immutable version.
### GitLab CI/CD
Store both values under **Settings → CI/CD → Variables**. Protect the deployment token, mask it, and scope it to the `production` environment.
```yaml title=".gitlab-ci.yml"
image: oven/bun:1
validate_chattybox:
stage: test
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
script:
- bunx --bun @openstaticfish/chattybox-cli validate
deploy_chattybox:
stage: deploy
environment: production
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
script:
- bunx --bun @openstaticfish/chattybox-cli validate
- bunx --bun @openstaticfish/chattybox-cli deploy --environment production --json
```
GitLab exposes `CHATTYBOX_DEPLOY_TOKEN` and `CHATTYBOX_API_URL` automatically to the job using their variable names. Use a protected default branch so protected variables are unavailable to untrusted branches. The Bun container examples explicitly use `--bun` so they do not depend on a separate Node installation; verify your pinned Bun/image version in CI.
### Bitbucket Pipelines
Add both values as deployment variables under **Repository settings → Pipelines → Deployments → Production**. Mark the deployment token as secured.
```yaml title="bitbucket-pipelines.yml"
image: oven/bun:1
pipelines:
pull-requests:
'**':
- step:
name: Validate ChattyBox configuration
script:
- bunx --bun @openstaticfish/chattybox-cli validate
branches:
main:
- step:
name: Deploy ChattyBox configuration
deployment: Production
script:
- bunx --bun @openstaticfish/chattybox-cli validate
- bunx --bun @openstaticfish/chattybox-cli deploy --environment production --json
```
Replace `main` if your default branch has another name. Bitbucket injects deployment variables only into steps associated with that deployment environment. The CLI has no dedicated `BITBUCKET_*` metadata mapping; it falls back to local Git for commit and branch, which may have no branch name in a detached checkout.
## Configuration Sections
| Section | Purpose |
|---|---|
| `schemaVersion` | Selects the public configuration contract. Version `1` is currently supported. |
| `project` | Optional project metadata such as its dashboard description. |
| `assistant` | Names the assistant and defines a built-in persona or custom system prompt plus fallback copy. |
| `knowledge.sources` | Selects homepage, sitemap, manual URL, or crawl discovery plus limits, filters, and refresh schedule. |
| `runtime` | Controls automatic/fixed locale, default locale, and page-level locale overrides. |
| `widget` | Controls enablement, position, copy, colors, and default/emoji/URL icon presentation. |
### Personas
Set `promptProfile` to `default`, `support`, `sales`, or `sarcastic` to use the maintained persona instructions. Set it to `custom` and provide `systemPrompt` for a custom persona. If both a built-in profile and `systemPrompt` are provided, the explicit prompt wins.
### Knowledge discovery
This expanded configuration fragment requires the published `0.3.1` config types and the matching `0.3.0` backend contract. Its daily schedule requires Starter or higher; `maxPages: 500` stores a request that remains subject to the run's effective capacity.
```json
{
"type": "website",
"url": "https://docs.example.com",
"mode": "sitemap",
"sitemapUrl": "https://docs.example.com/docs-sitemap.xml",
"include": ["/docs/"],
"exclude": ["/private/"],
"maxPages": 500,
"autoRescrape": true,
"rescrapeInterval": "daily"
}
```
Supported modes are:
- `homepage`: select only `url` for this refresh (existing pages are not deleted).
- `sitemap`: use `sitemapUrl`; an explicit sitemap yielding no URLs fails. If omitted, try `/sitemap.xml`, then `/sitemap_index.xml`, then the homepage when neither yields URLs.
- `manual`: index the non-empty `manualUrls` list.
- `crawl`: try conventional sitemaps, then follow links from `url` up to `maxDepth` (default `3`).
`include` and `exclude` use case-sensitive URL substring matching, not glob or regex syntax. Any include match admits a URL; any exclude match rejects it, even if included. Empty lists do not filter. Filters also apply to homepage and manual selection.
`maxPages` must be a positive integer; its stored request is not clamped, while per-run outbound discovery and selection use the effective capacity described above. `maxDepth` must be an integer from 0 through 20 and controls link-crawl fallback, not sitemap enumeration. Omitted `mode` selects crawl and preserves an explicit `maxDepth`, including zero. `autoRescrape: true` requires `rescrapeInterval: "daily"`, `"weekly"`, or `"monthly"`; an interval alone does not enable scheduling. Monthly means 30 days, and the scheduler may run after the due time.
### Locale and Widget Validation
Supported locale codes are `en`, `de`, `fr`, `es`, `it`, `nl`, `pl`, `pt`, `sv`, `fi`, `et`, `cs`, `cy`, and `id`. `localeMode` is `auto` or `fixed`; fixed requires `defaultLocale`. `allowLocaleOverride` is independently configurable. The shorthand `runtime.locale` selects fixed mode and disables overrides; current local validation rejects combining it with `localeMode`, `defaultLocale`, or `allowLocaleOverride: true`.
Widget positions are `bottom-right`, `bottom-left`, `top-right`, and `top-left`. All three theme colors use `#RRGGBB`, not short hex, named colors, or alpha. Icons use `default`, `emoji` (non-empty `emoji` string), or `url` (HTTP(S) `url`), with optional `small`, `medium`, or `large` size. Validation does not fetch icon URLs, check image MIME types, or require an emoji string to contain exactly one emoji. Source and icon URL validation checks syntax/protocol, not reachability or permission to crawl. Optional description, assistant prompt/fallback, widget title, and welcome copy must be non-empty when supplied; omit them to clear overrides.
## Typed Configuration Helper
Install the configuration package when building separate TypeScript tooling around the schema. The published `0.3.1` types support this baseline example:
```bash
bun add -d @openstaticfish/chattybox-config
```
```ts
const config = defineConfig({
schemaVersion: '1',
assistant: { name: 'Support' },
knowledge: {
sources: [{ type: 'website', url: 'https://docs.example.com' }],
},
widget: { enabled: true },
});
```
The CLI reads JSON files. `defineConfig()` is for typed application or build tooling; it does not make TypeScript files directly loadable by the CLI. Both `defineConfig(config)` and `validateConfig(config)` synchronously validate, throw an ordinary `Error` on the first failure, and return the same object without cloning, freezing, coercing, or inserting defaults. The package exports TypeScript types and these functions, not a JSON Schema document or `$schema` URL. The published `0.3.1` package provides TypeScript support for the expanded fields above.
For a working production integration today, use the [hosted widget](/docs/installation/) or build a custom interface with the [JavaScript SDK](/docs/sdk/).
### Drupal Chatbot Module
URL: https://chattybox.ai/docs/drupal-chatbot-plugin/
Description: Install the ChattyBox Drupal module with Composer and add source-cited AI support to public Drupal pages.
# Drupal Chatbot Module
Use the official ChattyBox Drupal module when you want a Composer-managed installation for a Drupal 10 or Drupal 11 site. It loads the hosted widget on public HTML routes and keeps the production API endpoint configured automatically. This guide covers the operational setup. The [Drupal AI chatbot module page](/drupal-chatbot-plugin/) covers the product at a glance and the evaluation workflow.
## Before Installing
Complete the [Getting Started](/docs/getting-started/) flow first: connect your public Drupal URL, review indexed pages, and verify representative answers in **Test Chat**. Then create a browser-safe public key in **Public Keys** and copy it from the project **Embed** tab.
## Composer Installation
The module is currently distributed as a tagged package in the public GitHub repository. It is not yet listed on Drupal.org or Packagist, so Composer needs the VCS repository declaration below before `composer require` can resolve it.
Add the public GitHub repository to the consuming Drupal project's root `composer.json`:
```json
{
"repositories": {
"chattybox-drupal": {
"type": "vcs",
"url": "https://github.com/OpenStaticFish/chattybox-drupal.git"
}
}
}
```
If the project already has a `repositories` section, merge the `chattybox-drupal` entry into it. Then install the tagged module:
```sh
composer require openstaticfish/chattybox-drupal:^0.1
```
The package is declared as a `drupal-module` and requires Drupal `^10 || ^11`. Standard Drupal Composer installer paths place it under `web/modules/contrib/`.
Review the [public Drupal module source](https://github.com/OpenStaticFish/chattybox-drupal) and tagged changes before upgrading. Directory-managed Drupal.org updates are not available yet.
To test the current development branch instead:
```sh
composer require openstaticfish/chattybox-drupal:dev-main
```
## Enable and Configure
1. Enable **ChattyBox** from **Extend**, or run `drush en chattybox`.
2. Open **Configuration > Web services > ChattyBox**.
3. Paste only the public widget API key from the project **Embed** tab.
4. Leave the hosted widget script URL unless ChattyBox has provided a preview or self-hosted loader URL.
5. Leave the language override blank to follow the project's locale policy, or enter a supported lowercase code such as `en`, `fr`, or `de`. In auto mode, page language wins over browser language; fixed mode uses the project's default. An override takes effect only if the project allows script overrides.
6. Enable the chatbot and save the configuration.
The module does not load on administrative routes or non-HTML responses. It adds the public key, managed production endpoint, optional locale, and widget loader through Drupal's declared library and `drupalSettings`.
Fresh installs start disabled, with an empty key and locale override. The settings form is at `/admin/config/services/chattybox` and requires the `administer chattybox configuration` permission. The module loads the widget; it does not crawl or synchronize Drupal content.
The API endpoint is built into the module, not discovered from the key. Changing the loader URL does not change that endpoint. If your **Embed** snippet uses another API deployment, use its manual widget snippet without the module. Remote script URLs must use HTTPS (HTTP is permitted only for local development hosts).
Public keys work across browser origins by default. If you enable an origin restriction in **Public Keys** > **Edit origins**, list each intended scheme, hostname, and port. Missing or disallowed request origins return 401 `Invalid API key`.
## Exclude Additional Routes
The module skips administrative routes automatically. A custom module can disable the widget on additional public routes with `hook_chattybox_load_widget_alter()`:
Administrative-route checks are not a privacy check on all frontend content. Add exclusions for checkout, account, and membership routes where appropriate.
```php
/**
* Implements hook_chattybox_load_widget_alter().
*/
function mymodule_chattybox_load_widget_alter(&$should_load, $config, $route_match) {
if ('commerce_checkout.form' === $route_match->getRouteName()) {
$should_load = FALSE;
}
}
```
## Manual Fallback
Composer is the recommended installation path. If your Drupal deployment cannot use Composer, copy the module into `web/modules/custom/chattybox` or another custom module directory, enable it, and configure it from **Configuration > Web services > ChattyBox**.
Do not paste a management credential into the module. The public widget API key is intended for frontend markup.
Choose one loader: do not enable the module alongside a theme snippet, GTM tag, or SDK mount. Its browser behavior reuses an existing marked script without changing that script's configuration.
## Verification
After configuring the module:
- Open a public Drupal page in an incognito window.
- Confirm the widget launcher appears once.
- Ask a real visitor question.
- Verify a supported answer cites indexed public Drupal pages and an unsupported question shows the fallback, which can have no sources.
- Check the browser console for missing `data-api-key`, `data-api-url`, or key errors.
- Test both excluded and included routes, with Drupal/page/CDN caches warmed as well as cold. Rebuild relevant caches after settings or hook changes. A server-side route exclusion does not tear down a widget already loaded during client-side navigation.
Continue with the [launch checklist](/docs/launch-checklist/) before announcing the chatbot.
### Installation Guides
URL: https://chattybox.ai/docs/installation/
Description: Install the ChattyBox website chatbot with one script tag across HTML, React, Docusaurus, WordPress, CMS, and GTM sites.
# 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()`](/docs/sdk/). To own the UI, use the [headless SDK](/docs/sdk/).
## Before Installing
Complete the [Getting Started](/docs/getting-started/) flow first: configure and scrape the source, review indexed pages, and verify representative answers in **Test Chat**.
Then create a browser-safe key in **Public Keys**. It works across production, preview/staging, and localhost origins by default. To add optional defense-in-depth hardening, choose **Edit origins**, enable **Restrict this key to specific origins**, and add the exact permitted origins. When enabled, matching includes scheme, hostname, and port: `https://example.com`, `https://preview.example.com`, and `http://localhost:3000` are separate entries. Return to **Embed**, select the key, and copy the generated snippet. It includes the public key and API URL for your project:
```html
```
For docs-oriented platforms, see the [MkDocs AI chatbot](/mkdocs-ai-chatbot/), [VitePress AI chatbot](/vitepress-ai-chatbot/), and [GitBook AI chatbot](/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-locale` overrides are allowed.
- Public key creation, deletion, and optional per-key origin restrictions. Open **Public Keys** > **Edit origins** to enable a restriction and 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](/docs/cli/), 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 loads configuration and translations once at initialization; it does not subscribe to dashboard changes or changes to page language. Reload to pick up saved settings. 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 ``. This works for static HTML, hand-coded sites, and templates that expose a global footer.
```html
Example Site
```
## 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.
```tsx
export default function RootLayout({ children }: { children: ReactNode }) {
return (
{children}
);
}
```
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.
```tsx
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](/docusaurus-ai-chatbot/)
For Docusaurus, create or update `src/theme/Root.tsx` so the widget is available across docs pages.
```tsx
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 ``. Fixed mode uses the project's default locale unless an allowed script override is present. The widget resolves locale only at initialization, not on client-side route changes; a full page reload picks up the new page language.
Keep the loader in your persistent application shell. Do not recreate it during normal client-side route changes; use v15 destruction only when you intentionally need teardown and have SDK `0.1.4` installed.
## Custom Interface
The hosted widget is optional. If you want full control over rendering, message state, and interaction design, use the [JavaScript SDK](/docs/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.
```html
```
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.
1. Open your GTM container.
2. Create a new **Custom HTML** tag.
3. Paste the ChattyBox snippet.
4. Use an **All Pages** trigger, or a narrower trigger for only the pages that should show the widget.
5. Preview the container, verify the widget loads, then publish.
```html
```
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](/docs/wordpress-chatbot-plugin/)
For a no-code WordPress installation, use the [ChattyBox WordPress plugin](/wordpress-chatbot-plugin/). Follow the [WordPress plugin guide](/docs/wordpress-chatbot-plugin/) 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: exclude checkout, account, password-protected, or membership pages explicitly when needed. 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.
```html
```
Avoid adding the widget to wp-admin, checkout, account, or private membership pages unless those pages are intentionally public and supported.
## [Drupal module](/drupal-chatbot-plugin/)
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`:
```json
{
"repositories": {
"chattybox-drupal": {
"type": "vcs",
"url": "https://github.com/OpenStaticFish/chattybox-drupal.git"
}
}
}
```
Then install the tagged module and enable it:
```sh
composer require openstaticfish/chattybox-drupal:^0.1
drush en chattybox
```
Open **Configuration > Web services > ChattyBox**, paste the public widget API key from the project **Embed** tab, and enable the chatbot. The production API endpoint is configured automatically. See the [Drupal chatbot module guide](/docs/drupal-chatbot-plugin/) for route exclusions and the manual fallback.
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](/docs/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`, missing `data-api-url`, or key errors. Check origins only if you explicitly enabled a restriction for the key.
### Launch Checklist
URL: https://chattybox.ai/docs/launch-checklist/
Description: Validate content, scraping, widget installation, answer quality, API keys, origins, and analytics before launching ChattyBox.
# Launch Checklist
Use this checklist before putting ChattyBox in front of customers. It catches the common setup gaps that make a chatbot look installed but not ready.
For a support rollout, pair this checklist with the [AI customer support chatbot guide](/ai-customer-support-chatbot/) so public-content answers have a clear escalation path for account-specific, sensitive, or unresolved questions.
## Content Readiness
- [ ] Public, crawlable content is selected for the chatbot to answer from.
- [ ] Private pages, admin pages, checkout flows, account pages, drafts, and staging content are excluded by deliberate source selection, not only `robots.txt` (which the crawler does not enforce).
- [ ] You chose the right input: sitemap, manual URLs, homepage only, or crawl. Crawl uses discovered conventional sitemaps before falling back to links; it does not fill an incomplete sitemap by following links.
- [ ] Important product, pricing, policy, support, FAQ, onboarding, and troubleshooting pages are included.
- [ ] Multilingual sites include the language versions you expect the widget to answer from.
## Scraping Validation
- [ ] The scrape ended, saved/selected counts were compared, and the expected pages are present. A **Completed** badge alone does not prove full coverage.
- [ ] The indexed page count matches what you expected for your plan and launch scope.
- [ ] **Partially indexed** pages were reviewed for missing text beyond the 512 KiB limit; long pages were split where needed.
- [ ] Separate embedding work finished and representative retrieval was tested.
- [ ] Recently edited or migrated pages have been re-scraped.
- [ ] Any missing pages were checked for authentication, bot challenges, failed/unsafe redirects, source filters, or JavaScript-only content. Important text is available in fetched HTML without JavaScript rendering.
- [ ] Obsolete stored pages were deleted from **Content**, not merely removed from the sitemap.
## Usage and Ownership
- [ ] The project owner can access the dashboard and manage the chatbot; public keys and organization membership are not dashboard permissions.
- [ ] **Account & Billing** at `/settings/account` has enough message allowance for tests and launch traffic across the owner's chatbots.
- [ ] Stored-page limits and the separate monthly page-refresh budget were checked. Manual index rebuilds also consume refresh work.
- [ ] The refresh schedule fits the plan: Free at most weekly, paid plans at most daily. Manual scrape retries follow the same cooldown, including after failed jobs.
- [ ] Pro/Business PAYG is either off, capped per feature, or intentionally uncapped; it does not remove the crawler's refresh cooldown or monthly refresh budget.
- [ ] If config locking is used, its irreversible restrictions and the separate secret deployment-token workflow are understood.
## Answer Quality
- [ ] You asked real test questions from sales, support, onboarding, and documentation use cases.
- [ ] Answers only use your indexed content and refuse questions your content cannot support.
- [ ] Source citations appear on useful answers.
- [ ] Citation links open the expected public source pages.
- [ ] Weak answers have been fixed by improving source content or adding missing pages, then re-scraping.
- [ ] Persona changes were saved and the enforced fallback was tested separately; Persona wording does not replace the configured missing-context response.
- [ ] Test questions include their own context rather than assuming earlier conversation turns reach the answer generator.
## Widget Installation
- [ ] The widget is installed on the intended public pages.
- [ ] The script loads only once per page.
- [ ] The script includes `data-api-key`.
- [ ] The script includes `data-api-url`.
- [ ] **Auto-detect** / **Fixed** and **Allow script override** are set intentionally. `data-locale` only wins when overrides are enabled, even in Fixed mode.
- [ ] Widget UI language, question/answer language, and indexed language versions were tested separately.
- [ ] The widget opens and sends a test question in an incognito window.
- [ ] Mobile viewport testing confirms the launcher and chat panel are usable.
## API Key and Optional Origin Restriction Checks
- [ ] The production public key exists in **Public Keys** and is the one selected in **Embed**.
- [ ] Any rotation was completed by installing and testing the new key before deleting the old one. Key names alone do not restrict environments.
- [ ] The public key has been tested on the intended production, preview/staging, and localhost sites; keys work from all browser origins by default.
- [ ] If optional hardening is needed, **Public Keys** > **Edit origins** has **Restrict this key to specific origins** enabled and lists the intended exact origins (scheme, hostname, and port must match).
- [ ] No private server API keys, admin tokens, or secrets are present in frontend code, GTM, CMS custom HTML, or page source.
## Browser and Deployment Checks
- [ ] Browser console has no ChattyBox errors.
- [ ] Content Security Policy allows the widget script and API URL if your site uses CSP.
- [ ] Ad blockers or consent tools are not blocking the widget on the pages where it is expected.
- [ ] The final deployed site, not only local development, has been tested.
## After Launch
- [ ] Review **Logs** on any plan, and **Analytics** / **Content Gaps** on Pro or Business.
- [ ] Interpret Analytics as up to 5,000 recorded interactions from the last 30 days, including Test Chat, not verified answer accuracy or visitor-only traffic.
- [ ] Check detected gaps, retest improved content, and resolve them manually. Resolved gaps disappear from the dashboard and do not automatically reopen on recurrence.
- [ ] If page attribution matters, verify **Popular Triggers**. The hosted widget sends source-page context; headless SDK `sendMessage()` does not currently send it.
- [ ] Add missing documentation, FAQs, or examples based on real visitor questions.
- [ ] Re-scrape updated pages after content changes.
- [ ] Rotate public widget keys if needed; update origin restrictions only when the optional restriction is enabled and your allowed domains change.
- [ ] Conversation deletion is not used to reset usage or analytics; those records are separate.
If any item fails, use [Troubleshooting](/docs/troubleshooting/) before launch.
### JavaScript SDK
URL: https://chattybox.ai/docs/sdk/
Description: Build a custom chatbot interface on ChattyBox retrieval and conversation infrastructure.
# JavaScript SDK
The npm package is the recommended way to integrate ChattyBox from application code. Configure its public key and API URL, then load the maintained floating widget from a persistent browser layout or use the headless methods with your own components.
**Version requirements:** The published npm SDK is **0.1.4**. Its lifecycle and strict NodeNext declaration fixes are available in this release. Full widget cleanup also requires the updated maintained `widget.js`; self-hosted installations must update that file separately.
## Quick Start
```bash
bun add @openstaticfish/chattybox
```
```ts
const chattybox = new Chattybox({
apiKey: import.meta.env.PUBLIC_CHATTYBOX_API_KEY,
baseUrl: import.meta.env.PUBLIC_CHATTYBOX_API_URL,
});
const widget = chattybox.mountWidget();
// Keep this loader for the lifetime of the page, including SPA navigation.
```
Call `mountWidget()` after `document.body` exists, not during rendering or server-side execution. It appends a floating widget under `document.body`, not inside your component. `{ locale: 'fr' }` requests French at initialization only if the project allows script locale overrides.
The `import.meta.env.PUBLIC_*` names in these examples are illustrative. Use your framework's public configuration convention, such as `import.meta.env.VITE_*` in Vite or `process.env.NEXT_PUBLIC_*` in Next.js. In Node.js, read and validate `process.env` values instead.
## Get Your Public Configuration
1. [Create a project and index your content](/docs/getting-started/).
2. Test representative questions in the dashboard.
3. Open **Public Keys** and create a browser key. It works from production, previews, staging, and localhost by default.
4. Open **Embed**, select that key, and copy the widget API URL shown with the generated snippet.
Public widget API keys are designed to appear in browser code. They identify a project but are not management credentials. For optional defense-in-depth hardening, use **Public Keys** > **Edit origins** to enable a restriction and list the exact browser origins to allow. The package is an ESM client for current Node.js and browser applications that provide `fetch`.
Restrictions match normalized scheme, hostname, and port, not paths or wildcard subdomains. The API uses the request's `Origin`, falling back to the origin of `Referer`. Missing or disallowed origins on a restricted key return 401 `Invalid API key`, just like an invalid or expired key. Node.js fetch does not automatically send either browser header. Origin checks are not authentication and cannot prevent a non-browser client from forging headers.
## Constructor and Exports
`new Chattybox(options)` takes `ChattyboxOptions`:
| Option | Type | Default / behavior |
| --- | --- | --- |
| `apiKey` | `string` | Required, nonblank public widget key. |
| `baseUrl` | `string` | Required, nonblank string. SDK `0.1.4` requires an absolute HTTP(S) URL without credentials, query string, or fragment. |
| `fetch` | `typeof globalThis.fetch` | Optional fetch-compatible implementation; otherwise global `fetch`. |
Copy the HTTP widget API URL from **Embed**, not the dashboard URL or a Convex `.cloud` client URL. Trailing slashes are removed, followed by a trailing `/chat` suffix. Do not include query strings or fragments. The client exposes readonly `apiKey` and normalized `baseUrl` properties.
The constructor throws an ordinary `Error` when its options are missing or not an object, `apiKey` or `baseUrl` is missing/non-string/blank, a supplied `fetch` is not a function, or `baseUrl` is not an absolute HTTP(S) URL without credentials, a query string, or a fragment.
The package exports `Chattybox`, `ChattyboxError`, and the types `ChattyboxOptions`, `SendMessageInput`, `ChatResponse`, `WidgetConfig`, `WidgetTranslations`, `HostedWidgetOptions`, and `HostedWidgetHandle`. It has no React component or hooks. The `./browser` IIFE bundle exposes the two constructors on `window.ChattyboxSDK`; loading that bundle alone does not mount UI.
## Mount the Hosted Widget from Code
Use this when you want ChattyBox's maintained floating interface initialized from application code:
```ts
const chattybox = new Chattybox({
apiKey: import.meta.env.PUBLIC_CHATTYBOX_API_KEY,
baseUrl: import.meta.env.PUBLIC_CHATTYBOX_API_URL,
});
const widget = chattybox.mountWidget({ locale: 'fr', debug: false });
```
`mountWidget(options?)` returns a `HostedWidgetHandle` synchronously, before the script has loaded or the UI is ready:
| Field / option | Behavior |
| --- | --- |
| `options.scriptUrl` | Defaults to `https://chattybox.ai/widget.js`; override only for a trusted preview or self-hosted loader. |
| `options.locale` | Sets `data-locale` if nonempty. Project `allowLocaleOverride` must permit it. |
| `options.debug` | Sets `data-debug="true"` only when truthy; diagnostics are off by default. |
| `handle.element` | The injected or reused `HTMLScriptElement`. |
| `handle.remove()` | In SDK `0.1.4`, the final matching handle emits the hosted removal signal before removing the script. With hosted `widget.js` v15 it destroys owned UI/styles, cancels startup work and retries, and aborts in-flight chat. |
With SDK `0.1.4` and hosted `widget.js` v15, use `remove()` for component cleanup or consent revocation; `window.ChattyBox.destroy()` is the hosted equivalent. Cleanup cannot undo a request already processed by the server. Keep the loader in a persistent shell across normal client-side navigation.
SDK `0.1.4` shares a marked script only for an identical mount configuration (public key, normalized API URL, script URL, locale, and debug setting). A changed configuration rejects until every existing handle is removed; it never silently keeps the old options. The SDK does not detect unmarked manual loaders. Choose one integration path per page; do not combine SDK mounting with a plugin, GTM tag, or separate script. The constructor's custom `fetch` is used only by headless methods, not passed to the hosted widget. There is no SDK ready promise, container target, or reactive locale-update API; hosted v15 provides `window.ChattyBox.destroy()`.
Identical mounts share one widget. Each returned handle owns a reference; call `remove()` on every handle during cleanup. Removing the last handle cancels pending initialization, requests, and retry timers, then removes the owned widget, styles, font links, script, and global API. Repeated cleanup is safe. A mount with a different key, API URL, script URL, locale, or debug setting throws until all previous handles have been removed. Remove the old mount before switching projects or locales.
The hosted v15 loader retries transport failures, interrupted successful response bodies, in-progress responses, rate limits, and server errors with the same request body and idempotency key. It makes at most 10 attempts total and never schedules an automatic retry beyond 30 seconds; readable `Retry-After` delays count against that window. After exhaustion, **Retry message** reuses that logical request; a new question starts a new request. Invalid JSON or an invalid response shape on a successful response is a terminal protocol error, not an automatic retry. Cross-origin API responses must expose `Retry-After` via `Access-Control-Expose-Headers`.
## Build Your Own UI
Use the headless methods below when your application owns the message list, input, loading and error states, citations, and accessibility.
### Send a Message
```ts
const chattybox = new Chattybox({
apiKey: import.meta.env.PUBLIC_CHATTYBOX_API_KEY,
baseUrl: import.meta.env.PUBLIC_CHATTYBOX_API_URL,
});
const answer = await chattybox.sendMessage({
message: 'How do I get started?',
});
console.log(answer.message);
console.log(answer.sources);
```
Set `PUBLIC_CHATTYBOX_API_URL` to the exact widget API URL from the Embed tab. The SDK accepts either the deployment root or a URL ending in `/chat`.
The response contains:
| Field | Type | Description |
|---|---|---|
| `message` | `string` | Answer text or the configured fallback message; render safely as text or sanitized Markdown, not raw HTML. |
| `conversationId` | `string` | Identifier used to continue this conversation. |
| `sources` | `string[]` | Source URLs for the answer; may be empty for a fallback. Validate HTTP(S) URLs before rendering links. |
`sendMessage(input)` returns `Promise`. `SendMessageInput` accepts only `message: string`, optional `conversationId: string | null`, and optional `idempotencyKey: string`. The SDK sends the public API key in the JSON body. It does not send page context (`sourceUrl` or `sourcePath`), a locale, or model options. Validate nonblank input and a maximum trimmed length of 2,000 characters before submitting; the backend enforces this limit, but its internal validation failures currently surface as generic HTTP 500 errors.
`sendMessage()` does not provide streaming, automatic retries, timeouts, an `AbortSignal` option, storage, or UI state. A custom fetch implementation can supply transport policy. This no-retry statement applies to headless chat: SDK `0.1.4` retries only `getWidgetConfig()` once after HTTP 400, and hosted v15 retries its startup GETs. There is no separate `wasAnswered` or fallback-status field in the public response, so do not invent a structured unsupported-answer result.
### Continue a Conversation
Keep the returned conversation ID in your UI state and send it with the next message:
```ts
const followUp = await chattybox.sendMessage({
message: 'How do I create a public widget key in the dashboard?',
conversationId: answer.conversationId,
});
```
Do not reuse one conversation ID across unrelated visitors. Create a new conversation by omitting `conversationId` for their first message.
Passing `null` also starts a new conversation. An ID groups stored messages within the project; the current public generation path does not pass previous turns to the model. Make follow-ups self-contained rather than assuming the model remembers the previous answer.
### Retry Safety
Supply a unique `idempotencyKey` for each logical message and retain the exact input for a retry:
```ts
const input = {
message: 'Where is the API reference?',
idempotencyKey: crypto.randomUUID(),
};
const result = await chattybox.sendMessage(input);
// If the response is lost, retry the same input, including its original conversationId.
```
The SDK sends the key as `Idempotency-Key` but does not create one or retry for you. Keys are project-scoped and must be 1-128 characters matching `[A-Za-z0-9][A-Za-z0-9._:-]*`. An identical completed request can be replayed; changed input, an in-progress request, or a terminal failure can return 409. Do not blindly retry every 409 or generate a new key after an ambiguous transport failure.
Replay is not permanent: completed and failed records expire 24 hours after reservation, while pending records are not reclaimed on time alone. A retry after terminal-record expiry can execute again. Keep retry windows bounded and investigate persistent conflicts instead of assuming unlimited deduplication.
### Handle Errors
```ts
try {
await chattybox.sendMessage({ message: 'Where is the API reference?' });
} catch (error) {
if (error instanceof ChattyboxError) {
console.error(error.status, error.code, error.message);
} else {
// Network failures and other non-HTTP errors are not wrapped by the SDK.
console.error(error);
}
}
```
`ChattyboxError.status` contains the HTTP status. `code` is present only when the API returns a string `code`; most current widget API errors do not. Non-2xx responses, a nonempty string `error` even with HTTP 200, invalid JSON, and non-object JSON throw `ChattyboxError`. Network/fetch failures pass through unchanged. SDK `0.1.4` also wraps unreadable response bodies as `ChattyboxError` with `RESPONSE_BODY_READ_FAILED`. Successful JSON objects are cast to the declared type without field-by-field runtime validation.
Common HTTP outcomes include 400 for malformed input or unsupported translation locales, 401 for key/origin failures, 403 for a disabled project widget (including headless chat), 409 for idempotency conflicts, 413 for chat bodies over 65,536 bytes, 429 for rate limiting, and 500 for internal failures. The SDK does not expose response headers on its result or error.
Headless `sendMessage()` does not automatically retry. If your UI implements retries, supply one `idempotencyKey` per logical message and reuse both the key and unchanged input for transport retries. Do not generate a new key for a lost response.
### Reuse Project Settings and Translations
The SDK also exposes `getWidgetConfig()` and `getWidgetTranslations(locale)`. These methods support clients that want to reproduce the hosted widget's project settings and localized labels:
```ts
const [config, labels] = await Promise.all([
chattybox.getWidgetConfig(),
chattybox.getWidgetTranslations('en'),
]);
```
A fully custom UI can ignore them. Keep each visitor's `conversationId` in that visitor's browser or session state; never share one global conversation ID.
`getWidgetConfig()` returns `Promise` and authenticates with `Authorization: Bearer`. SDK `0.1.4` retries exactly once with an encoded query-string key only after HTTP 400, for intermediaries that strip the header; it does not retry other statuses. `WidgetConfig` is `Record` with only three optional typed properties: `localeMode: 'auto' | 'fixed'`, `defaultLocale: string`, and `allowLocaleOverride: boolean`. Narrow other fields before using them. Current server fields and defaults are listed in [Hosted widget customization](/docs/widget/). A successful config request also marks the project as widget-installed, even if your custom client never renders a widget.
`getWidgetTranslations(locale)` returns `Promise` with `translations: Record`, `dir: 'ltr' | 'rtl'`, and the server-selected `locale: string`. This endpoint is public and does not use the API key or project locale settings. Pass one of `en`, `fr`, `de`, `pl`, `es`, `it`, `nl`, `pt`, `sv`, `id`, `et`, `fi`, `cy`, or `cs`. The SDK URL-encodes but does not normalize the locale: `fr-CA` and `FR` return 400, unlike the hosted widget's regional-locale normalization. An empty string selects English on the server. All current catalogs are LTR and can be cached for one hour.
For a custom UI, resolve the desired locale yourself, respect `allowLocaleOverride` and fixed/auto project settings if reproducing hosted behavior, and provide fallbacks for missing translation keys. Locale settings affect UI labels, not the language of a chat request or a guarantee about response quality.
## Next Steps
- Prefer a maintained, no-build UI? [Install `widget.js`](/docs/installation/).
- Customize the hosted UI in [Hosted widget customization](/docs/widget/).
- Before launch, test fallback answers, citations, and mobile behavior with the [launch checklist](/docs/launch-checklist/). Test exact origins too if you explicitly enable an origin restriction.
### Troubleshooting
URL: https://chattybox.ai/docs/troubleshooting/
Description: Fix common ChattyBox widget, API key, origin, scraping, language, citation, and weak-answer issues before launch.
# Troubleshooting
Use this page when the widget is installed but does not behave as expected.
## Widget Does Not Appear
Check the browser console first. ChattyBox reports missing required attributes there.
Common causes:
- The script is absent from both the deployed HTML and the live DOM.
- The script was added to the wrong template, layout, tag manager container, or CMS code area.
- The script is behind a consent rule or tag manager trigger that did not fire.
- The application component that mounts the loader never runs on that route.
- A Content Security Policy blocks `https://chattybox.ai/widget.js`.
- CSS or another widget overlaps the launcher.
- The deployed configuration has `widget.enabled: false`.
Smallest fix:
1. Open the deployed public page in an incognito window.
2. Search page source and the browser's Elements panel for `chattybox.ai/widget.js`; an SDK- or JavaScript-injected loader may appear only in the live DOM.
3. Confirm the script appears once and includes `data-api-key` and `data-api-url`.
4. Move the script to the global footer, app layout, Docusaurus root, or GTM All Pages trigger if it is missing.
For config-managed projects, `widget.enabled: false` prevents the hosted widget from initializing and makes public `POST /chat` requests return `403 Widget is disabled`, including headless SDK requests. Change that setting through the config deployment workflow, not by rotating the public key. Removing a loader script after initialization does not remove the already rendered widget.
## Missing `data-api-url`
The widget exits early when `data-api-url` is missing.
Use the full snippet from the dashboard or add the required attribute:
[Widget embed snippet]
Use the API URL from your dashboard instead of guessing. In production, it is expected to be a stable `https://...convex.site/chat` URL.
## Generic `401 Invalid API key`
For security, widget API endpoints return the same generic `401 Invalid API key` response for an unknown, expired, or origin-rejected public key. Do not rely on the response to identify the cause.
Common causes:
- The public widget key was copied incorrectly.
- The key was deleted, expired, or copied from a different backend deployment than the API URL.
- The key's project or owner is being deleted.
- Optional origin restriction is enabled for the key and the current site origin is not included.
Fixes:
1. Open the project in the ChattyBox dashboard.
2. Copy a fresh snippet from the **Embed** tab.
3. Check **Public Keys** > **Edit origins** only if **Restrict this key to specific origins** is enabled. Add the exact origin that serves the page, or disable the optional restriction. Scheme, hostname, and port must all match: `https://example.com`, `https://preview.example.com`, and `http://localhost:3000` are different origins. Paths do not need separate entries.
4. Redeploy or republish the site and test again in an incognito window.
A valid key for another chatbot on the same backend normally selects that chatbot rather than producing a `401`; check the project if answers are unexpectedly unrelated. Key names such as "production" and "staging" do not enforce environments. The HTTP API uses `Origin`, falling back to the origin of `Referer`; a restricted key rejects requests without a matching origin from either header. Origin restrictions are not a substitute for visitor authentication.
## Message Limits or Rate Limits
Check **Account & Billing** at `/settings/account` for message usage, plan, and optional Pro/Business PAYG budgets. Test Chat and public chat both consume the owner's shared message allowance. Deleting conversations or creating another key does not reset that allowance.
Monthly allowance errors and short-term request rate limits are different. For HTTP `429` responses, honor `Retry-After` when supplied instead of repeatedly retrying. For a monthly message-limit error, wait for the allowance to reset or adjust the plan/eligible PAYG budget. The **Logs** tab is conversation history, not a per-request error console; use the browser Network panel to inspect HTTP failures.
## Wrong Language
First check **Embed** > **Widget Language** (also available in the project's **Settings**). The hosted widget chooses its UI language in this order:
1. `data-locale` on the widget script, **only if Allow script override is enabled**.
2. In **Fixed** mode, the configured default language.
3. In **Auto-detect** mode, the page `` value, then the browser language if no page language exists, then the configured default if neither exists.
Unsupported locale values normalize to English. An unsupported but present page language does not cause the widget to try the next candidate. The configured default starts as English.
Fixes:
- For automatic language selection, choose **Auto-detect** and remove an incorrect `data-locale` or disable script overrides.
- Set ``, ``, or the matching supported language code on localized pages.
- To force the configured language, choose **Fixed** and disable **Allow script override**. With overrides enabled, `data-locale` still takes priority over Fixed mode.
- Save the settings, reload the installed widget, and test again. Locale is resolved at initialization, not on every client-side route change. A `locale` supplied to `mountWidget()` becomes `data-locale` and follows the same rules.
- Check for a failed `/widget-config` request if saved language settings are ignored. On a config-fetch failure the loader continues with defaults rather than the project's saved locale policy.
- Index each required language version if answers cite or retrieve content from the wrong language. The answer generator detects language from the question, separately from widget UI locale; Fixed widget language does not force answer language or translate source content. The default enforced missing-content fallback is English unless separately configured through config as code.
## No Citations or Weak Answers
ChattyBox answers from indexed content. Missing citations or weak answers usually mean the needed source content was not retrieved or does not clearly answer the question.
A reliable [grounded RAG chatbot](/rag-chatbot-for-website/) needs clear retrieved source content for every answer it gives.
Fixes:
- Ask the same question in the dashboard test chat and compare the cited pages.
- Make sure the source page is public and included in the crawl.
- Add clear headings, examples, FAQs, and direct answer text to the source page.
- Avoid relying on screenshots, videos, excluded hidden markup, JavaScript-only content, or iframes as the only source.
- Re-scrape the updated page when the cooldown allows it, wait for embedding work, then test again.
- Look for **Partially indexed** warnings; text beyond the 512 KiB per-page limit is not retained. Split long source pages rather than repeatedly rebuilding the same truncated text.
- Make each question self-contained. Saved conversation history is not currently included in the answer generator's prompt.
**Persona** adds site-specific instructions to built-in grounding rules; it cannot supply missing indexed content or replace the enforced missing-context/content-gap fallback. That fallback has a separate `assistant.fallbackMessage` setting in [configuration as code](/docs/cli/).
## Pages Not Scraped or Stale Content
Common causes:
- The page is missing from the submitted sitemap.
- Manual URL mode did not include the page.
- The page blocks ordinary HTTP fetches, requires authentication, returns a CAPTCHA/error page, or redirects to a blocked target.
- The page content changed after the last scrape.
- The content is only rendered by JavaScript, or is outside the selected semantic content root.
- The selected URLs exceeded the page allowance, the monthly refresh budget ran out, or an include/exclude rule filtered them out.
Fixes:
1. Confirm the page opens publicly in a private browser window.
2. Use sitemap mode for broad coverage or manual URLs for a curated set.
3. Submit the canonical URL rather than a tracking URL, redirect URL, or logged-in URL.
4. Re-scrape after publishing content changes and after the refresh cooldown: at least seven days since the latest job was created on Free, or 24 hours on paid plans, even if that job failed.
5. Compare the job's saved/selected counts and the **Content** list with your intended URLs. **Completed** can include skipped/failed URLs; **Completed with warnings** specifically flags partially retained page text, not all crawl failures. The UI does not provide a complete per-URL failure list.
ChattyBox does not currently read or enforce `robots.txt`. It follows safe HTTP redirects, so a redirect alone is not a failure. Do not remove access protections or put private content on a public URL to make it crawlable.
If a URL was removed from your site or source selection, its stored page may still be used. Delete it from **Content** as well as excluding it from future discovery. **Rebuild Index** uses stored text, not a fresh network fetch, and has its own plan cooldown plus usage against the [monthly refresh budget](/docs/scraping/#refreshing-content).
## Settings Will Not Save
Save **General Settings** with **Save Changes** and **Scraping Configuration** with **Save Config** before the first scrape. Saving one form does not save the other. A saved Website URL is required by the dashboard even when you enter Manual URLs.
If the project is **Config locked**, configuration must be deployed through the [CLI workflow](/docs/cli/). The lock is irreversible; Persona saves, scrape configuration, Scrape Now, content deletion, and index rebuilds are rejected even if a control is still visible. Only the branding preference remains dashboard-editable within hosted-widget configuration, subject to the plan. Public widget keys and deployment tokens are separate credentials.
If a project is missing or access is denied, confirm you signed in as its owner. A widget key, deployment token, or organization membership does not grant dashboard ownership permissions. Locked **Analytics** and **Content Gaps** tabs require Pro or Business; **Logs** is available on all plans.
## Still Stuck
Collect these details before contacting support:
- The public page URL where the widget should appear.
- A screenshot or copy of any browser console error.
- Whether the page uses plain HTML, Next.js, Docusaurus, WordPress, a CMS, or Google Tag Manager.
- Whether the snippet includes `data-api-key` and `data-api-url`.
- One test question that should work and the source page that answers it.
### WordPress Chatbot Plugin
URL: https://chattybox.ai/docs/wordpress-chatbot-plugin/
Description: Install and configure the ChattyBox WordPress plugin, control public route loading, and verify source-cited answers.
# WordPress Chatbot Plugin
Use the official ChattyBox WordPress plugin when you want a no-code installation that loads the hosted widget without editing theme files. This guide covers the operational setup. The [WordPress AI chatbot page](/wordpress-ai-chatbot/) explains content and crawl strategy, while the [WordPress plugin landing page](/wordpress-chatbot-plugin/) covers the product at a glance.
## Before Installing
Complete the [Getting Started](/docs/getting-started/) flow first: connect your public WordPress URL, review indexed pages, and verify representative answers in **Test Chat**. Then create a browser-safe public key in **Public Keys** and copy it from the project **Embed** tab.
## Install the Plugin
The plugin has no Composer, npm, or build-step dependency. It is currently distributed from the public ChattyBox GitHub repository, not the WordPress.org Plugin Directory, so use WordPress's **Upload Plugin** flow rather than directory search. Directory-managed automatic updates are not available yet.
The pinned 0.2.0 package declares WordPress 5.8+ and PHP 7.4+, with testing metadata up to WordPress 6.8. Test your actual WordPress/PHP versions and theme; that metadata is not a guarantee for every newer release.
1. Download the [pinned ChattyBox WordPress plugin 0.2.0 ZIP](https://github.com/OpenStaticFish/chattybox-wordpress/archive/328058002b626e8b4d3c65426dfcf881f950a263.zip), or inspect the [public source repository](https://github.com/OpenStaticFish/chattybox-wordpress).
2. In WordPress, open **Plugins > Add New > Upload Plugin**, upload the ZIP, and activate **ChattyBox AI Chatbot**. For a manual server install, copy the plugin directory into `wp-content/plugins/` first.
3. Open **Settings > ChattyBox**.
4. Paste the public widget API key from the project **Embed** tab.
5. Enable the chatbot and save the settings.
The plugin stores the public widget key and display settings in WordPress options. Never paste a ChattyBox management credential into the plugin.
## Configure Loading
The production defaults are:
- Widget script: `https://chattybox.ai/widget.js`
- API endpoint: configured automatically by the plugin
- Enabled: off until you enable the chatbot with a nonempty public key
- Locale override: blank; the hosted widget follows the project's locale policy (auto mode by default)
With auto mode, page `` takes priority over browser language. Fixed mode uses the project's default locale. The plugin's optional language override becomes `data-locale` and wins only when the project permits script overrides. Use a [supported lowercase locale code](/docs/widget/#officially-supported-languages); custom header/welcome text is not automatically translated.
The API endpoint is built into this plugin version, not discovered from the key. Changing **Widget script URL** does not change that endpoint. If the **Embed** snippet targets a different API deployment, use the manual script integration instead. Remote loader URLs must use HTTPS (HTTP is permitted only for local development hosts).
The plugin loads the widget on public frontend requests. It intentionally skips `wp-admin`, feeds, REST requests, and AJAX requests, so administrative and non-page responses do not receive the script.
These request guards do not test every frontend page's privacy or membership status. Checkout, account, password-protected, and membership pages need explicit exclusions where appropriate. Also confirm the theme outputs WordPress's footer scripts. The plugin does not crawl or sync posts; content indexing and refreshes happen in ChattyBox.
Public keys work across browser origins by default. Optional restrictions in **Public Keys** > **Edit origins** require each intended scheme, hostname, and port; blocked or missing request origins return 401 `Invalid API key`. Test the production page, not just the dashboard.
## Exclude Additional Routes
Use the `chattybox_load_widget` filter from a site-specific plugin or child theme when a public route should not show the widget:
```php
add_filter(
'chattybox_load_widget',
static function ( $should_load ) {
return $should_load && ! is_page( array( 'checkout', 'account' ) );
}
);
```
Keep the default plugin behavior enabled first, then add only the route exclusions your site needs. Test both an excluded route and a normal public page after changing the filter.
## Manual Script Fallback
Use the plugin as the default path. If your WordPress team already manages scripts through a theme, child theme, script plugin, or Google Tag Manager, you can load the hosted widget manually instead:
```html
```
Do not enable the plugin and add the same widget snippet at the same time. Choose one loader so visitors do not receive duplicate launchers.
## Verify the Installation
After configuring the plugin:
- Open a public WordPress page in an incognito window.
- Confirm the launcher appears once.
- Ask a real visitor question.
- Verify a supported answer cites indexed public WordPress pages and an unsupported question shows the fallback, which can have no sources.
- Check the browser console for missing `data-api-key`, `data-api-url`, or key errors.
- Test a checkout, account, or private route if you configured an exclusion.
- Purge any relevant WordPress/CDN page cache after changing settings or exclusions, and test a fresh page load. Neither removing a script nor hiding the widget with CSS is complete UI teardown or consent revocation.
Continue with the [launch checklist](/docs/launch-checklist/) before announcing the chatbot. Use [Analytics](/docs/analytics/) and **Content Gaps** to improve the WordPress content after real questions arrive.
## Product And Landing Pages
- [ChattyBox Source-Cited AI](https://chattybox.ai/): Turn public documentation, help articles, and website content into source-cited answers without maintaining custom RAG infrastructure.
- [Pricing](https://chattybox.ai/pricing/): Compare ChattyBox plans, including the free tier, paid plans, and optional pay-as-you-go overages.
- [About ChattyBox](https://chattybox.ai/about/): Learn what ChattyBox is, who it is built for, and how it helps teams answer questions from public content.
- [JavaScript Chatbot SDK](https://chattybox.ai/javascript-chatbot-sdk/): Install the ChattyBox npm SDK and build a custom source-cited AI chat experience on managed retrieval infrastructure.
- [React Chatbot SDK](https://chattybox.ai/react-chatbot-sdk/): Build a custom React chatbot interface with managed retrieval, conversation state, and source citations.
- [Next.js AI Chatbot SDK](https://chattybox.ai/nextjs-ai-chatbot/): Add a custom source-cited AI chatbot to a Next.js App Router application with a focused client boundary.
- [AI Chatbot for Documentation](https://chattybox.ai/ai-chatbot-for-documentation/): Turn public documentation into a source-cited AI chatbot for visitors, customers, and support teams.
- [AI Chatbot for Websites](https://chattybox.ai/ai-chatbot-for-website/): Add a website AI chatbot that answers from your own pages and shows visitors the sources behind each answer.
- [AI Chatbot for SaaS](https://chattybox.ai/ai-chatbot-for-saas/): Help SaaS visitors and customers get source-cited answers from product pages, docs, changelogs, and help content.
- [AI Customer Support Chatbot](https://chattybox.ai/ai-customer-support-chatbot/): Provide source-cited self-service for repeat public-content questions while preserving escalation for private, sensitive, or unresolved issues.
- [Best AI Documentation Chatbots](https://chattybox.ai/best-ai-documentation-chatbots/): Compare AI documentation chatbot options for grounded answers, citations, setup effort, and support workflows.
- [How to Add an AI Chatbot to Documentation](https://chattybox.ai/how-to-add-ai-chatbot-to-documentation/): A practical guide to adding a grounded AI chatbot to documentation with one widget script.
- [Docs Chatbot Readiness Checker](https://chattybox.ai/tools/docs-chatbot-readiness/): Free tool that checks one public documentation page plus robots.txt and sitemap.xml for AI chatbot readiness and returns specific fixes. Fetched content is discarded, never stored or indexed.
- [Docusaurus AI Chatbot](https://chattybox.ai/docusaurus-ai-chatbot/): Install an AI chatbot on Docusaurus docs that answers from crawled pages with source citations.
- [MkDocs AI Chatbot](https://chattybox.ai/mkdocs-ai-chatbot/): Add a grounded AI chatbot to MkDocs documentation without migrating content or changing hosting.
- [VitePress AI Chatbot](https://chattybox.ai/vitepress-ai-chatbot/): Embed a source-cited AI chatbot in VitePress docs for faster self-serve answers.
- [GitBook Documentation Chatbot](https://chattybox.ai/gitbook-ai-chatbot/): Use public GitBook documentation as source content for cited answers, then embed ChattyBox only where custom JavaScript is supported.
- [Mintlify AI Chatbot](https://chattybox.ai/mintlify-ai-chatbot/): Add a source-cited AI chatbot to Mintlify documentation and keep answers grounded in published docs pages.
- [Nextra AI Chatbot](https://chattybox.ai/nextra-ai-chatbot/): Embed an AI chatbot in Nextra docs that answers from indexed pages with citations.
- [Starlight AI Chatbot](https://chattybox.ai/starlight-ai-chatbot/): Give Astro Starlight documentation a grounded AI chatbot with simple widget installation.
- [ReadMe AI Chatbot](https://chattybox.ai/readme-ai-chatbot/): Add an AI chatbot to ReadMe documentation that answers from published guides, references, and tutorials.
- [Read the Docs AI Chatbot](https://chattybox.ai/readthedocs-ai-chatbot/): Create a source-cited AI chatbot for Read the Docs projects without changing documentation hosting.
- [Hugo AI Chatbot](https://chattybox.ai/hugo-ai-chatbot/): Add a grounded AI chatbot to Hugo sites and documentation using indexed public pages.
- [Confluence AI Chatbot](https://chattybox.ai/confluence-ai-chatbot/): Turn public Confluence spaces and knowledge base content into a source-cited AI chatbot.
- [Notion AI Chatbot](https://chattybox.ai/notion-ai-chatbot/): Create an AI chatbot for public Notion pages that answers from indexed workspace content.
- [Zendesk Guide AI Chatbot](https://chattybox.ai/zendesk-guide-ai-chatbot/): Add a grounded AI chatbot to Zendesk Guide articles with source citations back to help content.
- [Intercom Articles AI Chatbot](https://chattybox.ai/intercom-articles-ai-chatbot/): Create a source-cited AI chatbot for Intercom Articles without moving help center content.
- [WordPress AI Chatbot](https://chattybox.ai/wordpress-ai-chatbot/): Add a ChattyBox AI chatbot to WordPress pages, posts, docs, and knowledge base articles.
- [WordPress Chatbot Plugin](https://chattybox.ai/wordpress-chatbot-plugin/): Install the ChattyBox WordPress plugin and add a source-cited chatbot without editing your theme.
- [Drupal Chatbot Module](https://chattybox.ai/drupal-chatbot-plugin/): Install the ChattyBox Drupal module with Composer and add a source-cited chatbot without editing theme templates.
- [RAG Chatbot for Website](https://chattybox.ai/rag-chatbot-for-website/): Use retrieval-augmented generation to answer website questions from indexed source content.
- [AI Chatbot with Source Citations](https://chattybox.ai/ai-chatbot-with-source-citations/): Show visitors cited source pages for each AI answer so they can verify and keep reading.
- [Measure AI Support Ticket-Reduction Potential](https://chattybox.ai/reduce-support-tickets-with-ai-chatbot/): Measure repeat-question coverage, cited-answer quality, fallbacks, and support outcomes before making ticket-reduction claims.
- [Supported Languages](https://chattybox.ai/supported-languages/): See the languages ChattyBox supports for visitor-facing AI chatbot conversations.
- [Chatbot for API Documentation](https://chattybox.ai/chatbot-for-api-documentation/): Help developers find API answers from docs, guides, references, and troubleshooting content.
- [Knowledge Base and Help Center Chatbot](https://chattybox.ai/chatbot-for-knowledge-base/): Help visitors discover public knowledge base and help center articles with source-cited answers, without moving or replacing your content.
- [Alternatives and Comparisons](https://chattybox.ai/alternatives/): Compare ChattyBox with AI documentation chatbot alternatives.
- [Intercom Alternative for Documentation](https://chattybox.ai/intercom-alternative-for-docs/): Compare ChattyBox with Intercom for documentation-backed AI support and source-cited answers.
- [Zendesk Alternative for Documentation](https://chattybox.ai/zendesk-alternative-for-documentation/): Compare ChattyBox with Zendesk for documentation-focused AI support and self-service answers.
- [Kapa.ai Alternative](https://chattybox.ai/kapa-ai-alternative/): A self-serve, documentation-focused alternative for grounded AI support chat.
- [DocsBot Alternative](https://chattybox.ai/docsbot-alternative/): Compare the direct overlap in grounded documentation support, then separate DocsBot’s broader agents and actions from ChattyBox’s focused public-content answer layer.
- [SiteGPT Alternative](https://chattybox.ai/sitegpt-alternative/): Compare the shared website-answer use case without treating ChattyBox as a replacement for SiteGPT’s broader customer-service workflows.
- [Chatbase Alternative for Docs](https://chattybox.ai/chatbase-alternative-for-docs/): A Chatbase alternative for documentation sites that need citations and no-hallucination behavior.
- [Inkeep Alternative](https://chattybox.ai/inkeep-alternative/): Compare the shared public-documentation answer use case without treating ChattyBox as a replacement for Inkeep’s enterprise CX and operations agents.
- [Mendable Alternative](https://chattybox.ai/mendable-alternative/): A Mendable alternative for source-cited AI documentation search and support.
- [CustomGPT Alternative](https://chattybox.ai/customgpt-alternative/): A CustomGPT alternative for website documentation chat with one-script installation.