・約3分で読めます

AstroでGA4が計測ゼロになる罠 — is:inlineのJSXエスケープでgtagが壊れる原因と対処【2026】


PRXサーバー国内シェアNo.1のレンタルサーバー。高速・安定・サポート充実で初心者にもおすすめ。
Xサーバー 公式サイト →

「HTMLにGA4タグはちゃんと入っているのに、レポートが0のまま」——これは実際に当方が運営する2サイトで起きた、なかなか気づきにくいバグです。原因は Astroの <script is:inline> 内で使ったJSXエスケープが、文字としてそのまま出力されていた こと。結果としてGA4の初期化が壊れ、データが一切送信されていませんでした。

同じ構成(Astro + Cloudflare Pages)で運用している方が踏みやすい罠なので、原因と直し方、そして「本当に直ったか」を確かめる方法までまとめます。

症状:タグはあるのにデータが届かない

  • GA4の管理画面に「ウェブサイトから受信したデータはまだありません」と表示され続ける
  • 本番HTMLには gtag/js のスクリプトも測定ID(G-XXXXXXXX)も出力されている
  • それなのに、リアルタイムにもレポートにも何も入らない

タグが「ある」ので一見正常に見えますが、初期化スクリプトが実行時エラーで止まっているため、計測ヒット(collect)が一度も飛んでいない状態でした。

原因:JSXエスケープが文字として出力される

問題のコードは、GA4初期化を import.meta.env.PROD && (...) のJSX式の中に置き、関数本体の波かっこをJSXエスケープで書いていました。レンダリングされた本番HTMLを取り出すと、次のように エスケープ記法がそのまま文字として出力 されていました(雰囲気を伝えるため記号は全角で表記します)。

function gtag(){'{'}dataLayer.push(arguments);

本来は function gtag(){ dataLayer.push(arguments); } になってほしいところが、エスケープ用に書いた {'{'} がそのまま文字列として残ってしまっています。ブラウザはこれを「関数本体は空、dataLayer.push(arguments) はトップレベル」と解釈し、コンソールに次のエラーを出して初期化を停止します。

Uncaught ReferenceError: arguments is not defined

arguments は関数の外には存在しないため、ここで処理が止まり、gtag('config', ...) まで到達せず、GA4へは何も送信されません。

ポイントは、JSXの式コンテキスト内では波かっこが式として扱われること。そして is:inline のスクリプト本文はそのまま出力されるため、エスケープ記法を書くと「直る」どころか、その記法自体が画面に出てしまうのです。

対処:set:html にテンプレート文字列で渡す

最も確実なのは、JSXのエスケープに頼らず set:html で生のJSを文字列として渡す方法です。バッククォートのテンプレート文字列の中なら、波かっこはJSの文字列の一部として扱われ、JSXに解釈されません。

<script is:inline set:html={ ` ...gtagの初期化JSをそのまま文字列で... ` } />

具体的には、window.dataLayer = window.dataLayer || []function gtag(){ dataLayer.push(arguments); }gtag('js', new Date())gtag('config', 'G-XXXXXXXX', { send_page_view: true }) を1つのテンプレート文字列にまとめ、set:html に渡します。set:html はその文字列をそのままスクリプト本文として出力するため、壊れずに初期化されます。

補足:この記事のように技術解説でコード片を載せるときは、フォーマッタ(Prettier等)が例示コードまで整形して「直して」しまうことがあります。あえて崩した例を見せたいときは、プレーンテキストのコードブロックにしておくと安全です。

「本当に直ったか」を必ず検証する

ここが最重要です。HTMLにタグが出ているかだけでは「直った」と言えません。 実際に計測ヒットが飛ぶところまで確認します。

ヘッドレスブラウザ(Playwright等)で本番ページを開き、ネットワークに collect リクエストが出るかを見ます。

POST https://www.google-analytics.com/g/collect?...&en=page_view  => 204

en=page_view を含む collect が 204 で返れば、GA4へイベントが届いています。あわせてコンソールエラーが0であることも確認します。これで「タグはあるのに動いていない」状態を確実に潰せます。

教訓

  • GA4の生存確認は「HTMLにタグがあるか」ではなく「collectが実際に飛ぶか」で行う
  • Astroの is:inline で生のJSを書くときは、JSXのエスケープに頼らず set:html のテンプレート文字列 を使う
  • 新しくサイトを量産するときは、テンプレートにこの注意を明記しておくと、同じ事故を全サイトで繰り返さずに済む

地味ですが、計測がゼロだと「流入がないのか、測れていないのか」の区別がつかず、意思決定そのものが狂います。GA4を入れたら、必ず collect が飛ぶところまで見届けてください。


※ 本記事は当方の実運用での対応をもとにした技術メモです。測定IDなどは伏せています。Astroのバージョンや構成により挙動が異なる場合があります。

関連記事: CSPでGoogleアナリティクス・AdSenseがブロックされる罠 — GA4が動いているのに一部データが欠ける原因がCSP設定にある場合の対処法