Ishiguro Suguru

ReactでGA4の設定を行ったらPV(ページビュー)が2重に送信されていた件の対応備忘録。

結論:どう設定すればよいのか?

Googleタグマネージャー(GTM)から設定しよう!

GA4とGTMは裏で勝手に紐づいているようで、GA4のタグを埋め込むと自動的にGTMのイベントが発火してページビューがGA4に送信される。

そのため従来のGAにおけるSPA(Single Page Application)で行っていた処理(ルーティングの際にイベントを送信)は不要になる。
※カスタムイベントは従来どおりイベントを発火させたいタイミングで送信する記述が必要になる

方法:GA4のPV測定

そもそもGA4のPV測定はReact関係なしに大別して以下の方法がある。

  1. GA4のタグを埋め込む ← NG
  2. GTMのタグを埋め込む ← OK

GA4のタグを埋め込み任意のイベントを送信すればGTMの設定は不要。
GTMのタグを埋め込む場合はGTMの管理画面からGA4タグ設定が必要。

GA4・GTMともにアカウントを作成するとサービスを利用するためのタグが発行されるため、 SPA(React)のコード内に記載すればよい。
今回はReactの以下ライブラリを使って設定した。

  1. GA4:react-ga4 ← NG
  2. GTM:react-gtm-module ← OK

課題:問題が発生した”react-ga4”を使用したコード

実際に問題が発生したhookコードは以下の通り。
ルートのファイルで呼び出せばページ遷移時に処理が実行される。

ただGA4のPV数がどうもおかしいようでリアルタイムの数値を見るとPVを2重に送信している様子…。
原因特定のためデバックを行う。(後述)

import { useEffect } from "react";
import { useLocation } from "react-router-dom";
import ReactGA from "react-ga4";
import { GA4_ID } from "../../config";

export const useTracking = () => {
  const location = useLocation();

  // [INFO] ページ遷移時にGA4で測定
  useEffect(() => {
    ReactGA.initialize(GA4_ID);
    // [INFO] react-helmetで設定したtitleタグ情報はレンダリング直後には反映されない
    //        そのためsetTimeoutを使用してhelmetの処理終了を待つ
    window.setTimeout(() => {
      console.log(
        `[INFO][useTracking] page=${location.pathname}${location.search}`
      );
      ReactGA.send({
        hitType: "pageview",
        page: `${location.pathname}${location.search}`,
        title: document.title,
      });
    });
  }, [location]);
};

検証:GA4の”DebugView”で送信しているデータの確認

実際にどういうデータが送られるかはGA4の”DebugView”で確認できる。(Chromeのコンソールにもログが出力される)
事前にChrome拡張機能のインストールが必要。

[参考] [GA4] DebugView でイベントをモニタリングする

DebugViewで確認すると以下のように"page_view"が連続で2回実行されている。

Chromeのコンソールを確認してみると、どうやら"gtm.historyChange-v2"とかいうイベント実行後に “page_view"イベントが自動で送信されている事が判明。
※以下コンソールに出力されていたログの一部

Processing commands (1)
Processing data layer push: {event: "gtm.historyChange-v2", gtm.historyChangeSource: "pushState" ...
Processing GTAG command: ["event", "page_view", {page_location: ...

調査:“gtm.historyChange-v2"とは?

余分にPVを送る原因になっているイベント"gtm.historyChange-v2"とは?

  • GTMによって発生するイベント
  • GA4のタグを埋め込んでいるだけでも発生する
  • デフォルトは自動で発生する

このイベント発生をオフにする方法もあった。
GA4の「ブラウザの履歴イベントに基づくページの変更」をオフにする。
※GA4管理画面 > 管理 > データストリーム > ストリームの詳細 > 拡張計測機能 > ページビュー数 > 詳細設定を表示

しかしGA4からこのイベントをオフにしてもブラウザのページリロード時に2重に送信してしまう…
(通常のページ遷移は解消される) この原因は特定に時間がかかりそうなので、GTM経由で"gtm.historyChange-v2"を使った自動測定方法に変更した。

[参考] The gtm.historyChange-v2 dataLayer event

解決方法:“react-gtm-module"を使用したコードに変更

修正後のhookコードは以下の通り。
ルートのファイルで呼び出せばページ遷移時に処理が実行される。

上記のとおりPVに関しては自動で測定されるためTagManager.initializeを実行するだけで良い。
別途カスタマイズしたイベントを送信したい場合はTagManager.dataLayerを使う。

import { useEffect } from "react";
import { useLocation } from "react-router-dom";
import TagManager from "react-gtm-module";
import { GTM_ID } from "../../config";

export const useTracking = () => {
  const location = useLocation();

  // [INFO] ページ遷移時にGTMで測定
  useEffect(() => {
    TagManager.initialize({ gtmId: GTM_ID });
    // [INFO] react-helmetで設定したtitleタグ情報はレンダリング直後には反映されない
    //        そのためsetTimeoutを使用してhelmetの処理終了を待つ
    window.setTimeout(() => {
      console.log(
        `[INFO][useTracking] page=${location.pathname}${location.search}, title=${document.title}`
      );
      // [INFO] カスタムイベントを設定する場合は以下のdataLayerに値を設定する
      // TagManager.dataLayer({
      //   dataLayer: {
      //     event: "pageview",
      //     page: {
      //       url: `${location.pathname}${location.search}`,
      //       title: document.title,
      //     },
      //   },
      // });
    });
  }, [location]);
};

GTM管理画面の設定は、PV測定だけであれば以下のタグを設定するだけで良い。

最後に

現在のところページビューを測定するだけであれば細かいコードの記述は不要なようです。
カスタムイベントを送信する必要がないのであれば、上記hookのコードではなくベースのindex.htmlに直接GTMタグを埋め込んだほうが早い。

comments powered by Disqus