All posts

Publishing real MRR on a static site

The MRR on this site is read from the provider once a day, committed as a file, and built into plain HTML. No server, no key in the browser, no live number.

There are two ways to put a real revenue figure on a page. Ask the billing provider when somebody loads it, or decide the number before the page exists.

This site does the second one, and almost everything else about how it is built follows from that.

The browser never asks

Asking the provider at page load means the key that can ask lives where the reader can read it. There is no version of that which is safe on a static site, and the number is not worth a key.

So nothing on this site calls RevenueCat. A job runs once a day, away from the site entirely: it reads the RevenueCat API — MRR, active subscriptions, active users — normalizes the response into a shape this site owns, validates it, and commits the result as a file. The build reads that file. By the time anyone opens the page, the figure is already text in the HTML.

That is the whole trick. Astro renders the pages at build time, Cloudflare Pages serves them, and there is no application JavaScript on a public page — the analytics beacon is the one exception.

How the MRR figure reaches this page Behind the scenes, once a day: a scheduled job, the only place the secret key exists, reads the figures from RevenueCat, validates them, and saves them as a data file committed with the site. If validation fails, nothing is saved and yesterday's figure stays. On every visit: the site has already been built from that file into plain HTML, Cloudflare Pages serves it, and the reader sees the MRR as text, dated "as of" the day it was read. The reader's browser never contacts RevenueCat. Behind the scenes · once a day Key stays in here RevenueCat billing provider Daily job reads the figures Validate checks every number Data file saved with the site Fails? Nothing is saved, yesterday's figure stays. Every visit Never asks RevenueCat MRR as of Sep 26 Built to HTML number is plain text Served by Cloudflare Pages Reader sees it, already dated How the MRR figure reaches this page Behind the scenes, once a day: a scheduled job, the only place the secret key exists, reads the figures from RevenueCat, validates them, and saves them as a data file committed with the site. If validation fails, nothing is saved and yesterday's figure stays. On every visit: the site has already been built from that file into plain HTML, Cloudflare Pages serves it, and the reader sees the MRR as text, dated "as of" the day it was read. The reader's browser never contacts RevenueCat. Behind the scenes · once a day Key stays in here RevenueCat billing provider Daily job reads the figures Validate checks every number Fails? Nothing is saved, yesterday's figure stays. Data file saved with the site Every visit Built to HTML number is plain text Served by Cloudflare Pages Never asks RevenueCat MRR as of Sep 26 Reader sees it, already dated
Once a day, behind the scenes, the figure is read, checked and saved. Every visit after that only reads the page.

What it buys

The page cannot fail halfway. There is no spinner where a number should be, no request that times out, no state where the site is up but the figure is missing. It works with JavaScript switched off, because there is nothing to switch off.

It also means the site cannot accidentally show a number it did not check. Every figure in the file was validated before the commit that carries it existed. A failed fetch commits nothing, so the previous good file stays the published one.

What it costs

The figure is never live. It is as fresh as the last successful run, and on a bad day that is yesterday.

Hiding that would be the easy version, so the number carries the date it was read instead: From RevenueCat · as of — right under the MRR on the home page. If the job stops, the date stops moving, and the page says so without anyone having to notice.

The rule underneath

No billing figure is ever typed into this site by hand.

A product’s file carries a status and a join key — which provider, which project — and no amount. There is nowhere to write one. A hand-written number is correct on the day it is written and wrong every day after, and the wrong version is the one that stays up.

The status is load-bearing too. Only products that are actually live count toward the total on the home page, so revenue still trailing in from something that failed or was sold can never quietly inflate the headline.

Where it shows

One New Friend’s revenue and users are on its product page. The total is on the home page, dated.

The numbers are small. Publishing them honestly is the part I can control today.