[](#getting-started)
[](#trip-companion)
[](https://kotlinlang.org)
[](https://developer.android.com/compose)
[](LICENSE)
[](#privacy)
**Berlin first, all of Germany on board.**
Knows how long a change really takes, where to board, when a faster way turns up and when to get off –
on the phone, on the watch and on a page your friends can follow.
[Highlights](#highlights) · [How it works](#how-it-works) · [Getting started](#getting-started) · [Data & attribution](#data-sources-and-attribution) · [Privacy](#privacy) · [Roadmap](#roadmap)
[!NOTE]
In active development. The phone app, the Wear OS app, the live page and the route page work; there is no release yet.
Contents
- [Highlights](#highlights) · [All features](#all-features)
- [How it works](#how-it-works)
- [Transfer levels](#transfer-levels) · [Chart view](#chart-view) · [Setup and settings](#setup-and-settings) · [Trip companion](#trip-companion)
- [Live link and route link](#live-link-and-route-link) · [Little motions](#little-motions) · [Timetable sources](#timetable-sources) · [From OpenStreetMap to the app](#from-openstreetmap-to-the-app)
- [Screenshots](#screenshots)
- [Architecture](#architecture)
- [Getting started](#getting-started) – build, keys, tests, station data, web pages
- [Data sources and attribution](#data-sources-and-attribution)
- [Privacy](#privacy) · [Roadmap](#roadmap) · [Contributing](#contributing) · [For developers](#for-developers) · [License](#license)
Highlights
Most journey planners stop caring the moment you pick a connection. Next Stop keeps going – built
on open data and community services, with no account and no server of its own.
Transfer levels
Every change rated relaxed, normal, tight or sprint by the walking pace it needs – from live times and the real walk. You set how tight you go.
Exact transfer walks
Measured on the station's OpenStreetMap footways – stairs, lifts and platforms, not straight lines.
Trip companion
Next step, countdown and stops left with live times – in the app and as a live notification.
Boarding hints Board at the front, middle or rear – and be first at the stairs for your connection.
Shortcut alert
Keeps searching while you ride and speaks up when a faster way turns up.
Get-off reminders
Sound and vibration one stop before you get off, at every change – on the watch too.
Live vehicles
Buses and trains around you on the map, placed from real-time data, with their direction.
Stations up close
Entrances, accesses through buildings, lifts and the stop positions of bus and tram stops.
Made for Wear OS
Tiles, a complication, companion pages, a map and standalone search on the wrist.
Live link
Friends follow your trip in any browser – or get a connection as a step-by-step page to travel themselves.
All of Germany
Station data for all 16 states from OpenStreetMap; timetables nationwide through Transitous.
Private by design
No account, no ads, no tracking – and no server of ours in between.
All features
Plan – transfer levels, through-runs, means of transport, bike combo, chart view
| | |
|---|---|
| **Transfer levels** | Every change is rated by the live times and the walking pace it needs: *relaxed* (plenty of buffer, stroll), *normal* (normal walking pace), *tight* (works at a brisk pace) and *sprint* (only running or with luck, and every 0–1 min change). German UI: Entspannt, Normal, Knapp, Sprint. |
| **Slower on the move** | With luggage, a pram or a walking aid every walk counts 1.3 times as long, at every level. |
| **Exact transfer walks** | Change walks are measured on the OpenStreetMap footway network of the station. |
| **Through-runs** | When your train continues as another line, the app tells you to *stay seated* and which line it continues as. |
| **Means of transport** | S-Bahn, U-Bahn, tram, bus, ferry, regional – plus *Long-distance* (ICE, IC, EC, RJ …) and *Coach* (FlixBus …) as categories of their own, globally or per search. |
| **Deutschlandticket** | One switch turns long-distance and coach off together (the ticket covers neither); off again turns them back on. |
| **With bicycle** | Only show rides that take a bicycle along. |
| **Bike combo** | Cycle the first and last mile, take the bike on S-Bahn, U-Bahn, tram and regional trains; buses and coaches only where they carry bikes, otherwise that stretch is cycled. |
| **Chart or list** | Connections as columns on a shared time axis, one block per leg, the change minutes in the colour of their wait – or as a classic list. Via stops with an optional stay. |
| **Delays** | Three ways to show a late departure: new time + delay (default, `12:09 +2`), planned time + delay (`12:07 +2`), or the coloured new time alone. |
Ride – companion, boarding hints, shortcut alert, reminders
| | |
|---|---|
| **Trip companion** | Follows your trip with live times: the next step, the countdown to the departure, the stops left – in the app and as a live notification. |
| **Boarding hints** | *Board at the front / middle / rear* from change-position data; estimated for changes to buses and trams. |
| **Shortcut alert** | Searches in the background while you ride and alerts you when a faster way turns up – optionally only equally comfortable ones. |
| **Every minute counts** | A per-trip mode: sprint changes allowed, shortcut alert on, searching again from the next stop you can reach. |
| **Get-off reminders** | Sound and vibration one stop before you get off and shortly before arrival, at every change. |
| **Walk rerouting** | If you leave the planned walk, the way is recomputed and tells you what it costs. |
Map – live vehicles, stations, stop positions, search
| | |
|---|---|
| **Live vehicles** | Buses and trains around you, placed from real-time data, with a live dot and their direction; without a dot they run by the timetable. |
| **One card at a time** | Tap a stop, a vehicle or a place and one card shows it – with distances, and a map style of your choice (light, colourful, dark or automatic). |
| **Stations up close** | Entrances and exits of U- and S-Bahn stations, accesses through buildings and lifts – shown automatically by zoom, always, or only at the station you picked. |
| **Stop positions** | The individual stop positions (*Pos.*) of bus and tram stops, with the lines that stop at each. |
| **Search** | Place search over OpenStreetMap data, plus saved places, recent trips and contacts. |
Watch – tiles, complication, companion pages, map, search
| | |
|---|---|
| **Tiles & complication** | *Next departure* and *Favourite* tiles and a complication on the watch face. |
| **Companion pages** | Swipe through depart, ride, change and overview pages during a trip; get-off alerts with haptics. |
| **Map** | A map of the stops and departures nearby. |
| **Standalone search** | Type or speak a destination on the watch; it uses the phone's position or its own. |
Share, data and more – live link, route link, state packs, widgets, settings
| | |
|---|---|
| **As text** | A clean text summary of the connection for any messenger. |
| **Live link** | A static web page (`web/live`) where others watch your trip live in the browser. |
| **Route link** | A static web page (`web/route`, "So kommst du hin") that turns a shared connection into steps to travel yourself, with live times. |
| **State packs** | Station, entrance, change-position and transfer-walk data for all 16 German states, built from OpenStreetMap. |
| **Line colours** | From the providers' feeds and OpenStreetMap route relations, picked by place – tram 1 in Mannheim is not tram 1 in Karlsruhe. |
| **Many sources** | Berlin/Brandenburg through VBB and BVG, the rest of Germany (long-distance trains included) through Transitous. |
| **Widgets** | Departures, favourite, current trip, mini, next appointment and an automatic one that shows what matters now. |
| **Disruptions** | Notices for your saved routes, with an optional morning check. |
| **Lift status** | accessibility.cloud and DB FaSta, with warnings for lifts out of order on a journey. |
| **Fare zone hint** | A tag when a journey reaches VBB zone C. |
| **Next appointment** | From your calendar, with when to leave for it. |
| **Settings** | Everyday choices up front; data sources, API keys, an own server, the live page address and developer options under *Advanced*. |
How it works
Transfer levels
A change needs 1 min on the same platform, 3 to another, 5 at large rail stations, or its walk
plus 1 min. Beyond that, 5 spare minutes are relaxed and 2 normal. If it still works at a brisk
pace – the walk ×0.8 and no buffer, at least 2 min – it is tight; otherwise it is a sprint. A
journey found only by a search without any minimum change time counts as tight at least. The
rules live in Models.kt (changeNeed, paceTightness, journeyChangeRatings) and
WalkPace.kt (brisk and slower walking).
Chart view
Setup and settings
The same sketches move when you pick an option, and stand still when the system has animations
turned off.
Trip companion
Live link and route link
Both are static pages in web/; the trip or connection travels in the link fragment, and the
viewer’s browser asks the public timetable APIs itself.
Little motions
Loading
Picking a stop
Arrival
Short, soft and never in the way – and off when the system asks for reduced motion.
Timetable sources
The first three share VBB stop ids, so a stop found by one can be asked about at another.
Details: SourceChain.kt and FamilySource.kt.
From OpenStreetMap to the app
The pipeline needs no public server: it reads local Geofabrik .osm.pbf files. See
tools/README.md.
app/ Android phone app – Kotlin, Jetpack Compose, MapLibre, Glance widgets
wear/ Wear OS app – Compose for Wear OS, tiles, complication, Data Layer link to the phone
web/ Static pages: live tracking, route links and the info site – plain JS, no build step, offline tests
tools/ Python pipeline that turns OpenStreetMap data into the app's station assets
docs/ Design spec, key handling, licences, README images
You need a recent Android Studio, JDK 17 or newer (the bundled JetBrains Runtime works),
Node.js for the web tests and Python 3 for the data tools.
git clone <this repository>
cd next-stop
./gradlew assembleDebug # phone and watch debug APKs
./gradlew :app:installDebug # install the phone app on a connected device
Keys (optional)
Some sources need an access key. Copy secrets.properties.example to secrets.properties
(gitignored) and fill in what you have; the build turns the values into built-in keys. Without
it, keyed sources stay off until a key is entered in the settings – and a key entered there
always wins. Never commit keys and do not publish builds with keys built in.
More: docs/keys.md.
Building without public-transport-enabler
The library comes from JitPack, pinned to a commit. If JitPack fails to build it, set
```properties
# gradle.properties
nextstop.pte=false
```
The app then compiles `app/src/nopte/` instead of `app/src/pte/` and shows that source as
"not included in this build".
Tests
./gradlew test# unit tests (phone and watch)
node web/test/live.test.js # live page, offline
node web/test/route.test.js # route page, offline
python3 tools/test_build_station_asset.py # data pipeline self-tests
python3 tools/test_build_transfer_walks.py
python3 tools/test_extract_osm_pbf.py
Station data and web pages
Station data – the OpenStreetMap assets are committed. To rebuild them from a Geofabrik
extract (state by state or all of Germany), follow tools/README.md.
Live and route pages – web/ is static and served at https://nextstop.bapo.me, where the
app’s links lead by default. To use your own copy, upload it to any static host (Cloudflare
Pages, GitHub Pages, …) and enter its address in the app’s settings (Advanced). Open …/live/#demo
or …/route/#demo for made-up examples. See web/README.md.
Info site – web/index.html (German) and web/en/ (English) are the project’s website,
with its assets in web/site/. They sit beside the pages above and need nothing else.
No account, no ads, no analytics, no crash reporting. The app contains no tracking SDK.
No server of ours. Requests go straight from your device to the timetable, map and search
services you enabled; the live page asks the public APIs from the viewer’s browser.
Your keys stay on your device and are excluded from backups.
Map links you open with Next Stop (“navigate here” from another app) are read on your
device. Only a short link of Google Maps (maps.app.goo.gl/…) has to be asked once at its own
host where it leads; the map page behind it is not loaded.
Android’s backup (Google backup and phone-to-phone transfer) takes your settings,
favourites, saved places, “Meine Wege” and recent destinations, so a new phone starts where the
old one left off; cloud backup only where Android can encrypt it on the device (a screen lock is
set). Keys, caches, downloaded OpenStreetMap data and the widgets’ state are left out
(app/src/main/res/xml/data_extraction_rules.xml; the watch app likewise keeps its settings and
leaves out cached departures). Turn it off in the system settings under Google › Backup.
Permissions for features only: location (nearby stops, the companion), notifications (trip
and get-off reminders), and – only if you turn them on – contacts and calendar.
Roadmap
GPL-3.0 LICENSE
First release
Screenshots and a store listing
More networks beyond Berlin/Brandenburg with the same depth (boarding hints, lifts)
Keep the OpenStreetMap state packs fresh with a regular rebuild
Contributing
Bug reports, ideas and pull requests are welcome.
Everything in the repository is written in English (the app itself has English and German UI).
No personal data, credentials, or home or work addresses in code, sample data or screenshots;
use well-known central stations as examples.
Never commit keys (see docs/keys.md), and run the tests above before opening a
pull request.
App store permission. Next Stop’s own code comes with an
additional permission under GPLv3 section 7: it may also be
distributed through app stores whose terms add restrictions for users (such as Apple’s App
Store), as long as the full source stays freely available under GPLv3 and the app says where
to find it. The permission covers only Next Stop’s own code – third-party components such as
public-transport-enabler keep their plain licences. Contributions are accepted under GPLv3
with this permission.