Next.js & React SPA integration

Install the FlowConsent banner in a Next.js app (App Router or Pages Router) and enable SPA Mode so consent is re-checked on every client-side navigation.

The FlowConsent banner is a single self-contained <script> — the same snippet works on Next.js, Nuxt, SvelteKit, and any custom-code app, exactly like it does on Webflow, Framer, or WordPress. There is one extra step for single-page apps: enable SPA Mode so consent is re-checked when the user navigates client-side.

Why a SPA needs one extra step

On a classic multi-page site, every navigation is a full page reload, so the banner re-runs and re-blocks tracking scripts on each page. A Single Page Application (Next.js, React, Vue…) navigates with history.pushStateno page reload — so without SPA Mode, scripts injected after the first page would not be re-blocked on subsequent routes.

SPA Mode hooks pushState, replaceState, and popstate to re-verify consent on every client-side navigation.

Step 1 — Add the script

The banner already ships Google Consent Mode v2 defaults inside the bundle, so the snippet stays minimal: just load the script as early as possible.

App Router (app/layout.tsx)

import Script from 'next/script'
 
export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        {/* FlowConsent CMP */}
        <Script
          src="https://YOUR-WORKSPACE.consent.flowconsent.com/cookie-manager.js?code=YOUR_LICENSE_CODE"
          strategy="beforeInteractive"
        />
      </body>
    </html>
  )
}

strategy="beforeInteractive" makes Next.js load the script before hydration, so prior blocking is in place before any tracking fires.

Pages Router (pages/_document.tsx)

import { Html, Head, Main, NextScript } from 'next/document'
 
export default function Document() {
  return (
    <Html>
      <Head>
        {/* FlowConsent CMP — keep it first in <Head> */}
        <script src="https://YOUR-WORKSPACE.consent.flowconsent.com/cookie-manager.js?code=YOUR_LICENSE_CODE" />
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

You'll find your exact snippet (with your deployment URL and license code) in Builder → Deployment → Integration, where a Next.js tab generates this code for you.

Step 2 — Enable SPA Mode

In the Builder, open the Settings tab and turn on SPA Mode. Redeploy your banner so the change ships.

With SPA Mode on, FlowConsent will:

  • Intercept history.pushState and history.replaceState
  • Listen for popstate events
  • Re-block uncovered tracking scripts on each navigation
  • Emit a flowconsent:navigation event you can listen to

Step 3 — Let FlowConsent manage tracking scripts

Do not load tracking scripts (Google Analytics, Meta Pixel…) with next/script. Instead, declare them in Builder → Services and let FlowConsent inject them once consent is given.

// Avoid — tracking script outside FlowConsent's control
<Script src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX" strategy="afterInteractive" />
 
// Prefer — configure Google Analytics in Builder → Services

FlowConsent dispatches events you can subscribe to:

import { useEffect } from 'react'
 
export function useConsentListener() {
  useEffect(() => {
    const onConsent = (event) => {
      const { preferences } = event.detail
      if (preferences?.analytics) {
        // analytics consent granted — initialise your own analytics
      }
    }
    window.addEventListener('flowconsent:consent', onConsent)
    return () => window.removeEventListener('flowconsent:consent', onConsent)
  }, [])
}

Verification checklist

  • Script is in app/layout.tsx (App Router) or pages/_document.tsx (Pages Router)
  • App Router uses strategy="beforeInteractive"
  • SPA Mode is enabled in the Builder and the banner is redeployed
  • No next/script for tracking scripts — they're configured in Services
  • Banner appears on first load
  • No tracking requests in the Network tab before clicking Accept
  • Consent persists across client-side navigations