How To: Add Google Tag Manager to Next.js

Working with Next.js? At some point, you'll need to add analytics. Unfortunately at time of writing, all the guides on this are convoluted and kinda gross, but here's the fix. A scalable, quick and lightweight way to add all the martech analytics you could possibly need to your Next.js project, and manage it all in once place.

If you're in a rush, skip down about half way and get cracking with 10 lines of code that'll sort out every single project ever.

Traditionally, Google Tag Manager gets implemented by slapping a single script in the <head> and you're sorted. Within Google Tag Manager, you can set triggers to run various tags and scripts, and the main one used is a Page View. However, in the case of Next.js and other projects with router-based navigation, where the script is loaded once instead of being initialized on every router change, there's a little more setup to do.

When I first started working with React, I'd create a new trigger that watched the router for changes. Works well, but can also confuse marketing teams. Put yourself in their shoes; they're reading guides and articles telling them to set up everything with a magic Page View event that doesn't work for them.

Cue FOMO, confusion and stress. Let's not do that. Here's the fix.

Adding Google Tag Manager to Next.js with getanalytics.io

We'll be using a few packages to do this quickly, simply and with no BS whatsoever. Let me introduce you to getAnalytics.io by David Wells - The only analytics package you'll ever need.

The four principles of Analytics are:

  • You should never be locked into an analytics tool
  • DX is paramount. Adding & removing analytic tools from your application should be easy
  • Respecting visitor privacy settings & allowing for opt-out mechanisms is crucial
  • A pluggable API makes adding new business requests easy

.. which sounds pretty decent, huh. Setup takes just a minute, and extending it with additional tools works very similarly to how you'd add presets and plugins to Gatsby or Next; by installing a package and adding it to an array.

Why do I like it? It's free. It's easy. It doesn't F about with ugly code and it just works. I originally found it when looking to implement Segment to a project of mine and since then, it's found its way into my boilerplate.

It comes with three light-weight functions to track page views, identify users and create custom events, and it's all possible with like 10 lines of code. Here's how.

1. Add the Analytics.io package to your project

yarn add analytics @analytics/google-tag-manager

You can get all the documentation you need over on https://getanalytics.io/ but follow along for now, I won't steer you wrong.

2. Include in your project

Grab the GTM container ID (found in the Tag Manager Admin Panel tagmanager.google.com) and initialize the plugin with Analytics.

// Example File src/utility/analytics.js

import Analytics from 'analytics'
import googleTagManager from '@analytics/google-tag-manager'
const GTM_CONTAINER_ID = 'GTM_XXXXXXXX'

const analytics = Analytics({
    app: 'withseismic-web', // Call this whatever you like.
    plugins: [
        googleTagManager({
            containerId: GTM_CONTAINER_ID,
						enabled: true,
        }),
    ]
})

export default analytics

3. Implement Page Tracking

There are three types of tracking function available on the analytics package. The first, analytics.page() is the one that your marketing team will be interested in, and the one that you should implement straight away.

Here's how to add Page View tracking, and make sure it only fires on our production environment, so we don't pollute tracking (and use up quotas) with local tests.

Head over to your /pages/_app.js file (if you dont have one, read up and follow the instructions here)

Import useEffect from react, and call analytics.page() from within, making sure it's called once using the empty array at the end.

// _app.js (Read more here https://nextjs.org/docs/advanced-features/custom-app)
import { useEffect } from 'react'
import analytics from './analytics'


// Top-level Rendering.
function MyApp({ Component, pageProps }) {
  useEffect(() => {
    analytics.page() 
		// this will fire the Page Track function on every new router change.
  }, [])


  return (
    <>
      <Component {...pageProps} />
    </>
  )
}

export default MyApp

4. Sorted!

It's pretty much as simple as that. Right now, unless GTM already has GA and other scripts running then you won't be able to see any page view events anywhere, but what you will be able to do is

  • Create a test tag within GTM and trigger it using the Page View trigger. <script>console.log("GTM")</script>

  • Install GTM/GA Debugger and check out how it works. Hint, install, open dev tools, hit GTM/GA debugger, refresh page. (TO DO: Write article showing you how to use it)

  • Add Google Analytics to your GTM stack, and check that the page view events are pumping through directly to GA using the real-time report.

5. Next Steps.

Aside from the page() function, analytics also opens up two more functions, track and identify.

analytics.track({...event}) allows you to implement an event once and have it send out to as many different martech platforms as you've configured, whereas analytics.identify() takes a user id, email and other personal information to match events against a specific user - great for when you bring things like Segment.com and Klaviyo into play.

You'll probably want to check out how to adhere to a users Do Not Track settings, or stop various scripts from firing before receiving the all clear from your Cookie Consent banner, and that's super simple, too - Check out this Conditional Loading Documentation for more information.

What else can @getanalytics.io do?

A lot. It's really pretty handy.

Out of the box, analytics has plugins for a fair few tools your marketing & growth team will want to implement, if not now then in the future.

The great thing about using the Analytics package is that you only ever need to implement Page Tracking once, one function per tracked event, and one function per identity event.

So if you want to say, slot Mixpanel analytics in, feed Snowplow some events data and attribute some articles read by a customer to Hubspot, then it's a case of adding the plugin super quickly.

A list of all current plugins on getAnalytics.io

.. and what if you're trying to do something extra that isn't readily available? Writing a Provider plugin is a breeze. You can hook into the Page, Track and Identify callbacks with just a few lines of code... I'll be laying out how I built my own custom Klaviyo plugin later on. You can also extend the functionality of Analytics by building custom plugins that hook directly into the Analytics lifecycle to intercept page, track, identify and initialize calls.

Hell, you can even add your own events directly to Analytics if you want, too.

https://getanalytics.io/plugins/writing-plugins/

// Example Provider Plugin
export default function providerPluginExample(userConfig) {
  // return object for analytics to use
  return {
    /* All plugins require a name */
    name: 'my-example-plugin',
    /* Everything else below this is optional depending on your plugin requirements */
    config: {
      whatEver: userConfig.whatEver,
      elseYouNeed: userConfig.elseYouNeed
    },
    initialize: ({ config }) => {
      // load provider script to page
    },
    page: ({ payload }) => {
      // call provider specific page tracking
    },
    track: ({ payload }) => {
      // call provider specific event tracking
    },
    identify: ({ payload }) => {
      // call provider specific user identify method
    },
    loaded: () => {
      // return boolean so analytics knows when it can send data to third party
      return !!window.myPluginLoaded
    }
  }
}

TL;DR

  • yarn analytics
  • yarn add @analytics/google-tag-manager
  • Initialise Analytics with your credentials.
  • Call Analytics.page() using useEffect within _app.js
  • Done!

Make sure to read through the entire article - I guarantee you'll pick up some useful information along the way.

Take it easy!

Want more?

By clicking the button, I agree with the collection and processing of my personal data as described in the Privacy Policy.