AIにSNSの投稿を任せたい事業者向けに、1つのXアカウントを6ヶ月自動投稿した実測を公開しています。
最終更新: 2026-10-11
TL;DR: Cloudflare Web Analytics にデータが表示されない、ページビューが0のまま、というときの確認手順です。私はサイトを登録しただけで、計測できているつもりでした。登録は JS Snippet を自分で貼る方式で、Pages Functions が組み立てる HTML には誰もスニペットを入れていませんでした。数字が出ないときは、設定画面より先に実際の応答 HTML を
curlで確かめます。入っていなければ、HTML を組み立てる関数に<script>を1か所足せば済みます。
Pages Functions で HTML を生成している人向けの記録です。「Web Analytics に登録したのにデータが出ない」ときに、どこから確かめればいいかを書きます。サーバーログで人間とボットを数え直した経緯は「人間」4,165件を数え直したら35%が機械だったにあります。この記事はその途中で見つけた、計測コードが届いていなかった件だけを扱います。
サーバーログで人間とボットを数え直していた途中で、比べる相手にするつもりだった Web Analytics の側も確かめました。実際の配信 HTML を開くと、beacon.min.js も data-cf-beacon もありませんでした。
Web Analytics の設定は済ませてあり、計測できているつもりでした。設定画面を見て、安心していただけでした。
計測コードは、ブラウザまで届いていませんでした。ビーコンをコードに入れたのは9月25日で、それまでこのサイトのどのページにも載っていません。最初に Web Analytics へ登録した日は記録に残っていないので、何日分を取り逃したかは分かりません。
設定していたのは、アカウントの Analytics メニューからのサイト登録でした。サイトの管理画面を開くと「Install JS Snippet」とあります。</body> の直前に自分で貼る方式で、Cloudflare が HTML に何かを差し込んでくれる登録ではありませんでした。
貼る先も無かった。このサイトは静的な HTML ファイルを置いていません。Pages Functions のミドルウェアが Markdown を marked で変換し、組み立てた HTML を Response として返しているので、スニペットを入れるならコードの中しかありません。そこに入れていなかったので、ビーコンはどのページにも載っていませんでした。
同じ構成で数字が出ないときは、設定画面より先に、実際の応答 HTML を見た方が早いです。
curl -s https://自分のサイト.example/ | grep -E 'beacon\.min\.js|data-cf-beacon'
ブラウザの「ページのソースを表示」で beacon.min.js を検索しても確認できます。何も見つからなければ、少なくとも HTML に計測コードは入っていません。
HTML にビーコンが無かったら、次に登録の方式を確かめます。Web Analytics には入口が2つあって、どちらにも「Web Analytics」と書いてあり、どちらから登録したかで、ビーコンを HTML に入れるのが Cloudflare なのか自分なのかが変わります。迷いました。
| 入口 | 場所 | ビーコン |
|---|---|---|
| Pages のプロジェクトから | Workers & Pages → プロジェクト → Metrics タブの下の方 → Enable | Cloudflare が入れる |
| アカウントから | 左メニューの Analytics → Web analytics → Add a site | 自分で貼る(JS Snippet) |
自分がどちらで登録したかは、Web analytics のサイト一覧で見分けられます。自分で貼る方式なら、サイト名の横に「JS Snippet installation」と出ます。このサイトは2つ目で、Metrics タブはいまも「Web analytics is disabled」のままです。いま残っている登録は、ビーコンをコードに入れた日にやり直したものです。
1つ目の入口で有効にした場合、Functions が組み立てる応答にも Cloudflare がビーコンを入れてくれるのかは、試していません。この記事で確かめられるのは、2つ目の方式で自分で入れる手順までです。
同じ Analytics のメニューには Account analytics も並んでいて、国別のリクエスト数はそちらに出ます。似た名前が隣にあるのも、迷う理由の1つでした。
スニペットは、HTML を組み立てるコードの側に入れました。スニペットの中でサイトごとに違うのは site token だけです。管理画面の JS Snippet に書かれている "token":"…" の値で、これを環境変数で渡します。
Pages Functions の環境変数を型に追加します。
interface Env {
LOGS_DB: D1Database;
ADMIN_TOKEN?: string;
CF_WEB_ANALYTICS_TOKEN?: string;
ASSETS: Fetcher;
}
HTML を組み立てる buildHtmlPage() へトークンを渡し、設定されているときだけ </body> の直前にスクリプトを出します。
const webAnalyticsBeacon = webAnalyticsToken
? `<script type="module"
src="https://static.cloudflareinsights.com/beacon.min.js"
data-cf-beacon='{"token":"${escapeHtml(webAnalyticsToken)}"}'></script>`
: '';
条件付きにしたのは、ローカル開発でトークンが無いときまで計測スクリプトを出さないためです。このサイトにはトップページ、拡張子のない記事 URL、?view 付き Markdown という3つの HTML 応答経路がありますが、いずれも buildHtmlPage() を通るので、挿入処理は1か所で済みました。
wrangler.toml に site token を設定するWeb Analytics の JS Snippet に表示される site token を、wrangler.toml の [vars] に設定しました。
[vars]
CF_WEB_ANALYTICS_TOKEN = "Web Analytics の site token"
この site token はブラウザへ配信される公開識別子です。D1 の管理や認証に使う秘密情報ではありません。それでも、用途の違う ADMIN_TOKEN と同じ感覚で扱わないよう、変数名を分けています。
変数を作っただけでは、まだ何も計測されません。CF_WEB_ANALYTICS_TOKEN という名前を Cloudflare が自動で読むわけではないからです。Functions のコードで値を読み、data-cf-beacon の token として HTML に書き出したところで、ようやく使われます。
設定後は、最初と同じ方法で実際の応答を確認します。
curl -s https://自分のサイト.example/ | grep -E 'beacon\.min\.js|data-cf-beacon'
今度はビーコンの <script> が返れば、少なくとも計測コードがブラウザまで届く状態です。そのうえで DevTools の Network パネルを開き、スクリプトの取得やビーコン送信がブロックされていないかを確認します。Web Analytics の数字が出るかだけを待つより、「HTML にあるか」「読み込まれたか」「送信されたか」の順で切り分けた方が、どこで止まっているか分かります。
このサイトでは、登録をやり直した日のうちに、サイト一覧の「過去24時間」にページビュー1件、訪問1件が出ました。少なくとも1回は、ビーコンが最後まで動いたことになります。
数字が2種類になりました。
Web Analytics で見られるのは、ページビューと訪問数、どのページがどこから読まれたか、国、ブラウザや端末の内訳です。ASN や生の UA、IP といった1件ずつの中身は出ないので、そこは D1 のログで見ます。
ビーコンが発火したから人間、とまでは言えません。JavaScript を実行するヘッドレスブラウザもいるからです。
それでも、これまでは比べる相手の Web Analytics 自体が動いていませんでした。サーバーに届いただけのアクセスと、ページを描画して JavaScript まで動かしたアクセスを、ようやく並べられます。次に見るのは、同じ期間・同じ URL で D1 と Web Analytics の件数がどこまで離れるかです。