Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allow google analytics to load only after consented in Next.js

I integrated google analytics to next.js - to say, I followed these guides:

  1. https://frontend-digest.com/using-nextjs-with-google-analytics-and-typescript-620ba2359dea
  2. https://github.com/vercel/next.js/tree/canary/examples/with-google-analytics

Which works just fine, now the issue is I need to allow loading google analytics only after cookie consent, I store my cookie consent in localStorage at the moment simply in the format:

checkboxValues = {
  necessary: true,
  statistics: false,
  marketing: false,
};

Now I need to check localStorage.getItem('acceptCookies'); and make sure google analytics is loaded only when statistics: true.

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

import { GA_TRACKING_ID } from "../utils/gtag";

export default class MyDocument extends Document {
  render() {
    return (
      <Html>
        <Head>
          {/* Global Site Tag (gtag.js) - Google Analytics */}
          <script
            async
            src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
          />
          <script
            dangerouslySetInnerHTML={{
              __html: `
              window.dataLayer = window.dataLayer || [];
              function gtag(){dataLayer.push(arguments);}
              gtag('js', new Date());
              gtag('config', '${GA_TRACKING_ID}', {
                page_path: window.location.pathname,
              });
          `
            }}
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

for me to check for the localStorage before render() is not possible as localStorage is only available after componentDidMount. Stuck with this, any direction?

like image 216
ro ko Avatar asked Oct 12 '25 22:10

ro ko


2 Answers

there are built-in consent functions: https://developers.google.com/gtagjs/devguide/consent

so you in your case add

gtag('consent', 'default', {
  'analytics_storage': 'denied'
});

So it'll look something like:

    <script
        dangerouslySetInnerHTML={{
          __html: `
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
//this defaults to denying
    gtag('consent', 'default', {
      'analytics_storage': 'denied'
    });
          gtag('js', new Date());
//check for consent, you'll need to write your own function here, but you get the idea
if(consentGranted){
    gtag('consent', 'update', {
      'analytics_storage': 'granted'
    });
  }
        gtag('config', '${GA_TRACKING_ID}', {
            page_path: window.location.pathname,
          });

          `
            }}
          />

Alternatively, you could just wrap the "config" to line in the similar consent line, though this might not be as a "complete" solution as it only stops the pageview:

if(consent){    
gtag('config', '${GA_TRACKING_ID}', {
            page_path: window.location.pathname,
          });
    }
like image 132
XTOTHEL Avatar answered Oct 14 '25 12:10

XTOTHEL


As per this blog post you can create a cookie banner component which updates the Google Analytics consent:

'use client';

import { getLocalStorage, setLocalStorage } from '@/lib/storageHelper';
import { useState, useEffect } from 'react';

export default function CookieBanner(){

    const [cookieConsent, setCookieConsent] = useState(false);

    useEffect (() => {
        const storedCookieConsent = getLocalStorage("cookie_consent", null)

        setCookieConsent(storedCookieConsent)
    }, [setCookieConsent])

    
    useEffect(() => {
        const newValue = cookieConsent ? 'granted' : 'denied'

        window.gtag("consent", 'update', {
            'analytics_storage': newValue
        });

        setLocalStorage("cookie_consent", cookieConsent)

    }, [cookieConsent]);

    return (
...

Just call onClick={() => setCookieConsent(true)} when the user accepts cookie consent.

Update: storageHelper looks like this:

import "client-only";

export function getLocalStorage(key: string, defaultValue:any){
    const stickyValue = localStorage.getItem(key);

    return (stickyValue !== null && stickyValue !== 'undefined')
        ? JSON.parse(stickyValue)
        : defaultValue;
}

export function setLocalStorage(key: string, value:any){
    localStorage.setItem(key, JSON.stringify(value));
}
like image 33
Ryan Gaudion Avatar answered Oct 14 '25 11:10

Ryan Gaudion



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!