Add a Source-Cited AI Chatbot to Docusaurus 3
Docusaurus behaves like a single-page application after the first page load. A widget integration that only works on the initial document, or that appends a second loader on every route change, is not production-ready. This guide uses a stable script identity and a theme root that remains mounted across documentation routes.
Author and technical reviewer: Michael Fisher, ChattyBox maintainer. Published and technically checked July 10, 2026 against repository revision 3b0f4d5. The evidence is the runnable example and the repeatable checks below; this is an implementation tutorial, not a performance or accuracy benchmark.
1. Add the Root theme component
Create src/theme/Root.tsx in your Docusaurus site:
import React, { useEffect, type ReactNode } from 'react';
const WIDGET_ID = 'chattybox-widget';
export default function Root({ children }: { children: ReactNode }) {
useEffect(() => {
if (document.getElementById(WIDGET_ID)) return;
const script = document.createElement('script');
script.id = WIDGET_ID;
script.src = 'https://chattybox.ai/widget.js';
script.async = true;
script.dataset.apiKey = 'YOUR_API_KEY';
script.dataset.apiUrl = 'YOUR_CHAT_API_URL';
script.dataset.chattyboxWidget = 'true';
document.body.appendChild(script);
}, []);
return <>{children}</>;
}
The stable chattybox-widget ID is the important part. React Strict Mode can remount effects during development, and Docusaurus changes routes without replacing the document. The guard makes both cases idempotent.
Use the API URL shown by your ChattyBox project rather than copying an example deployment. See the widget installation reference for the current attributes and the Docusaurus product guide for source-selection and evaluation guidance.
2. Keep the loader mounted
Do not put this script inside an individual docs page or layout that Docusaurus replaces during navigation. The swizzled Root component wraps the application for its lifetime, so the widget remains available as visitors move between guides and references.
If your site already has src/theme/Root.tsx, merge the effect into the existing component rather than replacing authentication, analytics, or other providers.
3. Account for Content Security Policy
A restrictive policy needs to allow:
https://chattybox.aiinscript-srcfor the widget loader.- Your configured chat API origin in
connect-src. https://fonts.googleapis.cominstyle-srcandhttps://fonts.gstatic.cominfont-srcif the widget font is not already available.- Inline component styles in
style-srcfor the current widget build.
Start from your existing policy and add only the origins you actually use. Do not replace a restrictive policy with a broad wildcard.
4. Reproduce the integration checks
The complete sample lives in examples/docusaurus-chattybox. From that directory:
bun install
bun run start
Then verify:
- Open two different docs routes without a full browser refresh.
- Run
document.querySelectorAll('#chattybox-widget').lengthafter each navigation. It must remain1. - Ask a question answered by an indexed page and confirm the response links to that page.
- Ask an unsupported question and confirm the assistant falls back instead of inventing a source.
- Test the launcher at a narrow mobile viewport and check that it does not cover navigation or pagination controls.
The script-count check proves duplicate prevention. It does not prove retrieval quality. Use a representative question set and the scraping guide to validate source coverage before launch.
What to monitor after launch
Record unresolved questions, incorrect citations, stale source pages, and routes where the launcher obscures site controls. Re-test after Docusaurus theme upgrades because changes to navigation and content layout can affect placement even when the loader remains correct.
For a broader rollout sequence, use the documentation chatbot implementation checklist and launch checklist.
