15 million Germans use DB Navigator to plan train journeys. Almost all of them complain about booking. This is the gap I'd close — and how.
DB Navigator is Deutsche Bahn's official app for train travel in Germany. It does one thing exceptionally well: finding the right train connection. You can search by departure time, arrival time, filter for ICE only, sort by price — the connection search is genuinely excellent. Germany's train network is complex, with 5,700 stations and multi-operator journeys, and Navigator handles this better than any third-party app.
And then you try to buy the ticket.
The booking flow is where Deutsche Bahn loses its users. BahnCard discounts not applied automatically. Seat reservation as a hidden separate step. Fare class selection (Flexpreis vs Sparpreis) that feels deliberately confusing. The gap between "search" and "purchased ticket" is where business travellers miss connections, where families overpay, and where tourists give up and walk to the station instead.
Wants the cheapest or fastest connection, confirmed and paid in under 2 minutes. Business travellers need accurate seat + fare for expense claims.
Germany's national rail operator and the app's owner. Revenue comes from ticket sales. App is a cost-reduction vehicle vs. counter staff.
Regional trains (S-Bahn, RE, RB) are run by third parties — not DB AG. Navigator books tickets across these networks.
~6M Germans hold a BahnCard. These are DB's highest-value, most-loyal customers — 50% or 100% discount on all train journeys.
Trainline, Rome2Rio, and Omio all offer DB ticket booking. They compete on UX, not network access.
The fallback when the app fails. Machines in every station. Counter staff for complex bookings.
| Segment | Travel Frequency | Main Need | Where Booking Fails | Revenue Value |
|---|---|---|---|---|
| Business travellersFocus 25–50, regular ICE routes |
2–4x/week. Predictable routes. Berlin–Frankfurt, Hamburg–Munich. | BahnCard discount applied. Seat reserved. Booking receipt for expenses. Fast — under 90 seconds. | BahnCard not auto-applied. Seat reservation is a separate, confusing step. Fare class not explained. | Highest. Frequent, full-price flex tickets. BahnCard holders = most loyal customers. Every failed booking = Trainline revenue. |
| Commuters 20–45, same route daily |
Daily or weekly. Always the same journey. Often have a monthly Deutschlandticket. | Quick ticket for one-off trips outside their season ticket route. Or just live departure info. | Fare class confusion (is Deutschlandticket valid for this? Do I need a supplement?). App not smart about what they already own. | Medium. Occasional top-ups. Not the primary ticket buyer — their subscription handles most travel. |
| Leisure / tourists All ages, occasional |
1–4x/year. Groups or families. Advance bookings for cheap Sparpreis tickets. | Cheapest fare. Seat reservations for the group. Simple confirmation. | Multi-passenger booking is clunky. Sparpreis vs Flexpreis decision isn't explained. No summary before final payment. | Low per-trip, but high seasonal volume (holidays). Sparpreis tickets = price-sensitive, but still revenue. |
| International visitors Non-German speakers |
Few trips. Often unfamiliar with German rail conventions (reservations optional vs mandatory). | A ticket that definitely works. Clear instructions. English language option. | English UX has translation gaps. German rail conventions (seat reservations are optional, not included) aren't explained. Support is German-only. | Low but growing. Germany's rail tourism is increasing, especially ICE. DB leaves revenue on the table by not simplifying for visitors. |
Why business travellers? They travel multiple times per week, hold BahnCards (DB's most profitable customer segment), and their booking failures are the highest-cost — both in lost Flexpreis ticket revenue and in support calls when the wrong fare is charged on an expense claim. Fix the business traveller experience and the improvements cascade to all segments.
DB Navigator has 480,508 App Store Germany ratings (4.4/5). The gap between overall rating and specific booking flow complaints is wide — connection search drives the 4.4, booking flow drives the 1-star reviews.
"Ich habe BahnCard 50 und trotzdem vollpreisige Tickets gekauft weil der Rabatt beim Bezahlen einfach nicht angezeigt wurde. Erst am Bahnhof hab ich es gemerkt." (I have BahnCard 50 and still paid full price because the discount just wasn't shown during checkout. Only noticed it at the station.)
— App Store Germany review, 2025 (94 people found this helpful)"The connection search is world class. The booking UI looks like it was designed by the same department that writes tax forms."
— r/germany, 2026 (67 upvotes)Business traveller searches Berlin–Frankfurt for Monday 07:23. App applies BahnCard 50 automatically. User sees one screen: Sparpreis €32 (no flex) or Flexpreis €78 (refundable). Selects window seat. Pays. All done in under 90 seconds. Booking receipt mailed. Boards Monday.
BahnCard 50 shows up as a separate field the user has to manually select at step 3 (after route search, after fare class, before seat). User doesn't know it's there, or forgets, or assumes it was auto-applied from their account. Pays full price. Discovers at platform. Angry. Never books in-app again.
1. BahnCard not surfaced at search results — must be manually re-applied each session.
2. Seat reservation is a separate booking step with a separate mental model ("is my ticket valid without a seat?")
3. Fare class explanation is hidden behind an info icon nobody taps.
4. No total cost summary until final payment screen.
| Stage | User Action | App Performance | Emotion |
|---|---|---|---|
| Connection search | Types origin, destination, departure time. Filters by ICE. Sorts by price. | ✓ Excellent. Fast, accurate, multi-connection, real-time disruption info. | Happy. This part works. |
| Fare selection | Sees list of fare options. Sparpreis €49, Sparpreis Plus €69, Flexpreis €99. No explanation shown. | ✕ No explanation of what each fare includes. Info icon exists but isn't obvious. First-time users guess. | Confused. "Which one should I pick?" |
| BahnCard discount | Should see "BahnCard 50 applied — your price: €49 → €24.50" automatically. | ✕ BahnCard must be manually re-selected from a dropdown. Easy to miss if you don't know it's there. No "your BahnCard is saving you €X" confirmation. | Frustrated or unaware. Either discovers later or overpays. |
| Seat reservation | Wants a window seat. Finds seat reservation on a separate screen after fare selection. | ⚠ Seat map exists but loading is slow. Not clear if seat reservation is included in the fare price or extra. Feels like a second booking on top of the first. | Uncertain. "Did I already pay for this?" |
| Payment & summary | Sees final price for first time. Looks different from what they expected. | ✕ Total price only shown at final screen. No running total during booking. If BahnCard wasn't applied, full price shown — shock moment. | Anxious. "Wait, this isn't what I thought I was paying." |
| Ticket in-app | Gets PDF and in-app digital ticket. Has to navigate to "My Journeys" to find it. | ⚠ Digital ticket exists and is scannable. But finding it in the app hierarchy is non-obvious, especially for new users. | OK once they find it. First-time users confused. |
| Feature | DB Navigator | Trainline (DE) | Eurostar App | SNCF Connect |
|---|---|---|---|---|
| Loyalty card / discount auto-applied | ✗ Manual re-selection each session | ✓ Railcard auto-applied once account linked — confirmed on search results | ✓ Loyalty card applied at login — visible discount on every search result | ✓ Carte Avantage auto-applied — confirmed in search results ("Price after discount") |
| Fare class explanation at selection | ✗ Info icon only — no inline description | ✓ Inline description per fare: "No changes" / "1 change free" / "Fully flexible" | ✓ Fare includes/excludes list shown per option | ✓ Each fare class has a "what's included" summary visible without tapping |
| Seat reservation in same flow | ✗ Separate screen, feels like second purchase | ⚠ Offered inline but limited seat maps | ✓ Seat selection in main booking flow, same screen | ✓ Seat shown as part of fare in a unified screen |
| Running total visible during booking | ✗ Only at final payment screen | ✓ Price updates at each step | ✓ Price visible throughout checkout | ✓ Persistent price strip at bottom during booking |
| Saved travel preferences (class, seat) | ⚠ Partial — frequently used routes saved, not preferences | ✓ Saved seat preferences, class preference, railcard all auto-filled | ✓ Full traveller profile with defaults | ⚠ Basic profile — not full preference set |
| Connection search quality | ✓ Best in class for German rail — real-time disruptions, multi-operator | ⚠ Good but lacks real-time DB disruption depth | ⚠ Eurostar-only routes, limited regional rail | ✓ Excellent for French rail — equivalent depth |
Pattern: DB Navigator is behind every competitor on every booking flow feature — but ahead of all of them on connection search. The fix isn't a full redesign. It's taking 4 specific booking features that every competitor already has and backfilling them into Navigator's flow.
This is an information architecture problem, not a UX polish problem. The app is asking users to make three consecutive decisions that require expert knowledge (what is Sparpreis Plus? does my BahnCard apply here? is seat reservation free?), and then hiding that knowledge behind a tap. The result: users make the wrong decision or abandon.
When a BahnCard is linked to the user's account, apply it automatically at search. Show "BahnCard 50 applied — saving you €X" as a persistent label on every search result card. This is what Trainline and SNCF already do. The data is in the account. The fix is surfacing it at the right moment, not hiding it behind step 3 of the booking.
Today: select fare (screen 1) → select seat (screen 2, optional, confusing). Proposed: one booking screen showing fare options with seat reservation as an inline add-on per fare. If the user wants a specific seat, they tap it inline and the price updates live. No separate screen. No separate mental model of "is this another booking?" This is how Eurostar handles it.
Replace the info icon with two-line plain language descriptions per fare — always visible, not tap-to-reveal. "Sparpreis: Non-refundable. Seat not included (+€4.90). Cheapest option." "Flexpreis: Fully refundable up to 1 hour before. Seat included. Best for business." A user who understands what they're buying makes the right decision and doesn't abandon.
A small sticky footer during booking showing the running total: "€49.00 — Sparpreis, 1 adult, BahnCard 50 applied." Updates in real time as user adjusts fare class or adds seat. The final payment screen surprise is eliminated. This is standard on every major e-commerce checkout — train booking is not different.
Primary success metric. After all four changes, target a 15 percentage point increase in the % of users who start a booking flow and complete it. Measured as funnel completion: route search → payment confirmed. Baseline must be established before shipping any change.
% of bookings made by BahnCard holders where the discount was correctly applied. Today this is unknown to DB (no instrumentation). Target: 95% after P0 ship. Below 80% means the auto-apply logic has a bug (BahnCard not linked, expired card, etc.) and needs investigation.
Volume of customer service contacts citing BahnCard not applied / wrong price charged. This is a proxy for the real pain and a cost metric — each ticket costs DB ~€12 in service staff time. A 40% reduction in these tickets = direct cost saving that can be used to justify the engineering investment.
Target: business travellers complete a full booking (route → fare → seat → payment) in under 90 seconds. Today estimated at ~3.5 minutes for users who encounter the BahnCard or fare class confusion. Under 90 seconds matches the user's mental model of "quick" booking.
Engineering: apply BahnCard at search results, not at booking step 3. Add "BahnCard 50 applied — saving €X" label to search result cards. Add missing-BahnCard prompt for users who have a physical card but haven't linked it. Instrument BahnCard auto-apply rate from day 1.
Copy + UX change: replace info icon with always-visible two-line description per fare class. Requires sign-off from product, legal (fare conditions), and UX. Low engineering cost. A/B test description language to maximise conversion and reduce support contacts about "what does Sparpreis mean."
Major UX redesign of the core booking flow. Requires close collaboration with DB's backend team — seat reservation data needs to be loadable inline, not via a separate API call sequence. Design system changes. A/B test unified vs. existing flow. Primary KPI: booking completion rate change.
Persistent footer with running total during checkout. Saved travel preferences (Katja wants 2nd class, quiet zone, window seat — set once, apply every booking). Reduces repeat decision-making for frequent travellers. Ship after unified flow is stable.
The BahnCard fix is straightforward technically but has a dependency: the app needs to know the BahnCard is still valid. If a user's BahnCard has expired and the app auto-applies it, they'll board with a ticket that doesn't reflect their actual discount — which is a fare fraud scenario from the conductor's perspective. The auto-apply logic needs to check expiry and show a "your BahnCard expires in 14 days — renew to keep your discount" warning.
The unified booking screen change will face internal resistance. DB's booking flow was built with regional operator APIs in mind — some operators don't support seat reservation, some have different fare structures. Any PM working on this needs to either scope the redesign to ICE/IC routes only (where DB controls the booking flow end to end) or build fallback UX for routes where the unified flow isn't possible.
Scope the P1 launch to ICE routes only. Ship the quick wins first (BahnCard auto-apply + fare descriptions), establish the baseline metrics, then argue for the larger unified flow redesign with data.
Case Study by Yuvaraj Devadoss
← Back to portfolio