Open6

Next.js (TypeScript) に Google Analytics を導入する

taichi fukumototaichi fukumoto

@types/gtag.js をインストール

公式のコードは JS なので@types/gtag.js というパッケージを導入し、TypeScript 対応する。

Terminal
$ npm install -D @types/gtag.js
taichi fukumototaichi fukumoto

環境変数に GA の ID を設定

.env に GA の ID を記述する。GA の ID は UA- から始まるやつ。

.env.local
NEXT_PUBLIC_GA_ID=UA-SOMENUMBER-X
taichi fukumototaichi fukumoto

GA 用の関数作成と型定義

PV を計測するための関数と GA のイベント発火時の関数を lib/gtag.ts に作成する。

src/lib/gtag.ts
export const GA_ID = process.env.NEXT_PUBLIC_GA_ID || "";

// https://developers.google.com/analytics/devguides/collection/gtagjs/pages
// PV 数の計測
export const pageview = (url: string) => {
  if (!GA_ID) return;
  window.gtag("config", GA_ID, {
    page_path: url,
  });
};

// https://developers.google.com/analytics/devguides/collection/gtagjs/events
// GA イベントの発火
export const event = ({
  action,
  category,
  label,
  value,
}: {
  action: string;
  category: string;
  label: string;
  value?: number;
}): void => {
  if (!GA_ID) return;
  window.gtag("event", action, {
    event_category: category,
    event_label: label,
    value: value,
  });
};

関数を作成したら、next-env.d.ts に型定義も追加しておく。

next-env.d.ts
  /// <reference types="next" />
  /// <reference types="next/types/global" />
  /// <reference types="next/image-types/global" />

  // NOTE: This file should not be edited
  // see https://nextjs.org/docs/basic-features/typescript for more information.

+ interface Window {
+   gtag(type: "config", googleAnalyticsId: string, { page_path: string });
+   gtag(
+     type: "event",
+     eventAction: string,
+     fieldObject: {
+       event_label: string;
+       event_category: string;
+       value?: number;
+     }
+   );
+ }

taichi fukumototaichi fukumoto

PV を計測するための Hook を作成 して呼び出し

ページ遷移した時に発火し、 PV を計測するための Hook を作成する。

src/hooks/usePageView.ts
import { useRouter } from "next/router";
import { useEffect } from "react";

import { GA_ID, pageview } from "@/lib/gtag";

export const usePageView = () => {
  const router = useRouter();
  useEffect(() => {
    if (!GA_ID) {
      return;
    }

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const handleRouteChange = (url: string, { shallow }: any) => {
      if (!shallow) {
        pageview(url);
      }
    };

    router.events.on("routeChangeComplete", handleRouteChange);
    return () => {
      router.events.off("routeChangeComplete", handleRouteChange);
    };
  }, [router.events]);
};

Hook を作成したら pages/_app.tsx で呼び出す。

src/pages/_app.tsx
  import type { AppProps } from "next/app";

  import "@/styles/globals.css";
+ import { usePageView } from "@/hooks/usePageView";

  function MyApp({ Component, pageProps }: AppProps) {
+   // Google Analytics の PV をカウントするイベント
+   usePageView();

    return <Component {...pageProps} />;
  }
  export default MyApp;

taichi fukumototaichi fukumoto

GA スクリプトの埋め込み

pages/_document.tsx に GA のスクリプトを埋め込む。

src/pages/_document.tsx
  import Document, { Head, Html, Main, NextScript } from "next/document";

+ import { GA_ID } from "@/lib/gtag";

  class MyDocument extends Document {
    render() {
      return (
        <Html lang={"ja"} dir={"ltr"}>
          <Head>
           {/* ... その他のコード */}

+           {/* Google Analytics */}
+           {GA_ID && (
+             <>
+               <script async src={`https://www.googletagmanager.com/gtag/js?id=${GA_ID}`} />
+               <script
+                 dangerouslySetInnerHTML={{
+                   __html: `
+                   window.dataLayer = window.dataLayer || [];
+                   function gtag(){dataLayer.push(arguments);}
+                   gtag('js', new Date());
+                   gtag('config', '${GA_ID}', {
+                     page_path: window.location.pathname,
+                   });`,
+                 }}
+               />
+             </>
+           )}
          </Head>
          <body>
            <Main />
            <NextScript />
          </body>
        </Html>
      );
    }
  }

  export default MyDocument;