PVが測れていないサイトにGA4を入れ、ドメイン別の計測対応表を作った
PVが測れていないサイトにGA4を入れ、ドメイン別の計測対応表を作った
そういえばこのブログ、PVという概念がない。月にどれくらい読まれているのか、自分で答えられない。
手元に記録が残っていないか探させたら、出てきたのはSearch Consoleのスナップショットだけだった。検索クリックが月およそ480、検索結果への表示がおよそ2万。数字はある。ただしクリックはPVではない。検索からの流入回数であって、SNSの直リンクもサイト内の回遊も含まない。読まれた総量は、測っていない以上どこにも無い。
GA4を入れてほしい、と頼んだ。まず今どこに何が入っているのかを確認させたら、そこで手が止まった。
結論
- 保有ドメインは6件、稼働しているホストは26件あり、そのうち3ドメインは自分でも把握していなかった
- GA4が入っていなかったのは、いちばん見たい本体サイトとこのブログの2つだった
- 「このドメインはどのリポジトリか」を毎回grepで探し直していたので、対応表をドキュメントとして残させた
- 本体サイトはタグを本番へ戻した。計測が止まったのは2026-06-07で、サイト移行のときにタグが引き継がれていなかった
- ただし戻したあともGA側に1件も記録されない。ここは未解決のまま翌日へ持ち越した
手元にあったのは検索経由の数字だけだった
Search Consoleには直近3か月の実測が残っていた。このブログはクリック1,450、表示6.16万、平均掲載順位9.2。月に直すとクリック480、表示2万になる。ドメイン全体では3か月で6,790クリックだった。
この数字で分かるのは検索からの入口の広さだけで、入ったあとに何ページ見られたかは分からない。実PVを知るには計測タグが要る。nuxt.config.ts にはGAもCloudflare Web Analyticsも入っていなかった。
入れる前に、どこに何が入っているのか分からなくなった
タグを貼る対象を確定させるつもりで、ログイン済みのChromeを使って現状を洗わせた。
Cloudflareに登録されているドメインは6件。うち3件は、自分の口から名前が出てこなかった。本体サイトのドメインだけでサブドメインが16個ぶら下がっていて、全部を合わせると稼働ホストは26件になった。
26ホストのHTMLを1件ずつ取得して、G- GTM- UA- を検出させた。GAが入っていないのは、主力の本体サイトとこのブログの2つだった。業種別に切り出したランディングページ10件には、個別のGA4がすでに入って動いている。いちばん見たい2つだけが穴だった。
2回の誤診
1回目。あるサイトはトップページのHTMLにGTMのコンテナしか無く、その中身を取ると廃止済みのUAが出てきた。「実質計測ゼロ」と報告が上がってきたので、GA側のストリームを開かせた。過去48時間、データを受信中だった。UAは止まった残骸が同居していただけで、計測は生きている。トップページのHTMLだけを見て判定してはいけない。裏はGA側の受信状況で取る。
2回目。ChromeにはGoogleアカウントが3つログインしている。GAのアカウント一覧は、アクティブなアカウントによって中身が変わる。片方で「権限がありません」と出るプロパティが、もう片方では普通に見える。実際、本体サイト用のプロパティを「見当たらない」と報告してきたので、入っているはずだと押し返した。開いてみたら、URLまで登録済みのプロパティがちゃんとあった。ここで信じていたら、要らないプロパティを1つ増やしていた。
grepで探し直すのをやめるための対応表
持っているものを全部、対応表として正確に残しておいてほしいと頼んだ。
理由ははっきりしている。「このドメインはどのリポジトリだったか」を、これまで毎回grepで探し直していた。Git_repo の直下にリポジトリが200以上あるので、全体を対象にした grep -r は5分でタイムアウトして返ってこない。この日も1回落ちた。
リポジトリ特定の最短経路は結局CloudflareのDNSだった。CNAMEの向き先がそのままPagesのプロジェクト名になるので、ゾーンごとにDNSレコードを一覧すればドメインと配信元が1対1で並ぶ。
// Cloudflareにログイン済みのタブで、ゾーンごとにDNSを引く
const zones = (await (await fetch('/api/v4/zones?per_page=100', { credentials: 'include' })).json()).result
これでドメイン、ローカルリポジトリ、Cloudflareの配信先、GA4、Search Consoleの5列が埋まった。HTMLにしてChromeの前面タブに出させたら、本文が目次に14px重なっていた。目次の実幅はpadding込みで334px、右余白16pxで350px要るのに、336pxしか空けていなかった。直させてから読んだ。
タグを本番へ戻し、止まった日付を確かめた
本体サイトはNuxtで動いている。開発中のアクセスを数えないよう、本番ビルドのときだけタグが入る形で実装させた。
// nuxt.config.ts: 本番ビルドのときだけ計測タグを差し込む
$production: {
app: { head: { script: [ /* gtag/js?id=G-XXXXXXX と gtag('config', ...) */ ] } }
}
ビルドして、生成物241ページすべてにタグが出ていることを確認した。
デプロイ直前に、報告のなかの「5年間データが入っていない」という一言が引っかかった。どこで確認したのかと聞くと、根拠は「過去48時間に受信データなし」という表示だけだった。ホーム画面を過去12か月で見せたら、アクティブユーザー3.7万、表示回数5.3万、イベント18万が並んでいた。異常検知の記録も残っていた。2026-06-07に新規ユーザー数が予測704に対して実際3まで落ち、マイナス99.6%と記録されていた。5年ではなく2か月前で、原因はWordPressからNuxtへ移したときにタグを引き継がなかったことだった。
数字を推測で埋められると、こちらの判断ごと狂う。誤記は直させ、反省として1行だけ対応表に残させた。
204が返るのに、GAには届かない
デプロイ後、本番のHTMLに測定IDが入っていることを確認した。ところがブラウザで開いても計測が動かない。見ていたのは古いキャッシュで、ハードリロードしたら collect のリクエストが2件飛んだ。/g/collect はHTTP 204を返した。
それでもGAのリアルタイムは0のままだった。
最初に疑ったのは内部トラフィックの除外フィルタで、確かに登録はされていた。ただし状態は「テスト」で、テストでは実際には除外されない。それにこちらはスマホからも開いている。スマホは別IPなので、IPベースの除外では説明がつかない。仮説を取り下げさせた。
決定打はDebugViewだった。debug_mode を付けて強制送信しても「デバッグに使用するデバイス 0」のまま動かない。ここで分かったのは、GA4の /g/collect が測定IDが無効でも204を返して黙って捨てるという仕様だった。204は「受け取った」の証拠にならず、DebugViewに出ないことのほうが重い。
サイト側は正しく送っていて、GAのプロパティが受け取っていない。この状態で今日は終わった。対応表には、各プロパティへのリンクとこの未解決の状態をそのまま書かせた。
使っていないアカウントは置いておく
業種別ランディングページのうち5件は、サイト側で計測が動いているのにプロパティの置き場所が見つからなかった。確認していないGoogleアカウントが1つ残っているので、そこにある可能性が高い。
ただし切り替えは3回とも弾かれたし、そのアカウントは普段使っていない。5件はすでに計測が動いていて実務上の支障もない。とりあえず置いておく、と決めて対象外にした。分からないものを分からないまま台帳に書いておけば、次に必要になったときに探し直さずに済む。
学び
- クリックはPVではない。Search Consoleで見えるのは検索からの入口だけで、入ったあとの回遊は測れない
- トップページのHTMLにタグが無くても、計測が死んでいるとは限らない。GTM経由や別ストリームで生きていることがある。判定はGA側の受信状況で取る
- GAのアカウント一覧は、ブラウザでアクティブなGoogleアカウントによって変わる。「権限がありません」を「プロパティが無い」と読むと、要らないプロパティを増やす
- ステータスコードは計測できている証拠にならない。204で受理されていても、GAが記録しているとは限らない
- 「どのドメインがどのリポジトリか」は、頭ではなくDNSが持っていた。CNAMEの向き先がそのまま答えになる
明日やること
- 送信は成功しているのにGAに記録されない件を切り分ける(プロパティの状態確認、測定IDの現行値確認、移行前の測定ID確認、新ストリーム作成の順)
- このブログ用のGA4プロパティを新規作成してタグを設置する
- 残り3サイトのプロパティ作成とタグ設置
- Search Consoleに未登録の4ドメインを登録する
- 本体サイトの
nuxt.config.tsをコミットする(デプロイは済んでいるが未コミット)