← Back to Blog
nextjsgdprprivacyinstallationdeveloper guide

Privacy-First Analytics for Next.js: GDPR Compliant, No Cookie Banner

Add GDPR-compliant analytics to Next.js with no cookies or consent banner. 3KB script, zero Lighthouse impact.

EngageTrack Team··8 min read

Adding GDPR-compliant analytics to a Next.js application should not require a cookie consent banner, a 45KB tracking script, or a weekend of configuration. Next.js developers care about performance and user experience — GA4 undermines both.

EngageTrack provides nextjs analytics gdpr compliance out of the box: a 3KB cookieless script, zero Lighthouse performance impact, EU data hosting, and no consent banner required. This guide covers installation for App Router and Pages Router, proxy setup to bypass ad blockers, revenue attribution integration, and custom event tracking.

Why Is GA4 a Poor Fit for Next.js Applications?

Next.js applications are performance-optimized by default. The framework provides automatic code splitting, image optimization, font optimization, and static generation. Developers choose Next.js because they care about Core Web Vitals and user experience.

GA4 undermines that work in three ways:

Script size. GA4's gtag.js payload is 45KB+ gzipped. On a Next.js app where your entire first-load JS bundle might be 80–100KB, GA4 adds 50% overhead to your JavaScript footprint.

Cookies. GA4 sets multiple cookies (_ga, _ga_*, _gid) that persist for up to 2 years. Under GDPR, these require informed consent before being set. That means implementing a cookie consent banner — which adds another JavaScript bundle, another network request, and a UI element that degrades the first-visit experience.

Data transfers. GA4 sends data to Google's servers in the United States by default. Multiple EU data protection authorities have ruled this non-compliant with GDPR. Google's EU data residency options exist but add complexity and do not fully resolve the legal concerns.

EngageTrack avoids all three: 3KB script, zero cookies, EU-hosted in Frankfurt.

How Do You Install EngageTrack in a Next.js App Router Project?

Installation takes one line of code. In your root layout file:

// app/layout.tsx
import Script from "next/script";
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script
          defer
          data-site-id="YOUR_SITE_ID"
          src="https://cdn.engagetrack.net/sdk.js"
          strategy="afterInteractive"
        />
      </body>
    </html>
  );
}

The strategy="afterInteractive" prop tells Next.js to load the script after the page becomes interactive, which means it never blocks rendering or competes with your application code for the main thread.

For full installation details, see the Next.js installation guide.

EngageTrack automatically tracks:

  • Pageviews (including client-side navigations via next/link and router.push)
  • Traffic sources and UTM parameters
  • Outbound link clicks
  • File downloads
  • Scroll depth
  • Form submissions

No additional configuration is needed for these defaults. The script detects history.pushState navigation and fires pageview events on route changes.

Does It Work with Both App Router and Pages Router?

Yes. The script tag approach works identically in both routing modes:

App Router: Add the <Script> component to app/layout.tsx as shown above.

Pages Router: Add the <Script> component to pages/_app.tsx:

// pages/_app.tsx
import Script from "next/script";
import type { AppProps } from "next/app";
 
export default function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <Script
        defer
        data-site-id="YOUR_SITE_ID"
        src="https://cdn.engagetrack.net/sdk.js"
        strategy="afterInteractive"
      />
    </>
  );
}

Both approaches produce the same result: the tracking script loads once, persists across navigations, and tracks route changes automatically.

How Do You Proxy the EngageTrack Script to Bypass Ad Blockers?

Ad blockers block requests to known analytics domains. Since EngageTrack's CDN domain is on some blocklists, proxying the script through your own domain ensures 100% of visitors are tracked.

Next.js makes this straightforward with rewrites in next.config.ts:

// next.config.ts
import type { NextConfig } from "next";
 
const nextConfig: NextConfig = {
  async rewrites() {
    return [
      {
        source: "/stats/sdk.js",
        destination: "https://cdn.engagetrack.net/sdk.js",
      },
      {
        source: "/api/event",
        destination: "https://events.engagetrack.net/api/event",
      },
    ];
  },
};
 
export default nextConfig;

Then update your script tag to use the proxied path:

<Script
  defer
  data-site-id="YOUR_SITE_ID"
  data-api="https://yourdomain.com/api/event"
  src="/stats/sdk.js"
  strategy="afterInteractive"
/>

The script and event data now flow through your own domain. To your visitors' browsers and ad blockers, these look like first-party requests. For complete proxy configuration details, see the Next.js proxy guide.

How Do You Track Custom Events in Client Components?

EngageTrack exposes a global engagetrack object for custom event tracking. In Next.js Client Components:

"use client";
 
export function PricingButton({ plan }: { plan: string }) {
  const handleClick = () => {
    // Track custom event
    window.engagetrack?.track("pricing_click", { plan });
  };
 
  return (
    <button onClick={handleClick}>
      Choose {plan}
    </button>
  );
}

For TypeScript projects, add a type declaration:

// types/engagetrack.d.ts
declare global {
  interface Window {
    engagetrack?: {
      track: (event: string, props?: Record<string, string>) => void;
      identify: (userId: string, traits?: Record<string, string>) => void;
      getVisitorId: () => string;
    };
  }
}
 
export {};

How Do You Set Up Revenue Attribution with Next.js?

If your Next.js app uses Stripe for payments, you can pass EngageTrack's visitor ID into Stripe checkout metadata for revenue attribution:

"use client";
 
async function handleCheckout(priceId: string) {
  const visitorId = window.engagetrack?.getVisitorId();
 
  const response = await fetch("/api/create-checkout", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      priceId,
      engagetrackVisitorId: visitorId,
    }),
  });
 
  const { url } = await response.json();
  window.location.href = url;
}

In your Next.js API route:

// app/api/create-checkout/route.ts
import { NextRequest, NextResponse } from "next/server";
import Stripe from "stripe";
 
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
 
export async function POST(request: NextRequest) {
  const { priceId, engagetrackVisitorId } = await request.json();
 
  const session = await stripe.checkout.sessions.create({
    mode: "subscription",
    line_items: [{ price: priceId, quantity: 1 }],
    success_url: `${process.env.NEXT_PUBLIC_URL}/welcome`,
    cancel_url: `${process.env.NEXT_PUBLIC_URL}/pricing`,
    metadata: {
      engagetrack_visitor_id: engagetrackVisitorId,
    },
  });
 
  return NextResponse.json({ url: session.url });
}

When Stripe sends the webhook to EngageTrack, the visitor ID in the metadata links the payment to the original traffic source.

How Does EngageTrack Compare to Other Next.js Analytics Options?

FeatureEngageTrackGA4Vercel AnalyticsPlausible
Script size (gzipped)3KB45KB+1KB~1KB
CookiesNoneMultiple (2yr)NoneNone
GDPR compliant (no banner)YesNoYesYes
Revenue attributionStripe, LemonSqueezy, Paddle, PolarGoogle Ads onlyNoNo
Conversion funnelsYesYesNoBasic
Client-side nav trackingAuto (pushState)Requires configAutoAuto
Proxy support (ad blocker bypass)Yes (Next.js rewrites)ComplexN/A (first-party)Yes
Lighthouse impactZeroSignificantMinimalMinimal
REST APIFull read/writeReporting APILimitedRead-only
Visitor profilesYesLimitedNoNo
Custom eventsYesYesNo (Web Vitals only)Yes
EU data hostingFrankfurtOptionalEdgeEU
Starting price€5/moFree (with limits)Free tier + $14/mo$9/mo

FAQ

Does EngageTrack track client-side navigation in Next.js?

Yes. EngageTrack detects history.pushState and popstate events automatically. When users navigate via next/link, router.push, or the browser back button, EngageTrack fires a pageview event for each route change. No additional configuration is needed — it works with both App Router and Pages Router out of the box.

Does EngageTrack affect my Lighthouse score?

No. The 3KB script loads with strategy="afterInteractive", which means it executes after the page is interactive. It uses the sendBeacon API for data transmission, which is non-blocking and does not compete with your application for network resources. Lighthouse audits with and without EngageTrack produce identical scores.

Can I use EngageTrack with Next.js middleware for geo-based analytics?

EngageTrack handles geolocation server-side — the tracking script sends events to EngageTrack's EU-hosted API, which resolves the visitor's country and city from the request IP without storing the IP address. You do not need Next.js middleware or edge functions for geolocation. The data appears in your dashboard automatically.

Do I need to configure anything for Next.js static export?

For output: "export" (static HTML), add the script tag directly to your root layout as shown above. The next/script component works in static exports. The only limitation is that the proxy rewrite approach requires a server, so for fully static deployments on a CDN, use the direct CDN URL for the script.

Does it work with Next.js 16 and React 19?

Yes. EngageTrack's tracking script is framework-agnostic — it is vanilla JavaScript that runs in the browser. It is fully compatible with Next.js 16, React 19, and any future versions. The next/script component is simply a convenient way to load it; a plain <script> tag in your HTML works identically.


Adding privacy-first analytics to your Next.js app takes one line of code and zero configuration. No cookies, no consent banner, no Lighthouse penalty. Start your free 14-day trial of EngageTrack and have analytics data flowing in under 2 minutes. No credit card required.

Related Articles