メインコンテンツへスキップ
kt-tech.blog

【Next.js】Google Analytics4を導入してみた

技術7分で読めます

この記事でわかること

  • Next.js(App Router)に GA4 を自前のコンポーネントで入れる手順と、その仕組み
  • クライアント遷移でもページビューを送るために usePathname / useSearchParams を使う理由
  • Next.js 15 以降でこのコンポーネントがビルドを止める理由と、Suspense で囲う対処
  • 現在は公式の @next/third-parties を使うのが早いということ

Next.js(App Router)のプロジェクトがあり、Google Analytics のアカウントを作れること。本文の手順は Next.js 13 時点のものです(Next.js 15 以降の注意点は本文の警告を参照)。デプロイ先として Vercel を想定しています。

はじめに

こんにちは!Web系の企業に勤務し、地方からフルリモート勤務をしている@takakouと申します

今回は、【Next.js】Google Analytics4を導入してみた というテーマで記事をシェアします!

記事執筆は未熟者で、至らない点もあるかと思いますが、皆さんのコメントやフィードバックをお待ちしています!

ポイント
2026年時点の補足: Next.js 14 以降は、公式の @next/third-parties に GA 用のコンポーネントが入っています。npm i @next/third-parties して <GoogleAnalytics gaId="G-XXXXXXXXXX" /> を layout に置くだけで済み、本記事のような手書きのコンポーネントは不要です。これから入れるならそちらを推奨します。以下は仕組みを知りたい場合や、自前で制御したい場合の手順として読んでください。

動作環境

記事執筆時の環境です。

端末

  • PC : MacBook Air (M1, 2020)
  • RAM : 8GB
  • OS : macOS Monterey(ver12.1)

バージョン

  • Next.js : 13.4.19
  • React : 18.2.0
  • npm : 9.8.1

Google Analytics とは

Google Analytics は、Google が提供するウェブ解析ツールです。ウェブサイトやモバイルアプリのユーザーの行動を詳しく分析できます。主な機能は次のとおりです。

  • トラフィック分析:

どのような経路でユーザーがサイトにアクセスしてきたか、例えば検索エンジン、リファラーサイト、直接アクセスなどの情報を取得することができます。

  • ユーザーの行動分析:

ユーザーがサイト内でどのページを訪れたか、どのページでどれくらいの時間を過ごしたか、どのページで離脱したかなどの情報を分析することができます。

  • ユーザーのデモグラフィック情報:

年齢、性別、地域などのユーザーの基本的なデモグラフィック情報を取得することができます。

  • コンバージョンの追跡:

オンラインストアや広告キャンペーンの成果を測定するためのツールとして、コンバージョン(目標達成)の追跡機能があります。

  • カスタムレポート:

ユーザーのニーズに合わせてカスタムレポートを作成することができます。

実装手順

Google Analytics 側の設定

Google Analytics の設定手順(Xserver) を見ながら設定をし、計測タグの ID をメモしておきます。設定完了後に G-XXXXXXXXXX のような ID が出てくるはずです。

gtag の型定義を install

Bash
npm i -D @types/gtag.js

.env.local に定義

JavaScript
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
注意
NEXT_PUBLIC_ を付けた環境変数はビルド時にバンドルへ埋め込まれ、ブラウザから丸見えになります。GA の計測 ID は公開されても問題ない値なのでこれで良いですが、API キーの類をここに入れてはいけません。

libs/gtag.ts を作成

TypeScript
export const GA_TAG_ID = process.env.NEXT_PUBLIC_GA_ID || "";

export const IS_GATAG = GA_TAG_ID !== "";

export const pageview = (path: string) => {
  window.gtag("config", GA_TAG_ID, {
    page_path: path,
  });
};

コンポーネントを作成

TypeScript
"use client";

import { usePathname, useSearchParams } from "next/navigation";
import Script from "next/script";
import { useEffect } from "react";
import { IS_GATAG, GA_TAG_ID, pageview } from "@/../libs/gtag";

const GoogleAnalytics = () => {
  const pathname = usePathname();
  const searchParams = useSearchParams();

  useEffect(() => {
    if (!IS_GATAG) {
      return
    }
    const query = searchParams.toString()
    const url = query ? `${pathname}?${query}` : pathname
    pageview(url)
  }, [pathname, searchParams])

  return (
    <>
      <Script
        strategy="lazyOnload"
        src={`https://www.googletagmanager.com/gtag/js?id=${GA_TAG_ID}`}
      />
      <Script id="gtag-init" strategy="afterInteractive">
        {`
          window.dataLayer = window.dataLayer || [];
          function gtag(){dataLayer.push(arguments);}
          gtag('js', new Date());
          gtag('config', '${GA_TAG_ID}', {
            page_path: window.location.pathname,
          });
        `}
      </Script>
    </>
  );
};

export default GoogleAnalytics;
重要
Next.js 15 以降はこのままだとビルドが通りません。useSearchParams を使うコンポーネントは Suspense 境界で囲うのが必須になりました。GA は全ページ共通の layout に置くため、これを見落とすとサイト全体のビルドが止まります。具体的な踏み抜け方は Next.js 13→16 アップグレードの全記録 に書いています。

layout.tsx で読み込み

JavaScript
import { Suspense } from 'react'
import GoogleAnalytics from '@/components/GoogleAnalytics/GoogleAnalytics'

<html lang="ja">
  <head>
    <Suspense fallback={null}>
      <GoogleAnalytics/>
    </Suspense>
  </head>
  <body>
    <div>
      <Header/>
      <div className='m-1 mt-5 rounded-lg'>
        {children}
      </div>
      <Footer/>
    </div>
  </body>
</html>

Vercel で環境変数を設定

Vercel のプロジェクト設定で NEXT_PUBLIC_GA_ID を環境変数として定義し、値も入れておきます。

反映を確認

デプロイをし直し、少しサイトを操作した後にGoogle Analyticsの画面を見にいきましょう。GoogleAnalyticsの画面が設定のような画面から切り替わり、計測画面になっていればOKです。

Tips
レポートへの反映には最大 48 時間かかることがあります。ただし「リアルタイム」レポートは即時に入るので、正しく入ったかを確かめるならそちらを見るのが早いです。

参考リンク

おわりに

GoogleAnalyticsの設定がとても簡単だったので驚きました。

とりあえず今回は設定を計測されるか試してみたいだけだったのでここで終わります。

間違っている点等ありましたら指摘いただけると嬉しいです!

更新履歴

  1. ページビューの URL 組み立てが pathname + searchParams.toString() となっており、クエリの ? が欠けて連結されていたのを修正。Next.js 15 以降は useSearchParams に Suspense 境界が必須で、このコンポーネントがサイト全体のビルドを止めることを警告として追加し、layout の例を Suspense で囲んだ形に修正。現在は公式の @next/third-parties で済むことを冒頭に注記。見出しがすべて同じ階層で目次が崩れていたのを実装手順の下に入れ子にする形に修正。NEXT_PUBLIC_ の環境変数がブラウザから見えることと、リアルタイムレポートで確認するコツを補足。コードブロックの言語指定とファイル名キャプションを整理。裸 URL をタイトル付きリンクに変更。
  2. OGP Description の修正