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.
Before You Customize
Create the project, index its content, and verify representative answers in Test chatbot before spending time on presentation. See Getting Started for the complete sequence.
Configure the Hosted Widget
- Go to your Dashboard and select your project.
- Navigate to Customize → Appearance to edit the widget's appearance, branding, and Language settings.
- Check the relevant autosave status; correct validation errors or retry failed saves before testing the installed widget.
Installation code and public keys are managed under Install. When you are ready to install:
- Open Install → Keys & domains to inspect or create a public browser key and check its origin settings.
- Under Install → Website installation, select a suitable key and copy the generated snippet. A key created without restrictions works across origins; a key prepared for a website can already be restricted to that site's origin. Check the selected key before using staging or localhost.
- Optionally enable exact origin restrictions for defense in depth; these do not authenticate visitors.
- Follow the Installation Guides for your platform.
<script
src="https://chattybox.ai/widget.js"
data-api-key="YOUR_API_KEY"
data-api-url="https://adorable-woodpecker-629.convex.site/chat"
async
></script>
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
-
Accent Color - Pick your brand's primary color. This affects the launcher, key highlights, and user messages.
-
Position - Choose where the widget appears on the screen.
-
Header Title - Set the title shown at the top of the chat window.
-
Welcome Message - Customize the first message visitors see when they open the chat.
-
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. The Icon Size control appears when you choose an image URL or upload an image. Uploaded icons must be at most 512 KiB and use an accepted image MIME type (PNG, JPEG, WebP, SVG, GIF, or ICO). The current-source hosted v16 loader uses iconSize to size the launcher and icon; verify the deployed loader before relying on that behavior.
Confirm the relevant autosave status, then reload the installed page to verify changes. 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; current-source hosted v16 uses size for the launcher and icon |
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 |
In the current-source hosted loader, a failed or invalid configuration fetch leaves the widget unavailable rather than rendering a fallback UI. A successful config response with enabled: false also prevents rendering; the chat API rejects a disabled widget with HTTP 403, including SDK requests. Verify the deployed loader version before relying on current-source behavior.
The current-source hosted v16 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 v16 separately retries its startup config and translation GETs for retryable failures. Chat messages 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. Verify the deployed loader before relying on current-source behavior.
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-keyidentifies the public widget key.data-api-urltells the widget where to send requests. In production this is a stablehttps://...convex.site/chatURL from your dashboard.data-localerequests a specific widget UI language if project overrides are allowed. The current-source loader also observes changes to this attribute.data-coloranddata-positionoverride 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.
For a new message, the current-source hosted widget attempts to include the current HTTP(S) page's origin and path for Popular Triggers analytics, without checking whether the page is public. Invalid or over-length context is omitted; retries retain the original request's context. It removes query strings, fragments, and credentials, but paths can contain sensitive identifiers. 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. Current-source hosted v16 creates an idempotency key per message and makes at most 10 automatic transport attempts for network errors, interrupted successful response bodies, HTTP 429, HTTP 5xx, and 409 responses with a readable Retry-After header. It schedules no further retry if the delay would exceed the 30-second budget; this is not a hard timeout for an in-flight request. Browser CORS can hide Retry-After. This retry behavior is not provided by headless sendMessage(); the hosted 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; stored server messages may remain. Sources are deduplicated and limited to three displayed entries; fallback answers can have no sources. Verify the deployed loader version before relying on current-source behavior.
If the widget does not appear after installation, see Troubleshooting.
For platform-specific examples, start with Docusaurus, MkDocs, VitePress, WordPress, or GitBook.
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):
.chattybox-widget {
display: none;
}
CSS hiding does not stop initialization, API requests, or error reporting and is not a consent or privacy control. The loader does not make a consent decision: gate script insertion until required consent and prevent reinsertion on revocation or excluded routes. For client-side route transitions or consent revocation, current-source hosted widget.js v16 provides window.ChattyBox.destroy(). SDK 0.1.4 mount handles are reference-counted: remove every matching handle to signal final teardown. Verify that the deployed loader supports teardown; removing only a script tag is insufficient. Teardown removes owned UI/styles and cancels pending work, but cannot undo requests already processed by the server.
Browser Controls
In current-source hosted v16, window.ChattyBox exists during startup with status: 'loading' and destroy(). After successful initialization, check window.ChattyBox?.status === 'ready' before calling open(), close(), toggle(), or sendMessage(text). 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) returns a UI-operation promise, not an answer promise; sends while another message is pending are ignored. This global is distinct from the SDK constructors on window.ChattyboxSDK. Verify the deployed loader version before relying on this behavior.
Site-controlled day/night themes (current source)
The current-source config-as-code workflow supports optional widget.theme.light and widget.theme.dark palettes. Each accepts primaryColor, backgroundColor, and textColor as six-digit hex colors; omitted colors inherit the base widget.theme. Existing single-theme configurations continue to work unchanged. This requires the current-source CLI/backend and hosted loader v16; published CLI/config 0.3.1 does not accept these new fields.
Set data-theme="light" or data-theme="dark" on the loader script before it runs to select the initial palette. Then connect your site's toggle to the browser API:
window.ChattyBox?.setTheme('light');
window.ChattyBox?.setTheme('dark');
window.ChattyBox?.setTheme(null); // Restore the configured base appearance.
The widget updates its existing styles without resetting messages, sources, draft text, or a pending request. Theme selection cannot change widget enablement or remove attribution. Your site owns preference persistence and OS-theme behavior; the widget only selects the configured palette.
Custom Integrations
Need a more tailored setup than the hosted widget? Build your own interface with the JavaScript SDK, or contact support@chattybox.ai for architecture help.
Multilingual Support
The current-source ChattyBox widget resolves a UI locale according to the project's fixed or auto mode. It observes changes to <html lang> and the loader script's data-locale, updating labels in place without resetting the conversation, draft, or pending retry. Navigation alone does not select a language; update one of those attributes when appropriate. Dashboard setting changes still require reinitialization.
Officially Supported Languages
The widget has translation catalogs for 14 languages. All current catalogs use left-to-right layout. Project-authored text and AI-generated answers are not translated by the UI catalogs.
| 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 current-source hosted loader sends its resolved UI locale with chat requests. The backend detects language from the question and attempts language-aware retrieval and generation. A recognized question-language signal takes precedence over UI locale for product-owned fallback messages; if detection is inconclusive or relies only on the ASCII English heuristic, UI locale can select their language. It does not translate project-authored fallback text or change AI-generated output. 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:
- Allowed script override - A supported
data-localewins only whenallowLocaleOverrideis not false, even in fixed mode. - Fixed mode - Without a supported allowed override, use
defaultLocaleand ignore page/browser language. - Auto mode - Try page
<html lang>,navigator.language, each entry ofnavigator.languages, legacyuserLanguage, thendefaultLocale, selecting the first supported language. - Normalization - Matching ignores case and recognized regional values such as
fr-CAreduce to their supported base language. Unsupported candidates are skipped; if none is supported, use English. Defaults are auto mode, English, and script overrides allowed.
Custom header titles and welcome messages are displayed verbatim, not translated automatically. Current-source default titles and welcome messages use localized labels. 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 a supported data-locale to the loader script:
<script
src="https://chattybox.ai/widget.js"
data-api-key="YOUR_API_KEY"
data-locale="de"
data-api-url="https://adorable-woodpecker-629.convex.site/chat"
async
></script>
:::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 - Uses the configured default language unless an allowed script override is present
- Allow script override - Enable/disable the
data-localeattribute override
Access these settings in your Dashboard → Project → Customize → Appearance → Language. Confirm the language autosave status and resolve errors before testing.
Content Language Matching
For the best multilingual experience, index useful content in the languages your visitors ask about:
- Scrape all language versions of your documentation using the
sitemap.xmlfile - The scraper attempts to detect page language; inspect extracted content and citations rather than assuming detection is always correct
- 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
<html lang="de">(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
- Set
<html lang>on your pages - Helps with accessibility and widget detection - Test with
data-localeduring development - Verify each language renders correctly - Scrape all language versions - Use
sitemap.xmlfor comprehensive multilingual indexing - Review real questions - Inspect conversations for language-specific content gaps; the dashboard does not currently expose a widget-locale distribution report