4.2 KiB
ÖBB Train Planner
Checks the ÖBB real-time schedule, picks the best train for your upcoming calendar events, and shows a live "leave by" countdown from your current location.
What's included
oebb-planner/
├── server/
│ ├── index.js ← Node.js proxy server (ÖBB API + ICS parser)
│ └── package.json
├── oebb-planner.jsx ← React front-end (use in Claude.ai artifacts or any React app)
└── README.md
Quick start
1 — Start the proxy server
The server bypasses ÖBB's CORS restrictions and parses ICS calendar files.
cd server
npm install
npm start
# → ÖBB Planner API running on http://localhost:3001
Requires Node.js ≥ 18 (uses built-in
fetchandAbortSignal.timeout).
For development with auto-reload:npm run dev
2 — Open the React app
Paste oebb-planner.jsx into a Claude.ai artifact (or your own React app).
The app detects whether the server is online and shows a status indicator in the header.
Calendar integration
The app reads any standard ICS calendar. Only events that have a location field and fall within the next 14 days are imported.
Option A — ICS URL (Google Calendar, Outlook, Fastmail…)
- In the app, open the Calendar panel → ICS URL tab
- Paste your calendar's secret ICS address
Google Calendar:
Settings → click your calendar → scroll to "Secret address in iCal format" → copy the URL
Apple Calendar (iCloud):
Calendar app → right-click calendar → "Share Calendar" → enable public calendar → copy the URL
(change webcal:// to https:// or paste as-is — the server handles both)
Outlook:
Settings → View all Outlook settings → Calendar → Shared calendars → Publish → ICS link
Option B — Upload .ics file
Export your calendar as a .ics file from any app (File → Export in Apple Calendar, etc.) and upload it via the Upload File tab.
How the train matching works
- Your current GPS location is used to find the nearest ÖBB station (via the HAFAS
LocGeoPosAPI). - Each event's location field is used to search for the nearest destination station (
LocMatch). - The HAFAS
TripSearchendpoint finds journeys departing up to 2 hours before your event. - The "leave by" time = next catchable train departure − 12 minutes (default walk time to station).
- Data refreshes automatically every 60 seconds.
Server endpoints
| Method | Path | Description |
|---|---|---|
POST |
/api/hafas |
Proxy to fahrplan.oebb.at/bin/mgate.exe |
GET |
/api/calendar?url=<ics_url> |
Fetch & parse a remote ICS calendar |
POST |
/api/calendar/parse |
Parse raw ICS content sent in request body |
GET |
/api/health |
Liveness check |
Customisation
| Variable | Location | Default | Description |
|---|---|---|---|
WALK_MINS |
oebb-planner.jsx |
12 |
Walk time from your location to origin station |
PORT |
server/index.js |
3001 |
Server port |
horizonDays |
server/index.js |
14 |
How far ahead to look for calendar events |
PROXY |
oebb-planner.jsx |
http://localhost:3001 |
Server URL |
Deploying beyond localhost
To run this on a server or share it with others:
- Set
PORTvia environment variable:PORT=8080 npm start - Update
PROXYinoebb-planner.jsxto your server's URL - Restrict CORS in
server/index.jsif needed:app.use(cors({ origin: "https://your-app.example.com" }));
Troubleshooting
"Server offline" shown in the app
→ Make sure npm start is running in the server/ directory.
No trains found for an event
→ Check that the destination in your calendar event is a recognisable ÖBB station name
(e.g. "Graz Hbf", "Salzburg Hauptbahnhof"). Verbose postal addresses are trimmed automatically.
Calendar import returns 0 events
→ Only events with a LOCATION field set are imported. Make sure your events have a location
and fall within the next 14 days.
ÖBB returns errors
→ The HAFAS API occasionally changes. Check fahrplan.oebb.at is reachable from your server.