はじめに:計測漏れに気づけない怖さ
「設定したはずのイベントが、GA4のレポートに出てこない」。これ自体はまだマシです。少なくとも「おかしい」と気づけているからです。
本当に怖いのは、計測漏れに気づけないケースです。
add_to_cartは取れているが、特定の商品ページだけ発火していない- スマホ版のフォーム送信イベントだけ、いつの間にか取れなくなっていた
- リニューアル後、
purchaseイベントのvalue(売上金額)が常にnullで入っている
こうした「部分的な欠損」は、ダッシュボードの数字を眺めているだけでは発見できません。数字はそれらしく出ているのに、実際は本来の7割しか取れていない、ということが平気で起こります。そしてその7割の数字をもとに広告予算を判断してしまう。これが計測漏れの一番の怖さです。
GA4のUI上で全イベントを目視チェックするのは現実的ではありません。そこで本記事では、「期待するイベント定義」を先に決めておき、BigQuery上の実データと突き合わせて差分を機械的に検出するやり方を紹介します。さらに、その差分をClaude Codeに渡して原因の切り分けと修正提案までやらせる流れまで通します。
💡 補足 前提として、GA4のBigQueryエクスポートが有効になっている必要があります。エクスポートの設定や、移行直後にデータが取れない場合の切り分けはGA4移行後にデータが取れていない問題を解決するGTMデバッグ手順で扱っています。
ステップ1:期待するイベント定義を「台帳」にする
差分検出の前に、まず「何が取れているべきか」を明文化します。頭の中にあるだけでは突き合わせができません。小さなECサイトなら、主要イベントは10個前後に収まるはずです。
たとえば次のような一覧を作ります。CSVでもスプレッドシートでも構いませんが、ここではBigQueryで扱いやすいよう、そのままテーブルとして持つ前提で書きます。
| event_name | 必須パラメータ | 想定される最小発火数/日 |
|---|---|---|
| page_view | page_location | 100 |
| view_item | item_id, value | 30 |
| add_to_cart | item_id, value | 10 |
| begin_checkout | value | 5 |
| purchase | transaction_id, value | 1 |
この「台帳」が、後続の検算の基準になります。重要なのは、event_name だけでなく必須パラメータと最小発火数まで決めておくことです。イベント自体は発火していても、肝心のパラメータが欠けているケースが非常に多いからです。
最小発火数の見積もりは厳密でなくて構いません。「purchase が1日0件はさすがにおかしい」「view_item が1日1桁なのは少なすぎる」という、ざっくりした下限で十分です。目的は精密な予測ではなく、「明らかに壊れている状態」を機械的に拾うことだからです。運用しながら数字を直していけば、台帳は自然と精度が上がっていきます。
💡 補足 台帳をBigQueryのテーブルにしておくと、後述のJOINがそのまま書けて便利です。スプレッドシートで管理したい場合は、外部テーブル(Google Sheets connector)として参照する手もあります。更新のたびにクエリを直さずに済みます。
ステップ2:実データとの差分をBigQueryで検出する
GA4エクスポートの events_* テーブルに対して、台帳と突き合わせるクエリを書きます。ここでは「直近7日間で発火したイベントごとの件数」と「value パラメータが欠損している割合」を一度に出します。
-- 直近7日間のイベント別:発火数とvalue欠損率
WITH events AS (
SELECT
event_name,
-- value パラメータ(数値)を取り出す
(SELECT ep.value.double_value
FROM UNNEST(event_params) ep
WHERE ep.key = 'value') AS value_param,
-- item_id(文字列)を取り出す
(SELECT ep.value.string_value
FROM UNNEST(event_params) ep
WHERE ep.key = 'item_id') AS item_id_param
FROM `your_project.analytics_XXXXXX.events_*`
WHERE _TABLE_SUFFIX
BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY))
AND FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))
)
SELECT
event_name,
COUNT(*) AS event_count,
-- value が必要なイベントでの欠損率
ROUND(
COUNTIF(value_param IS NULL) / COUNT(*) * 100, 1
) AS value_null_pct,
ROUND(
COUNTIF(item_id_param IS NULL) / COUNT(*) * 100, 1
) AS item_id_null_pct
FROM events
GROUP BY event_name
ORDER BY event_count DESC
次に、これを「台帳テーブル」と突き合わせて、期待しているのに一度も発火していないイベントを炙り出します。台帳を expected_events というテーブルに入れておけば、LEFT JOIN で一発です。
-- 台帳にあるのに実データに存在しないイベントを検出
WITH actual AS (
SELECT DISTINCT event_name
FROM `your_project.analytics_XXXXXX.events_*`
WHERE _TABLE_SUFFIX
BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY))
AND FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))
)
SELECT
e.event_name,
e.min_daily_count AS expected_min,
CASE WHEN a.event_name IS NULL
THEN '❌ 一度も発火していない'
ELSE '✅ 発火あり'
END AS status
FROM `your_project.config.expected_events` e
LEFT JOIN actual a
ON e.event_name = a.event_name
ORDER BY status DESC
このクエリの結果が、計測漏れの「容疑者リスト」になります。❌ が付いたイベント、あるいは value_null_pct が想定外に高いイベントが、調査対象です。
ここで一度、結果を冷静に読むことが大事です。❌ が出たからといって全部が実装ミスとは限りません。たとえば季節商材で、その週はたまたま該当商品の閲覧がゼロだった、という正常な欠損もあり得ます。一方で value_null_pct が100%のような「全件欠損」は、ほぼ確実に実装側の問題です。0%でも100%でもない中途半端な欠損率(たとえば40%)こそ、特定の条件下でだけ壊れているサインで、一番厄介です。デバイス別・ページ別にもう一段ブレイクダウンすると当たりがつきやすくなります。
💡 補足 発火はしているが件数が極端に少ないケースも見逃せません。
event_countを台帳のmin_daily_count × 7と比べ、半分以下なら警告、といった閾値判定を同じクエリに足しておくと、部分的な欠損も拾えます。
ステップ3:Claude Codeに原因と修正提案を出させる
容疑者リストが手に入ったら、Claude Codeに渡します。ポイントは、差分の事実(数字)と、サイト側の実装情報(GTMコンテナのエクスポートJSONや該当ページのHTML)を一緒に渡すことです。数字だけでは原因の特定はできません。
Claude Codeを使う場合、プロジェクトのディレクトリにGTMコンテナのエクスポートJSONを置いておき、こう指示します。
GA4の計測差分の調査をお願いします。
【検出された問題】
- add_to_cart: 7日間で 12 件しか発火していない(期待: 70件以上)
- view_item: value_null_pct が 100%(value が一切入っていない)
【手元の資料】
- gtm_container_export.json(GTMの設定一式)
- product_page.html(商品詳細ページのHTML抜粋)
この2つの問題について、考えられる原因をGTM設定とdataLayerの
両面から切り分けて、優先度順に挙げてください。
そのうえで、具体的な修正方法(GTMのどのタグ/トリガーを
どう直すか、dataLayerの push をどう書くべきか)を提案してください。
このように、「事実」と「実装」をセットで渡し、原因の切り分け→修正提案の順で出力させると、回答の精度が上がります。Claude Codeはファイルを直接読めるので、GTMのJSONとHTMLを照合しながら「add_to_cart のトリガーが Click - All Elements になっていて、ボタンの data 属性とマッチしていない」といった具体的な指摘まで出してくれることがあります。
view_item の value 欠損なら、dataLayer に value を push していない(あるいは文字列で push していて数値として認識されていない)といった原因が典型です。Claude Codeには、修正後の dataLayer のコード例まで書かせると、そのまま検証に進めます。
⚠️ 注意 AIの提案は必ず検算してください。Claude Codeが「このトリガーが原因です」と言い切っても、それは資料から導いた仮説にすぎません。修正を本番に入れる前に、必ずGTMのプレビューモード(Tag Assistant)で実際に発火を確認し、修正後に再度ステップ2のBigQueryクエリを回して
value_null_pctが下がったか・件数が回復したかを数字で確かめます。「AIが直したと言った」と「実データで直った」は別物です。
修正→プレビュー確認→翌日のBigQuery再集計、というループを回して初めて「計測漏れが直った」と言えます。AIはこのループを速く回すための道具であって、検算の代わりにはなりません。
定期実行で「漏れに気づけない」状態をなくす
一度直しても、サイトの改修やテーマ更新で計測はまた壊れます。だからこそ、ステップ2の差分検出クエリをスケジュールクエリやMCP経由で定期的に走らせ、❌ が出たらSlackなどに通知する仕組みにしておくのがおすすめです。
Claude CodeからMCP経由でBigQueryを直接叩けるようにしておけば、「先週との計測差分を出して」と頼むだけで、その場で差分集計から原因の当たりづけまで進められます。この環境構築はClaude Code × MCPでBigQueryに直接つなぎ、社内アナリティクスを高速化するで解説しています。
まとめ
計測漏れの一番の問題は「気づけないこと」です。本記事の流れを整理すると、次の3点に尽きます。
- 期待するイベントを台帳化する:event_name・必須パラメータ・最小発火数を先に決める
- BigQueryで実データと突き合わせる:発火していないイベント・パラメータ欠損率を機械的に検出する
- Claude Codeに原因と修正を提案させ、必ず検算する:事実と実装をセットで渡し、提案はプレビューと再集計で確かめる
AIに丸投げするのではなく、「機械的に差分を出す」部分と「AIに仮説を出させる」部分、そして「人間が数字で検算する」部分を分けて組み立てる。これが、計測を信頼できる状態に保ついちばん確実なやり方です。