DEV Community

Mihai Bojin
Mihai Bojin

Posted on • Originally published at mihaibojin.com on

Privacy-friendly analytics in GatsbyJS

Photo: Privacy please!
"Photo by Jason Dent on Unsplash"

πŸ”” This article was originally posted on my site, MihaiBojin.com. πŸ””


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,
        },
      },
    },
  ],
};
Enter fullscreen mode Exit fullscreen mode

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.

Integrating with the consent banner

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;
Enter fullscreen mode Exit fullscreen mode

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

import CookieConsent from 'cookie-consent';
...
<CookieConsent/>
Enter fullscreen mode Exit fullscreen mode

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 liked this article and want to read more like it, please subscribe to my newsletter; I send one out every few weeks!

Top comments (0)