Google Analytics and Next.js

One of the amazing things about Next.js is that it not only generates static HTML files for you, but it also re-hydrates into a fully-featured React.js app when the page loads in the browser.

If you use the <Link> component (we do in the Next.js starter), that means the whole page doesn't have to reload to pull in the new page.  This takes advantage of the Next.js router, and while it's amazing, it means our Analytics integration can be a little trickier.

In this article, we'll show you how to track page views and other metrics, even if you're using the <Link> component. 

We've taken inspiration from this article that describes how to do this with a regular React.js app.

Installing the Package

The first thing you'll need to do is add the react-ga package.

yarn add react-ga

Creating Utility Functions

Next, we'll create some utility functions to help us out in using this package. Create a file called analytics.js in the utils folder.  

import ReactGA from 'react-ga'

const GA_TRACKING_ID = "UA-YOUR_GA_ID"

export const initGA = () => {
 console.log('GA init')
 ReactGA.initialize(GA_TRACKING_ID)
}

export const logPageView = (url) => {
 console.log(`Logging pageview for ${url}`)
 ReactGA.set({ page: url })
 ReactGA.pageview(url)

}

export const logEvent = (category = '', action = '') => {
 if (category && action) {
    ReactGA.event({ category, action })
 }
}

export const logException = (description = '', fatal = false) => {
 if (description) {
   ReactGA.exception({ description, fatal })
 }
}

Updating Layout.js

Let's add a couple of hooks to the main Layout.js file.  We need to catch the Next router events, and we need useEffect to run our code.

If you don't have the hooks defined at the top of your Layout.js file, you can do that using this:

import React, { useState, useEffect } from 'react'
import { useRouter } from 'next/router'
import { initGA, logPageView } from "utils/analytics"

If you haven't already registered the router hook, go ahead and do that. I usually put this near the top of my component. We'll also use a state variable to check whether we've initialized the analytics yet.

const router = useRouter()
const [isGaLoaded, setIsGaLoaded] = useState(false)

Now we'll need to add our code to initialize Google Analytics and track page views. You'll notice that we've checked if type(window) is undefined. This ensures our code will ONLY run on the browser, not during the build.

useEffect(() => {
  if (typeof (window) === undefined) return

  const handleRouteChange = (url) => {
    logPageView(url)
  };

  if (!window.GA_INITIALIZED) {
    initGA()
    window.GA_INITIALIZED = true
  }

  router.events.on("routeChangeComplete", handleRouteChange);

  return () => {
    if (typeof (window) === undefined) return
    router.events.off("routeChangeComplete", handleRouteChange);
  };

}, [router.events]);

That's it!  You're all set.  Once you've confirmed everything is working, you can remove the console.log() statements that are in there to clean things up.Something else you can do to make life easier later on is to move theGA_TRACKING_ID variable from your analytics.js file into an environment variable to make things easier to move around.

Google Tag Manager

If you're using Google Tag Manager, you can use a similar solution using the react-gtm-module package.