Hosting · 3 min setup
How to add analytics to a Cloudflare Pages site
functions/_middleware.js using HTMLRewriter. If Rocket Loader is on for the zone, add data-cfasync="false" before src so Cloudflare leaves the tag alone.Updated
Cloudflare Pages has a feature most hosts don't: middleware that runs at the edge on every request. That gives you a no-template-edit install option, and it's also the right place to report AI crawlers for a static site, because the edge is the only layer that sees them. (Cloudflare also steers new projects toward Workers with static assets; the same tag-in-HTML approach applies there, and the AI crawler docs have a Workers snippet.)
Cloudflare Pages at a glance
- Simplest
- Tag in your HTML / framework layout
- No-template option
functions/_middleware.js+HTMLRewriter- Rocket Loader
- Add
data-cfasync="false"beforesrc - Previews
*.pages.devdropped via Allowed hostnames- CSP
_headersfile in your build output
How to install VisitTrack on Cloudflare Pages
Step 1: Copy your site id
Add your domain in VisitTrack and copy the snippet from the install step. Replace
SITE_IDbelow.Step 2: Add the tag to your HTML (recommended)
In your static
index.html, base template or framework layout, inside<head>. Thedata-cfasync="false"attribute is only needed if Rocket Loader is enabled on your zone, and must come beforesrc.<head><script defer data-cfasync="false" data-site="SITE_ID" src="https://visitrack.app/tracker.js"></script>Step 3: Or: inject it with Pages Functions
No access to templates (for example a pre-built export)? This middleware appends the tag to the
<head>of every HTML response and passes everything else through unchanged.functions/_middleware.js// functions/_middleware.js — injects the tag into every HTML response export async function onRequest(context) { const response = await context.next(); const type = response.headers.get("content-type") || ""; if (!type.includes("text/html")) return response; return new HTMLRewriter() .on("head", { element(head) { head.append( '<script defer data-site="SITE_ID" src="https://visitrack.app/tracker.js"></script>', { html: true }, ); }, }) .transform(response); }Step 4: Keep preview deployments out
Branch and preview deployments get
*.pages.devURLs. In VisitTrack, save your production domain under Settings → General → Allowed hostnames so those hits are dropped.
How to check VisitTrack is working on Cloudflare Pages
- Open the production domain and view source: the tag is in
<head>(with the middleware option, view source shows the rewritten HTML). - Browse two pages; VisitTrack's live view shows you within seconds.
- If the tag's
typewas rewritten (for example totext/rocketscript) in the delivered HTML, Rocket Loader is handling it — adddata-cfasync="false".
Does VisitTrack track Cloudflare Pages page navigation?
Static pages count one pageview per load; framework sites with client-side routing (SvelteKit, Astro with view transitions, React Router, Nuxt) are followed through the History API. Cloudflare's caching doesn't affect counting — the script runs in the visitor's browser.
How to track custom events and goals in Cloudflare Pages
Use data-vt-goal on elements and window.visitrack("name") in your client code. For signups or payments handled in a Pages Function, POST /api/track with a secret API key stored as an encrypted environment variable in the Pages project settings (bound to context.env).
// functions/api/signup.js
export async function onRequestPost({ request, env }) {
const { email, visitorId } = await request.json();
// …create the account…
await fetch("https://visitrack.app/api/track", {
method: "POST",
headers: { Authorization: `Bearer ${env.VISITRACK_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ type: "event", visitorId, name: "signup" }),
});
return Response.json({ ok: true });
}Track AI crawlers on Cloudflare Pages
AI crawlers don't run JavaScript, so a static site only sees them at the edge. This middleware (from the AI crawler tracking docs) reports every request with waitUntil, so the crawler never waits. cf-connecting-ip is the genuine client address, so crawler verification works immediately. If you also use the injection middleware above, combine both into one _middleware.js.
Note that once a middleware runs on every path, requests for static assets become Functions invocations, which count toward your Workers request allowance. Use _routes.json to exclude asset folders if that matters for your traffic.
// functions/_middleware.js — from /docs/ai-crawler-tracking
export async function onRequest(context) {
const { request, next, waitUntil } = context;
const url = new URL(request.url);
waitUntil(
fetch("https://visitrack.app/api/collect-bot", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
siteId: "SITE_ID",
path: url.pathname,
userAgent: request.headers.get("user-agent"),
ip: request.headers.get("cf-connecting-ip"),
}),
}).catch(() => {}),
);
return next();
}Script options you might need on Cloudflare Pages
All optional — add them to the same tag. Full reference: script configuration.
| Attribute | What it does |
|---|---|
data-cookieless | Store nothing in the browser; the server derives a daily-rotating id. See cookieless mode. |
data-exclude="/app/*" | Never track these paths (comma-separated, * wildcard). Checked on every navigation. |
data-allow-local | Track on localhost and *.local — for testing an install only. |
data-debug | Log every event the script sends, and why it skipped one, to the console. |
data-auto="false" | Turn off automatic events (downloads, contact clicks, form submits, rage clicks, JS errors, 404s). |
Cloudflare Pages troubleshooting
The tag loads but nothing is recorded
Rocket Loader may be deferring or rewriting it. Add data-cfasync="false" before src, or turn Rocket Loader off for the zone.
*.pages.dev hosts in the Hostname tab
Save your production domain under Allowed hostnames in VisitTrack.
CSP blocks the script
Add the origin in your _headers file: /* then Content-Security-Policy: script-src 'self' https://visitrack.app; connect-src 'self' https://visitrack.app; (merged into your existing policy).
The middleware doesn't run
It must live at functions/_middleware.js in the project root (not inside the build output) and be deployed through Pages.
Cloudflare Pages analytics FAQ
How do I add a tracking script to Cloudflare Pages?
Add the script tag to your site's HTML or framework layout. Without template access, a functions/_middleware.js using HTMLRewriter can append it to every HTML response.
Does Cloudflare Rocket Loader break VisitTrack?
It can rewrite third-party scripts. Add data-cfasync="false" before the src attribute on the VisitTrack tag so Rocket Loader skips it.
How is VisitTrack different from Cloudflare Web Analytics?
Cloudflare Web Analytics is free and traffic-focused. VisitTrack adds custom events, goals, funnels, revenue attribution, session replays and AI-crawler reports. See VisitTrack vs Cloudflare Web Analytics.
Can I track AI crawlers on a static Cloudflare Pages site?
Yes, with the edge middleware above. It reports each request's path, user agent and IP to VisitTrack, which classifies GPTBot, ClaudeBot, PerplexityBot and others.
Do preview deployments count in VisitTrack?
Only until you save Allowed hostnames. After that, hits from *.pages.dev preview URLs are dropped before they're stored.
Keep going
- Vercel analyticsUse VisitTrack on Vercel: add the tag in your framework, keep preview deployments out with VERCEL_ENV or allowed hostnames, and set CSP headers.
- Netlify analyticsAdd VisitTrack on Netlify with Snippet injection (no code) or in your framework, keep deploy previews out, and set CSP in _headers.
- Astro analyticsAdd VisitTrack to Astro with one is:inline tag in your shared layout — works for static, SSR and ClientRouter (view transitions) sites.
- SvelteKit analyticsAdd VisitTrack to SvelteKit by adding one tag to src/app.html — client-side navigations are tracked, and kit.csp gets two extra sources.
- Install the tracking scriptThe reference tag, CSP notes and how to check it's working.
- Custom events and signupsvisitrack(), data-vt-goal, scroll events and server-side signups.
- Use casesHow SaaS teams, indie hackers, stores and agencies use VisitTrack.
- VisitTrack vs Google AnalyticsCookie-free analytics with revenue attribution, compared honestly.
Add VisitTrack to your Cloudflare Pages site
Cookie-free analytics with revenue attribution, live visitors, funnels and session replays. One script tag, every feature on every plan. 14 days free, no card required.
Not on Cloudflare Pages? See all 29 integration guides.