Using Google Analytics with Next.js

Next.js is a JavaScript framework that enables building of Server Side Rendered (SSR) views of applications and web sites using the React.js library. The core team from Zeit has placed a lot of emphasis on the ease of use. In my experience Next.js is currently the easiest way to build SSR React apps, which blur the lines on whether your JavaScript code is executed in the browser or on the server.

The framework takes care of the complexities of server side rendering and routing in the background, so you can focus on creating valuable features - not caring if the page is rendered in the browser on on the server side using Node.js. Traditionally web applications have been built so that pages are loaded with full page loads, possibly enhanced with some dynamic functionality with JavaScript.

In addition to apps themselves, the utilities are built to support the traditional page-load based web building. An example of this is web analytics tools, such as Google Analytics. In a page-load app you just needed to a script tag to each page and let GA do it’s magic. When you’re running any single page application (built with Angular, React, Vue or whatever) you’ll need to jump some extra hoops to log traffic.

Tracking page loads with Next.js and the GA API

React is a JavaScript view library, which is based on components. Next.js uses React for generating views seamlessly on the server as well as the client. This means that we can extend and add tracking functionality to our view components to track user behaviour using Google Analytics by faking real page loads (in the traditional sense) in our templates.

Next.js offers a bunch of good examples to work with other use cases, in this case walk through on how to use the React-GA example in your own projects. First to help with working with React there is a utility library called react-ga, that abstracts the Google Analytics library. First start by adding this to your project’s package.json file using Yarn (the NPM client works just as fine):

yarn add react-ga

Once this is done, you’ll have added react-ga as a dependency to your project and the library is available in your node_modules directory. We’ll add our own abstraction layer on top of ReactGA to centralise our tracking logic. Create a the utility to utils/analytics.js with the following contents:

import ReactGA from 'react-ga'

export const initGA = () => {
  console.log('GA init')
  ReactGA.initialize('UA-xxxxxxxxx-1')
}

export const logPageView = () => {
  console.log('Logging pageview for ${window.location.pathname}')
  ReactGA.set({ page: window.location.pathname })
  ReactGA.pageview(window.location.pathname)
}

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

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

The code snippet is pretty self-explanatory. It imports the react-ga module, wraps the boilerplate functionality as initialization with your selected account ID, and logging behind a simple API that we’ll use in our React components. Speaking of components, as the next step we’ll continue by creating our core layout component to the project (components/Layout.js):

import React from 'react'
import { initGA, logPageView } from '../utils/analytics'

export default class Layout extends React.Component {
  componentDidMount () {
    if (!window.GA_INITIALIZED) {
      initGA()
      window.GA_INITIALIZED = true
    }
    logPageView()
  }
  render () {
    return (
      <div>
        {this.props.children}
      </div>
    )
  }
}

If you’re familiar with React, you’ll see that what we’re doing is hooking our helper utility to the componentDidMount lifecycle hook. This means that this code will be executed each time the component has been mounted. In this case Next.js and React will handle this behind scenes as users navigate your site.

The output returned by the render function is just the child components wrapped in a div, component does not add anything to the rendered HTML - all tracking is done via the Google Analytics JavaScript API using our wrapper utility and the ReactGA module. To take our component into use you’ll need to include it and use it in our entrypoints, for example in page/about.js:


import Layout from '../components/Layout'

export default () => (
  <Layout>
    <div>About us</div>
  </Layout>
)

With the above code every page load now triggers a GA call. When you navigate from view to view, Next only passes you the data without a complete page load. Since we are taking use of the lifecycle hooks in React to do this - you get easy tracking for your whole Next.js powered application or decoupled website.

-- Jani Tarvainen, 28/07/2017