βš™οΈInstallation

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.AIchatConfig must exist before popup.js runs; 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.js script tags or multiple AIchatConfig blocks. Only one pair should run per document.

Related

Was this helpful?

If you have questions or suggestions, email us at support@pivra.ai .