GoogleAnalytics with Next.js

Snippet for introducing GA to Next.js in the case of using App Router

date

Add environment variables

$ echo "NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=XXXXXXXXX" >> .env.local
$ echo "NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=XXXXXXXXX" >> .env.production

Steps

Add type definition

// yarn
$ yarn add -D @types/gtag.js

// npm
$ npm i --save-dev @types/gtag.js

Define a function for PageView

gtag.ts
export const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_ID || "";
export const existsGaId = GA_TRACKING_ID !== "";

export const pageview = (path: string) => {
  window.gtag("config", GA_TRACKING_ID, {
    page_path: path,
  });
};

Add script

CustomScript.tsx
"use client";

import { usePathname, useSearchParams } from "next/navigation";
import Script from "next/script";
import { useEffect } from "react";
import { existsGaId, GA_TRACKING_ID, pageview } from "@/gtag";

export const CustomScript = () => {
  const pathname = usePathname();
  const searchParams = useSearchParams();

  useEffect(() => {
    if (!existsGaId) {
      return;
    }
    const url = pathname + searchParams.toString();
    pageview(url);
  }, [pathname, searchParams]);

  return (
    <>
      <Script
        strategy="lazyOnload"
        src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
        async
      />
      <Script id="gtag-init" strategy="afterInteractive">
        {`
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', '${GA_TRACKING_ID}', {
            page_path: window.location.pathname,
          });
        `}
      </Script>
    </>
  );
};

Load script in layout file

layout.tsx
import React, { ReactNode, Suspense } from "react";
import { CustomScript } from "@/CustomScript";

const Layout = async ({ children }: { children: ReactNode }) => {
  return (
    <html lang="ja">
      {process.env.NODE_ENV === "production" && (
        <head>
          <Suspense>
            <CustomScript />
          </Suspense>
        </head>
      )}
      <body>{children}</body>
    </html>
  );
};
Share