# 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.

1.  How to create a new web property in GA
    
2.  How to deploy Next.js Application with the environment variable for GA\_ID
    

Let’s get started!

# **Step 1: Create or modify \_document.tsx**

```typescript
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**

```typescript
// 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**

```typescript
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)

```typescript
// 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](http://localhost) and checking the real-time metrics in google analytics.
