Deutsche Bahn Train Times, Fares & Routes Scraper avatar

Deutsche Bahn Train Times, Fares & Routes Scraper

Pricing

from $11.54 / 1,000 results

Go to Apify Store
Deutsche Bahn Train Times, Fares & Routes Scraper

Deutsche Bahn Train Times, Fares & Routes Scraper

Scrape German and European train connections from bahn.de: departure and arrival times, duration, transfers, ICE/IC/RE train types and cheapest fares across 5500+ stations. Export to JSON, CSV or Excel.

Pricing

from $11.54 / 1,000 results

Rating

0.0

(0)

Developer

Scrapers Lat

Scrapers Lat

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

21 hours ago

Last modified

Share

Deutsche Bahn Train Times, Fares & Routes Scraper

Deutsche Bahn Train Times, Fares & Routes Scraper

Here is one real result, with every field the actor returns (the fares array is trimmed from 11 entries to 4 here for readability; the actor returns all of them):

{
"from": "Berlin Hbf",
"to": "München Hbf",
"departure": "2026-08-11T08:36:00",
"arrival": "2026-08-11T12:46:00",
"durationMinutes": 250,
"transfers": 0,
"trainTypes": ["ICE"],
"trains": ["ICE 1005"],
"price": 103.99,
"currency": "EUR",
"priceClass": "KLASSE_2",
"departurePlatform": "4",
"arrivalPlatform": "22",
"operators": ["DB Fernverkehr AG"],
"amenities": ["Bordrestaurant", "ICE Sprinter", "Komfort Check-in verfügbar"],
"occupancy": [
{ "class": "1st", "level": 1, "text": "Geringe Auslastung erwartet" },
{ "class": "2nd", "level": 2, "text": "Mittlere Auslastung erwartet" }
],
"occupancyFirstClass": "Geringe Auslastung erwartet",
"occupancySecondClass": "Mittlere Auslastung erwartet",
"runsOn": "nicht täglich; 10. Aug bis 11. Okt 2026",
"runsWeekdays": ["MO", "DI", "MI", "DO", "FR", "SA", "SO"],
"legs": [
{
"from": "Berlin Hbf",
"to": "München Hbf",
"departure": "2026-08-11T08:36:00",
"arrival": "2026-08-11T12:46:00",
"train": "ICE 1005",
"trainType": "ICE",
"trainNumber": "1005",
"direction": "München Hbf",
"stops": 7,
"departurePlatform": "4",
"arrivalPlatform": "22",
"operator": "DB Fernverkehr AG",
"amenities": ["Bordrestaurant", "ICE Sprinter", "Komfort Check-in verfügbar"],
"occupancySecondClass": "Mittlere Auslastung erwartet"
}
],
"notices": [],
"fromExtId": "8098160",
"toExtId": "8000261",
"tripId": "c0a26fd4_3",
"searchDate": "2026-08-11",
"fares": [
{ "name": "Super Sparpreis", "class": "2nd", "price": 77.99, "currency": "EUR" },
{ "name": "Sparpreis", "class": "2nd", "price": 112.99, "currency": "EUR" },
{ "name": "Flexpreis", "class": "2nd", "price": 161.1, "currency": "EUR" },
{ "name": "Probe BahnCard 25", "class": "2nd", "price": 19.9, "currency": "EUR" }
],
"cheapestFareName": "Probe BahnCard 25",
"cheapestFarePrice": 19.9,
"observedAt": "2026-08-10T14:18:23.098Z",
"error": null
}

The most complete Deutsche Bahn connection scraper available. It returns every field bahn.de exposes for a train connection (times, duration, transfers, trains, platforms, operators, live occupancy and amenities), adds the full fare breakdown (Flexpreis, Sparpreis, Super Sparpreis and BahnCard offers) with the cheapest fare called out, and gives you route, date, time, class and transfer filters to target exactly the connections you need.

📥 Input · 📤 Output · 💰 Pricing · ▶️ Examples

Apify Coverage Output Billing

Table of contents

What it does

The actor searches bahn.de for train connections between two stations on a given date and time, then writes one normalized record per connection to the run's dataset. Each record carries departure and arrival times, duration, number of transfers, train types and numbers, platforms, operators, live occupancy per class, on-board amenities, and the day-of-week service pattern. Each connection is broken down into per-leg details in legs.

With withDetails on (the default), each connection is enriched with the full fare breakdown in fares (Flexpreis, Sparpreis, Super Sparpreis and BahnCard offers per class), and the cheapest available fare is surfaced as cheapestFareName and cheapestFarePrice. Missing source values are returned as null, never invented. The search covers Germany and connected European hubs such as Wien Hbf, Zürich HB, and Amsterdam Centraal.

Quickstart

Open the actor, paste this into the input, and press Run. It returns the 10 fastest Berlin to München connections tomorrow morning with full fare details.

{
"fromStation": "Berlin Hbf",
"toStation": "München Hbf",
"time": "08:00",
"searchType": "ABFAHRT",
"travelClass": "KLASSE_2",
"onlyFastConnections": true,
"withDetails": true,
"maxConnections": 10
}

fromStation and toStation are required. Leave date empty to search tomorrow. bahn.de sells tickets roughly 6 months ahead.

Input reference

FieldTypeRequiredDefaultDescriptionExample
fromStationstringyes(none)Origin station or city.Berlin Hbf
toStationstringyes(none)Destination station or city.München Hbf
datestringnotomorrowTravel date in YYYY-MM-DD. Defaults to tomorrow when empty.2026-09-01
timestringno08:00Departure or arrival time in 24h HH:MM.17:30
searchTypeenumnoABFAHRTWhether time is the desired departure (ABFAHRT) or arrival (ANKUNFT).ANKUNFT
travelClassenumnoKLASSE_2Travel class: KLASSE_2 (2nd) or KLASSE_1 (1st). Prices returned for the selected class.KLASSE_1
maxTransfersintegerno(no limit)Maximum transfers per connection.1
onlyFastConnectionsbooleannotrueReturn only the fastest connections (bahn.de "fast connections").false
withDetailsbooleannotrueEnrich each connection with the full fare breakdown and cheapest fare.false
maxConnectionsintegerno10Maximum number of connections to collect.25

Output reference

One dataset item per connection. Types: string, number, integer, boolean, object, array, or null when the source value is absent.

FieldTypeDescription
fromstringResolved origin station name.
tostringResolved destination station name.
departurestringDeparture timestamp (local ISO, no zone).
arrivalstringArrival timestamp (local ISO, no zone).
durationMinutesintegerTotal travel time in minutes.
transfersintegerNumber of transfers on the connection.
trainTypesstring[]Train categories used, for example ICE, IC, RE.
trainsstring[]Train names/numbers used, for example ICE 1005.
pricenumberHeadline price for the selected class.
currencystringPrice currency, usually EUR.
priceClassstringClass the price applies to (KLASSE_1/KLASSE_2).
departurePlatformstringPlatform at the origin, or null.
arrivalPlatformstringPlatform at the destination, or null.
operatorsstring[]Operating companies, for example DB Fernverkehr AG.
amenitiesstring[]On-board amenities, for example Bordrestaurant.
occupancyobject[]Live occupancy per class with class, level, and text.
occupancyFirstClassstring1st class occupancy text, or null.
occupancySecondClassstring2nd class occupancy text, or null.
runsOnstringHuman-readable service period text.
runsWeekdaysstring[]Weekday codes the connection runs on (MO..SO).
faresobject[]Full fare breakdown (with withDetails): each has name, class, price, currency.
cheapestFareNamestringName of the cheapest available fare, or null.
cheapestFarePricenumberPrice of the cheapest available fare, or null.
legsobject[]Per-leg breakdown: stations, times, train, platforms, operator, stops, amenities, occupancy.
noticesarrayService notices/warnings for the connection.
fromExtIdstringbahn.de external station ID for the origin.
toExtIdstringbahn.de external station ID for the destination.
tripIdstringbahn.de trip identifier for the connection.
searchDatestringDate searched (YYYY-MM-DD).
observedAtstringISO 8601 timestamp of when the record was collected.
errorstringnull on success. On a failed run, a single item with a populated error field is written instead.

Example output record

Real record from a live run (input {"fromStation": "Berlin Hbf", "toStation": "München Hbf", "withDetails": true, "maxConnections": 10}), with fares trimmed to 2 entries for brevity:

{
"from": "Berlin Hbf",
"to": "München Hbf",
"departure": "2026-08-11T08:36:00",
"arrival": "2026-08-11T12:46:00",
"durationMinutes": 250,
"transfers": 0,
"trainTypes": ["ICE"],
"trains": ["ICE 1005"],
"price": 103.99,
"currency": "EUR",
"priceClass": "KLASSE_2",
"departurePlatform": "4",
"arrivalPlatform": "22",
"operators": ["DB Fernverkehr AG"],
"amenities": ["Bordrestaurant", "ICE Sprinter", "Komfort Check-in verfügbar"],
"occupancySecondClass": "Mittlere Auslastung erwartet",
"runsWeekdays": ["MO", "DI", "MI", "DO", "FR", "SA", "SO"],
"fares": [
{ "name": "Super Sparpreis", "class": "2nd", "price": 77.99, "currency": "EUR" },
{ "name": "Probe BahnCard 25", "class": "2nd", "price": 19.9, "currency": "EUR" }
],
"cheapestFareName": "Probe BahnCard 25",
"cheapestFarePrice": 19.9,
"tripId": "c0a26fd4_3",
"searchDate": "2026-08-11",
"observedAt": "2026-08-10T14:18:23.098Z",
"error": null
}

Run via API and CLI

Start a run and wait for it to finish, then read the dataset. Replace <TOKEN> with your Apify API token.

Run synchronously and get dataset items in one call:

curl -X POST "https://api.apify.com/v2/acts/scrapers_lat~deutsche-bahn-scraper/run-sync-get-dataset-items?token=<TOKEN>" \
-H "Content-Type: application/json" \
-d '{"fromStation":"Berlin Hbf","toStation":"München Hbf","time":"08:00","withDetails":true,"maxConnections":10}'

Start a run asynchronously:

curl -X POST "https://api.apify.com/v2/acts/scrapers_lat~deutsche-bahn-scraper/runs?token=<TOKEN>" \
-H "Content-Type: application/json" \
-d '{"fromStation":"Hamburg","toStation":"Amsterdam Centraal","date":"2026-09-01","travelClass":"KLASSE_1"}'

Apify CLI:

apify call scrapers_lat/deutsche-bahn-scraper \
--input '{"fromStation":"Köln Hbf","toStation":"Frankfurt(Main)Hbf"}'

Fetch results

Every run writes to a dataset. Fetch items as JSON, CSV, or Excel by changing format:

# JSON
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&clean=true&format=json"
# CSV
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&clean=true&format=csv"
# Paginate large datasets
curl "https://api.apify.com/v2/datasets/<DATASET_ID>/items?token=<TOKEN>&offset=1000&limit=1000"

<DATASET_ID> is returned as defaultDatasetId in the run object. Use offset and limit to page through large result sets. clean=true drops empty and internal fields.

Billing and limits

  • Pay per result. You are charged per connection record returned (result event). See the pricing tab for the current per-result price.
  • Fare details add-on. When withDetails is on and the fare breakdown is fetched, a small details charge applies per enriched connection. Turn withDetails off to skip it.
  • No charge on failure. If a run errors or no connections are found, the actor writes a single item with a populated error field and does not charge for it. Empty runs cost nothing.
  • Spend cap respected. Set maxTotalChargeUsd on the run; once reached, the actor stops emitting and charging further billable results.
  • Free Apify plans are capped at 10 connections per run. Upgrade for higher maxConnections.

FAQ and troubleshooting

A run returned "Station not found". Why? The station name could not be resolved. Use the bahn.de station spelling, for example Berlin Hbf, München Hbf, or Frankfurt(Main)Hbf.

Why is the price different from what I see on bahn.de? price is the headline fare for the selected class at search time. Fares change with demand and availability. The full breakdown is in fares, with the lowest surfaced as cheapestFareName / cheapestFarePrice.

Can I search by arrival time instead of departure? Yes. Set searchType to ANKUNFT and time becomes the desired arrival time.

How far ahead can I search? bahn.de sells tickets roughly 6 months ahead. Dates beyond that return no connections.

Does it cover trains outside Germany? It covers connections that bahn.de sells, including European hubs such as Wien Hbf, Zürich HB, and Amsterdam Centraal.

Is this an official Deutsche Bahn tool? No. This actor is independent and has no affiliation with Deutsche Bahn. It reads only data that is publicly available on bahn.de. Use it in accordance with the source's terms.

More scrapers at scrapers.lat

Built and maintained by scrapers.lat, where we publish scrapers for US and Latin American public platforms: company registries, government data, finance, e-commerce and more. Browse the catalog or request a custom scraper at scrapers.lat.


Independent tool, not affiliated with Deutsche Bahn. Accesses only publicly available bahn.de data. Use in accordance with the source's terms of service.