LIVE NOW · VERIFIED PUBLIC CAMERA FEEDS
You built the map.
We have the feeds.
datum (n.) — the surveyed reference surface every other measurement is judged true against. That's the job: everyone else's camera list is a claim; this one is checked.
In the worst registry we've measured, half the cameras reported “active” weren't sending a picture — we checked. ~8,500 cameras are active right now, across six registries — Caltrans (California, SF to San Diego), Washington State, Austin, Ottawa, Ontario 511 and TfL London (~9,000 cameras listed in total) — fetched by us, coordinate-sanity-checked, health-polled on a loop and trust-scored, so you can tell the ones that are actually live from the ones their city only says are live. Free key in one request. No dashboard, no sales call, no waitlist.
DOCS → /llms.txt /openapi.json · no signup to read either
// FIRST CALL · UNDER A MINUTE
Two commands. No signup flow.
Copy the block. It runs as-is — change the email, and step 2 picks the
key up automatically (needs jq; or paste the key by hand).
The GET also works with no key at all at 60 requests/hour,
so you can skip step 1 entirely if you just want a look.
total: 542 — what's left of Austin's 817 active cameras once the
filter keeps only the ones that pass every check; the other 273
this run were caught serving a placeholder, same as below. Austin
throttles our polling, so that count moves cycle to cycle — see
Ottawa's 207-of-411 for the reproducible version of
this same finding. hasMore: true means it's still a slice, not
the set — page with &offset=, limit
maxes at 500. minTrust=N filters the same way, on
stats.trustScore instead.
// DISCOVER COVERAGE FIRST
Ask what's there before you ask for it.
GET /api/registries is the whole fleet in one call — coverage,
licensing, and whether a browser can actually read the pixels — with zero
camera rows downloaded.
pixelReadable: true on TfL London and Caltrans California —
verified in a real headless browser, not asserted. A
<img src="{feedUrl}"> renders
any camera in this API. Reading actual pixels — fetch(),
<canvas>, deck.gl's BitmapLayer — only
works cross-origin where pixelReadable is true:
~4,000 cameras across those two registries today, no proxy required.
Everywhere else, fetch feedUrl server-side.
// WHY A DIRECTORY AND NOT A LIST
“Active” is a claim. We check it.
A published camera list is a snapshot of intent. Ottawa's has no status field at all; Austin's says which of its cameras are switched on. Neither can tell you which cameras are returning actual pixels right now — and both are already out of date by the time you read them. So we fetch instead of trusting.
Five of the 207, run 2026-07-22 UTC against Ottawa's own feed URLs. Five HTTP 200s carrying one byte-identical, 22,379-byte JPEG — a bilingual “Camera Video Unavailable / Caméra vidéo non disponible” card, not a street.
- A status column is a promise. A fetch is evidence. Every
active camera in the directory is polled on a loop, and what comes
back is recorded:
uptime24h,uptime7d,lastOkAt. - Frozen frames are caught too.
freshcompares the image hash between polls — a camera stuck on a placeholder answers 200 forever but stops changing, and that shows up. - It rolls into one number.
trustScore(0–100) folds uptime, verification status and freshness together, so you can sort by "actually worth rendering" instead of by luck.nullmeans never polled — which is different from bad. - We keep the receipts, not just the verdict. Cameras that fail
verification come back as
verificationStatus: "contradicted"with a note saying what we caught, rather than quietly disappearing from the response. - And we're not immune to it either. Politeness costs us reach:
our poller deliberately backs off rather than hammer a source, so a
registry with an aggressive CDN costs us coverage on any single pass.
That's exactly why
trustScoreis a rolling measurement over many samples, not one check — and why the number above is Ottawa's, not a source that throttles us.
The same pattern shows up on the other two registries, at different rates — we're not singling one city out. Austin's count moves with how much of its CDN we can reach in a given cycle, since we poll it politely rather than push through the throttling: 273 of 817 on this run, 338 on an earlier one — real, measured, just not a fixed number. Ontario 511, the newer of the two, comes in lower: 61 of 1,663. Across all three registries that's 541 cameras, right now, marked active with no picture behind them. TfL London's 788 active cameras: zero.
// WHAT YOU GET
Five things the raw city feeds don't give you.
All of it travels inside the same camera object — nothing to join, nothing to look up in a second place.
01
Coordinates that survive a fetch
Each camera's coordinates are checked against the city's bounding box and de-duplicated — registries hand out one placeholder coordinate for whole batches — and its feed URL is fetched to confirm it returns an actual image.
That's auto_checked. Landmark-level confirmation
(verified) is a later pass we don't run yet, and we don't
pretend otherwise.
02
Uptime we measured, not uptime we were told
Every active camera is polled on a loop and every result is kept.
uptime24h, uptime7d, lastOkAt,
fresh and a 0–100 trustScore ride along with
every camera in the response.
A camera nobody has polled yet reports null, not zero. We
don't invent a number to fill the field.
03
Licensing attached to every row
registry.licenseName, licenseUrl,
attribution and commercialOk travel with each
camera. Austin, Ontario 511 and TfL London publish clear terms —
commercialOk: true. Ottawa doesn't, so it's null.
null means unknown, not cleared. We won't guess
on your behalf.
04
Docs written for the thing reading them
/llms.txt is the entire API as one plain-text file —
endpoints, field semantics, rate limits, and the gotchas that would
otherwise cost you an afternoon. /openapi.json for the
machine-readable spec. Neither needs a key.
Those gotchas aren't hypothetical — each one is written down because somebody hit it first.
05
Coverage before you fetch a single camera
GET /api/registries lists every source we ingest —
activeCameras/totalCameras, licensing,
tosNotes, and both proxyOk (legal) and
pixelReadable (technical, browser-verified) — with zero
camera rows downloaded.
Then narrow for real: minTrust or
verificationStatus on GET /api/cameras keep
only what's worth rendering — not everything a registry lists.
// WHAT'S LIVE, WHAT ISN'T
Cameras are deep. The rest is roadmap.
This is Phase 1. Everything under NOT BUILT YET is exactly that — not behind a flag, not in private beta, not "contact us". It does not exist yet, and nothing on this page pretends it does.
LIVE TODAY
- GET /api/camerasFilter by
city,country,bbox,minTrustorverificationStatus. Paginated:limit(max 500),offset,total,hasMore. - GET /api/cameras/{id}One camera, full record.
- GET /api/registriesCoverage, licensing and
pixelReadableper source — no camera download required. - POST /api/keysFree key, issued instantly to any email. Shown once.
- GET /llms.txt · GET /openapi.jsonAgent docs and the OpenAPI spec. No key required.
- Rate limits, in the open60 req/h without a key, 3,600 with
one.
X-RateLimit-*on every response,Retry-Afteron a 429. - Six registriesCaltrans California, Washington State, Austin, Ottawa, Ontario 511, TfL London — ~9,000 cameras listed, ~8,500 active, health-polled continuously.
NOT BUILT YET
- /frame · /streamA same-origin image proxy, CORS solved.
Today:
<img src="{feedUrl}">renders fine everywhere, butfetch(),<canvas>and deck.gl'sBitmapLayeronly work whereregistry.pixelReadableistrue— that's TfL London today, not Austin, Ottawa or Ontario 511. FetchfeedUrlserver-side for the rest. - Historical framesNothing is archived yet. There is no back-in-time endpoint to call.
- Aircraft (ADS-B) · satellites (TLE)Planned as passthrough behind the same key. Not in the API today.
- More registriesThe adapter shape is proven on four. Which comes fifth is the question below.
NOTED
We'll email when the things you picked ship.
Your picks go straight into the build order. Meanwhile the cameras are live — grab a key and make the first call.
Public data only. Free tier stays free.