Skip to content

Install the AI chat widget

The loader is about 6 KB gzipped. It renders a chat button and lazy-loads the chat when the visitor hovers or clicks the button, or when the browser is idle. The widget runs in a Shadow DOM, so your CSS and the widget’s CSS don’t affect each other.

Find your bot id in Dashboard → Bot → Install.

Paste before </body>:

<script src="https://w.feedbotai.com/v1/feedbot.js" data-bot-id="YOUR_BOT_ID" async></script>
  1. Create a new tag of type Custom HTML.
  2. Paste the snippet above and trigger it on All Pages.
  3. Submit and publish the container.

Bot → Install → Let your coding agent install it gives you step-by-step Markdown instructions for this bot. Copy or download them and paste into Claude Code, Codex or Cursor. The identity secret is never included.

app/layout.tsx
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://w.feedbotai.com/v1/feedbot.js"
data-bot-id="YOUR_BOT_ID"
strategy="lazyOnload"
/>
</body>
</html>
);
}

To pass the signed-in user, see Identify users.

@feedbotai/react wraps the same loader in a component and a hook.

Terminal window
pnpm add @feedbotai/react
app/layout.tsx
import { FeedbotWidget } from "@feedbotai/react";
<FeedbotWidget
botId={process.env.NEXT_PUBLIC_FEEDBOT_BOT_ID!}
user={user ? { id: user.id, email: user.email, name: user.name } : null}
userHash={userHash}
metadata={user ? { plan: user.plan } : undefined}
/>

Compute userHash on the server, see Identify users. Setting user to null calls reset, so the widget forgets the visitor on logout.

Props: botId (required), user (id, email, name, phone), userHash, metadata, open (controlled), position, primaryColor, mode (floating or inline), container, apiUrl, scriptUrl, and the callbacks onReady, onOpen, onClose, onMessage. position, primaryColor, mode, container and apiUrl are read once, when the script loads.

The useFeedbot() hook returns open, close, toggle, sendMessage, identify, setMetadata, reset and registerAction:

const { sendMessage } = useFeedbot();
<button onClick={() => sendMessage("How do I upgrade?")}>Ask about upgrading</button>

Appearance comes from the dashboard. You can override it with data-* attributes on the script tag:

Attribute Values Description
data-bot-id uuid Required. Your bot id.
data-open "true" Open the chat on page load.
data-position bottom-right, bottom-left Button position. Default: the dashboard setting.
data-primary-color CSS color Brand color, e.g. #1d4ed8. Default: the dashboard setting.
data-lang en, ru, de, fr, es, pt Language of the widget interface. Regional codes like pt-BR work too. See Language.
data-mode inline Render inside a container instead of a floating button.
data-container CSS selector Container for inline mode. Default: #feedbot.
data-api-url URL Custom API base URL (self-hosting and testing).

The widget interface language is picked in this order:

  1. data-lang on the script tag;
  2. the bot language set in the dashboard;
  3. the visitor’s browser language, when the bot language is Auto or not supported;
  4. English.

This only sets the buttons and labels. The bot answers in the language the visitor writes in.

<div id="chat" style="height: 560px"></div>
<script
src="https://w.feedbotai.com/v1/feedbot.js"
data-bot-id="YOUR_BOT_ID"
data-mode="inline"
data-container="#chat"
async
></script>

The loader waits up to 10 seconds for the container to appear, so it also works when the container is rendered by your framework after the script loads. On screens narrower than 640px the floating chat opens full screen.

In Bot → Install → Allowed domains, list the domains where the widget may run. Subdomains of a listed domain are allowed too. Requests from other origins are rejected, so nobody can use your bot and quota on their site. If the list is empty, the widget runs anywhere.

Widgets installed with feedbot-0.0.x.js and FeedbotWidget.renderApp(...) keep working, including links like https://w.feedbotai.com/?projectId=…. You don’t need to change anything, but the new loader adds streaming, buttons, identify and the JS API.