How to Add Google Analytics to a Next.js Application (including TypeScript)


How can we add Google Analytics to a Next.js application?

This tutorial assumes that we have a Google Analytics project created for our Next.js project with a Measurement ID.

1. Create a Google Analytics environment variable

First, let’s create an environment variable for our Google Analytics Measurement ID.

NEXT_PUBLIC_GA_ID=G-FSC4AH1C9X 

Locally, this should reside in a .env.local or .env file.

Remember to set this environment variable wherever this application is deployed in production.

2. Inject Google Analytics script in _document.js

Next, we’ll want to inject the Google Analytics Global Site Tag (gtag.js) into our site’s <head>.

To access the Next.js <Head> tag, we’ll need a Next.js custom document called /pages/_document.js.

Here, we’ll inject the Google Analytics script into /pages/_document.js.

import Document, { Html, Head, Main, NextScript } from 'next/document';
const gtag = `https://www.googletagmanager.com/gtag/js?id=${process.env.NEXT_PUBLIC_GA_ID}`;
export default class MyDocument extends Document {
  render() {
    return (
      <Html>
        <Head>
          <script async src={gtag} />
          <script 
            dangerouslySetInnerHTML={{
              __html: `
                window.dataLayer = window.dataLayer || [];
                function gtag(){dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', '${process.env.NEXT_PUBLIC_GA_ID}', {
                  page_path: window.location.pathname,
                });
              `
            }}
          />
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

3. Track page views in _app.js

In order to track page views in our application, we’ll want to add a simple useEffect() hook into our _app.js that listens for routeChangeComplete events.

import { useEffect } from 'react';
import { useRouter } from 'next/router';
function MyApp({ Component, pageProps }) {
  const router = useRouter();
  useEffect(() => {
    const handleRouteChange = url => {
      window.gtag('config', process.env.NEXT_PUBLIC_GA_ID, {
        page_path: url,
      });
    }
    router.events.on('routeChangeComplete', handleRouteChange);
    return () => {
      router.events.off('routeChangeComplete', handleRouteChange);
    }
  }, [router.events]);
  return <Component {...pageProps} />
}
export default MyApp

4. Optional: only track in production

If we want to limit analytics to our production environment, we can check process.env.NODE_ENV.

Modify _document.js

In /pages/_document.js, let’s declare a boolean variable to check for production (can be outside the component).

const isProd = process.env.NODE_ENV === "production";

Then, we can wrap everything in <Head> in a conditional.

<Head>
  {isProd && (
    <>
      {/* The two script tags */}
    </>
  )}
</Head>

Modify _app.js

In /pages/_app.js, let’s declare the same boolean variable for production.

const isProd = process.env.NODE_ENV === "production";

Then, we can modify handleRouteChange to only fire in production.

const handleRouteChange = url => {
  if (isProd) {
    window.gtag('config', process.env.NEXT_PUBLIC_GA_ID, {
      page_path: url,
    });
  }
};

Add Google Analytics to TypeScript Next.js

If we want to add Google Analytics to a TypeScript application, we’ll need to add a few types.

First, we’ll need to install the types library for gtag.js.

npm i -D @types/gtag.js

In /pages/_document.tsx, we’ll want to type the return object.

// ...
export default class MyDocument extends Document {
  render(): JSX.Element {
    // ...
  }
}

Similarly, in /pages/_app.tsx, we’ll want type the parameters

const App = ({ Component, pageProps }: AppProps): JSX.Element => {
  // ...
  const handleRouteChange = (url: URL) => {
    // ...
  }
  // ...
};