Deutsche Bahn Timetable Scraper - Schedules & Real-Time Delays
Deutsche Bahn Timetable Scraper
Scrape journey plans from Deutsche Bahn (bahn.de), the largest rail operator in Europe. Returns ICE, IC/EC, IR, RE, RB, and S-Bahn schedules with platforms, transfers, real-time delays, occupancy forecasts, and segment-level routing across Germany plus international DB routes (AT, CH, FR, NL, BE, PL, DK).
Deutsche Bahn Timetable Scraper Features
- Pulls journey plans from the bahn.de Reiseauskunft (HAFAS) JSON API.
- Returns ~5 connections per request and paginates by advancing the search time forward, so you get a continuous list of departures rather than five and a polite shrug.
- Resolves station names automatically — pass "Berlin Hbf" or an EVA/IBNR code, the scraper handles the lookup.
- Surfaces real-time delay (
departure_time_realtime) when bahn.de has it, alongside the scheduled time. - Captures train type (ICE, IC, EC, IR, RE, RB, S, U, Bus), train number, operating carrier (DB Fernverkehr, Flixtrain, ODEG, etc.), and per-segment platforms.
- Exposes occupancy forecasts for both 1st and 2nd class (0-4 scale) and a flat list of
risNotizenadvisories like construction work or board-only stops. - Supports both 1st and 2nd class fare classes, plus a long-distance-only filter that strips S-Bahn and regional trains.
- Pure JSON API — no browser, no captcha solving, no fragile selectors.
Who Uses Deutsche Bahn Timetable Data?
- Travel aggregators — Feed schedules into trip planners or fare comparison front-ends without paying for a commercial HAFAS licence.
- Mobility researchers — Build datasets of train frequencies, transfer patterns, and on-time performance across the German rail network.
- Logistics planners — Track route options for time-sensitive freight or business travel, including platform-level detail.
- Fare comparison tools — Cross-reference DB schedules against Flixtrain, ÖBB, SNCF, and other operators.
- Travel-tech startups — Prototype itinerary products against a stable API surface before committing to a paid integration.
How Deutsche Bahn Timetable Scraper Works
- Provide an origin and destination — station names like "Berlin Hbf" or numeric EVA/IBNR codes both work.
- The scraper resolves each station against bahn.de's autocomplete endpoint, then queries the journey API for the requested date and time.
- Each batch returns about five connections; the scraper advances the search time and queries again until it hits
maxItemsor runs out of departures within a 24-hour window. - Records save as flat JSON with all the fields you'd expect, plus a deeplink back to bahn.de for each journey.
Input
{
"origin": "Berlin Hbf",
"destination": "München Hbf",
"date": "",
"time": "",
"fareClass": "2",
"includeLocalTrains": true,
"maxItems": 50,
"proxyConfiguration": {
"useApifyProxy": true,
"apifyProxyGroups": ["RESIDENTIAL"]
}
}
| Field | Type | Default | Description |
|---|---|---|---|
origin |
string | "Berlin Hbf" | Departure station name (e.g. "Berlin Hbf", "München Hbf") or EVA/IBNR code. |
destination |
string | "München Hbf" | Arrival station name or EVA/IBNR code. |
date |
string | tomorrow | Travel date in YYYY-MM-DD format. Empty defaults to tomorrow. |
time |
string | "08:00" | Departure time in HH:MM (24h). Empty defaults to 08:00. |
fareClass |
string | "2" | "1" for 1st class, "2" for 2nd class. |
includeLocalTrains |
boolean | true | Include S-Bahn, RE, RB, U-Bahn, Tram, Bus. Set to false to restrict to ICE/IC/EC/IR. |
maxItems |
integer | 50 | Maximum journey records to return. |
proxyConfiguration |
object | Apify Residential | Standard Apify proxy config. Residential is recommended for production runs. |
Long-distance only example
{
"origin": "Hamburg Hbf",
"destination": "Frankfurt(Main)Hbf",
"includeLocalTrains": false,
"fareClass": "1",
"maxItems": 30
}
EVA code example
{
"origin": "8011160",
"destination": "8000261",
"date": "2026-05-15",
"time": "07:00",
"maxItems": 100
}
Deutsche Bahn Timetable Scraper Output Fields
{
"journey_id": "21d88e04_3",
"origin_station": "Berlin Hbf",
"origin_id": "8011160",
"destination_station": "München Hbf",
"destination_id": "8000261",
"departure_time": "2026-04-26T08:36:00",
"departure_time_realtime": "",
"arrival_time": "2026-04-26T12:46:00",
"arrival_time_realtime": "",
"duration_minutes": 250,
"transfers": 0,
"train_segments": [
"ICE 1005 | Berlin Hbf -> München Hbf | 08:36 -> 12:46 | platforms 4/22 | DB Fernverkehr AG"
],
"platform_departure": "4",
"platform_arrival": "22",
"train_type": "ICE",
"train_number": "1005",
"train_name": "ICE 1005",
"carrier": "DB Fernverkehr AG",
"delay_minutes": null,
"cancelled": false,
"occupancy_class_1": 1,
"occupancy_class_2": 2,
"ris_notizen": ["Hält nur zum Einsteigen"],
"bahn_de_url": "https://www.bahn.de/buchung/fahrplan/suche#sts=true&so=Berlin%20Hbf&zo=M%C3%BCnchen%20Hbf&..."
}
| Field | Type | Description |
|---|---|---|
journey_id |
string | Stable trip identifier from bahn.de (tripId). |
origin_station |
string | Departure station name. |
origin_id |
string | EVA/IBNR code for the origin. |
destination_station |
string | Arrival station name. |
destination_id |
string | EVA/IBNR code for the destination. |
departure_time |
string | Scheduled departure (ISO 8601 local time). |
departure_time_realtime |
string | Real-time-adjusted departure when bahn.de has it. Empty otherwise. |
arrival_time |
string | Scheduled arrival. |
arrival_time_realtime |
string | Real-time-adjusted arrival when available. |
duration_minutes |
number | Total scheduled duration in minutes. |
transfers |
number | Number of train changes. |
train_segments |
array of string | Per-leg formatted lines: train, route, times, platforms, carrier. |
platform_departure |
string | Departure platform at the origin. |
platform_arrival |
string | Arrival platform at the destination. |
train_type |
string | Primary train type — ICE, IC, EC, IR, RE, RB, S, U, Bus. |
train_number |
string | Primary train number (e.g. "1005"). |
train_name |
string | Friendly name (e.g. "ICE 1005"). |
carrier |
string | Operating carrier — DB Fernverkehr AG, Flixtrain, ODEG, and so on. |
delay_minutes |
number|null | Real-time delay in minutes at origin. null when no real-time data is available. |
cancelled |
boolean | True if any segment is cancelled. |
occupancy_class_1 |
number | 1st-class occupancy forecast (0=unknown, 1=low, 2=medium, 3=high, 4=very high). |
occupancy_class_2 |
number | 2nd-class occupancy forecast on the same 0-4 scale. |
ris_notizen |
array of string | Real-time advisories (cancellations, platform changes, board-only stops). |
bahn_de_url |
string | Direct deeplink into bahn.de for this trip. |
FAQ
How do I scrape Deutsche Bahn schedules?
Deutsche Bahn Timetable Scraper hits the bahn.de Reiseauskunft JSON backend directly. You pass an origin, destination, and date — the scraper resolves stations, queries the journey API, and returns clean records. No browser, no captcha solving.
How much does Deutsche Bahn Timetable Scraper cost to run?
The scraper runs on pay-per-event pricing: $0.10 per actor start plus $0.001 per record. A 50-record run lands at about $0.15. Bulk operators can negotiate a custom rate.
What data can I get from bahn.de?
Deutsche Bahn Timetable Scraper returns 24 fields per journey, including station names and EVA codes, scheduled and real-time departure/arrival times, transfers, per-segment train info (type, number, platforms, carrier), occupancy forecasts for both classes, and any active real-time advisories.
Does Deutsche Bahn Timetable Scraper need proxies?
Deutsche Bahn Timetable Scraper works without proxies for small runs but ships with Apify Residential enabled by default. bahn.de sits behind Akamai, which gets uncomfortable around ~5 req/s per IP — proxies prevent that conversation.
Can I get fare data?
Deutsche Bahn Timetable Scraper does not return ticket prices. The bahn.de fare endpoint moved behind authentication in 2026 and is no longer reachable from the public web SPA. The scraper covers schedules, routing, platforms, and real-time data — everything except the price tag.
Does it support international DB routes?
Deutsche Bahn Timetable Scraper supports any journey routable through DB's Reiseauskunft, including international routes to Austria, Switzerland, France, Netherlands, Belgium, Poland, and Denmark. Pass any DB-recognised station name and it works.
Need More Features?
Need station-board mode, fare data, or a different rail operator? File an issue or get in touch.
Why Use Deutsche Bahn Timetable Scraper?
- Affordable — $0.10/start + $0.001/record. A 1000-journey run is roughly $1.10, which is less than the train fare.
- First on Apify — There is no other Deutsche Bahn scraper on the store. The commercial HAFAS licence runs into thousands of euros per year, which is a different conversation.
- Real-time aware — Surfaces delays, cancellations, platform changes, and occupancy directly from the same feed bahn.de's app uses, so the data matches what passengers actually see.