Vehicle position
SNCB: belgium's national train operator
- Format
- GeoJSON
- Updates
- Every 20 seconds (derived from the GTFS-RT feed)
- Latest snapshot
- Snapshots stored
- about 3,283,138
curl -H "Authorization: Bearer $MOBILITYTWIN_TOKEN" "https://api.mobilitytwin.brussels/sncb/vehicle-position"
The estimated positions of SNCB/NMBS trains: where the timetable (GTFS) has each train at the moment of every GTFS-RT poll, placed along Infrabel's track segments. Realtime delays are not applied, since the realtime feed's trip ids match the timetable for only about half the trains.
Which days have data
Data from 21 Aug 2024 to 2 Nov 2026, on 796 days. 30 of the last 30 days have data. A typical day holds 3776 snapshots. Days are in UTC.
2026
JanFebMarAprMayJunJulAugSepOctNovDec
2025
JanFebMarAprMayJunJulAugSepOctNovDec
2024
JanFebMarAprMayJunJulAugSepOctNovDec
- Full day
- Partial, 50–90% of a typical day
- Low, under 50%
- No snapshot
- Not expected
Click a day above, or pick a date, to get its requests.
Parameters
| Name | Meaning |
|---|---|
timestamp | Return the last snapshot at or before this moment, in Unix seconds or ISO 8601 (e.g. 2026-05-06T12:00:00Z). Without it, the latest snapshot is returned. |
start_timestamp | Start of the range, in Unix seconds or ISO 8601. |
end_timestamp | End of the range, in Unix seconds or ISO 8601. |
limit | Maximum number of snapshots, at most 100. |
offset | Number of snapshots to skip, to page through a range. |
Response fields
A GeoJSON FeatureCollection. Field names without a prefix are in each feature's properties.
| Field | Type |
|---|---|
name_end | string |
name_start | string |
ptcarid_end | string |
ptcarid_start | string |
trip_headsign | string |
trip_id | string |
Python example
import requests
import geopandas as gpd
from datetime import datetime, timedelta, timezone
yesterday_noon = (datetime.now(timezone.utc) - timedelta(days=1)).replace(
hour=12, minute=0, second=0, microsecond=0
)
params = {
"timestamp": yesterday_noon.isoformat(), # ISO accepted; epoch also works
}
url = "https://api.mobilitytwin.brussels/sncb/vehicle-position"
data = requests.get(url, headers={
'Authorization': 'Bearer [MY_API_KEY]'
}, params=params).json()
gdf = gpd.GeoDataFrame.from_features(data["features"])
# Show all currently running trains with their route
for _, train in gdf.iterrows():
print(f"{train['name_start']} → {train['name_end']} ({train['trip_headsign']})")
# Plot train positions on a map
gdf.plot(figsize=(10, 8), color="#006ab3", markersize=10)