Strongly Typed Google Analytics V4 with Next.js

Andrew Ross
6 min readJun 7, 2021

--

There are a number of articles out there describing various methods of configuring `google analytics` with `next.js` — all written with untyped JavaScript. This article aims to remedy the absence of a strongly typed reference. The official next.js example serves as a good reference, yet, it too lacks strong types as it is written with JavaScript.

Install `@types/gtag.js` as a dev dependency

Open your terminal and run

terminal

We will not be needing the vanilla (non-typed) `gtag.js` package, the `react-ga` package, or any other package for that matter. This is where declaration (`**/*.d.ts`) files really shine! Before getting started, navigate to your `tsconfig.json` file and ensure that the `include` flag specifies the `**/*.d.ts` glob pattern

tsconfig.json

Referencing Types in a local declaration file

First, create a root `index.d.ts` file. This is where we will configure a triple-slash directive types-reference to the `@types/gtag.js` dev-dependency. Once configured and declared, the types contained within `@types/gtag.js` will be globally available for consumption — no imports required. Sure is nice

From typescriptlang.org:

/// <reference types=”…” />

”Similar to a `/// <reference path=”…” />` directive, which serves as a declaration of dependency, a `/// <reference types=”…” />` directive declares a dependency on a package. The process of resolving these package names is similar to the process of resolving module names in an import statement. An easy way to think of triple-slash-reference-types directives are as an import for declaration packages.”

”Use these directives only when you’re authoring a d.ts file by hand.”

As the official TS Docs indicate one should _only_ use these directives when authoring (or extracting from) a .d.ts file by hand — which fits the bill for our use-case with `@types/gtag.js`. I like to refer to unpaired or lone dev dependencies as stagpendencies — they could use an introduction

With the formalities out of the way, add the following code to your `index.d.ts` file to give this package a proper “intro”:

index.d.ts

Google Analytics V4 — Acquire a Tracking ID

Head over to google analytics and sign in. If you don’t have an account, create one, then sign in. Once signed in and on the landing page, click on the `Admin` gear icon in the bottom left corner then select `+ create property` as pictured below

Create Property

Next, add a property name and _do not_ select `create a universal property` under advanced options. This writeup does not cover universal properties — universal properties require the `@types/google.analytics` dev dependency to be properly typed.

Property Setup

then provide business information about your new google analytics property. Since the property I’m creating is an example for this article, I’ve selected `other` as the property type and only the top three options as being my intended use of google analytics. That said, if you are tracking a commerce site, for example, select additional desired options for your project.

analytics options

Configure a Data Stream for your Property

Configure a datastream

Next, let’s configure a data stream for our new property to start collecting data. Select `web` as a platform then fill in the website url and stream-name fields appropriately. The website url field should be the primary url of your production landing page.

data stream setup

Once finished, click “Create stream”. This should navigate you to the “Web Stream Details” view. Copy the `Measurement ID` for your newly created property. We will be using this as an environmental variable. Note: do not use your stream id value. These two key-val pairs are not interchangeable. The `measurement ID` is always prefixed with `G-` in version 4 (as opposed to UA- in version 3) followed by a random 10-character-alphanumeric string (e.g., `G-ABC4850XYZ`)

Web stream details

Back to your Code Editor

After copying the measurement ID for your new property, open your code editor, create a `.env.local` file in the root directory, then add the following key-value pair

.env.local

Next, create a root `lib` directory and an `analytics.ts` file therein. It is important to handle your `measurement id` environmental variable as a conditionally undefined string (process.env.* values always resolve to `string | undefined`)

@/lib/analytics.ts

@/lib/analytics.ts

Consuming the globalized reference types

As mentioned previously, there is no need to import anything to consume the reference `@types/gtag.js` types declared in the root `index.d.ts` file. Let’s start with `pageview`:

@/lib/analytics.ts

you should see the following intellisense definition when hovering over the appended `gtag` of `window.gtag`

Intellisense on hovering window.gtag

if you Ctrl+click while hovering the window-appended `gtag`, it will take you to the `node_modules/@types/gtag.js` declaration file where you can view all of the type definitions provided by the `@types/gtag.js` package.

Let’s export one additional function to track events associated with pageviews:

@/lib/analytics.ts

The `action` parameter measures user-initiated events. The destructured `{ event_category, event_label, value }` parameters capture relevant analytics data for each of the `action` events.

The `Gtag.EventNames` (user actions) corresponds to the following unions defined by the `EventNames` type:

EventNames type

While we only used `event_category`, `event_label`, and `value` in this writeup, the `Gtag.EventParams` interface has the following shape

EventParams interface

any of these parameters can be used to track user-mediated events.

The contents of your `@/lib/analytics.ts` file should now look as follows:

@/lib/analytics.ts final

`pages/_document.tsx`

Nearly finished. Navigate to `pages/_document.tsx` and import the `GA_TRACKING_ID` constant that we exported from `@/lib/analytics.ts`

imports in @/pages/_document.tsx

This file is important because it is used to augment the html, head, and body tags for all of the page files in our next.js repo. We will be injecting the `Head` of `_document.tsx` with two `script` tags as follows:

@/pages/_document.tsx returned TSX

For a holistic picture of `_document.tsx`, I’ll include the contents of my current working file:

@/pages/_document.tsx full

Wrapping this up in the root `pages/_app.tsx` file

Navigate to the custom `pages/_app.tsx` file and import `gtag` as a wildcard (*) from `@/lib/analytics`. We will also be needing `useEffect` from `React` and `useRouter` from `next/router`. Add the following code within the default export function but before the returned tsx in your `_app.tsx` file:

@/pages/_app.tsx handle route change

This code tracks pageview change events for the entirety of your app. I’ve included the full contents of my _app.tsx file below to provide a holistic view once more:

@/pages/_app.tsx full

Push — Deploy — Profit

Ensure that your deployment environment is provided with the `NEXT_PUBLIC_GA_TRACKING_ID` key-value pair, push your changes, successfully deploy, profit.

add the NEXT_PUBLIC_GA_TRACKING_ID key-value pair to your production environment

Check back in on google analytics after navigating around your newly deployed site to see if the data was successfully logged. That’s all there is to incorporating strongly typed definitions into your next.js google analytics repo.

Data trickles in…

--

--

Andrew Ross
Andrew Ross

Written by Andrew Ross

JAMstack Development Lead at Takeda

No responses yet