はじめに:なぜNext.jsでのGA4導入は難しいのか?
企業のウェブ担当者やマーケティング責任者の皆様にとって、Google Analytics 4(GA4)への移行は喫緊の課題です。特に、モダンなフロントエンド技術であるNext.js(ネクストジェイエス)を採用している場合、その導入は一筋縄ではいきません。
Next.jsはReactをベースとしたフレームワークであり、高いパフォーマンスと開発体験を提供しますが、その内部構造、特にSPA(Single Page Application)的な動作が、従来のGoogle Analytics(ユニバーサルアナリティクス、UA)の計測手法と相性が悪い部分があります。本記事では、この課題を克服し、Next.js環境でGA4を正しく、かつパフォーマンスを維持して導入するための具体的な方法を解説します。
Problem: UA終了とNext.js特有の課題
従来のUAとGA4の根本的な違い
UAとGA4の最も大きな違いは、「計測の単位」です。UAがセッションとページビュー(PV)を中心としていたのに対し、GA4はユーザーが行う全ての行動を「イベント」として捉えます。
- UA: ページロード時に`pageview`を自動計測。
- GA4: デフォルトで拡張計測機能により様々なイベント(スクロール、クリックなど)を自動計測するが、SPAではページ遷移時に明示的なイベント発火が必要となる。
この違いが、Next.jsのようなSPAフレームワークでの導入を複雑にしています。
Next.jsがもたらす計測上の課題(SPAとルーティング)
Next.jsが提供するクライアントサイドでのルーティング(ページ遷移時にブラウザ全体のリロードを伴わない遷移)は、ウェブサイトの高速化に貢献します。しかし、従来のGAタグはページのフルロードを前提としているため、ページ遷移してもPVイベントが自動で発火しません。
「ブラウザのリロードなしにURLだけが変わる」というSPA特有の動作が、GA4に「新しいページが表示された」と認識させるための追加実装を必要とします。
Agitation: 間違った導入が引き起こす深刻なデータ損失
ページビューの重複計測と計測漏れ
最も避けたいのは、データの不正確性です。
計測漏れ
クライアントサイドのページ遷移時にPVイベントを手動で発火させないと、実際のトラフィックの一部が記録されません。特に重要なコンバージョン経路を見失う可能性があります。
重複計測
誤って設定すると、ページの初回ロード時にGA4の基本タグが発火し、さらにNext.js側の手動イベント発火も行われ、PVが二重にカウントされてしまい、ユーザーあたりのPV数が水増しされます。
SEOパフォーマンスへの悪影響と表示速度の低下
GA4のタグはJavaScriptであり、その読み込みと実行はウェブサイトのCore Web Vitalsに影響を与える可能性があります。特にタグの設置場所や読み込み方法を間違えると、以下の問題が発生します。
- LCP(Largest Contentful Paint)の悪化: タグの同期読み込みによるメインスレッドのブロック。
- CLS(Cumulative Layout Shift)の発生: タグの非同期読み込みによって発生するコンテンツのズレ。
Next.jsでは、パフォーマンスを最大限に引き出すためのタグのロード戦略が必須です。
Solution: Next.jsプロジェクトにGA4を正しく導入する実践ガイド
共通の準備:計測IDとGoogleタグの取得
まず、GA4の管理画面から測定ID(例: G-XXXXXXXXXX)と、<script>形式のGoogleタグ(gtag.js)のコードスニペットを取得します。
Next.jsの環境では、パフォーマンスを考慮し、このタグの設置にはnext/scriptコンポーネントを利用することを強く推奨します。
// components/GoogleAnalytics.js (Pages Router / App Router共通)
import Script from 'next/script';
const GA_MEASUREMENT_ID = 'G-XXXXXXXXXX'; // 自身の測定IDに置き換える
export const GoogleAnalytics = () => {
return (
<>
{/ Google Tag Managerまたはgtag.jsの基本タグをheadタグ内に記述 /}
<Script
async
src={`https://www.googletagmanager.com/gtag/js?id=${GA_MEASUREMENT_ID}`}
strategy="afterInteractive" // ページ描画後、アイドル時間中にロード
/>
<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}', {
page_path: window.location.pathname, // 初回ロード時のPVを発火
});
`,
}}
/>
</>
);
};
ポイント: strategy="afterInteractive"を使用することで、ページの主要コンテンツのロードを妨げません。
Pages Router環境でのGA4導入手順と実装例
Pages Router(pages/ディレクトリベース)では、アプリケーション全体のエントリーポイントである_app.js(または_app.tsx)を利用します。
Next.jsのrouterオブジェクトが提供するrouteChangeCompleteイベントを購読し、ページ遷移が完了するたびに手動でPVイベントをGA4へ送信します。
// pages/_app.js の一部
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { GoogleAnalytics } from '../components/GoogleAnalytics';
// ページ遷移時にGA4のPVイベントを手動で送信する関数
const handleRouteChange = (url) => {
window.gtag('config', 'G-XXXXXXXXXX', {
page_path: url,
});
};
function MyApp({ Component, pageProps }) {
const router = useRouter();
useEffect(() => {
// ページ遷移完了時のイベントを購読
router.events.on('routeChangeComplete', handleRouteChange);
// クリーンアップ関数
return () => {
router.events.off('routeChangeComplete', handleRouteChange);
};
}, [router.events]);
return (
<>
<GoogleAnalytics /> {/ 基本タグの設置 /}
<Component {...pageProps} />
</>
);
}
App Router環境でのGA4導入手順と実装例
App Router(app/ディレクトリベース)では、クライアントコンポーネント("use client"宣言が必要)内でusePathnameフックを利用し、URLの変更を検知します。
App Routerの特性上、レイアウトファイル(app/layout.js)で基本タグを読み込み、クライアントコンポーネントとしてパスの変更を監視するのが推奨されます。
// components/GA4PageTracker.js (use clientが必要)
'use client';
import { useEffect } from 'react';
import { usePathname, useSearchParams } from 'next/navigation';
const GA_MEASUREMENT_ID = 'G-XXXXXXXXXX';
export default function GA4PageTracker() {
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
if (typeof window.gtag !== 'undefined') {
const url = pathname + (searchParams.toString() ? `?${searchParams.toString()}` : '');
// PVイベントを手動発火
window.gtag('config', GA_MEASUREMENT_ID, {
page_path: url,
});
}
}, [pathname, searchParams]); // パスまたはクエリパラメータの変更時に実行
return null; // このコンポーネント自体は何も描画しない
}
// app/layout.js の一部 (サーバーコンポーネント)
import { GoogleAnalytics } from '@/components/GoogleAnalytics';
import GA4PageTracker from '@/components/GA4PageTracker';
export default function RootLayout({ children }) {
return (
<html lang="ja">
<head>
{process.env.NODE_ENV === 'production' && <GoogleAnalytics />}
</head>
<body>
{children}
{process.env.NODE_ENV === 'production' && <GA4PageTracker />}
</body>
</html>
);
}
注意: process.env.NODE_ENV === 'production'の条件を付けることで、開発環境での不要な計測を防ぐことができます。
Narrow down/Proof: 正確性を高めるための追加設定と検証
Next.jsでのイベント計測実装の基本
GA4で最も重要となるコンバージョンイベントやその他のカスタムイベントは、Next.jsのコンポーネント内で直接呼び出すことができます。
例えば、資料ダウンロードボタンのクリックイベントを計測する場合:
// components/DownloadButton.js
const handleDownloadClick = () => {
// イベントを発火
window.gtag('event', 'document_download', {
document_name: 'Next.js_GA4_Guide',
category: 'e-book',
});
// ダウンロード処理...
};
// ... ボタンのJSX ...
<button onClick={handleDownloadClick}>資料をダウンロード</button>
GA4とVercel連携、Google Tag Manager (GTM) の活用
Next.jsの開発・ホスティングによく利用されるVercelとの連携自体に特別な設定はありませんが、GTMを導入することで、コードを触らずにイベント計測やタグの変更が可能になり、ウェブ担当者の運用負荷を大幅に軽減できます。
GTMを利用する場合も、基本となるGTMのタグの埋め込みにはnext/scriptを利用し、GTM側でPVイベントをNext.jsのルーティングイベントに合わせて発火させる設定を行います。
導入後の動作検証とデバッグ
導入後は必ず以下のツールで検証を行い、計測の正確性を担保してください。
- GA4 DebugView: リアルタイムでイベントが正しく送られているか、二重計測が発生していないかを確認します。
- ブラウザの開発者ツール (Networkタブ): GA4へのリクエスト(
collect?v=2)がページ遷移時に一度だけ送信されているかを確認します。
Action: 正確なデータでマーケティング施策を加速させるために
まとめと次のステップ
Next.jsのSPA特性を理解し、Pages Routerではrouter.events、App RouterではusePathnameフックを利用することで、GA4のPV計測を正確に行うことができます。この正確なデータ基盤が、GA4の強力な分析機能や機械学習機能を最大限に活用するための第一歩となります。
データは企業の重要な資産です。正確なデータに基づき、ユーザー体験の改善、コンバージョン率の向上、そして最終的なビジネスゴールの達成に繋げてください。

