Install the chat widget in Next.js and React
Add the intoCHAT widget to a Next.js app with next/script in the root layout, or to a React app with index.html or a useEffect hook, without duplicate bubbles.
The intoCHAT widget is a plain script, not a React component. It reads your agent ID from its data-chatbot-id attribute and adds the launcher to document.body, outside your React tree, so re-renders and route changes don't touch it.
Next.js App Router
Load the script once in the root layout with the Script component from next/script:
import Script from 'next/script'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://www.intochat.ai/api/embed.js"
data-chatbot-id="YOUR_AGENT_ID"
strategy="lazyOnload"
/>
</body>
</html>
)
}
- The data attribute. Next.js forwards extra attributes such as
data-chatbot-idto the final script element, which is where the widget looks for it. - The strategy.
lazyOnloadloads the widget during browser idle time, after the page's other resources.afterInteractive, the default, loads it earlier, so the launcher appears sooner. Both work. - Not
beforeInteractive. That strategy is for scripts the page needs before it becomes interactive. The chat widget isn't one, and loading it that early only competes with your own code. - Server Components. The layout can stay a Server Component, because this
Scripthas no event handlers.
Next.js loads the script only once, even as visitors move between routes. In the Pages Router, add the same Script to pages/_app instead.
To show the chat under some routes only, put the Script in a nested layout. Once loaded, the launcher stays on the page after client-side navigation to other routes, until the next full page load.
React with Vite or Create React App
Choose one of two options, not both. The embed script ignores a second copy for the same agent, so using both only loads it twice.
Option 1: index.html. Paste the script tag from the Share tab just before </body> in index.html: in the project root for Vite, or in public/index.html for Create React App.
Option 2: a component. Use this if you want to decide in code whether the widget loads, for example only in production:
import { useEffect } from 'react'
export default function IntoChatWidget() {
useEffect(() => {
// Load the widget only once, even when StrictMode runs effects twice
if (document.getElementById('intochat-embed')) return
const script = document.createElement('script')
script.id = 'intochat-embed'
script.src = 'https://www.intochat.ai/api/embed.js'
script.setAttribute('data-chatbot-id', 'YOUR_AGENT_ID')
document.body.appendChild(script)
}, [])
return null
}
Render IntoChatWidget once, in your root component such as App. Set the attribute before the element is added to the page, as above.
StrictMode and duplicate launchers
In development, React StrictMode runs effects twice. The id check at the top of the effect keeps the script from being added twice. Even without it you wouldn't get a second launcher, because the embed script adds only one per agent and page. Don't remove the script in a cleanup function: removing it doesn't remove the launcher, which stays in document.body until the next full page load.
Client-side actions
The agent can call functions in your app during a chat, for example to read state or open a form. Register them with window.IntoChatActions.register. See Client-side actions.
Content Security Policy
Allow https://www.intochat.ai in script-src, connect-src and frame-src. If your policy uses nonces, pass the nonce to the Script component. Next.js forwards it like the data attribute.
Check it
Open any route. The launcher appears in the bottom corner and stays as you navigate. Two launchers mean two snippets with different agent IDs are loaded. No launcher and "Chatbot not found." in the console means the agent ID is wrong. See Troubleshooting for other cases, and the Next.js and React guides for more background.