Next.js App & Pages Router

Initialize consent in the root document/layout before Google tags.

Content and code last checked 2026-10-06 by ConsentEase product documentation. This is a review of the written content and code, not a test on a live third-party platform.

Choose the correct router

Next.js requires beforeInteractive scripts in the root app layout for App Router, or pages/_document for Pages Router. A nested page/layout is not the universal installation point. Review Next.js placement rules.

App Router

In app/layout.tsx, use next/script for immediate defaults in the root layout. Extract the inline JavaScript from the first block of the canonical snippet without its script tags, then use the public loader URL:

import Script from "next/script";
import type { ReactNode } from "react";

const consentDefaultsJavaScript = `window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
  'ad_storage': 'denied',
  'ad_user_data': 'denied',
  'ad_personalization': 'denied',
  'analytics_storage': 'denied',
  'functionality_storage': 'denied',
  'personalization_storage': 'denied',
  'security_storage': 'granted',
  'wait_for_update': 500
});
gtag('set', 'ads_data_redaction', true);
gtag('set', 'url_passthrough', true);
window.uetq = window.uetq || [];
window.uetq.push('consent', 'default', {'ad_storage': 'denied'});`;

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Script id="consentease-defaults" strategy="beforeInteractive">
          {consentDefaultsJavaScript}
        </Script>
        <Script id="consentease-banner" strategy="afterInteractive"
          src="https://consentease.io/api/consent/YOUR_PUBLIC_ID/script.js" />
        {children}
      </body>
    </html>
  );
}

Keep all consent signals from this shared default block. Replace YOUR_PUBLIC_ID with the correct site's ID.

Pages Router

Place default initialization in pages/_document.tsx:

import { Html, Head, Main, NextScript } from "next/document";
import Script from "next/script";

const consentDefaultsJavaScript = `window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
  'ad_storage': 'denied',
  'ad_user_data': 'denied',
  'ad_personalization': 'denied',
  'analytics_storage': 'denied',
  'functionality_storage': 'denied',
  'personalization_storage': 'denied',
  'security_storage': 'granted',
  'wait_for_update': 500
});
gtag('set', 'ads_data_redaction', true);
gtag('set', 'url_passthrough', true);
window.uetq = window.uetq || [];
window.uetq.push('consent', 'default', {'ad_storage': 'denied'});`;

export default function Document() {
  return (
    <Html lang="en">
      <Head>
        <Script id="consentease-defaults" strategy="beforeInteractive">
          {consentDefaultsJavaScript}
        </Script>
      </Head>
      <body><Main /><NextScript /></body>
    </Html>
  );
}

Load the banner once in pages/_app.tsx, not on each page:

import Script from "next/script";
import type { AppProps } from "next/app";

export default function App({ Component, pageProps }: AppProps) {
  return <>
    <Script id="consentease-banner" strategy="afterInteractive"
      src="https://consentease.io/api/consent/YOUR_PUBLIC_ID/script.js" />
    <Component {...pageProps} />
  </>;
}

Ordering and verification

Use the actual website public ID. Apply the site's CSP nonce/hash handling. Do not use lazyOnload for consent defaults. Google scripts must not run before their defaults; account for any framework-managed Google integration.

Test fresh initial loads, server-rendered pages, hydration and client transitions. The sample is not evidence that an arbitrary Next.js release/deployment passes acceptance checks.

Verify the published site

Use separate fresh browser contexts for no choice, accept, reject and custom preferences. Check tag consent requirements, network traffic, storage and reopening preferences. Test relevant routes and mobile layouts. A theme installation does not prove coverage of checkout, embedded frames or hosted third-party pages.

Related articles

Still need help?

Contact the ConsentEase team and include the website and steps you tried.