📊

Next.js × GAイベントトラッキング実装で学んだこと

2025/01/28に公開

はじめに

最近、Next.jsプロジェクトでGoogle Analytics(GA4)のイベントトラッキングを実装する機会がありました。その過程で学んだことを共有したいと思います。

注意事項

本記事では Next.js アプリケーションでのイベントトラッキングの実装に焦点を当てているため、GA4/GTMのコンソールでの設定(トリガーの作成やタグの設定など)については割愛しています。設定については、以下の公式ドキュメントを参照してください:

注意: この記事はNext.js Pages Routerベースの実装です。

最近のNext.js(バージョン13以降)では、App Routerが導入され、イベントトラッキングの実装方法に若干の違いがあります。この記事の内容は主にPages Routerを使用しているプロジェクト向けです。

App Routerでの主な違い:

  • クライアントコンポーネントでの 'use client' ディレクティブの使用
  • app/layout.tsxでのスクリプト読み込み
  • usePathname(), useSearchParams() を使用したページ遷移トラッキング

最新のNext.jsプロジェクトを開始する場合は、公式ドキュメントでApp Routerの実装方法を確認することをおすすめします。

GA/GTMの基本的な関係

実装を始める前に、GAとGTMの関係性を理解することが重要です:

  1. GTM (Google Tag Manager)

    • タグの管理ツール
    • イベントのトリガー設定
    • GA4へのデータ送信設定
    • いわば「データの交通整理係」
  2. GA4 (Google Analytics 4)

    • データの収集・分析
    • レポートの作成・表示
    • いわば「データの分析係」

データ送信の基本的な仕組み

GAイベントトラッキングは、以下のような流れで動作します:

  1. ウェブサイト上でユーザーアクションが発生
  2. 特定のイベントがトリガーされる
  3. データがGTMを通じて送信される
  4. GA4でデータが収集・分析される

この仕組みにより、柔軟で詳細なユーザー行動の追跡が可能になります。

dataLayerとは

GA4でイベントトラッキングを実装する前に、重要な概念であるdataLayerについて説明します。

dataLayerは:

  • Google Tag Managerが提供するグローバルJavaScriptオブジェクト
  • ウェブサイトからマーケティングおよび分析ツールへのデータ送信を抽象化する仕組み
  • イベントや変数を動的にプッシュし、GTMがそれらを処理するためのキュー

特徴

  • ブラウザのグローバルスコープで利用可能
  • 配列のようなインターフェースを持つが、オブジェクトをプッシュして操作する
  • シングルページアプリケーション(SPA)においても、イベントの追跡を柔軟に管理可能
  • GTMがリアルタイムでデータを検知し、設定されたタグやトリガーに基づいて処理を実行

基本的な使い方

// dataLayerの初期化
window.dataLayer = window.dataLayer || [];

// イベント発生時にデータをプッシュ
window.dataLayer.push({
  'event': 'button_click',      // イベント名
  'custom': {                   // カスタムデータ
    'button_name': 'submit',
    'page_section': 'header'
  }
});

重要なポイント

  1. データの永続性

    • dataLayerは一時的なデータストア
    • ページ遷移で内容はリセット
    • GTMが検知したデータは即座に処理される
  2. データの構造

    • イベント名は必須
    • カスタムデータの構造は自由に設計可能
    • GTM側の設定と整合性を取る必要がある
  3. 処理の流れ

    • Webサイトでイベントが発生
    • dataLayer.push()でデータを追加
    • GTMがdataLayerの変更を検知
    • GTMの設定に基づいて、GA4などの各種ツールにデータを転送

イベントトラッキングの方法

GA4でのイベントトラッキングには主に2つの方法があります:

1. gtag()を使用する方法

window.gtag('event', 'click', {
  event_category: 'category',
  event_label: 'label'
});

この方法は:

  • GA4に直接イベントを送信
  • GTMを経由しないため、GTM側でのイベント制御ができない
  • シンプルな実装で済む

2. dataLayer.push()を使用する方法(本記事での実装)

window.dataLayer.push({
  event: 'click',
  custom: {
    content_name: contentName
  }
});

この方法は:

  • GTMを経由してGA4にイベントを送信
  • GTM側でイベントの制御や加工が可能
  • イベントの設定変更をコードの修正なしでGTM側で行える
  • GA4以外のマーケティングツールへのデータ送信も容易

本記事では、より柔軟なイベント管理を可能にするdataLayer.push()を使用した実装方法を紹介します。

GA4の初期設定

まず、Next.jsプロジェクトでGA4を利用するための基本設定を行います。

1. 環境変数の設定

# .env.local
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX  # あなたのGA4測定ID

2. GoogleAnalytics Providerの作成

// components/providers/GoogleAnalytics.tsx
import Script from 'next/script'
import { useRouter } from 'next/router'
import { useEffect } from 'react'

export const GoogleAnalytics = ({ children }) => {
  const router = useRouter()
  const GA_MEASUREMENT_ID = process.env.NEXT_PUBLIC_GA_ID

  useEffect(() => {
    const handleRouteChange = (url: string) => {
      window.gtag('config', GA_MEASUREMENT_ID, {
        page_path: url,
      })
    }

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

  return (
    <>
      {/* Google Tag Manager */}
      <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','GTM-XXXXXX');
          `
        }}
      />

      {/* Google Analytics */}
      <Script
        strategy="afterInteractive"
        src={`https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`}
      />
      <Script
        id="gtag-init"
        strategy="afterInteractive"
        dangerouslySetInnerHTML={{
          __html: `
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());
            gtag('config', '${GA_MEASUREMENT_ID}');
          `
        }}
      />
      {children}
    </>
  )
}

3. _app.tsxでの設定

// pages/_app.tsx
import { GoogleAnalytics } from '@/components/providers/GoogleAnalytics'

const App = ({ Component, pageProps }) => {
  return (
    <GoogleAnalytics>
      <Component {...pageProps} />
    </GoogleAnalytics>
  )
}

export default App

4. 型定義の追加

// types/global.d.ts
interface Window {
  dataLayer: any[]
  gtag: (command: string, ...args: any[]) => void
}

このセットアップにより:

  1. GTMとGA4の基本的なトラッキングコードが導入される
  2. ページ遷移のトラッキングが可能になる
  3. カスタムイベントの送信が可能になる

実装例

GAイベントトラッキングの実装例を見ていきましょう。

イベントトラッキング用の関数

// lib/gtag.ts
export const contentView = ({ contentName }: { contentName: string }) => {
  if (window && window.dataLayer) {
    window.dataLayer.push({
      event: 'content_view',
      custom: {
        content_name: contentName
      }
    })
  }
}

export const contentDownload = ({ 
  contentName,
  fileName 
}: { 
  contentName: string
  fileName: string 
}) => {
  if (window && window.dataLayer) {
    window.dataLayer.push({
      event: 'content_download',
      custom: {
        content_name: contentName,
        file_name: fileName
      }
    })
  }
}

Next.jsコンポーネントでの実装

コンテンツをモーダルで表示し、表示時とダウンロード時にイベントを発火させる実装例です:

import { FC, useEffect } from 'react'
import { contentView, contentDownload } from '@/lib/gtag'

const ContentModal: FC<Props> = ({
  isOpen,
  data,
  onClose
}) => {
  // コンテンツ表示時のトラッキング
  useEffect(() => {
    if (isOpen && data?.title) {
      gtag.contentView({
        contentName: data.title
      })
    }
  }, [isOpen, data?.title])

  // ダウンロード時のトラッキング
  const trackDownloadEvent = () => {
    if (data?.title && data?.file?.name) {
      gtag.contentDownload({
        contentName: data.title,
        fileName: data.file.name
      })
    }
  }

  return (
    <div className="content-view">
      <h1>{data?.title}</h1>
      <button onClick={trackDownloadEvent}>
        ダウンロード
      </button>
      <button onClick={onClose}>
        閉じる
      </button>
    </div>
  )
}

テストの実装例

Jest + Testing Libraryを使用したテストの実装例です:

import { fireEvent, render, screen } from '@testing-library/react'

declare global {
  interface Window {
    dataLayer: any[]
  }
}

describe('GAイベントトラッキング', () => {
  beforeEach(() => {
    // 各テストケース実行前にdataLayerをリセット
    window.dataLayer = []
  })

  it('モーダルが開かれた時にcontentViewイベントが発火する', () => {
    render(
      <ContentModal
        isOpen={true}
        data={{ title: 'サンプルコンテンツ' }}
      />
    )

    // dataLayerに正しいイベントデータがプッシュされているか確認
    expect(window.dataLayer).toContainEqual({
      event: 'content_view',
      custom: {
        content_name: 'サンプルコンテンツ'
      }
    })
  })

  it('ダウンロードボタンクリック時にdownloadイベントが発火する', () => {
    render(
      <ContentModal
        isOpen={true}
        data={{
          title: 'サンプルコンテンツ',
          file: { name: 'sample.pdf' }
        }}
      />
    )

    // ダウンロードボタンをクリック
    fireEvent.click(screen.getByText('ダウンロード'))

    // dataLayerに正しいイベントデータがプッシュされているか確認
    expect(window.dataLayer).toContainEqual({
      event: 'content_download',
      custom: {
        content_name: 'サンプルコンテンツ',
        file_name: 'sample.pdf'
      }
    })
  })
})

このテストでは:

  1. 各テストケース実行前にdataLayerを初期化
  2. コンポーネントをレンダリング
  3. イベントが発火される条件を満たす
  4. dataLayerに正しいデータがプッシュされているか検証

しています。これにより、イベントトラッキングが意図通りに機能することを担保できます

開発時の動作確認方法

ローカル環境で確認できること

  1. ブラウザ検証ツールConsoleでのdataLayerへのイベント送信
// Console で確認
console.log(window.dataLayer)

ブラウザの検証ツールコンソール画面
2. ブラウザ検証ツールNetworkタブでのリクエスト送信

  • GTMへのリクエストが送信されているか確認("collect"でフィルタ)
  • ステータスコードの確認

本番環境で確認できること

  1. GTMのプレビューモードでのイベント確認
  2. GA4のデバッグビューでのデータ収集確認

※ローカル環境(localhost)ではGA4へのデータ送信は行われません

まとめ

GAイベントトラッキングの実装で学んだ主なポイント:

  1. GTMとGA4の役割の違いを理解する
  2. Next.jsでの適切な初期設定
  3. dataLayerを使ったイベント送信の実装
  4. Reactコンポーネントでの適切なイベント発火タイミングの制御
  5. テストでのdataLayerのモック方法

今後の課題:

  • GA4でのカスタムレポート作成
  • イベントパラメータの標準化
  • エラー時のトラッキング実装

参考資料

合同会社春秋テックブログ

Discussion