self-hosting

What self-hosted analytics actually costs to run on Cloudflare

A pageview-by-pageview breakdown of Workers, D1 and Durable Object usage — why the write pattern decides everything, and where the free tier finally runs out.

"Self-hosted" used to mean a virtual machine, a database to back up, a TLS certificate to renew and a security update to apply on a Sunday. On a serverless edge platform it means none of those, and the cost profile is different enough to be worth working through properly.

Here is the arithmetic for analytics running on Cloudflare Workers, D1 and Durable Objects.

What each pageview costs you

A pageview arrives as one HTTP request to a Worker. What happens next is the whole cost story.

The naive design writes one database row per pageview. At 100,000 pageviews a month that is 100,000 writes, plus a read for every dashboard query that has to scan them. D1's free tier allows 100,000 writes per day, so this survives — until a busy day, at which point it does not.

The design that actually works never lets a pageview touch the database. Each site has a Durable Object that holds the current period in memory, increments counters there, and flushes aggregated rows to D1 periodically. A thousand pageviews across a minute become a handful of INSERT ... ON CONFLICT DO UPDATE statements against pre-grouped rows rather than a thousand inserts.

The difference is not marginal. It is the difference between a write budget consumed in an afternoon and one that lasts indefinitely, and it is why the storage design matters more than the query design in analytics.

The free tier, concretely

Cloudflare's free tier at the time of writing:

ResourceFree allowance
Workers requests100,000 per day
Worker CPU time10ms per invocation
D1 rows read5 million per day
D1 rows written100,000 per day
D1 storage5 GB
Durable ObjectsIncluded, SQLite-backed classes

The binding constraint for analytics is Workers requests: 100,000 a day, and one request per pageview. That is roughly three million pageviews a month across all your sites before anything is billed — which is far more than most sites, and more than most agencies' entire client portfolio.

CPU time is not a constraint for this workload. Hashing an identifier and forwarding to a Durable Object is well under a millisecond.

D1 storage deserves a note: aggregate rollup rows are tiny and can be kept forever, while row-level pageview facts are the ones that accumulate. Keeping the detailed rows on a rolling window — sixty days is a reasonable default — bounds storage permanently while leaving the historical aggregates intact.

What it costs past the free tier

On the Workers paid plan, $5 a month covers 10 million requests, with additional requests billed at $0.30 per million. So a site doing 10 million pageviews a month — a genuinely large site — costs about $5, plus a few cents for D1 operations.

Compare that with the hosted alternatives at the same volume: Plausible Cloud is around $169 a month at 10 million pageviews, Fathom similar. The gap is not because those companies are overcharging; it is because they are running the infrastructure, the support and the business, and you are running a Worker.

The costs that are not on the invoice

Being honest about the trade requires listing these.

Setup. Provisioning the database, the KV namespace, the Durable Object binding, the custom domain and the DNS records. This should be a single command; if it is a fifteen-step manual runbook, that is a real cost and it recurs every time you deploy for another site.

Upgrades. You decide when to deploy a new version. Nobody does it for you.

Nobody to call. With a hosted tool, a problem is someone else's pager. Self-hosted, at 2am, it is yours. For analytics specifically, this matters less than for most systems — a few hours of missing measurement is an inconvenience, not an outage — but it is not nothing.

The database is yours to look after. On D1 that means very little in practice; there is no machine to patch. But exports and retention are your decisions now, and defaults left alone are decisions too.

When self-hosting is the wrong answer

  • You want a vendor to be accountable for uptime under a contract.
  • Nobody on the team is comfortable with a CLI, and nobody wants to be.
  • You need features that a small tool will not have: predictive segments, media mix modelling, an integration with a specific advertising platform.
  • One site, low traffic, and $9 a month is genuinely not worth thinking about.

When it is clearly right

  • Multiple sites. Per-site subscriptions across an agency's clients add up fast; a Worker serving twenty sites costs the same as one serving one.
  • The data must stay in your infrastructure. A regulated sector, a client requirement, a transfer question you would rather not have.
  • You want the history to outlive the subscription. Data in your own database remains readable whether or not you keep paying anyone.
  • You want to run SQL against it. Direct access to the database is an analysis capability no dashboard replaces — and it is the only way to answer a question the funnel report was not built for.

The honest summary

For most sites, self-hosted analytics on an edge platform costs nothing to run and about an hour to set up, once. The recurring cost is zero and the recurring work is close to it, because there is no server.

What you are really choosing is not price. It is whether you would rather have a vendor relationship with a support line, or a database in your own account that nobody can take away — including by going out of business, changing their pricing, or being acquired.

Common questions

How much does self-hosted analytics cost on Cloudflare?

For most sites, nothing. Cloudflare's free tier allows 100,000 Worker requests per day — roughly three million pageviews a month across all your sites — and analytics that aggregates in a Durable Object before writing to D1 stays well inside the database limits. Past the free tier, the Workers paid plan is $5 a month for 10 million requests.

Why does the write pattern matter so much for analytics cost?

Writing one database row per pageview consumes a write budget quickly and makes every dashboard query scan a large table. Counting into pre-grouped rows in memory and flushing periodically turns thousands of writes into a handful, which is the difference between exhausting a free tier in an afternoon and never approaching it.

What are the hidden costs of self-hosting analytics?

Setup time, deciding when to deploy upgrades, and having no vendor to call when something breaks. On a serverless platform there is no server to patch or back up, so the ongoing operational work is small — but retention policy and exports become your decisions rather than a vendor's defaults.

How long should analytics data be retained?

Aggregate rollup rows describe no individual and are tiny, so they can be kept indefinitely as the historical record. Row-level pageview data carries a pseudonymous identifier and should be kept on a rolling window — sixty days is a common default — which also bounds storage growth permanently.