2026 · Solo developer — the API, the caching, and the template fields designers build against
Live match data
A caching layer that lets ad creatives show live scores without melting the API behind them.
- Engineering
- Product

The brief
Showing a live score in an ad sounds simple. The problem is the arithmetic. Live football data comes from a paid API that bills per request and caps you at a few thousand calls a day, and an ad campaign serves millions of impressions. If every impression asks the API for the score, you burn the daily limit in the first few minutes of the first match and the bill is absurd.
So the interesting problem isn't getting the data. It's getting it to millions of people without asking for it millions of times.
The build
It's a Cloudflare Worker sitting between the creatives and the upstream API, with a KV cache at the edge. A creative asks the Worker for data, the Worker serves it from cache, and only goes upstream when that cache has expired. One upstream call ends up serving every impression that lands in the same window, and the cached response comes back in a few milliseconds from wherever the person happens to be.
The cache windows are set per endpoint, because different things go stale at different speeds. Live scores refresh every minute. A league table can sit for fifteen. A match that has finished isn't going to change again, so it caches for hours. If the upstream API falls over, the Worker serves the last thing it had rather than nothing, on the grounds that a slightly old score beats an empty box.
The part I'm happiest with isn't the caching though. The feed hands back fields that are already formatted for display, so a designer building a creative writes {home.name} or {display_time} in a template and never has to think about the API underneath. Kick-off times come back in the right timezone, team names in the right language, and a match in progress returns the minute instead of a start time. That's the difference between a data source someone can use and one they have to ask me about.
One smaller thing I like: on match day the feed queries by date rather than by status, so a game doesn't vanish from the widget at the exact moment it kicks off and flips from scheduled to live.

Adding a sport
None of that is really about football, which was rather the point. When we wanted basketball it was mostly a new upstream source behind the same cache and the same display fields, and it now covers 111 women's competitions.
The one thing that didn't carry over is scoring moments. Football exposes goal events with a minute attached, so you can trigger an animation the moment someone scores. The basketball data has no play-by-play at all, so there's no moment to trigger on. That's a limit of the source rather than something I can code around, and it seemed worth writing down plainly instead of leaving it as a gap people keep asking about.
My role
Mine end to end. The Worker, the caching, the endpoints, and the template fields the creatives get built against.
The result
It ran on Coca-Cola's World Cup campaign in Spain, feeding live matches into the creative across about 1.5 million impressions. Almost all of those were served from cache rather than from the API behind it, which was the whole point.