AnveVoice

Add a Voice AI Agent to Next.js (next/script Guide)

Add the AnveVoice voice agent to Next.js with next/script in the App Router root layout or Pages Router _app, with strategy choice and load-once behavior.

How to add AnveVoice to a Next.js app

Import Script from next/script and render it once in your root layout (App Router) or in pages/_app (Pages Router). Next.js loads the script a single time across client-side navigation. The default afterInteractive strategy suits a voice widget. Steps checked against the official documentation on 2026-10-14.

At a glance

  • Where the code goes: app/layout.tsx (App Router) or pages/_app.tsx (Pages Router)
  • Component: Script from next/script, strategy afterInteractive (default) or lazyOnload
  • Coding needed: A few lines of JSX; no package to install
  • Time: About 5 minutes including a test build

Before you start

Create the bot at app.anvevoice.app (the Free plan is $0, no card) and copy the embed ID. Do not paste the raw HTML script element into a layout: in Next.js the idiomatic route is the built-in Script component from next/script, which controls when the file loads relative to hydration. Check which router you use. A project with an app/ directory and layout.tsx uses the App Router; a project with pages/_app.tsx uses the Pages Router. If you have both, install the tag in each router's top-level file. The code below targets the current Next.js documentation, which describes version 16.

App Router: the root layout

The Next.js scripts guide says to load a third-party script for all routes by including it in your root layout, and that Next.js ensures it only loads once even when a visitor moves between pages. The Script component works inside a Server Component layout, so you do not need a use client directive unless you add onLoad, onReady or onError handlers.

  • 1. Open the root layout — Edit app/layout.tsx (or app/layout.js). It is the file that renders the html and body elements.
  • 2. Add the Script component — Import Script from next/script and render it inside body, after children, as in the example. Replace YOUR_EMBED_ID with your own value. Code: import Script from "next/script"; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body> {children} <Script src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID" strategy="afterInteractive" /> </body> </html> ); }
  • 3. Restart and test — Run next dev or a production build. The microphone button should appear bottom-right on every route.

Pages Router: _app

For the Pages Router, Next.js documents the same idea in the custom App component: include the Script next to the page component so it loads for any route that is accessed.

  • 1. Open pages/_app.tsx — Create the file if you do not have one; Next.js uses it to wrap every page.
  • 2. Render the Script beside the page — Add the Script after Component so the page content renders first. Code: import type { AppProps } from "next/app"; import Script from "next/script"; export default function MyApp({ Component, pageProps }: AppProps) { return ( <> <Component {...pageProps} /> <Script src="https://anvevoice.app/embed.js?embedId=YOUR_EMBED_ID" strategy="afterInteractive" /> </> ); }

Choosing a strategy

Next.js offers four loading strategies. afterInteractive is the default and loads early but after some hydration; the docs list tag managers and analytics as typical uses. lazyOnload waits for browser idle time and the docs name chat support plugins as an example, which is the category a voice widget sits in. Pick afterInteractive if you want the button visible as soon as the page is interactive, or lazyOnload if you prefer to protect your Lighthouse score and accept a short delay. Avoid beforeInteractive. It is meant for critical scripts such as bot detectors and cookie consent managers, and the docs say it injects into the head and must sit in a root layout. The worker strategy is experimental and, per the Next.js reference, does not work with the App Router.

Scope and removal

The recommendation in the Next.js docs is to include third-party scripts only in the pages or layouts that need them. To show the agent on marketing pages only, put the Script in a route-group layout such as app/(marketing)/layout.tsx instead of the root layout. To remove it later, delete the component and redeploy; no other cleanup is required.

Check that it works

  • 1. Build and run in production mode — Run next build and next start so you test what visitors get, not the development server.
  • 2. Open the site and find the button — A round microphone button appears bottom-right. Click it, allow microphone access and ask a question.
  • 3. Navigate between pages — Move through a few links. The button should stay in place without reloading, since the script loads once.

Common problems

  • Nothing loads: confirm the Script sits inside the root layout that wraps your pages, not inside a nested layout for a different route group.
  • Content Security Policy errors: if you send a CSP header from middleware or next.config, allow https://anvevoice.app in script-src. The Script component forwards a nonce attribute you pass to it.
  • Microphone blocked: a Permissions-Policy header that sets microphone to empty blocks the browser prompt. Allow microphone for self.
  • Hydration warnings: they usually come from other code. The Script component renders no visible markup of its own.

Sources

  • Next.js Docs: How to load and optimize scripts (App Router) (https://nextjs.org/docs/app/guides/scripts) — checked 2026-10-14
  • Next.js Docs: Script component API reference (https://nextjs.org/docs/app/api-reference/components/script) — checked 2026-10-14
  • Next.js Docs: Scripts (Pages Router) (https://nextjs.org/docs/pages/guides/scripts) — checked 2026-10-14

Related

  • How to add AnveVoice to a React app
  • How to add AnveVoice to a site hosted on Netlify
  • How to add AnveVoice to a React Router app
  • How to add AnveVoice using Google Tag Manager

Try AnveVoice on your site

Free plan: $0, 50,000 tokens a month, no card. Get your embed ID in the dashboard, then paste one tag.