React(SPA構成)でGA4+GTMを本番導入した時の気付きやトラブルシューティング
三菱UFJフィナンシャル・グループ(MUFG)の戦略子会社であるJapan Digital Design株式会社でフロントエンドエンジニアをしている小笠原と申します。
今回は、Reactを用いてSPAを作成しGA4とGTMを導入した結果、様々な気付きがあったので、トラブルシューティングなども含め記事にまとめました。
はじめに
本記事では、GA4+GTMの構成に関する事前知識となるような内容を記載しています。そのため、体系的な話や、GAからGA4の移行、GTMタグと広告の連携など高度なことについては記述しておりません。
使用ライブラリについて
React: v18系
React Router 6系
GA4: react-ga4
SPAの注意点
通常のReactでSPAを実装した場合、正しくページロードが起こらない可能性があります。
今回は、React Router(6系)などの履歴を追跡できるライブラリを用いて対応しております。
GA4やGTMタグがロードされるまではGTMイベントを送信しないように実装する必要があります。
ページレンダリング時にGTMイベントを送信する場合、複数回送信されないように実装する必要があります。
以下のようにスクリプトをインストールしますが、サードパーティ製のライブラリを使用している場合は二重管理とならないように注意します。
全体像(GTM、GA4のデータの流れ)
全体的な流れとして、以下の通り進みます。
Websiteからイベントが発火した時に、GTMのサーバーへデータを送信します。
GTMでは設定したトリガーが該当のタグを呼び出して、GA4へデータを送信します。
GA4からBigQueryなど、データ分析用のDBへデータを流し込みます。
※BigQueryについては、詳しくは以下の公式ドキュメントをご覧ください。(https://support.google.com/analytics/answer/9358801?hl=ja )
環境分割時の注意点
環境分割時の注意点としては、GA4のID更新が挙げられます。
develop, staging, productionなどの並列環境でGTMやGA4を分けることは可能ですが、当然それぞれの設定は自分たちで行う必要があり、それがイベントタグやトリガー、変数など数多くの設定項目を要するGTMの場合は、やや面倒となります。
GTMの設定を全て手で行うのは大変なので、ほとんどのケースでは、GTMの機能にある設定ファイルのエクスポートとインポート機能(https://support.google.com/tagmanager/answer/6106997?hl=ja%C2%A0)を利用しますが、今回の場合、GA4のIDも引き継がれてしまう恐れがあります。
例えば「develop環境でテストが完了し、staging環境に反映しよう」となった時にGTMのdevelopからエクスポートし、GTMのstagingにインポートするとGA4のIDも引き継がれてしまい、それに気付かないとGA4の計測が正しく計測できません。
そのため、インポート前のjsonファイルを変更する、あるいはインポート完了後に、GTMのGUI上で該当環境のGA4のIDを正しいものに更新する必要があります。これらの問題を変換するスクリプトはGitHub上にもありますが、アプリケーション固有の課題を解決するためには独自で作った方が良いかもしれません。
GA4について
トラッキングパートナー統合機能
今回のケースでは用いておりませんが、コンバージョン トラッキング パートナー統合機能(https://support.google.com/analytics/topic/9578449?hl=ja&ref_topic=12403939&sjid=16964806091040918370-AP)があるため、要件によっては活用可能です。
拡張イベント計測機能
拡張イベント計測機能(https://support.google.com/analytics/answer/9216061?hl=ja)を使用することで、GA4の管理画面でイベントが有効化され `page_view` などを収集できるため、多くのサイトで計測に使用されています。こちらの機能を有効化することで、イベントをSPAから送る実装を独自に書く必要がなくなりますが、要件次第では使用しないこともあります。
GTMについて
イベント発火によるデータ送信について
GTMへ送信するペイロードには、イベント名とユーザー定義変数とその値を設定します。
検索条件を計測したい場合の例をご紹介します。
sendDataToGTM({
event: 'search-conditions',
'search-conditions-text': 'foo',
'search-conditions-type': 'kind',
'search-conditions-count': '50',
});
ここで注意すべき点として、イベントの収集に適用される上限が挙げられます。イベント名やイベントパラメータ名は、40文字以内というGTMの仕様があり(https://support.google.com/analytics/answer/9267744?hl=ja) 、超過文字は計測画面(GA4)で削られます。
また、イベントパラメータ値は100文字以内という制約もありますので、字数については注意した方が良いでしょう。
イベント名が40文字を超過した不正な例
sendDataToGTM({
event: 'foobar-screen-foobar-button-foobar-action-1',
'search-conditions-text': 'foo',
'search-conditions-type': 'kind',
'search-conditions-count': '50',
});
`foobar-screen-foobar-button-foobar-action-1` は43文字のため、文字数が超過するようなイベント名を付けると最後の数字が消えてしまい、何の計測か不明となってしまいます。
また、コンバージョンのように `_c` がsuffixにつくような計測をしたい時にも40文字という最大文字数という制約があるため、この点も考慮して命名を決めていく方が良いと思います。
GTMから送る時のインターフェイス
`react-gtm-hook` というライブラリはフックとして利用できるため、以下のように使います。
// ペイロードには、GTMに送りたいデータを格納
const payload = {
event: 'search-conditions',
'search-conditions-text': 'foo',
'search-conditions-type': 'kind',
'search-conditions-count': '50',
}
const gtmDispatch = useGTMDispatch()
gtmDispatch(payload)
しかし、この処理を各コンポーネントで記述してしまうと、メンテナンスコストが肥大化してしまうため、以下のような事前に必要なGTMイベントを全てカスタムフックに定義します。
なお、今回の例では、説明用を意図しており簡易コードのため、動作を保証していません。
また、プロダクトコードをそのまま載せることはできないので、公開できる内容へ変更しています。実際は、`searchConditions` というGTMイベント自体を定数に定義する形で、このフックにはTypeScriptのsatisfies Operatorなどを使ってGTMイベントの追加し忘れを防ぐなど、考慮すべき点はあります。
import { useGTMDispatch } from '@elgorditosalsero/react-gtm-hook'
export const useGTMEvents = () => {
const gtmDispatch = useGTMDispatch()
return {
/**
* 検索条件を変更した時に送信されます。
*/
searchConditions: (text: string, type: 'all' | 'kind' | 'each', count: number) => {
gtmDispatch({
event: 'search-conditions',
'search-conditions-text': text,
'search-conditions-type': kind,
'search-conditions-count': count,
})
},
// ... GTMで定義されたイベントを定義する。
}
}
使用する時は、各コンポーネントから呼び出します。
export const SearchButton = ({ text, type, count }: { text: string; type: 'all' | 'kind' | 'each'; count: number }) => {
const { searchConditions } = useGTMEvents()
return (
<button
onClick={() => {
searchConditions(text, type, count)
}}
>
Search
</button>
)
}
新たに追加されたイベントは同様にフックに定義し、コンポーネントから呼び出すような実装をしていくことになります。
実装後、GTM経由でGA4にイベントが送られるかどうかをチェックします。
Q&A(トラブルシューティング)
GA4に送られるデータを削除したい
データを削除したいときは、データ削除リクエスト(https://support.google.com/analytics/answer/9940393?hl=ja#zippy=%2C%E3%81%93%E3%81%AE%E8%A8%98%E4%BA%8B%E3%81%AE%E5%86%85%E5%AE%B9)を進める必要がありますが、事前にテスト環境などで個人情報やセンシティブなデータが送られていないか、という確認が他のSaaS同様必須となります。もし本番稼働後に、GTMをリリースした結果GA4に不正なデータが送られてしまったら、GTMのバージョン機能を使ってロールバックした方が早いこともあるかと思います。
社内からのアクセスを除外したい
特定のユーザー(社内)などを除外する、内部トラフィックデータフィルター(https://support.google.com/analytics/answer/10104470?sjid=5722119567393959147-AP)はあるので、IPアドレス毎に設定可能です。
ただし、通常のアプリケーションでマイページなどからデータ収集を制限したい場合のような個別対応としては相応しくないので、その場合は別途実装が必要になります。
開発環境では Google公式から提供されているオプトアウト アドオン(https://chrome.google.com/webstore/detail/google-analytics-opt-out/fllaojicojecljbmefodhfapmkghcbnh?hl=ja)
という拡張機能があります。テスト時はなるべく余計なデータを送りたくないケースも多いと思いますので、この拡張機能を使ってGA4のデータの送信を無効にできます。
注意点としては、QAチームへチェックを依頼したが、この拡張機能がONになっていて実際はGA4にデータが送られてこないという状況が発生することも考えられるため、使用する時にはご注意ください。
社内からのアクセスは計測しても良いが表示する時に除外したい
計測自体は行いたい場合は、レポートデータのフィルタ機能(https://support.google.com/analytics/answer/11377859?sjid=5722119567393959147-AP)の利用が良いでしょう。
GTMからGA4にデータが送られない
GTM上でデバッグする時は、プレビュー機能を使うことができます。この機能で、開発環境にあるデータの送信状況を具体的に確認できます。
ただし、GA4にちゃんと送られているか、という点についてはDebugViewを利用してGA4へのデータの流れを確認することができます。(https://support.google.com/analytics/answer/7201382?sjid=16964806091040918370)
ボットの対策をしたい
GA4では、既知のボットトラフィックは除外されるため、何か設定を見直す必要がありません。(https://support.google.com/analytics/answer/9888366?sjid=16964806091040918370-AP)
所感
フロントエンドの実装としては、他にも汎用的なインターフェイスにするにはどうしたら良いか?使いやすい形とは何か?エラー時はどういう処理を加えるか?全体的に持ち回るデータをどうするか?GTMイベント送信のテストコードをどうするか?など、考慮すべき点は多く実際の開発時は試行錯誤を重ねた上で実装しております。ただし、今回は書ききれない点もあり、全て踏み込んではいないことをご了承ください。
GA4+GTMの構成については、アプリケーション毎の要件次第ではあるものの、いくつかの注意点などがあったので事前知識として残しておきたいと思い、記事を書かせていただきました。
最後までご覧いただきありがとうございました。
最後に
Japan Digital Design株式会社では、一緒に働いてくださる仲間を募集中です。カジュアル面談も実施しておりますので、下記リンク先からお気軽にお問合せください。
この記事に関するお問い合わせはこちら
Japan Digital Design 株式会社
Technology & Development Division
Senior Engineer
Shinnosuke Ogasawara