Photo: Privacy please!
Photo by Jason Dent on Unsplash

For my site, I wanted to capture user analytics without tracking users who don't want to be tracked. Here in Europe, the General Data Protection Regulation (GDPR) protects consumers' privacy. In particular, the ePrivacy directive requests users' consent before setting any tracking cookies.

A quick search revealed gatsby-plugin-gdpr-cookies, a plugin that supports Google Analytics, Google Tag Manager, and Facebook Pixel.

In short, it provides a mechanism for asking the user to explicitly consent to any cookies being set; precisely what I needed!

Installing the plugin

I installed the plugin with npm install gatsby-plugin-gdpr-cookies then added it to my gatsby-config.js file:

module.exports = {
  plugins: [
    {
      resolve: `gatsby-plugin-gdpr-cookies`,
      options: {
        googleAnalytics: {
          trackingId: /*GA_TRACKING_ID*/,
          cookieName: "gatsby-gdpr-google-analytics",
          anonymize: true, // https://github.com/andrezimpel/gatsby-plugin-gdpr-cookies#anonymize
          allowAdFeatures: false,
        },
      },
    },
  ],
};

Then, nothing...

It turns out configuring this plugin is a bit more cumbersome than the documentation indicates.

The plugin requires you to set the cookie named cookieName, for example: gatsby-gdpr-google-analytics=true, to enable tracking.

This was not immediately obvious, and I ended up spending unnecessary time to figure out why it wasn't working.

With that out of the way, I needed a toggle to track if users had already accepted the banner. Typically, I'd have used another cookie - but that would defeat the purpose.

Local storage to the rescue! I found Josh Comeau's excellent tutorial on sticky-state and implemented it.

A simple React component later, and some TailwindUI code for the banner and it was ready to go!

Here's the resulting code (simplified):

import * as React from 'react';
import { useLocation } from '@reach/router';
import { initializeAndTrack } from 'gatsby-plugin-gdpr-cookies';

function isBrowser() {
  return typeof window !== 'undefined';
}

function getValue(key, defaultValue) {
  return isBrowser() && window.localStorage.getItem(key)
    ? JSON.parse(window.localStorage.getItem(key))
    : defaultValue;
}

function setValue(key, value) {
  window.localStorage.setItem(key, JSON.stringify(value));
}

function useStickyState(defaultValue, key) {
  const [value, setter] = React.useState(() => {
    return getValue(key, defaultValue);
  });

  React.useEffect(() => {
    setValue(key, value);
  }, [key, value]);

  return [value, setter];
}

const CookieConsent = () => {
  const location = useLocation();
  if (isBrowser()) {
    initializeAndTrack(location);
  }

  const [bannerHidden, setBannerHidden] = useStickyState(
    false,
    'consentCookieHidden',
  );

  const EnableAnalytics = () => {
    document.cookie = 'gatsby-gdpr-google-analytics=true';
    setBannerHidden(true);
  };

  return (
    <>
      {!bannerHidden && (
        <div>
          <span>
            We use cookies to personalize content and analyze our
            traffic.
          </span>
          <button onClick={EnableAnalytics}>OK</button>
        </div>
      )}
    </>
  );
};

export default CookieConsent;

The final thing left is to call this component in the site's footer.

import CookieConsent from 'cookie-consent';
...
<CookieConsent/>

This ensures no analytics code is run and no cookies are set until the user clicks OK.

And that's it! This is how you can get your users' consent before enabling analytics and tracking cookies!

If you enjoyed this post, please share it with your friends!