🐱

Next.js で GTM + GA4を利用する

9 min read

概要

Next.jsにGoogle Tag Manager(以降はGTMと記載します)、Google Analytics 4(以降はGA4記載します)を連携させる手順をまとめた記事です。

対象読者

以下の条件を満たす人を対象読者とします。

  • Next.js(TypeScript)で開発をしている
  • GA4でアクセス解析をやりたい

前提条件

  • Next.jsで運用済のアプリケーションが存在する
  • GA4のプロパティを作成してある

具体的な手順

ここからは具体的な手順になります。

私が友人と開発している、猫のLGTM画像を共有できるサービス LGTMeow に設定した例を元に解説します。

GTMの設定

GTMのアカウントを作成

以下の情報を入力します。

  • アカウント名
  • コンテナ名
  • ターゲット プラットフォーム

アカウント名は分かりやすい名前であれば問題ありません。

コンテナ名は対象サイトのドメイン名を入れるのが良さそうです。

URLが https://lgtmeow.com であれば lgtmeow.com となります。

create-tag-manager-account

GA4 連携用のタグを追加

最初にGA4の測定ID(G-から始まる12桁の値)を控えておきます。

タグ → 新規からGA4との連携設定を作成します。

create-ga4-tag1

タグの名前は分かりやすい名前であれば何でも大丈夫です、ここではGAとしました。

さきほど控えておいた測定ID(G-から始まる12桁の値)を入力します。

「この設定が読み込まれるとページビューイベントを送信する」にチェックを入れます。(Defaultでチェックされているハズ)

create-ga4-tag2

余談ですがGA4のタグをそのまま利用していた際は以下のように next/router によるページ遷移が発生した際にページビューイベントを送信する必要がありました。

これが不要になる点もGTMを利用するメリットだと思います。

src/utils/gtag.ts
export const gaMeasurementId = process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID || '';

// https://developers.google.com/analytics/devguides/collection/gtagjs/pages
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const pageview = (url: string) => {
  // eslint-disable-next-line @typescript-eslint/no-unsafe-call
  window.gtag('config', gaMeasurementId, {
    page_path: url,
  });
};
src/pages/_app.tsx
import '../../styles/globals.css';
import React, { useEffect } from 'react';
import type { AppProps } from 'next/app';
import { useRouter } from 'next/router';
import * as gtag from '../utils/gtag';
import GoogleAnalytics from '../components/GoogleAnalytics';

const CustomApp = ({ Component, pageProps }: AppProps): JSX.Element => {
  const router = useRouter();

  useEffect(() => {
    const handleRouteChange = (url: string) => {
      gtag.pageview(url);
    };
    router.events.on('routeChangeComplete', handleRouteChange);

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

  return (
    <>
      <GoogleAnalytics />
      {/* eslint-disable-next-line react/jsx-props-no-spreading */}
      <Component {...pageProps} />
    </>
  );
};

export default CustomApp;

配信トリガーはAll Pages(ページビュー)を設定します。

create-ga4-tag3

ここまで設定できたら、ワークスペースの右上の「公開」を押下して、このバージョンを公開します。

workspace_publish

Next.jsのアプリケーションにタグを追加する

以下のようなComponentを定義します。

src/components/GoogleTagManager.tsx
import Script from 'next/script';
import React from 'react';

export type GoogleTagManagerId = `GTM-${string}`;

type Props = {
  googleTagManagerId: GoogleTagManagerId;
};

const GoogleTagManager: React.FC<Props> = ({ googleTagManagerId }) => (
  <Script
    id="gtm"
    strategy="afterInteractive"
    dangerouslySetInnerHTML={{
      __html: `
      (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
      new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
      j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
      'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
      })(window,document,'script','dataLayer','${googleTagManagerId}');
      `,
    }}
  />
);

export default GoogleTagManager;

.envNEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID を追加します。

設定するのは GTM- から始まるGTMのコンテナIDです。

NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID=GTM-XXXXXXX

window.dataLayer を呼び出せるように型定義を追加します。

src/utils/gtm.ts
export const googleTagManagerId =
  process.env.NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID || '';

declare global {
  interface Window {
    dataLayer: Record<string, unknown>[];
  }
}

_app.tsx でさきほど作成したGTM用のComponentを呼び出します。

src/pages/_app.tsx
import { AppProps } from 'next/app';
import { googleTagManagerId } from '../utils/gtm';
import GoogleTagManager, {
  GoogleTagManagerId,
} from '../components/GoogleTagManager';

const App = ({ Component, pageProps }: AppProps): JSX.Element => (
  <GoogleTagManager
    googleTagManagerId={googleTagManagerId as GoogleTagManagerId}
  />
  {/* eslint-disable-next-line react/jsx-props-no-spreading */}
  <Component {...pageProps} />
);

export default App;

この状態でアプリケーションにアクセスするとGA4にイベントが送信できていることを確認できるかと思います。

noscriptタグについて

公式だと以下のようなタグをbodyの一番上に追加するように記載されています。

<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

Next.jsの場合 _document.tsx に以下のように <noscript> タグを追加することで対応できます。

src/pages/_document.tsx
import Document, {
  DocumentContext,
  Head,
  Html,
  Main,
  NextScript,
  DocumentInitialProps,
} from 'next/document';
import React from 'react';
import {googleTagManagerId} from '../infrastructures/utils/gtm';

export default class CustomDocument extends Document {
  static async getInitialProps(
    ctx: DocumentContext,
  ): Promise<DocumentInitialProps> {
    const initialProps = await Document.getInitialProps(ctx);

    return {
      ...initialProps,
    };
  }

  render(): JSX.Element {
    return (
      <Html prefix="og: https://ogp.me/ns#">
        <Head />
        <body>
          <noscript
            dangerouslySetInnerHTML={{
              __html: `
              <iframe
                src="https://www.googletagmanager.com/ns.html?id=${googleTagManagerId}"
                height="0"
                width="0"
                style="display:none;visibility:hidden"
              />`,
            }}
          />
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

しかしそもそもNext.jsでアプリケーションを開発している場合、クライアントサイドのJavaScriptが無効な場合まともに動作させる事は難しいです。

要件にもよりますが <noscript> は省略しても良いかもしれません。

カスタムイベントの送信

ここまでで基本的な設定は完了ですが、最後にGA4にカスタムイベントを送信する方法を紹介します。

LGTMeow の「他の猫ちゃんを表示」ボタンのクリックをカスタムイベントとして登録してみます。

GTM上でデータレイヤーの変数を追加

変数 → 新規 → データレイヤーの変数を追加します。

create_var1

create_var2

名前は fetch_random_images_trigger とします。

トリガーの追加

トリガー → 新規 → カスタムイベントを選択します。

create_trigger1

  • イベント名は「fetch_random_images」とします
  • このトリガーの発生場所は「一部のカスタムイベント」とします
  • イベント発生時の条件は Event 等しい fetch_random_images とします

create_trigger2

GA4用のイベントタグの追加

タグ → 新規 → Googleアナリティクス: GA4イベント → 設定タグに既存のGAを選択 → イベント名にさきほど作成したイベントを選択します。

トリガーにはさきほど設定したトリガーを選択します。

add_tag

ここまで設定できたら、ワークスペースの右上の「公開」を押下して、このバージョンを公開します。

workspace_publish

ボタンクリック時にイベントを送信する

Next.js側の対応です。

さきほど作成した src/utils/gtm.ts に以下の関数を追加します。

// ランダムでLGTM画像を表示させる機能が利用された際に実行する
type SendFetchRandomImagesLabel = 'fetch_random_images_button';

export const sendFetchRandomImages = (
  label: SendFetchRandomImagesLabel,
): void => {
  window.dataLayer.push({
    event: 'fetch_random_images',
    fetch_random_images_trigger: label,
  });
};

「他の猫ちゃんを表示」ボタンのクリック時に sendFetchRandomImages を呼び出すようにします。

  const handleRandom = async () => {
    try {
      const imageList = await fetchRandomImageList();
      setAppState({ imageList: imageList.images, isFailedFetchImages: false });

      sendFetchRandomImages('fetch_random_images_button');
    } catch (e) {
      setAppState({ imageList: [], isFailedFetchImages: true });
    }
  };

GA4の管理画面でイベントが送信されているかテスト

「他の猫ちゃんを表示」ボタンをクリックしてリアルタイムでイベントが送信されているか確認します。

realtime

今回は例として単純なカスタムイベントを定義しました。

本来この程度であればわざわざカスタムイベントを設定しなくても、イベントの計測を行なうことが可能です。

ソースコードを変更しなくてもさまざまな計測ができるのがGTMを利用するメリットなので、 カスタムイベントを使うかどうかは慎重に考える必要があります。

おわりに

以上がNext.jsでGTM、GA4を使う方法になります。

この記事を書くために以下の記事を参考にさせていただきました。

以上になります。最後まで読んでいただきありがとうございました。

Discussion

ログインするとコメントできます