How to use google analytics with next.js app?
The accepted answer does not work. Instead, to correctly initialize gtag
, do the following in _document.js
or wherever you defined Head
:
import { Head } from 'next/document';export default class MyDocument extends Document { render() { return ( // ... <Head> <script async src="https://www.googletagmanager.com/gtag/js?id=[Tracking ID]" /> <script dangerouslySetInnerHTML={{ __html: ` window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', '[Tracking ID]', { page_path: window.location.pathname }); `, }} /> </Head> ); }}
The above will track page views on page load. To track navigation add the following to _app.js
:
import { useRouter } from 'next/router';export default const App = () => { const router = useRouter(); const handleRouteChange = (url) => { window.gtag('config', '[Tracking ID]', { page_path: url, }); }; useEffect(() => { router.events.on('routeChangeComplete', handleRouteChange); return () => { router.events.off('routeChangeComplete', handleRouteChange); }; }, [router.events]); return ( // ... );};
See also:
To setup Google analytics with NextJS using Typescript
I'm using below setup for my personal site (https://github.com/GorvGoyl/Personal-Site-Gourav.io) and it's working fine without any linting errors. Analytics is enabled only for production.
- Create a Google analytics project and get Measurement ID.
- In your NextJS project, create
/lib/gtag.ts
file and add your Google Measurement ID:
export const GA_TRACKING_ID = "<INSERT_TAG_ID>";// https://developers.google.com/analytics/devguides/collection/gtagjs/pagesexport const pageview = (url: URL): void => { window.gtag("config", GA_TRACKING_ID, { page_path: url, });};type GTagEvent = { action: string; category: string; label: string; value: number;};// https://developers.google.com/analytics/devguides/collection/gtagjs/eventsexport const event = ({ action, category, label, value }: GTagEvent): void => { window.gtag("event", action, { event_category: category, event_label: label, value, });};
- Also install gtag
types
:
npm i -D @types/gtag.js
- Create
/pages/_document.tsx
:
import Document, { Html, Head, Main, NextScript } from "next/document";import { GA_TRACKING_ID } from "../lib/gtag";const isProduction = process.env.NODE_ENV === "production";export default class MyDocument extends Document { render(): JSX.Element { return ( <Html> <Head> {/* enable analytics script only for production */} {isProduction && ( <> <script async src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`} /> <script // eslint-disable-next-line react/no-danger 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> ); }}
- Create
/pages/_app.tsx
:
import { AppProps } from "next/app";import { useRouter } from "next/router";import { useEffect } from "react";import * as gtag from "../lib/gtag";const isProduction = process.env.NODE_ENV === "production";const App = ({ Component, pageProps }: AppProps): JSX.Element => { const router = useRouter(); useEffect(() => { const handleRouteChange = (url: URL) => { /* invoke analytics function only for production */ if (isProduction) gtag.pageview(url); }; router.events.on("routeChangeComplete", handleRouteChange); return () => { router.events.off("routeChangeComplete", handleRouteChange); }; }, [router.events]); // eslint-disable-next-line react/jsx-props-no-spreading return <Component {...pageProps} />;};export default App;
In your _document.js
you override the getInitialProps
method. You can also override the render
method. Simply add
render() { return ( <Html lang={this.props.lang || "en"}> <Head> <script dangerouslySetInnerHTML={{ __html: `[google analytics tracking code here]` }} /> </Head> <body> <Main /> <NextScript /> </body> </Html> ); }
Make sure you import the required components:
import Document, { Html, Head, Main, NextScript } from "next/document"