Next.js β popup widget (App Router & Pages Router)
Install the Pivra popup on a Next.js site using next/script, a small client component, and your chatbot ID from the dashboard.
Updated 19 Apr 2026
Before you start
In the Pivra dashboard open Install chatbot and choose Next.js (or Popup) to copy the snippet for your chatbot. You need:
- Chatbot ID β shown on the Install screen
- Public API key (optional) β only if you enabled keyed access for embeds
The default embed host is https://embed.pivra.ai unless your workspace uses a custom embed domain (white-label).
Recommended: App Router (Next.js 13+)
1. Client component
Create components/pivra-chat.tsx. The dashboard Install β Next.js tab generates the same pattern with your real chatbotId:
'use client';
import Script from 'next/script';
const EMBED_HOST = process.env.NEXT_PUBLIC_EMBED_URL ?? 'https://embed.pivra.ai';
export function PivraChat({
chatbotId,
publicKey,
}: {
chatbotId: string;
publicKey?: string;
}) {
const keyPart = publicKey ? `,apiKey:'${publicKey}'` : '';
return (
<>
<script
dangerouslySetInnerHTML={{
__html: `window.AIchatConfig={chatbotId:'${chatbotId}'${keyPart}};`,
}}
/>
<Script src={`${EMBED_HOST}/popup.js`} strategy="lazyOnload" />
</>
);
}
You can pass chatbotId from env vars (below) so staging and production use different bots without code changes.
2. Add to app/layout.tsx
Mount the widget once for the whole site so the script is not loaded twice:
import { PivraChat } from '@/components/pivra-chat';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<PivraChat
chatbotId={process.env.NEXT_PUBLIC_PIVRA_CHATBOT_ID!}
publicKey={process.env.NEXT_PUBLIC_PIVRA_PUBLIC_KEY}
/>
</body>
</html>
);
}
To show chat only on certain routes, render <PivraChat /> from those layouts or pages instead of the root layout β still only one instance per page tree that wraps the visitor.
3. Environment variables
In .env.local:
NEXT_PUBLIC_EMBED_URL=https://embed.pivra.ai
NEXT_PUBLIC_PIVRA_CHATBOT_ID=your-id-from-dashboard
# NEXT_PUBLIC_PIVRA_PUBLIC_KEY=... # optional, if you use a public key
For local development against a self-hosted embed server, set NEXT_PUBLIC_EMBED_URL to that origin (for example http://localhost:3003).
Why next/script and a client component
- One load β avoids duplicate popups if the layout re-renders.
lazyOnloadβ loads after the page becomes interactive so it does not block first paint.- Config before script β
window.AIchatConfigmust exist beforepopup.jsruns; the inline<script>tag above ensures order.
Pages Router
Use the same PivraChat component in pages/_app.tsx:
import type { AppProps } from 'next/app';
import { PivraChat } from '../components/pivra-chat';
export default function MyApp({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
<PivraChat chatbotId={process.env.NEXT_PUBLIC_PIVRA_CHATBOT_ID!} />
</>
);
}
Behaviour and troubleshooting
- Launcher β fixed control (usually bottom-right) to open chat.
- Panel β opens over your site; closing returns the launcher.
- Two widgets β search the repo for duplicate
popup.jsscript tags or multipleAIchatConfigblocks. Only one pair should run per document.
Related
- Embed your chatbot on any website β WordPress, Shopify, Webflow, raw HTML, iframe, and direct link.
Was this helpful?
If you have questions or suggestions, email us at support@pivra.ai .