Cat logomenu

How to Set up Google Tag Manager in NextJS

Make your marketing team happy by configuring GTM to track your single page app performance

Updated in 2020 to provide more information about firing the GTM script when the route changes

GTM Docs vs. React

The app I’m currently working on is bootstrapped using NextJS and needs to implement Google Tag Manager. The task was assigned to me, but Google’s “Quick Start Guide” for GTM wanted me to do this:

  1. “Copy the following JavaScript and paste it as close to the opening <head> tag as possible on every page of your website, replacing GTM-XXXX with your container ID:”
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXX');</script>
<!-- End Google Tag Manager -->

And also this:

2. “Copy the following snippet and paste it immediately after the opening <body> tag on every page of your website, replacing GTM-XXXX with your container ID:”

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

Uh, gross.

It’s not like I’m 1000% opposed to using dangerouslySetInnerHTML but… I mean, I’d rather not do it. So instead, I went looking for a more React-like implementation, and I ended up with react-gtm-module. Their docs aren’t written specifically for NextJS, so

Initializing the Script in Your _.app.js File

For basic use cases, we can get this set up in just a few minutes. We’re just going to edit our _app.js file. (If you don’t have an _app.js file in your Next app, you’re probably on an older version of NextJS.):

import App, { Container } from "next/app"
import React from "react"
import "./app.css"
import TagManager from "react-gtm-module"

const tagManagerArgs = {
  id: "GTM-XXXX",
}

const MyApp = ({ Component, pageProps }) => {
  useEffect(() => {
    TagManager.initialize(tagManagerArgs)
  }, [])

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

export default MyApp

Or, if you’re using class components:

import App, { Container } from "next/app"
import React from "react"
import "./app.css"
import TagManager from "react-gtm-module"

const tagManagerArgs = {
  id: "GTM-XXXX",
}

class MyApp extends App {
  componentDidMount() {
    TagManager.initialize(tagManagerArgs)
  }

  render() {
    const { Component, pageProps } = this.props
    return (
      <Container>
        <Component {...pageProps} />
      </Container>
    )
  }
}

export default MyApp

But wait! We still have one more thing to do to make sure that GTM actually registers all the right user activity. Before that, though,

Puss in Boots from the Shrek movies making big kitten eyes and saying 'please'

If this guide is helping you, please consider signing up for my mailing list! You’ll get an update straight to your inbox whenever I have a new post.

Okay, let’s finish up:

Firing the Script on Route Changes

Owing to the way that React apps generally work, this won’t be enough. The script will only fire on the first page, because subsequent navigation doesn’t actually reload; it only updates the browser history to reflect the new URL. This will make your SEO team think that all your potential customers are just visiting one page and then bouncing right off.

Yikes.

There are some hoops you can jump through on your end that involve calling lower-level methods on the NextJS router to manually fire script events whenever a route change completes, but I’m honestly not wild about that. It sounds like a hack, and I only want to implement hacks if I can’t do something better.

Instead, I think it’s better to do what this user who ran into the same issue recommends: Ask your SEO team to add the “History Change” trigger to the tags they want to fire on every page. This way, the tag will register all your SPA route changes, and everyone will be happy!

What about you?

  • Did you run into any other issues, or find a more elegant solution than this? Hit me up @glassblowerscat!
  • I’ll be posting more NextJS-related tutorials soon. Sign up for my newsletter if you want to get notified when a new post goes up.

Give us a share!