agentlyticsby measuremy.site

How I built a self-hosted analytics MCP server on Cloudflare Workers and D1

I wanted to ask my coding agent "why did traffic jump yesterday?" and get an answer with numbers, not a link to a dashboard. So the analytics behind measuremy.site expose everything over MCP. I've now published a single-site version as open source: agentlytics-mcp, MIT licensed, which you deploy to your own Cloudflare account. This post walks through how it works.

The pieces

Everything runs on Workers and D1, so there is no server to patch and the free tier covers most small sites.

Counting visitors without cookies

Nothing is stored in the browser. To tell visitors apart within a day, the worker computes a hash:

salt    = HMAC(HASH_SECRET, day number)
visitor = HMAC(salt, site id | IP address | user agent)

Only the hash is stored, never the IP address or user agent. Because the salt changes every UTC day, the same person gets a different id tomorrow, so nobody can be followed across days. The cost is real: "unique visitors this month" isn't something this design can answer, and a funnel only counts a visitor when every step happens on the same day. For a small site deciding what to post next, daily uniques are enough.

The worker also keeps the browser and OS names ("Firefox", "macOS"), the country Cloudflare reports, the page path, the referring host and any UTM tags. Hits from other domains are rejected, so nobody can fill your analytics from elsewhere.

Hourly rollups

Every hour the cron rebuilds the last 48 hours of a rollup_hourly table: total pageviews, and pageviews per source, page and event, each with distinct visitors. Rebuilding a trailing window absorbs late events, and the upsert only rewrites rows whose numbers changed, which keeps D1 write costs down. Questions about arbitrary filters still go to the raw events table, which is indexed by site, type and time.

Finding spikes

A spike is an hour that is far above what that hour normally looks like. For each hour the detector takes the same hour of the week over the previous four weeks (or the same hour over the previous seven days for a new site) and computes the median and the median absolute deviation. An hour counts as a spike when it is at least four robust deviations above the median, at least 10 pageviews above it, and at least 50% higher. Using the median rather than the mean means one past spike doesn't hide the next one.

Then it explains the spike. For every source, page and event, it compares the spike hour with the same baseline hours, and keeps the ones that rose by a meaningful share of the extra traffic. The result reads like "news.ycombinator.com: +140 pageviews, 92% of the spike; /launch: +120". Notes you leave with the add_annotation tool (a deploy, a post, an email) in the 24 hours before are attached too, so the agent can say "this followed your Reddit post".

The MCP endpoint

The server speaks MCP's streamable HTTP transport, but statelessly: each POST is a JSON-RPC message (or a batch), answered in one response. There are no sessions to store, which suits Workers. It implements initialize, tools/list, tools/call and prompts, and checks one bearer key by comparing hashes.

The tools are deliberately specific rather than one "run SQL" tool:

Small, well-described tools with structured JSON results are much easier for an agent to use correctly than raw tables, and they keep a leaked key from doing much damage.

Deploy your own

The README has a Deploy to Cloudflare button that creates the database, runs the migrations and asks for your domain and two keys. Or do it by hand in about five commands. Then add the script tag to your site and connect your agent:

claude mcp add --transport http agentlytics https://YOUR-WORKER/mcp --header "Authorization: Bearer YOUR_KEY"

Want to try the tools before deploying anything? The read-only demo key connects your agent to measuremy.site's own live analytics.

Self-hosted or hosted

The open-source version is one site per deploy and has no dashboard: your agent is the interface. The hosted version at measuremy.site runs the same tools for several sites and adds a dashboard with filters, AI explanations of spikes, tracking of posts that mention you on Hacker News, Bluesky and YouTube, and alerts. Use whichever fits; the data model is the same.

See it on your own site

agentlytics is cookieless analytics your coding agent can read. Free for 5,000 pageviews a month, no card.

Start free See the live demo

Add agentlytics analytics to this project. Follow the instructions at measuremy.site/llms.txt

More from the blog