API
Everything this site measures is readable as JSON or CSV. No key, no sign-up, no quota beyond the rate limits below.
Before you start
All endpoints are GET, return UTF-8, and need no authentication. Timestamps are epoch seconds unless a field is named otherwise. Addresses in a path must be URL-encoded.
If a server has an alias, requesting the alias returns the canonical server's data directly rather than redirecting. Servers that don't exist and servers that have been removed both return the same 404, deliberately.
Errors are always JSON with an error field, including on the CSV endpoint — check the status code before parsing a response as CSV.
This is a hobby project running on one small box. The endpoints are stable in practice but carry no versioning promise — if you build something that depends on them, tell me at kaiwojciak@gmail.com and I'll warn you before anything breaks. A link back is appreciated, not required.
/api/serversEvery visible server, with its current verdict. One object per server; no history.
addressstring- The canonical address, as stored.
displayNamestring | null- Owner-set name, when there is one.
statusstring- One of major-slump, slump, stable, bump, major-bump, gathering.
verbstring- The same verdict as a phrase — “is in a slump”.
provisionalboolean- True when there isn’t enough history to stand behind the verdict yet.
pctnumber | null- Percent difference from the expected level.
znumber | null- Standard deviations from expected. Null while gathering.
onlinenumber | null- Players right now. Null when the last successful ping is over 30 minutes old.
maxnumber | null- Slot count the server reported alongside it.
offlineboolean- True when recent pings are failing.
blurbstring | null- Owner-written one-liner.
claimedboolean- Whether an owner has proven they run it.
iconstring | null- The server’s own icon as a data:image/png URI.
tags{ slug, label }[]- Categories the owner applied and a moderator approved. Empty for most servers.
/api/servers/{address}/historyOne server’s verdict plus its 7-day chart, bucketed to 30 minutes — the same data the page draws.
/api/servers/crescenta.org/historyaddress, status, verb, online, max, offline- As above.
subtitlestring- The one-line explanation shown under the verdict.
chart[]array- Buckets, oldest first: ts (bucket start), online (bucket average, null if no successful ping), offline (bucket had only failures), and mu / lower / upper describing the expected band.
The chart is averaged into buckets. For the individual measurements behind it, use the export below.
/{address}/export.csv · /{address}/export.jsonRaw per-poll measurements for one server. The unaggregated numbers every other endpoint is derived from.
/crescenta.org/export.csv?range=90d?range= takes 1d, 7d, 30d, 90d or all, defaulting to 30d.
timestamp / tsISO 8601 / number- When the ping was sent. The CSV column is an ISO 8601 UTC string; the JSON field is epoch seconds.
onlinenumber | null- Players at that moment. Empty in CSV and null in JSON when the ping failed — not 0, which would claim the server was up and empty.
maxnumber | null- Slot count, same null rule.
reachable0 / 1 · boolean- Whether that ping got an answer.
A response is capped at 50,000 rows, keeping the most recent. When that clips something the JSON sets truncated: true and the CSV response carries X-Export-Truncated: 1. Narrow the range and fetch twice if you need the whole run.
Gaps are real: a stretch with no rows means the poller wasn't running, which is not the same as the server being down. A row with reachable=0 is the one that means down.
/{address}/badge.svg · /{address}/badge.pngThe status badge as an image, for embedding. ?metric=players swaps the verdict for a live player count.
/crescenta.org/badge.svg?metric=playersBoth formats render an “unknown” badge with a 404status for an address we don't track, so an embed shows something honest rather than a broken image. They cache for five minutes, matching the poll interval.
Rate limits
Counted per IP address, in fixed windows. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (epoch seconds); going over returns 429 with Retry-After.
/api/servers— 120 requests per minute./api/servers/{address}/history— 120 per minute.export.csvandexport.json— 10 per 5 minutes, shared between the two formats. These read raw rows and are much the most expensive thing here.
Badges are not rate limited: they exist to be embedded on pages that other people load, so throttling them would punish the wrong party.
What the numbers mean
Player counts come from the same public Server List Ping any Minecraft client sends. They are the server's own claim about itself — a proxy or a plugin can report whatever it likes — and we record what we were told.
A verdict compares the last three hours against what that specific server normally does at that weekday and hour, over the past four weeks. It is a comparison with a server's own past, not a ranking against other servers, so a “bump” on a 20-player server and on a 2,000-player one mean the same thing.
See the terms for the usual no-warranty language, which applies here too.