Next.js × GAイベントトラッキング実装で学んだこと
はじめに
最近、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の関係性を理解することが重要です:
-
GTM (Google Tag Manager)
- タグの管理ツール
- イベントのトリガー設定
- GA4へのデータ送信設定
- いわば「データの交通整理係」
-
GA4 (Google Analytics 4)
- データの収集・分析
- レポートの作成・表示
- いわば「データの分析係」
データ送信の基本的な仕組み
GAイベントトラッキングは、以下のような流れで動作します:
- ウェブサイト上でユーザーアクションが発生
- 特定のイベントがトリガーされる
- データがGTMを通じて送信される
- 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'
}
});
重要なポイント
-
データの永続性
- dataLayerは一時的なデータストア
- ページ遷移で内容はリセット
- GTMが検知したデータは即座に処理される
-
データの構造
- イベント名は必須
- カスタムデータの構造は自由に設計可能
- GTM側の設定と整合性を取る必要がある
-
処理の流れ
- 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
}
このセットアップにより:
- GTMとGA4の基本的なトラッキングコードが導入される
- ページ遷移のトラッキングが可能になる
- カスタムイベントの送信が可能になる
実装例
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'
}
})
})
})
このテストでは:
- 各テストケース実行前にdataLayerを初期化
- コンポーネントをレンダリング
- イベントが発火される条件を満たす
- dataLayerに正しいデータがプッシュされているか検証
しています。これにより、イベントトラッキングが意図通りに機能することを担保できます
開発時の動作確認方法
ローカル環境で確認できること
- ブラウザ検証ツールConsoleでのdataLayerへのイベント送信
// Console で確認
console.log(window.dataLayer)
ブラウザの検証ツールコンソール画面
2. ブラウザ検証ツールNetworkタブでのリクエスト送信
- GTMへのリクエストが送信されているか確認("collect"でフィルタ)
- ステータスコードの確認
本番環境で確認できること
- GTMのプレビューモードでのイベント確認
- GA4のデバッグビューでのデータ収集確認
※ローカル環境(localhost)ではGA4へのデータ送信は行われません
まとめ
GAイベントトラッキングの実装で学んだ主なポイント:
- GTMとGA4の役割の違いを理解する
- Next.jsでの適切な初期設定
- dataLayerを使ったイベント送信の実装
- Reactコンポーネントでの適切なイベント発火タイミングの制御
- テストでのdataLayerのモック方法
今後の課題:
- GA4でのカスタムレポート作成
- イベントパラメータの標準化
- エラー時のトラッキング実装
Discussion