Skip to content

Stats

A click is written twice, both times inside ctx.waitUntil, never on the response path. A failed analytics write costs a click in the stats; it never costs a redirect.

D1 stats_daily Analytics Engine
Holds clicks + bots, per link, per UTC day country, device, OS, browser, in-app, referer host, decision branch
Retention permanent 3 rolling months
Latency immediate ~1 minute of ingestion
Read by GET /api/stats Cloudflare SQL API, from a laptop

The daily counter in D1 exists because Analytics Engine only keeps three months. Without it there would be no history at all.

Terminal window
curl -s "https://301.so/api/stats?days=7" \
-H "Authorization: Bearer $TOKEN" -A "my-client/1.0"

Shape and parameters: API reference. Readable the instant the click lands, because it is a plain INSERT … ON CONFLICT DO UPDATE in SQLite.

Analytics Engine is queried through Cloudflare’s SQL API with an account-scoped token:

Terminal window
ACC=<account id>
curl -s "https://api.cloudflare.com/client/v4/accounts/$ACC/analytics_engine/sql" \
-H "Authorization: Bearer $CF_TOKEN" \
--data "SELECT blob2 AS slug, blob9 AS webview, blob11 AS outcome,
SUM(_sample_interval) AS clicks
FROM clicks_301so
WHERE timestamp > NOW() - INTERVAL '7' DAY
GROUP BY slug, webview, outcome
ORDER BY clicks DESC FORMAT JSON"

Column order is a contract — queries address columns by position, so new fields are only ever appended. Inserting one in the middle would rewrite the past.

Column Contents
index1 link_id (sampling is per index)
blob1blob5 hostname, slug, team id, country, colo
blob6blob9 device, OS, browser, in-app browser
blob10, blob11 referer hostname, decision branch
double1 1 if bot

Why the worker never reads Analytics Engine

Section titled “Why the worker never reads Analytics Engine”

Reading it needs an account-level Cloudflare token. Putting one inside a worker that serves public traffic would trade the entire Cloudflare account against a stats screen. So the read path stops at D1, and dimensions are read from Vincent’s machine — where the token already lives.