Optimizing your experience
Gradient background

Debugging gatsby-plugin-google-gtag for Google Analytics 4 with Gatsby

Clarice Bouwer

Software Engineering Team Lead and Director of Cloudsure

Tuesday, 31 August 2021 · Estimated 3 minute read

In this article I will cover how I installed and configured the plugin, added my custom track event, tried to test it and it didn't work so I went through a checklist of debugging the thing.


I assume that you are already familiar with Gatsby. At the time of writing, I am using Gatsby 3.11.0.

You also need the Google Analytics 4 property. Read this article to add a Google Analytics 4 property to a site that already has analytics.


I installed the gatsby-plugin-google-gtag plugin - at the time of writing it's version 3.12.0 - and configured it pretty much according to the documentation.

I have omitted what I don't need so refer to the original documentation for more attributes.

The piece of code below can be copied into your gatsby-config.js file within the plugins attribute.

module.exports = {
  plugins: [
      resolve: `gatsby-plugin-google-gtag`,
      options: {
        // You can add multiple tracking ids and a pageview event will be fired for all of them.
        trackingIds: [
          'GA-TRACKING_ID', // Google Analytics / GA
        // This object gets passed directly to the gtag config command.
        // This config will be shared across all trackingIds.
        gtagConfig: {
          // Anonymizes the last digits of the user’s IP.
          // To comply with policies and legal regulations.
          anonymize_ip: true,
          cookie_expires: 0,
        // This object is used for configuration specific to this plugin.
        pluginConfig: {
          // As false it puts the tracking script in the body instead of the head.
          head: false,
          // Optional parameter to honor the Do Not Track feature.
          respectDNT: true,

Track a custom event

I have an anchor component which checks the type of link and renders the appropriate anchor type for me. Links internal to the website use Gatsby's Link component while outbound links use the gatsby-plugin-google-gtag plugin's OutboundLink component.

Here is the crux of my plugin:

import React from 'react';
import PropTypes from 'prop-types';
import { Link } from 'gatsby';
import { OutboundLink } from 'gatsby-plugin-google-gtag';

const trackClickEvent = (data) => {
  if (typeof window !== 'undefined' && window.gtag) {
    window.gtag('event', 'click', data);

const Anchor = ({ to, title, children }) => {
  const trackingData = { to, title };

  if (!to) return <span title={title}>{children}</span>;

  if (to && to.startsWith('/')) {
    return (
      <Link to={to} title={title} onClick={() => trackClickEvent(trackingData)}>

  return (
      rel="noreferrer noopener"
      onClick={() => trackClickEvent(trackingData)}

Anchor.propTypes = {
  children: PropTypes.node.isRequired,
  title: PropTypes.string,
  to: PropTypes.string,

export default Anchor;

I have only added a track click event to my project (because I am not that creative to come up with anything else to track 😒 but that's probably a good thing!).

const trackOnClick = (data) => {
  // Guard against SSR && make sure that the gtag exists globally
  if (typeof window !== 'undefined' && window.gtag) {
    window.gtag('event', 'click', data);

Debug checklist

It didn't work 😔 so I went through a few things.

Please let me know if you experience this issue and have found a different solution.

Serve from the production server

  • Manually clean your .cache directory. This isn't always necessary but it is a good precaution to take and can mitigate frustration. The cache goes stale and references get outdated.
  • Build your site. It optimizes and packages up the site using its config, data, and code to compile a production-ready set of static HTML pages that will later get rehydrated into a React application.
  • Serve your project using the production server.
gatsby clean && gatsby build && gatsby serve

If you do not have the Gatsby CLI globally installed then you should run your commands using what you have configured in your package.json config by running npm or yarn. This will run the executable available within the /node_modules/ directory.

Do not honor the respectDNT option

DNT stands for Do Not Track. This feature will cause the window.gtag to be undefined if it is enabled so set it to false. Check out the Chrome browser setting.

I had this set to false using an environment variable HONOR_DNT=false and respectDNT: process.env.HONOR_DNT || true but it didn't work 😢. I haven't yet fully investigated why.

It is probably wise to enable this in production.

Temporarily stop your Ad blocker

An ad block will block all tracking scripts. Be sure to disable it.


While I was debugging I tested scenario after scenario to see which one was the bad sheep. I'd type id window.gtag in the console expecting to see a function instead of undefined.

Once it was working I inspected the Network tab and noticed that requests were being made to https://www.google-analytics.com/g/collect 🎉