A football club's next fixture is public information that is strangely hard to look up. Official sites bury it under everything else they have to say, the apps want an account and a cookie banner, and all of them show the kickoff in the club's time zone, which is only yours if you live there. N17 Time answers one question, when Tottenham play next, on one page, in the reader's own time, with nothing to accept and nothing to install unless you want to.

N17 Time is the practice's own product, built and shipped in a day in September 2026 and added to since. The front page shows the next match: opponent, home or away, kickoff in your local time with a countdown, the ground and its address with directions on an away day, the opponent's last five results as letters rather than colours alone, and the club's place in the table. Behind it sit a full season of fixtures and results under month headings, and the league table. While a match is on, the page shows the score. It sets no cookies, carries no crests or photographs, works with scripting disabled, and is readable offline once it has been opened once. Even the name keeps its distance: N17 is the stadium's postcode, not a club mark.

Two files, one key, one schedule

The plan written for it earlier in the year was a considered piece of architecture: onion layers, repository wrappers, separate folders for domain, infrastructure and presentation, forty-odd tickets. It was a plan for a page that displays one football fixture, and when the day came to build it, it was closed unbuilt. What shipped is two source files on an edge worker, one namespace in a key-value store holding one key, one schedule and one secret. The worker refreshes the fixture and the opponent's form from a third-party fixtures feed on the hour and writes a snapshot, and every visit is served from the snapshot, never from the feed. About thirty-five tickets closed together that afternoon, and the record names them as what they were: a plan closed rather than work delivered.

Serving from a snapshot is also what makes the page hard to break. If the feed stops answering, the hourly run fails before it writes and the last good snapshot stays up. That was established on launch day by putting a bad credential in and waiting for the next scheduled run, rather than by reasoning about it: the run failed, the page did not notice, and visitors saw nothing. The season page cost no new storage and no new scheduled work, because the hourly refresh simply asks for the season unfiltered and keeps it in the same snapshot. The front page is about thirteen kilobytes and the season page under thirty, against a budget of fifty, with no framework, no images and no web fonts.

A score a few minutes behind, by choice

The feed's free tier reports a running score with a delay it does not publish, so before anything was built the delay was measured against a public scoreboard across two live matches: between three and six minutes. A paid tier removes it; a score a few minutes old was judged acceptable, and the free tier kept. One scheduled trigger every two minutes replaced the hourly one. Outside a match a tick reads the snapshot and exits. Inside the window it asks for the match once and writes only when something has changed, and the hourly refresh is skipped while play is on, so the page can never jump to the following fixture mid-game. The first real match ran the whole cycle unattended, fixture to live to full time to next fixture, for under one per cent of the free request allowance, and pitch to page was six to ten minutes a goal.

Two things the free tier does not do are stated rather than papered over. It has never reported half time, in two matches watched, so the page does not claim it. And once, it answered a poll with two different scores on consecutive reads. The change that would guard against that costs two minutes on every goal, so it was parked until the next match said whether it was worth it, and the next match, watched read by read from before kickoff to after the whistle, said leave well alone.

Kept by hand, and said so

The free tier covers the league and one European competition. Everything else, the domestic cups included, is on paid plans, and paid coverage was declined. So cup ties come from a short list kept by hand: a line after each draw, a time once the kickoff is confirmed, a score after the match, and the page says Kickoff TBC until it knows. The upkeep is written down beside the feature, which is the honest price of a free page.

The away grounds are hand-kept too, for a different reason. The feed does carry venue records, but they proved stale, with clubs still listed at grounds they have left, so the twenty grounds of the season are kept in a list checked against the clubs' own pages, pinned by a test so that the list is looked at every summer when the promoted clubs arrive. Directions are a plain link to a map search, which requests nothing until it is tapped. The league table, by contrast, needed no hand at all: the feed publishes the official table, deductions included, so there was nothing to compute, and a failed call keeps the previous one.

— On free data —

Where the free tier reaches, the page trusts it. Where it does not, a list is kept by hand, and the upkeep is written down.

Watched from outside

Two monitors on a free plan fetch the page every five minutes. One looks for a phrase from the footer's disclaimer, which is in the page in every state it can be in, so it notices a page the worker did not render as well as a page that is down. The other works the opposite way round and alerts when a phrase appears: the line the page prints once its data is more than a day old. That one means the refresh has been failing for a day while the page goes on serving its last good copy, which is exactly the failure no visitor would think to report.

Installability was checked on a real phone rather than assumed from the tests. Twenty-six tests covered the offline path and all of them passed, and on a phone in flight mode the offline notice did not appear, because an installed app resumes without reloading and the browser can serve the page from its own cache while it is still fresh. The tests were not wrong about what they tested; they were exercising a path the device had no particular reason to take. The page now asks the browser directly whether it is online, and says so itself.

What it costs to run

Everything it runs on is a free plan: the worker, the store, the static assets, the analytics, the monitors. The analytics set no cookies, and their beacon is the one request the page makes beyond its own domain. The domain is its only bill, bought at cost from the platform's registrar. The footer credits the feed and says plainly that the page is unofficial.

It was also built to be forked. A sibling for a second club further down the football pyramid, where the feed does not reach, took a Sunday afternoon and a Monday from the same code, and within a fortnight the sibling had started giving features back: its cup ties, league table and directions reached N17 Time the day after they reached it, each answered differently because the data behind it is different.

N17 Time is small enough that the habits show. The plan was cut to what the problem needed. Every claim the page makes was tested against a device or a live match rather than a test suite alone. The limits of free data were measured, accepted and written down. And the one failure nobody would report is the one the monitors watch for.