04. GA4でアプリの使われ方を計測する
アプリを公開すると、次に知りたくなるのは「実際に使われているのか」です。
どの画面で離脱しているのか。追加した機能は触られているのか。広告を見た人と見なかった人で、その後の行動は違うのか。こうした問いに勘ではなく数字で答えるための土台が Firebase Analytics と、その実体である GA4(Google Analytics 4) です。
ただし、イベントを送るだけでは、独自パラメータを通常レポートの分析軸として使えない場合があります。
独自パラメータをレポートや探索で使うには、カスタム定義の登録が必要です。登録は過去の通常レポートへ遡及しませんが、イベント数や標準ディメンションは別です。また、既にBigQueryへエクスポートしていた生イベントのパラメータは、未登録でも分析できます。
この記事では、「イベントを送る」から「実際に読める数字になる」までの間にある、忘れられがちな手順を埋めていきます。
この記事のサブコンテンツ
Section titled “この記事のサブコンテンツ”- FirebaseコンソールとGA4管理画面の使い分け
- イベント設計をコードの正本から導く
- カスタムディメンションを登録する
- 自分の開発トラフィックを除外する
- GA4 Data APIで集計を自動化する
- 数字を読む前に確認することと次のステップ
1. FirebaseコンソールとGA4管理画面の使い分け
Section titled “1. FirebaseコンソールとGA4管理画面の使い分け”最初に、いちばん紛らわしいところをはっきりさせます。
Firebase Analytics の実体は GA4 プロパティです。同じデータを2つの管理画面から見ている、という関係です。そして画面によってできることが違います。
| やりたいこと | どこで |
|---|---|
| ユーザー数・D1リテンションをざっと見る | Firebaseコンソール → Analytics |
| カスタムディメンションの登録 | GA4の管理(Firebase側には存在しません) |
| データ保持期間、Google Signals のオンオフ | GA4の管理 |
| デベロッパートラフィックの除外フィルタ | GA4の管理 |
| BigQueryへのエクスポート設定 | Firebaseコンソール → プロジェクトの設定 → 統合 |
「Firebaseコンソールを探したけれど見つからない」設定は、GA4側も確認してください。
Expoでは @react-native-firebase/analytics を使います。
npx expo install @react-native-firebase/app @react-native-firebase/analytics expo-dev-client expo-build-propertiesパッケージの追加だけでは設定は完了しません。FirebaseプロジェクトにiOS / Androidアプリを登録し、設定ファイルを取得して ios.googleServicesFile・android.googleServicesFile へ指定します。@react-native-firebase/app のconfig pluginと、iOSのフレームワーク設定も(SPMとCocoaPodsで構成が異なります)React Native FirebaseのExpo導入手順に従って設定し、開発ビルドを作り直してください。
応用事項編01のFirebase JS SDKとReact Native Firebaseは別のSDKです。同じFirebaseプロジェクトを指定してもAuthのログイン状態まで自動共有されるわけではありません。Analyticsに渡すユーザーIDや同意状態は明示的に連携し、メールアドレス・習慣名などをイベントへ送らないようにします。
プロパティIDを控えておく
Section titled “プロパティIDを控えておく”GA4の管理 → プロパティ設定に、9〜10桁の数字のプロパティIDがあります。これは後でData APIを叩くときにも、BigQueryのデータセット名(analytics_<プロパティID>)にも使うので、いま控えておいてください。
G- で始まる測定IDとは別物です。ここを取り違えるとAPIが動きません。
2. イベント設計をコードの正本から導く
Section titled “2. イベント設計をコードの正本から導く”送るパラメータを1か所に集める
Section titled “送るパラメータを1か所に集める”イベント名とパラメータを各画面に直接書くと、必ず表記ゆれが起きます。level と Level、user_exit と userExit が混ざった時点で、集計は破綻します。
スキーマを1つのファイルに集約し、そこを正本にしてください。
// アプリが送りうるイベントとパラメータの正本。// GA4 への登録は、このファイルから機械的に導出する。
export const EVENTS = { challengeStart: 'challenge_start', questionResolved: 'question_resolved', challengeComplete: 'challenge_complete', challengeAbandon: 'challenge_abandon',} as const;
// イベントスコープのカスタムディメンションとして登録するパラメータexport const DIMENSIONS = [ 'category', // 問題カテゴリ 'level', // 難易度 'entry_point', // どこから開始したか 'outcome', // correct / incorrect / timeout 'exit_reason', // user_exit / navigation / interrupted] as const;
// 指標(数値)として登録するパラメータexport const METRICS = [ 'response_time_ms', 'current_question_index',] as const;
export const MAX_LEVEL = 6;検証で落ちたイベントは、黙って消えます
Section titled “検証で落ちたイベントは、黙って消えます”送信前にパラメータを検証する層を置くのは良い習慣ですが、ここには実際に踏むと痛い罠があります。
import { getAnalytics, logEvent } from '@react-native-firebase/analytics';import { MAX_LEVEL } from './schema';
export async function logChallengeStart(params: { category: string; level: number }) { if (params.level < 1 || params.level > MAX_LEVEL) { // ⚠️ ここで捨てると、警告ログしか残らない console.warn('[analytics] invalid level', params.level); return; } await logEvent(getAnalytics(), 'challenge_start', params);}3. カスタムディメンションを登録する
Section titled “3. カスタムディメンションを登録する”ここがこの記事でいちばん重要な節です。
独自パラメータをレポートで使うには登録が必要です
Section titled “独自パラメータをレポートで使うには登録が必要です”アプリが logEvent('challenge_abandon', { exit_reason: 'user_exit', level: 3 }) を送っていても、GA4側で exit_reason と level をカスタムディメンションとして登録していなければ、それらを通常レポートの分析軸にできません。
イベント数自体は確認できます。未登録のカスタム定義は選択肢やData APIのスキーマに存在しない場合があり、必ず (not set) という行になるわけではありません。登録済みでも値を送っていないイベントでは (not set) になり得るため、登録漏れと送信漏れを分けて確認します。
https://analytics.google.com/ を開いて、
- 左下の ⚙「管理」
- 真ん中のプロパティ列の中のカスタム定義
- 「カスタム ディメンション」タブ → 「カスタム ディメンションを作成」
| 欄 | 入れる値 |
|---|---|
| ディメンション名 | exit_reason(表示用の名前。日本語でも可) |
| 範囲 | イベント |
| イベント パラメータ | exit_reason ← ここはコードと1文字も違わないこと |
数値として集計したいもの(response_time_ms など)は、「カスタム指標」タブの方に登録します。
登録漏れを防ぐ
Section titled “登録漏れを防ぐ”手で登録していると、パラメータを追加したときに必ず登録を忘れます。コードの正本とGA4の現状を突き合わせて、差分だけを作るスクリプトを書いておくのが確実です。
【AIエージェントへの依頼】
`analytics/schema.ts` の DIMENSIONS / METRICS を読み込み、Google Analytics Admin API で現在GA4に登録済みのカスタム定義と比較して、不足しているものだけを作成するスクリプトを書いてください。
要件:- 既定では差分を表示するだけで、何も作成しないこと- `--apply` を付けたときだけ作成すること- 既に登録済みのものは二重登録しないこと- 上限50個を超える場合は、作成せずに警告して終了すること差分表示はこんな出力になります。
アプリが送るパラメータ: 42 / 宣言: 42ズレなし。登録予定 — ディメンション 17 / 指標 224. 自分の開発トラフィックを除外する
Section titled “4. 自分の開発トラフィックを除外する”リリース直後のデータは、たいていあなた自身の操作で汚染されています。開発中に何百回もアプリを起動しているので、当然です。
AdMobには「テストデバイスをADID/IDFAで登録する」機能がありますが、GA4に同等のものはありません。端末IDを受け付ける口がないからです。代わりに、デベロッパートラフィック フィルタ + 端末側で debug_mode を立てるという組み合わせを使います。
端末を登録する
Section titled “端末を登録する”Android — リリースビルドにも効きます。パッケージ名を指定するだけです。
# 有効にするadb shell setprop debug.firebase.analytics.app com.example.myapp
# 解除するadb shell setprop debug.firebase.analytics.app .none.iOS — npx expo prebuild で生成された ios/ の .xcworkspace をXcodeで開き、Scheme → Run → Arguments Passed On Launch に -FIRDebugEnabled を追加して一度起動します。
この設定はそのインストールに永続します(-FIRDebugDisabled を渡すまで)。一度登録すれば、以後はXcodeを経由せず起動しても内部トラフィック扱いのままです。
GA4側でフィルタを作る
Section titled “GA4側でフィルタを作る”GA4の管理 → データ設定 → データフィルタで「デベロッパートラフィック」フィルタを作成します。ここまでコード変更はゼロです。
おまけ:DebugViewが同時に使えます
Section titled “おまけ:DebugViewが同時に使えます”除外に使う debug_mode は、DebugViewが使うフラグと同じものです。つまり同じ操作で、
- レポートからは自分のトラフィックが除外され
- DebugViewでは自分のイベントがリアルタイムに見える
という状態になります。イベントとパラメータが届いているかの確認に使えます。DebugViewで見えることは、カスタム定義への登録や通常レポートへの反映が済んだ証明ではありません。フィルタの検証は公式の手順に従って行います。
5. GA4 Data APIで集計を自動化する
Section titled “5. GA4 Data APIで集計を自動化する”管理画面を毎回開いて数字を拾うのは続きません。GA4 Data APIは完全に無料なので、集計をスクリプト化してAIに読ませる形にしておくと、分析が習慣になります。
① APIを2つ有効化する(どちらも無料、課金設定は不要)
Google Cloud Consoleの「APIとサービス → ライブラリ」で、
- Google Analytics Data API(データを読む用)
- Google Analytics Admin API(前節の登録スクリプト用)
FirebaseプロジェクトはそのままGCPプロジェクトなので、新規作成は不要です。
② サービスアカウントを作る
Google Cloud Console → IAMと管理 → サービスアカウント → 作成。
作成後、「キー」タブからJSONキーを作成してダウンロードし、リポジトリの外に置きます。
mkdir -p ~/.config/myappmv ~/Downloads/xxxxx-*.json ~/.config/myapp/ga4.jsonchmod 600 ~/.config/myapp/ga4.json③ そのアドレスをGA4側に登録する
これをやらないと、上を全部やっても 403 PERMISSION_DENIED になります。
GA4の管理 → プロパティ列 → 「プロパティのアクセス管理」 → 右上の「+」→「ユーザーを追加」 → メールアドレス: [email protected] → 役割: 読むだけなら「閲覧者」、カスタム定義を作るなら「編集者」 → 「新規ユーザーにメールで通知」のチェックは外す(サービスアカウントは受け取れません)④ 集計スクリプトを作って実行する
tools/ga4_dashboard.py を次の内容で作成します。標準ディメンションであるイベント名とイベント数を取得する最小例です。独自パラメータの集計は、カスタム定義の登録後に追加してください。
import jsonimport osfrom google.analytics.data_v1beta import BetaAnalyticsDataClientfrom google.analytics.data_v1beta.types import ( DateRange, Dimension, Metric, RunReportRequest,)
property_id = os.environ["GA4_PROPERTY_ID"]if not property_id.isdigit(): raise ValueError("GA4_PROPERTY_IDには数字のプロパティIDを指定してください。")
client = BetaAnalyticsDataClient()report = client.run_report(RunReportRequest( property=f"properties/{property_id}", date_ranges=[DateRange(start_date="7daysAgo", end_date="yesterday")], dimensions=[Dimension(name="eventName")], metrics=[Metric(name="eventCount")], limit=1000,))print(json.dumps({ "rowCount": report.row_count, "rows": [ {"event": row.dimension_values[0].value, "count": int(row.metric_values[0].value)} for row in report.rows ],}, ensure_ascii=False, indent=2))実行用のPython環境を用意します。認証やAPIエラーで失敗した場合は、0件として扱わずエラーを確認してください。1,000行を超える集計ではページングを追加します。
python3 -m venv .venvsource .venv/bin/activatepython -m pip install google-analytics-dataexport GA4_PROPERTY_ID=あなたのプロパティIDexport GOOGLE_APPLICATION_CREDENTIALS=$HOME/.config/myapp/ga4.jsonpython3 tools/ga4_dashboard.pyBigQueryが必要になるのはどんなときか
Section titled “BigQueryが必要になるのはどんなときか”Data APIで取れるのは集計値だけです。1件ずつの生イベントを見たい場合は、FirebaseコンソールからBigQueryエクスポートを有効にします。
SparkプランでもBigQueryサンドボックスを利用できます。全機能を使う場合はBlaze等の課金設定が必要です。保存量・クエリ量・テーブル有効期限などの制限はFirebaseのBigQueryエクスポート案内で確認してください。個人アプリでもイベント量やクエリの書き方で費用が変わるため、無料枠に必ず収まるとは限りません。
そしてBigQueryには、Data APIにない利点があります。生ログにはパラメータがそのまま入るので、GA4へのカスタムディメンション登録の有無に関係なく中身が読めます。ただし、その期間にエクスポートが有効で、データが保持されていた場合に限ります。あとから連携を有効にして、任意の過去データを復元できるわけではありません。
6. 数字を読む前に確認することと次のステップ
Section titled “6. 数字を読む前に確認することと次のステップ”計測が動き始めると、今度は数字を読み違えるという別の落とし穴が待っています。実際に踏んだものを挙げておきます。
そのイベントは、本当にあなたが思っているものを数えていますか
Section titled “そのイベントは、本当にあなたが思っているものを数えていますか”「離脱率67%」という数字が出たとします。しかし離脱イベントが3つの理由で発火する設計だったとしたら、その内訳を見るまで何も言えません。
exit_reason | 発火条件 | 意味 |
|---|---|---|
user_exit | 閉じるボタン / Escape | 意図的な中断。これが本命の信号 |
navigation | 明示的な退出なしに画面遷移 | 別タブを押しただけでも発火する |
interrupted | 未完了の記録を次回起動時に検出 | アプリのkill、電話、開発中のホットリロード |
3番目が効きます。未完了レコードを次の起動時に拾って送る設計にしていると、開発中にホットリロードするたびに1件積まれます。「離脱」の相当部分が自分の開発操作だった、ということが普通に起こります。
数字を疑う前に、そのイベントの発火条件をコードで確認してください。
数が足りない段階で結論を出さない
Section titled “数が足りない段階で結論を出さない”離脱11人・完走6人という規模では、率の不確実性が大きくなります。件数と期間を併記し、仮説を探す観察と、効果を判断する比較を分けてください。必要なサンプル数は基準となる率や検出したい差で変わるため、「30件あれば判定可能」といった共通の閾値では決められません。
計測を直すことと、人を集めることは、どちらが先という話ではなく両方必要です。
プライバシー設定を忘れずに
Section titled “プライバシー設定を忘れずに”同じGA4の管理画面で、次の2つも確認しておいてください。掲載情報の「データセーフティ」や「Appのプライバシー」の申告と、実態を一致させる必要があります。
- データ保持期間: 既定より短くできます(例: 2か月)
- Google Signals: 不要ならオフにする
応用事項編の残り
Section titled “応用事項編の残り”- クラウド連携: 01. Firebaseでユーザー認証とクラウド保存を実装する
- リテンション: 02. Push通知を実装してアクティブ率を向上させる
- AI機能: 03. AI機能(Gemini API)をアプリに組み込む
- 計測: 04. GA4でアプリの使われ方を計測する(この記事)
計測が整うと、次に直すべきものを勘ではなく数字で決められるようになります。そうなると今度は、改善のたびに発生するストア掲載情報の更新が手作業として重くのしかかってきます。
最後の記事「05. ストア掲載情報の更新をAPIで自動化する」で、そこを仕組みに置き換えましょう。