Integrate Google Analytics 4 with Next.js in Typescript
There are numerous examples of integrating Next.js in javascript, and even then, these articles focus on integrations with previous versions of GA 4.
This article focuses only on GA 4 and how you can integrate it with your Next.js application written in typescript.
This article does not cover the following topics — Let me know in the comments if you want them to be.
How to create a new web property in GA
How to deploy Next.js Application with the environment variable for GA_ID
Let’s get started!
Step 1: Create or modify _document.tsx
import Document, { Head, Html, Main, NextScript } from 'next/document'
// You can import from other folder based on your project.
import { GA_TRACKING_ID } from '../utils/constants'
export default class MyDocument extends Document {
render() {
return (
<Html>
<Head>
{/* Global Site Tag (gtag.js) - Google Analytics */}
<script async src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`} />
<script dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_TRACKING_ID}', { page_path: window.location.pathname, });
`,
}} />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
Step 2: Add GA_TRACKING_ID constant
// File: constants.ts
export const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_ID
Your editor might complain that NEXT_PUBLIC_GA_ID does not exist on env
object. We will handle that later.
Step 3: Modify or create _app.tsx
import App, { NextWebVitalsMetric } from 'next/app'
import '../styles/globals.css'
import type { AppProps, AppContext } from 'next/app'
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
function MyApp({ Component, pageProps }: AppProps) {
return (
<Component {…pageProps} />
)
}
MyApp.getInitialProps = async (appContext: AppContext) => {
// calls page's `getInitialProps` and fills `appProps.pageProps`
const appProps = await App.getInitialProps(appContext)
return { …appProps }
}
export function reportWebVitals({ id, name, label, value, }: NextWebVitalsMetric): void {
window.gtag('event', name, {
event_category: label === 'web-vital' ? 'Web Vitals' : 'Next.js custom metric',
value: Math.round(name === 'CLS' ? value * 1000 : value), // values must be integers
event_label: id, // id unique to current page load
non_interaction: true, // avoids affecting bounce rate.
})
}
export default MyApp
Note: Your editor will complain that gtag does not exist on the window object. So let’s handle that.
Step 4: Handle global variables types
Create a new file in your application directory (does not matter where you put it)
// File: environment.d.ts (You can name this anything you want) declare global {
interface Window {
gtag: any // you can create a Type for this. I left it to any
}
namespace NodeJS {
interface ProcessEnv {
NEXT_PUBLIC_GA_ID: string
}
}
} // If this file has no import/export statements (i.e. is a script) // convert it into a module by adding an empty export statement. export {}
You can verify if your code is working by starting the server in localhost and checking the real-time metrics in google analytics.