•CASE STUDY

Surge (Dynamic) Pricing for Ride-Hailing

4 min read·757 words·Advanced

Asked at

1 candidate report in Dec 2025

How to use this case study

SDE-2 / Mid

  • Explain splitting a city into zones
  • Measuring demand (ride requests) and supply (available drivers) per zone
  • Setting a price multiplier when demand is higher

SDE-3 / Senior

  • Go deeper on the streaming pipeline
  • Smoothing to avoid oscillation
  • Caps
  • Serving multipliers at quote time
  • Locking the quoted price

Staff / Principal

  • Discuss marketplace goals (reliability vs rider cost vs driver earnings)
  • Experiments
  • Forecasting
  • Fairness and regulatory constraints

Problem RestatementProblem

OpenAI asked: you operate a ride-hailing platform. Design a system that sets surge multipliers (e.g., 1.5x) for each region in near real time. The pricing strategy must balance rider experience (not too expensive, rides available), driver supply (higher prices attract drivers to busy areas), and marketplace efficiency (most requests get matched quickly).

Why Surge Exists (simply)

When many people request rides in one area and few drivers are there, wait times explode. A higher price (1) reduces some demand (people wait or walk) and (2) attracts drivers to that area. The goal is to keep waiting times reasonable, not to maximize price.

ArchitectureArchitecture

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
    RQ["Ride requests / app opens"] --> K[("Kafka - demand events")]
    DL["Driver locations + status"] --> K2[("Kafka - supply events")]
    K --> AGG["Stream aggregation per H3 cell, per minute"]
    K2 --> AGG
    AGG --> CALC["Surge calculator - every 1-2 min"]
    FC["Short-term demand forecast"] --> CALC
    CALC --> SM[("Surge map - cell to multiplier, version")]
    SM --> QUOTE["Pricing / quote service"]
    QUOTE --> APP["Rider app - price shown, locked for N min"]
    SM --> DRV["Driver app - heat map"]

The Calculation

  1. Zones: split the city into hexagonal cells (e.g., Uber's H3 at a neighborhood size), and group small cells to avoid noisy tiny areas.
  2. Measure per cell, per minute:
  • Demand: ride requests plus app opens (people checking prices), including recently unfulfilled requests.
  • Supply: available drivers in or near the cell (plus drivers about to finish trips nearby), and estimated pickup times.
3. Imbalance score: e.g., ratio = demand / effective_supply, or better, the predicted ETA / probability a request goes unfulfilled.

  1. Multiplier: map the imbalance to a multiplier through a curve, e.g., 1.0 when balanced, rising gradually, and capped (e.g., max 3x, lower during emergencies by policy or law).
  2. Smoothing: combine with the previous value (e.g., exponential smoothing), and limit how fast it can change, so prices don't jump up and down every minute (oscillation). Spatially smooth with neighboring cells to avoid sharp price borders.
  3. Forecasting: add expected demand spikes (a concert ending, rain starting) to act slightly early.

Deep Dive — Showing a surge price a rider will acceptDeep dive

The multiplier moves with supply and demand. The rider needs a number they can trust before they commit.

Weak

Price at the moment of charging

Compute the multiplier when the trip is confirmed.

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
  Q["Rider sees estimate: $18"] --> WAIT["They think about it for 40 s"]
  WAIT --> CONF["Confirm"]
  CONF --> RECALC["Multiplier recomputed - demand rose"]
  RECALC --> CHARGE["Charged $26"]
  CHARGE --> ANGRY["Different from the number they agreed to"]

The rider is charged a price they never saw. It also creates a perverse incentive to hesitate or retry, and it is the kind of thing regulators and journalists write about.

Good

Show the multiplier and refresh it

Display the current multiplier, recomputing as the rider looks at the screen.

Honest, and unusable: the price changes while they are deciding. Riders re-open the app hoping for a lower number, which adds load and produces no commitment — the estimate is information rather than an offer.

Best

Lock a quote for a few minutes

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
  MAP[("Surge map: cell -> multiplier, version, timestamp")] --> QS["Quote service - reads in milliseconds"]
  QS --> QUOTE["Quote: price + quote_id, locked for a few minutes"]
  QUOTE --> RIDER["Rider sees exactly what they will pay"]
  RIDER --> BOOK["Books with the quote_id - honoured even if surge rose"]
  QUOTE --> EXP["Expires - a fresh quote is issued"]
  MAP --> DRV["Drivers see a heat map - where to reposition"]
  GUARD["Caps, emergency freeze, no per-rider personalisation"] --> QS
  • A quote is an offer, not an estimate. It carries an id and an expiry, and it is honoured for its lifetime — so the rider commits to a number rather than to a formula.
  • Reading the surge map is a lookup, because it is precomputed per cell and replicated. Quoting must be fast and must not depend on recomputing demand.
  • Drivers get the map too, which is the mechanism by which surge is supposed to work: the multiplier exists to move supply, and it only does that if drivers can see where.

The guardrails are part of the design, not an afterthought: caps on the multiplier, an emergency freeze for disasters and severe weather, and no personalisation per rider — the multiplier depends on the place and time, never on who is asking. That last one is what keeps the mechanism defensible, and it is worth stating unprompted.

Evaluate the whole thing with experiments on completion rate and wait time, not on revenue per trip. Surge that raises revenue while riders give up is a failure the obvious metric will call a success.

Measuring Success (experiments)

  • Metrics: request completion rate, pickup ETA, rider conversion (people who accept the price), driver earnings, and cancellations.
  • A/B test curve shapes and smoothing parameters, by city or with switchback experiments (alternating time windows), since the marketplace effects spill across users.

Wrap-UpWrap-up

Split cities into H3 cells, stream demand (requests, app opens) and supply (available and soon-available drivers) into per-cell, per-minute aggregates, and every minute or two compute a multiplier from the imbalance (or predicted ETA) through a capped curve, smoothed over time and space and nudged by short-term forecasts. Publish a versioned surge map read by the quote service, lock quoted prices for a few minutes, show drivers the heat map, enforce caps and fairness rules, and tune it all through marketplace experiments.

More Case Studies

Frequently Asked Questions

What is the Surge (Dynamic) Pricing for Ride-Hailing system design question?

Surge (Dynamic) Pricing for Ride-Hailing is a system design interview question asked at FAANG companies. It covers real-time, geospatial, algorithms, data pipelines and tests your ability to design scalable, production-ready systems. InterviewSkool's breakdown walks you through requirements, API design, architecture, and trade-offs.

Which companies ask the Surge (Dynamic) Pricing for Ride-Hailing question?

OpenAI have reportedly asked variations of this question in system design interviews. The exact wording may differ, but the core design challenges remain the same.

How should I prepare for the Surge (Dynamic) Pricing for Ride-Hailing interview question?

Start with the problem statement and scale estimates, then design the high-level architecture. Focus on the core components, data model, and API design. InterviewSkool's breakdown covers the full solution with mermaid diagrams and trade-off analysis to help you prep efficiently.

What level is the Surge (Dynamic) Pricing for Ride-Hailing question?

This question is suitable for SDE-2, SDE-3, and Staff engineer interviews. The level guidance on this page provides specific tips for each level — SDE-2 candidates should focus on core architecture, while Staff engineers should discuss trade-offs, monitoring, and incremental rollouts.

Practice with a Mock Interview

Apply what you learned in a live system design mock interview with InterviewSkool's AI interviewer.

Start System Design Interview →