Access status: Trackser Live currently serves the Trackser app exclusively. API keys are not issued publicly at this time. If you have a project that would benefit from this data, get in touch — if there's sufficient demand, external access is something we'd consider.
Authentication
All API requests require an API key. Pass it as a header or a query parameter:
# As a header (preferred)
GET /live/central/line/latest.json
X-API-Key: YOUR_API_KEY
# As a query parameter
GET /live/central/line/latest.json?key=YOUR_API_KEY
Keep your key out of source control. Use environment variables.
Making requests
Live data endpoints serve pre-built snapshots from Cloudflare R2.
Responses are typically returned in under 100ms. All responses
include Access-Control-Allow-Origin: *
— you can call these endpoints from a browser without a proxy.
JavaScript / Node.js
const API_KEY = process.env.TRACKSER_API_KEY;
const LINE_ID = 'central';
const response = await fetch(
`${BASEURL}/live/${LINE_ID}/line/latest.json`,
{ headers: { 'X-API-Key': API_KEY } }
);
const data = await response.json();
console.log(`${data.trains.length} trains on the ${LINE_ID} line`);
console.log(`Data as of: ${data.as_of}`);
// Find stalled trains
const stalled = data.trains.filter(t => t.isMaybeStalled);
console.log(`Potentially stalled: ${stalled.length}`);
Python
import requests
import os
API_KEY = os.environ['TRACKSER_API_KEY']
LINE_ID = 'northern'
response = requests.get(
f'{BASEURL}/live/{LINE_ID}/line/latest.json',
headers={'X-API-Key': API_KEY}
)
data = response.json()
print(f"Data as of: {data['as_of']}")
print(f"Total trains: {len(data['trains'])}")
# Find trains heading northbound
northbound = [t for t in data['trains'] if t.get('direction') == 'Northbound']
print(f"Northbound: {len(northbound)}")
cURL
# Train count on the Jubilee line
curl -s "${BASEURL}/live/jubilee/line/latest.json" \
-H "X-API-Key: YOUR_KEY" | jq '.trains | length'
# Stats-only (lightweight health check)
curl -s "${BASEURL}/live/metropolitan/line/latest-stats.json" \
-H "X-API-Key: YOUR_KEY" | jq '{trainCount: .stats.trainCount, as_of: .as_of}'
Handling gzip
The /latest.json endpoints serve gzip-compressed
responses. Most HTTP clients decompress automatically when you send
Accept-Encoding: gzip — the Fetch API,
requests, and curl all do this by default.
If your client can't handle gzip, use the
/latest-plain.json variants. These are identical in
content but served uncompressed.
Data freshness
Each response includes an as_of ISO 8601 timestamp.
Snapshots are built every minute. Under normal conditions, data will
be 0–90 seconds old when you receive it.
Always check as_of before acting on data. If it's more
than two minutes in the past, check the
status page — TfL's upstream feed may be
degraded.
Line IDs
metropolitan chiltern bakerloo central circle district
hammersmith-city jubilee northern piccadilly victoria waterloo-city
Response structure
{
"as_of": "2026-03-22T09:43:00.000Z",
"status": "ok",
"sources": {
"unified": "ok",
"trackernet": "ok"
},
"stats": {
"buildTimeMs": 1240,
"trainCount": 38,
"trkReceived": 42,
"trkExpected": 42
},
"trains": [ ... ]
}
Error responses
| Status | Meaning | Action |
|---|---|---|
401 |
Unauthorized — missing or invalid API key | Check your key and how you're sending it |
404 |
Not found — invalid line ID or endpoint path | Check the API reference for valid paths |
429 |
Rate limit exceeded | Back off and retry with exponential backoff |
503 |
Service unavailable | TfL upstream issue. Check status and retry. |
Best practices
- Poll, don't hammer. Data is updated once per minute — polling more frequently wastes requests without gaining freshness.
-
Use stats endpoints for health checks.
/latest-stats.jsonis a fraction of the size of the full snapshot. -
Verify
as_of. A 200 response doesn't guarantee the data is current — check the timestamp. - Implement exponential backoff. On 429 or 503, wait and retry with increasing delays.
- Never hardcode API keys. Use environment variables or secrets management.
-
Prefer the
X-API-Keyheader over the query parameter — it won't appear in server logs or browser history.
Support
For technical questions, integration queries, or to discuss data access: support@curiosity175.co.uk