AstroのGA4にlocalhostやpages.devのアクセスが混ざる問題を、hostnameガードで防ぐ
AstroでGA4のタグを入れるとき、import.meta.env.PROD で本番ビルドのときだけ読み込む、という書き方がよく紹介されている。この書き方だけだと、本番以外のURLからもGA4にPVが送られる。自分のサイトで実際に起きたことと、直した方法をまとめる。
症状:BigQueryに、127.0.0.1 と pages.dev のPVが入っていた
BigQueryに出力したGA4のデータを、page_location ごとに数えてみた。全309PVの内訳は次の通りだった。
| page_locationの種類 | PV |
|---|---|
| 本番ドメイン(getcclab.com / www) | 280 |
| ローカル(127.0.0.1) | 6 |
| Cloudflare Pagesの確認用URL(pages.dev) | 23 |
ローカルが6、pages.dev が23で、合わせて約1割がサイト運営側のノイズだった。
原因:PROD は「本番のURL」を意味しない
import.meta.env.PROD は、astro build で作ったビルドかどうかを示すだけで、どのドメインで表示されているかは見ていない。次の2つの場合に、タグが発火してしまう。
astro buildのあとにastro previewで確認すると、127.0.0.1で配信されるが、ビルドは本番用なのでタグが読み込まれる- Cloudflare Pagesは、デプロイごとに確認用のURL(
〇〇.pages.dev)でも同じ内容を配信する。そこにアクセスしても、タグが読み込まれる
対処:ホスト名を見てから読み込む
タグの読み込みを、ホスト名が本番ドメインのときだけにした。
{import.meta.env.PROD && (
<script is:inline>
(function () {
var h = location.hostname;
if (h !== 'getcclab.com' && h !== 'www.getcclab.com') return;
var s = document.createElement('script');
s.async = true;
s.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX';
document.head.appendChild(s);
window.dataLayer = window.dataLayer || [];
window.gtag = function () { dataLayer.push(arguments); };
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
})();
</script>
)}
ポイントは、gtag.js 自体も、ホスト名が合ったときにだけ読み込むようにしたところ。config だけ条件にしても、スクリプトは読み込まれる。
動作確認
デプロイ後、ブラウザで本番と pages.dev を開いて、ページ内の状態を調べた。
| URL | gtag.js のscriptタグ | dataLayer の件数 |
|---|---|---|
| getcclab.com | あり | 4 |
| pages.dev | なし | 0 |
本番では計測が動き、pages.dev では何も送られていないことを確認できた。
過去データは、SQLで除外する
すでにBigQueryに入っている過去分は消せないので、集計のときに除外する。
SELECT COUNT(*) AS pv
FROM `プロジェクトID.analytics_XXXXXXXXX.events_*`
WHERE event_name = "page_view"
AND REGEXP_CONTAINS(
(SELECT value.string_value FROM UNNEST(event_params) WHERE key = "page_location"),
r"^https://(www\.)?getcclab\.com/"
)
この条件で数えると、上の表の「本番ドメイン」の280が返ってくる。
残っている課題
この方法で防げるのは、ホスト名が違うアクセスだけだ。本番のURLを自分で見たアクセスは、これでは除外できない。そちらはGA4側のIPアドレスによる除外か、ブラウザの拡張機能での対処になる。