The API
One public URL that returns where someone is, right now. No key, no SDK. If it can read a web address, it can read a location. It answers where, not when — no arrival dates, no history, just the current place.
Read a location
GET /v1/{id}Returns JSON with Access-Control-Allow-Origin: *, cached 30 seconds at the edge. Add ?format=text for a bare line, or ?format=svg for a badge you can drop into an <img> tag.
{
"schema": "whereabouts/v1",
"id": "k7m2p9x4qn8wr3fd",
"precision": "city",
"updatedAt": "2026-08-08T19:34:01Z",
"stale": false,
"location": {
"displayName": "Nevada",
"country": { "code": "US", "name": "United States", "flag": "🇺🇸" },
"state": { "code": "NV", "name": "Nevada" },
"city": "Las Vegas",
"coordinates": null,
"timeZone": {
"identifier": "America/Los_Angeles",
"offsetMinutes": -420,
"localTime": "12:39"
}
}
}Use it
const res = await fetch("https://getwhereabouts.com/v1/k7m2p9x4qn8wr3fd")
const where = await res.json()
document.querySelector("#where").textContent = where.location.displayNameWhy the ids look like that
Ids are sixteen random characters minted by the server. There is no directory, no username and nothing to enumerate — knowing someone’s name gets you no closer to their location. The link is the only key, which is why it needs no other authentication, and why replacing it is one tap in the app.
Treat a link like a password that happens to be a URL: unguessable, but readable by anyone you hand it to. Every response is served noindex.
The fields
- precision
region,cityorexact, chosen by the person publishing.coordinatesare non-null only atexact; atregion,cityis null too. Stripped on write and again on read, not merely hidden.- stale
- True when the phone hasn’t checked in for six hours. The location is still the last known one — a hint, not a fault.
- location.displayName
- The one string to show if you only show one thing. A US state name, or a country name everywhere else.
Publish a location
The iOS app does this for you. The wire protocol is three calls, in case you want your own publisher.
POST /v1/links → { id, token, url }PUT /v1/{id} Authorization: Bearer <token>DELETE /v1/{id} Authorization: Bearer <token>POST /v1/links takes no body — the server mints the id, so there is no name to look anyone up by. PUT takes the document above minus the server-derived id and stale. DELETE empties the link; add ?release=1 to destroy it for good.