-
Step 1 · Decide what to publish and how you define status
List your services, define operational / degraded / down
The first job isn't drawing the page, it's defining what "up" means. Without a clear definition you'll end up arguing with users in the comments during an outage.
Service list (from the user's point of view, not your architecture):
- Website
- API
- Images / downloads
- Admin panel
Three states (write them into the page):
- Operational: core features work
- Degraded: usable but slow, or partly broken (e.g. images load slowly)
- Down: core features unavailable
Don't list too many: five or fewer. Twenty internal microservices mean nothing to users and far more explaining when things break.
Define your SLA at the same time: how availability is calculated (per minute? share of successful requests?) and over what window (30 days). Put it at the bottom of the page — it is both a promise and a boundary: if you promise 99.9%, you must be able to measure 99.9%. Don't publish a number you can't measure.
Checklist
- Service list is 5 items or fewer, written from the user's point of view
- The thresholds for the three states are on the page
- The availability formula and window are defined
-
Step 2 · Data source: probe results into JSON
Probe every minute, write status.json, the page only reads a file
The difference between a status page and a monitoring dashboard: monitoring is for you, a status page is for your users. So the data should be "official" — probe from the user's perspective, not from server-internal metrics.
What the probe script does:
- Makes a real request to each service (HTTP GET / API call)
- Records status code, response time and timestamp
- Decides the state (only N consecutive failures count as down, so a blip doesn't raise a false alarm)
- Writes
data/status.json
{ "updated": "2026-09-27T08:00:00Z", "overall": "ok", "services": [ { "name": "Website", "status": "ok", "latency_ms": 180 } ], "incidents": [ { "date": "2026-09-20", "title": "...", "status": "resolved" } ] }Key design point: the status page must be independent of the services it monitors (never on the same machine). Otherwise when the service dies the status page dies with it — the most embarrassing failure of all.
Hosting suggestion: put the status page on GitHub Pages / Vercel or a second server, and keep the probe script on your own server.
Checklist
- status.json updates once a minute
- The status page still opens when the service is down
- Only consecutive failures count as an outage
-
Step 3 · The page: current state + incident history + 90-day uptime
One screen answering: is it fine now, and did it break recently
Visitors open a status page to learn exactly two things: is it working now and has it been breaking a lot lately.
Three blocks:
- Big status bar on top: one line plus a colour (green operational / amber degraded / red down), with the last-updated time
- Service list: one row each — status dot, name, and a 90-day uptime bar
- Incident history: the last 10 entries, newest first, each written as "time · scope · cause · resolved"
The 90-day bar: one cell per day, green operational, amber degraded, red down. This is the single most trust-building block — publishing your history beats any claim that "we are very stable".
Incident template:
09-20 14:05 detected image load failures → 14:22 traced to a faulty CDN node → 14:40 switched to a backup node and recovered. Impact: about 35 minutes, images failed to load. Cause: upstream CDN node failure.Don't write: "service disruption due to uncontrollable factors" — that only makes people trust you less.
Subscriptions: add a "subscribe to status changes" entry point (RSS or email, see the Newsletter scenario) so users don't have to keep refreshing.
Checklist
- The overall status is visible on the first screen
- There is a 90-day uptime bar
- Incidents record time, impact, cause and outcome
-
Step 4 · Launch + alerting + postmortems
Update the page during an incident, write the record afterwards
Launch: host it independently (never on the same machine as the monitored service) + HTTPS + an indexable
sitemap(people do search for "<product> status").Order of operations during an incident (write this into your runbook):
- Probe alert fires → confirm it's real (visit it yourself once)
- Flip the status page to "down" first, even before you know the cause — what users fear most is "it's broken and nobody said so"
- Investigate and fix
- Set it back to "operational" and add an incident entry
Core principle: publish first, assign blame later. "Confirmed outage, working on it, expecting recovery by X" is a hundred times better than two hours of silence.
Keep the postmortems: for every incident record the timeline, root cause, fix and how to prevent it next time. Those records become your best engineering asset — and your answer to users.
Metrics: track
pvandstatus_viewon the page itself. Views spike during an outage — that number tells you how many people actually care, which is honest feedback about your audience.Drill: once a quarter, trigger a fake outage by hand (edit status.json) and confirm the alert arrives, the page can be updated, and the team knows the process. A runbook nobody has rehearsed isn't a runbook.
Checklist
- The status page is deployed independently of the monitored service
- There is a written incident procedure
- You have drilled it once a quarter