round_circle
round_circle

Reputation: 1015

How to handle cookie consent in Next JS?

On my Next JS website I needed to implement Google Analytics (GA) and Facebook Pixel (FP), which I did according to the documentation and is working as far as I can tell. Now, I need to make everything GDPR compliant, so that only after explicitly accepting cookies, these services can send information. I am not sure whether I did this the right/optimal way, so would appreciate if someone more knowledgeable than I could have a look. I use react-cookie-consent for the popup, which adds a cookie with a boolean indicating whether cookies were accepted or declined. With the following code I want to make sure that: 1. on first visit GA and FB are not activated until accepted is clicked (see handleAccept function). 2. on subsequent visits, GA and FB are active when previously the user accepted cookies. Here is my app.js:

import "../styles/globals.css";
import CookieConsent from "react-cookie-consent";
import * as gtag from "../lib/gtag";
import * as fbq from "../lib/fpixel";
import { useEffect } from "react";
import Script from "next/script";
import { useRouter } from "next/router";

function MyApp({ Component, pageProps }) {
  // for Google analytics and Facebook tracking
  const router = useRouter();
  useEffect(() => {
    fbq.pageview();
    const handleRouteChange = (url) => {
      gtag.pageview(url);
      fbq.pageview();
    };
    router.events.on("routeChangeComplete", handleRouteChange);
    return () => {
      router.events.off("routeChangeComplete", handleRouteChange);
    };
  }, [router.events]);
  
  // for subsequent page visits
  useEffect(() => {
    if (checkConsented()) {
      window.gtag("consent", "update", {
        ad_storage: "granted",
        analytics_storage: "granted",
      });
      window.fbq("consent", "grant");
    }
  }, []);

  function handleAccept() {
    window.gtag("consent", "update", {
      ad_storage: "granted",
      analytics_storage: "granted",
    });
    window.fbq("consent", "grant");
  }

  return (
    <>
      <Script
        strategy="afterInteractive"
        src={`https://www.googletagmanager.com/gtag/js?id=${gtag.GA_TRACKING_ID}`}
      />
      <Script
        id="gtag-init"
        strategy="afterInteractive"
        dangerouslySetInnerHTML={{
          __html: `
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('consent', 'default', {
              'ad_storage': 'denied',
              'analytics_storage': 'denied'
            });
            gtag('js', new Date());
            gtag('config', '${gtag.GA_TRACKING_ID}', {
              page_path: window.location.pathname,
            });
          `,
        }}
      />
      <Script
        strategy="afterInteractive"
        dangerouslySetInnerHTML={{
          __html: `
            !function(f,b,e,v,n,t,s)
            {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
            n.callMethod.apply(n,arguments):n.queue.push(arguments)};
            if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
            n.queue=[];t=b.createElement(e);t.async=!0;
            t.src=v;s=b.getElementsByTagName(e)[0];
            s.parentNode.insertBefore(t,s)}(window, document,'script',
            'https://connect.facebook.net/en_US/fbevents.js');
            fbq('consent', 'revoke');
            fbq('init', ${fbq.FB_PIXEL_ID});
          `,
        }}
      />
      <CookieConsent
        buttonText="Accept"
        enableDeclineButton
        onAccept={() => {
          handleAccept();
        }}
        declineButtonText="Decline"
      >
        We use cookies to improve your experience on our site.
      </CookieConsent>
      <Component {...pageProps} />
    </>
  );
}

// function for checking whether visitor has consented before
function checkConsented() {
  let decodedCookie = decodeURIComponent(document.cookie);
  decodedCookie = decodedCookie.split(";");
  decodedCookie = decodedCookie.find((cookie) => {
    return cookie.substring(0, 13) === "CookieConsent";
  });
  if (!decodedCookie) {
    return false;
  }
  if (decodedCookie.substring(14, 18) === "true") {
    return true;
  }
  return false;
}

export default MyApp;

Will this work for my 2 goals? And is there a better way of doing this?

Upvotes: 11

Views: 9233

Answers (1)

Manuel Escobar
Manuel Escobar

Reputation: 89

According to the package's docs, you can retrieve the cookie's value like this:

import CookieConsent, { Cookies, getCookieConsentValue } from "react-cookie-consent";

console.log(getCookieConsentValue());

So you could skip your checkConsented() function and just use getCookieConsentValue() instead.

Upvotes: -1

Related Questions