Designing a Food Delivery ETA Estimation System
A complete, ground-up walkthrough of how DoorDash, Uber Eats, Swiggy, Zomato and Deliveroo predict — in real time, for millions of orders a day — exactly when your food will arrive. From the first tap on “Checkout” to the courier ringing your doorbell.
The Big Idea, in One Breath
A food delivery ETA estimation system is the invisible service that answers a single, high-stakes question for every food order on the planet: “How many minutes until this specific meal is at this specific door?” It must answer that question in a few tens of milliseconds, update it as reality unfolds, and be within a couple of minutes of the truth — every single time.
Under the hood, it is not one prediction. It is a chain of predictions — how long the merchant takes to prep, how long a courier takes to arrive, how long the pickup takes, how long the drive takes, and how long the last hundred metres take — all stitched together and continuously re-estimated as the order progresses.
Think of an airline flight tracker. Before the flight even boards, the airline has to promise you an arrival time. Then, as the aircraft taxis, climbs, cruises, hits headwinds, is rerouted around weather, descends, waits for a gate — the promised arrival keeps updating. A food delivery ETA is exactly this, except the “aircraft” is a scooter, the “weather” is city traffic, and the passenger paying attention to the ETA is you, sitting hungry on your couch.
per ETA request
error target
per order lifecycle
What ETA Estimation Really Is
Before designing one, we need to pin down exactly what the system does — and what it does not. “Predicting a delivery time” sounds simple, but a modern ETA service is a stack of forecasts, constraints and business rules.
2.1 A Working Definition
A food delivery ETA estimation system is a real-time service that, given the current state of an order (merchant, items, courier, geography, weather, marketplace conditions), returns:
- a point estimate in minutes for when the customer will receive the order,
- a confidence range (e.g.
22–27 min) that reflects real uncertainty, - a break-down across the phases: prep, courier travel to store, wait at store, drive to customer, hand-off, and
- a versioned decision so we can audit which model produced which number for which order.
2.2 Where You Encounter It
Pre-Order ETA
The number shown before you tap “Place Order.” It powers your buying decision — and, indirectly, whether the platform earns your revenue at all.
Post-Order Countdown
The updating clock inside the order-tracking screen. Refreshes as the order moves through prep, pickup and delivery.
Assignment Decisions
The internal ETA fed to the courier dispatcher to decide who should pick up which order and in what sequence.
Operational Guardrails
The ETA feeds into SLA monitoring, refund automation and merchant health dashboards — a bad ETA is not just a UX bug, it is a P&L bug.
2.3 What It Is Not
An ETA system is not a routing engine, a dispatch optimiser, or a mapping service — even though it depends on all three. It is a prediction layer that consumes their outputs, blends historical experience with live signals, and emits a number a human can act on.
The router tells you the shortest path. The dispatcher tells you the right courier. The ETA system tells you, honestly, how long it will actually take — accounting for the fact that the courier will hit two red lights, the restaurant is running late, and the apartment building has three lifts and no lobby.
Why It Matters So Much
On a food delivery platform, the ETA is the single number the customer looks at more than any other. It shapes willingness to order, tolerance for delay, and the emotional experience of the entire wait. Getting it right is not a nicety — it is a foundational unit of platform trust.
3.1 The Business & Human Problem
- Conversion at checkout falls off a cliff once the ETA crosses ~40 minutes; even a two-minute improvement is worth measurable revenue.
- Contact rate to customer support spikes for orders that arrive later than promised — each contact costs money and lowers CSAT.
- Refund and credit exposure is directly proportional to the number of orders that miss their promised time by a certain margin.
- Courier utilisation depends on accurate ETAs: too optimistic and couriers stack up outside restaurants, too pessimistic and the fleet is over-supplied.
- Merchant fairness hinges on the ETA correctly attributing delays — a slow ETA that is really the courier’s fault must not damage the restaurant’s ratings.
3.2 What Makes It Uniquely Hard
Harder than ride-hailing ETA
- Two independent parties (restaurant + courier) both introduce variance.
- Prep time depends on menu items, batch size, and kitchen queue — not just distance.
- The final drop-off can hide inside a mall, campus or apartment complex.
Harder than logistics ETA
- The prediction must be produced in tens of milliseconds, not overnight.
- It must update continuously without whipsawing the number on the customer’s screen.
- Marketplace supply/demand shifts by the minute — last week’s model is already stale.
Every minute of ETA error costs the platform money, courier time and customer trust. Under-promise and you lose the order at checkout. Over-promise and you lose the customer forever. The ETA system exists to walk that razor-thin line — billions of times a year — without stepping off either side.
The Building Blocks
A production ETA system is roughly a dozen components co-operating. Each has one narrow job. Understanding them separately is the first step to designing the whole thing.
ETA Gateway
Thin HTTP/gRPC service that receives ETA requests from checkout, tracking, dispatch and merchant tooling. Enforces auth, rate limits and shape.
Feature Fetchers
Fan-out clients that gather live signals — merchant queue, courier location, traffic tile, weather — in parallel, with tight budgets and fallbacks.
Feature Store
Low-latency KV (Redis / DynamoDB / feature store) for pre-computed aggregates: merchant historical prep, zone travel speeds, courier reliability.
Routing / Map Service
Provides road-network travel-time estimates between two points at the current minute of day, honouring one-ways, restrictions and live traffic.
Merchant Prep Model
Predicts kitchen preparation time from item mix, batch size, current queue depth, day-of-week and merchant health.
Courier Travel Model
Predicts courier travel time to the store and from the store to the customer, given mode of transport (bike, moped, car) and city context.
Handoff / Last-Metre Model
Estimates the wait at the store to receive the food and the time from courier arrival to actual doorbell — often the noisiest phase.
ETA Fuser
Blends phase predictions into a single point estimate + confidence interval, applies business guardrails, and stitches display vs. internal ETA.
Event Stream
Kafka / Pub/Sub topic of order lifecycle events (placed, accepted, prepping, ready, picked-up, delivered). Drives ETA recompute.
Feedback & Retraining
Actual delivery times are labelled and looped back into training pipelines. Powers weekly / daily model refresh.
Policy Layer
Business rules on top of raw model output: minimum quote, buffer minutes, launch-city overrides, merchant-specific caps.
Observability
Metrics (MAE, bias, quantile error), traces per request, and dashboards per city / cohort so ops can spot regressions before customers do.
Signals & Feature Engineering
The quality of an ETA is bound by the quality of its signals. Weak features guarantee a weak model, no matter how sophisticated the architecture. This chapter catalogues the signals that actually move the needle.
5.1 The Four Signal Families
Order Signals
Item count, cuisine, total price, prep-heavy flags (pizza, sushi), catering size, contains-alcohol, allergy notes.
Merchant Signals
Rolling average prep time, current queue depth, ticket-machine backlog, staff-on-shift signal, historical variance by hour.
Courier & Fleet Signals
Nearest courier distance, transport mode, active-order count, on-time rate, position accuracy, current heading.
Environment & Context Signals
Live traffic tile, rain/snow, city event, day-part, holiday flag, zone-level supply/demand, address complexity (apartment, gated).
5.2 A Minimal Feature Vector
{
"order_id" : "o_44e1",
"items_count" : 6,
"prep_heavy" : true,
"menu_tags" : ["pizza", "salad"],
"merchant_id" : "m_512",
"merchant_prep_p50_5m": 11.2,
"merchant_queue" : 4,
"courier_transport" : "moped",
"courier_to_store_km": 1.4,
"courier_active_orders": 1,
"store_to_cust_km" : 3.2,
"traffic_index_zone" : 0.68,
"weather_rain_mm_1h" : 3.1,
"address_type" : "apartment_gated",
"day_part" : "friday_dinner"
}5.3 Live vs Pre-Computed Features
Some features must be freshly measured on every request (courier distance, current queue). Others can be pre-computed hourly and cached (merchant p50 prep by day-part, zone travel-speed matrix). A hybrid design — hot signals from Redis / streaming feature store, cold aggregates from batch — is what makes sub-50 ms serving possible.
Two rules of thumb: never let a single feature fetch exceed 15 ms at P99, and always have a fallback value that is monotonically safe (e.g. if merchant queue is unavailable, use their rolling p90 — not their p50). Silent zeros are how good ETA systems get quietly worse.
Modelling Patterns: Rules, ML, and Hybrid
Once the features exist, the interesting question is what turns them into minutes. There is no single “ETA model.” Every mature system uses a layered mix of heuristics, per-phase regressors and marketplace overrides.
6.1 Heuristics & Baselines
Every stack starts with a rule-based baseline: ETA = merchant.avg_prep + haversine(store, customer) / avg_speed + buffer. It is bad at extremes but great as a floor and as a fallback when models are unhealthy.
6.2 Per-Phase ML Regressors
| Phase | Typical model | Target |
|---|---|---|
| Prep time | Gradient-boosted trees (LightGBM / XGBoost) | Minutes from order-accept to food-ready |
| Courier to store | Boosted trees + map ETA feature | Minutes courier drives to pickup |
| Store wait | Quantile regression | Minutes at store before pickup complete |
| Store to customer | Boosted trees + graph neural net (large scale) | Minutes to drop-off |
| Last-metre / handoff | Small neural net + address embedding | Courier arrival → customer receives |
6.3 End-to-End Models
Some platforms train a single deep model that outputs the whole ETA (often a transformer or graph neural network over city road networks). They win on accuracy in the average case but are harder to explain, debug and roll back. Most stacks use per-phase models plus an end-to-end “critic” that catches obvious mistakes.
6.4 Quantile Regression & Uncertainty
The customer does not just want a number, they want a reliable number. Quantile regression produces P50 (median), P90 (safe promise) and P10 (best case) at once. The displayed ETA is often a policy blend such as ETA_display = clamp(P70, floor=P50+1, ceil=P95).
features = fetch_features(order)
// 1. baseline heuristic (always available)
base = heuristic_eta(features)
// 2. per-phase predictions
prep = prep_model.predict(features)
to_stor = travel_model.predict(features, leg="courier_to_store")
wait = handoff_model.predict(features, phase="store_wait")
to_cust = travel_model.predict(features, leg="store_to_customer")
last_m = handoff_model.predict(features, phase="dropoff")
// 3. blend + guardrails
eta = fuser.combine([prep, to_stor, wait, to_cust, last_m])
eta = policy.apply(eta, city=features.city, tier=features.tier)
// 4. safety net
if abs(eta - base) > base * 0.5:
eta = policy.reconcile(eta, base, reason="model_out_of_bounds")
return eta_with_interval(eta)Rules encode the promises you must never break. Per-phase models encode what you have learned from millions of orders. End-to-end models catch the patterns humans cannot articulate. Fuse them with clear precedence — and never let a fancy model quietly overrule a hard business floor.
Streaming vs Batch, Monolith vs Distributed
Two architectural axes must be picked early: how often the ETA is recomputed, and how the compute is spread. Both decisions have long, expensive tails.
7.1 When Does the ETA Recompute?
- Request-driven — whenever any client (checkout, tracking, dispatcher) asks. Guarantees freshness but hits the model hard.
- Event-driven — when order lifecycle events fire (accepted, ready, picked-up). Push the ETA to clients over websocket / SSE.
- Time-driven — every N seconds while an order is in flight, to keep the tracking screen accurate.
Serious systems use all three: request-driven for checkout, event-driven for major state changes, and time-driven for the tracking countdown.
7.2 Streaming, Micro-Batch or Batch?
Streaming (event-at-a-time)
- Best UX — the ETA updates within a second of reality changing.
- Needed for live courier GPS, live merchant queue, live traffic.
- Higher engineering cost: stateful processing, back-pressure, exactly-once.
Micro-batch / Batch
- Great for computing historical aggregates and per-cohort features.
- Powers nightly retraining and long-term calibration jobs.
- Never good enough for the live prediction path itself.
7.3 Deployment Shape
| Shape | When it fits | Trade-offs |
|---|---|---|
| Single monolith service | Small city, single model, first launch | Fast to build; won’t scale to global marketplace |
| Per-model microservices | Per-phase model teams, different SLOs | Clean ownership; more RPC hops in the hot path |
| Model server + orchestrator (Triton / TorchServe) | Large ML footprint, GPU inference | Great throughput; needs careful traffic shaping |
| Regional shards | Global scale; city-specific models | Data locality wins; adds routing complexity |
7.4 Sharding Strategy
City is the natural unit of scale — road network, merchant mix and fleet mode differ per city. A common pattern is region → city → zone sharding for models and feature stores, with a global façade for cross-region traffic. Order state itself is partitioned by orderId in the event stream.
Friday 7 PM in a top-10 city can be 30× an average minute. Auto-scale on request queue depth per city, not on global CPU, and pre-warm inference workers before predictable peaks.
End-to-End Flow: One Order’s Life
Let us follow one real order — a Friday night pizza — from the checkout screen to the doorbell, and watch how the ETA is produced, updated and (hopefully) honoured along the way.
Checkout ETA
Customer opens the app. Gateway receives an ETA request with cart, merchant, address. Features fetched in parallel (~35 ms). Prep, travel and handoff models fire. Fuser returns ETA=32±3 min. Displayed as “30–35 min”.
Order Placed
An order.placed event lands on Kafka. Dispatcher pulls the ETA and starts scoring candidate couriers with their own internal ETA numbers.
Merchant Accepted
order.accepted fires. Prep model recomputes with the exact accept timestamp and the current kitchen queue. ETA updates to 31 min; pushed to the customer’s tracking screen.
Courier Assigned
courier.assigned event includes the courier’s current GPS. Travel model recomputes both legs. Store-wait model updates. Fused ETA drops slightly to 29 min.
Courier at Store
courier.arrived_store. The system now knows the wait is starting. If the merchant is not ready, ETA nudges up minute-by-minute using live queue features.
Picked Up
courier.picked_up. Remaining ETA = travel_to_customer + handoff. Live GPS ticks recompute the leg every 15 seconds; changes < 30 s are smoothed to avoid flicker.
Approaching / Handoff
Geofence around the drop-off triggers a “courier arriving” UI. Last-metre model estimates 90 seconds for the apartment lobby. Delivered event closes the loop.
Labelling & Learning
Actual delivered time is compared against every ETA emitted during the lifecycle. Per-phase errors flow into the training dataset for tomorrow.
Quality Attributes: The “-ilities”
The non-functional targets for an ETA system have their own personality. Accuracy matters, but so does calibrated bias, smoothness of updates, and honest handling of uncertainty.
Latency
< 50 ms P95 for checkout; < 100 ms P95 for tracking updates. Non-negotiable, because it blocks page render.
Throughput
Sized for peak dinner-time load per city; global QPS in the hundreds of thousands.
Accuracy (MAE / P90)
Median absolute error < 2 min in mature cities; P90 error < 6 min. Both matter more than mean.
Calibrated Bias
Aggregate over-/under-promise per cohort must sit tightly around zero. Chronic under-promising loses conversions; chronic over-promising loses trust.
Smoothness
ETA should never jump by > 5 min in one update or oscillate between two values — even if the raw model would.
Reliability
Graceful degradation is a first-class feature: if any sub-model is down, fall back to heuristic + last-known interval.
Scalability
City-sharded; each city’s models scale independently. Model server pooled by warm workers.
Explainability
Every ETA carries a breakdown (prep / travel / handoff), model version, and feature snapshot for post-hoc audit and support.
9.1 The Latency Budget
| Hop | Target | How |
|---|---|---|
| Gateway parse + auth | < 3 ms | Warmed workers, cached JWKS |
| Feature fan-out | < 20 ms | Parallel calls, deadlines, safe fallbacks |
| Phase model inference | < 15 ms | Boosted-tree models in-process; big models on warm servers |
| Fuser + policy | < 3 ms | Vectorised in-memory blend |
| Serialise + return | < 3 ms | Protobuf / MsgPack, HTTP/2 keep-alive |
| Total end-to-end | ~40–50 ms P95 | Well under checkout render budget |
Common Pitfalls & Trade-offs
Every food delivery platform, sooner or later, ships the same handful of ETA bugs. Knowing them turns a full quarter of firefighting into a paragraph in a design review.
10.1 Ten Traps We’ve All Fallen Into
Bias without noticing
Model trained on delivered orders only inherits selection bias — the slow ones are cancelled and never labelled. Sample cancelled orders explicitly.
Point estimate with no interval
Serving a single number hides real variance. Always emit at least P50 and P90 — the UI can decide how much to expose.
Feature staleness
Cached zone-speed is 40 minutes old, current rain is not applied. Add TTL and health checks on every feature; degrade loudly.
Wild swings in tracking ETA
Raw model updates whipsaw the customer’s screen. Apply a smoothing filter (EWMA / hysteresis) before display.
Ignoring the last metre
Getting from “courier at building” to “food in hands” is often the biggest single variance. Model it, don’t constant-pad it.
Silent map service failures
If the map ETA falls back to Haversine, the platform stops honouring one-ways and traffic overnight. Fail loud, not quiet.
Training/serving skew
Feature transformations differ between offline notebook and online service. Use one shared feature library on both paths.
City-agnostic model
A single global model averages away city character. Train per city or add strong city / zone embeddings.
ETA divorced from dispatch
The customer sees 25 min, dispatch believes 40 min. Same source of truth — internal and display ETA come from the same fuser.
No shadow mode for new models
Ship v2, wreck a whole city’s conversion for an afternoon. Every new model runs in shadow with online metrics for at least a week.
10.2 The Trade-offs You Cannot Avoid
Accuracy vs Smoothness
- Raw model = most accurate but jittery.
- Smoothed model = calmer UX, small MAE cost.
- Almost every platform picks smoothness on the display path, accuracy on the internal path.
Optimism vs Trust
- Optimistic ETAs boost checkout conversion.
- Broken promises hurt retention worse than a slower quote.
- Optimise the P70 quote, not the P50 — small buffer, big trust gain.
Context
We must decide how internal (dispatch) ETA and external (customer) ETA relate to each other.
Decision
Both are produced by the same fuser in the same request; the internal ETA is the raw fuser output, the display ETA is a policy-transformed version (quantile choice + smoothing + minimum floor). Both are versioned and logged.
Consequences
Consistent operational metrics between dispatch and CX; no divergence bugs; policy changes to display ETA never accidentally leak into dispatch logic and vice versa.
How ETA Systems Evolve
Food delivery ETAs have been on a decade-long journey from “guess and hope” to “calibrated marketplace forecast.” Understanding the waves helps you place your own platform.
Wave 1 — Fixed Windows (pre-2013)
“30–60 minutes” painted on every order. Cheap, uninformative, no differentiation.
Wave 2 — Heuristics with Maps (2013–2016)
Distance-based travel time + fixed prep constant per merchant. First real per-order ETA.
Wave 3 — ML Per Phase (2016–2019)
Gradient-boosted models for prep and travel legs, live GPS, quantile output. Modern era begins.
Wave 4 — Marketplace-Aware (2019–2023)
ETAs conditioned on live supply/demand; dispatch and ETA co-designed; graph neural nets on road networks.
Wave 5 — Foundation Models & LLMs (2024+)
Pretrained spatio-temporal foundation models, LLM-assisted explanation of ETA to support agents, cross-market transfer learning.
11.1 Adjacent Systems That Plug In
Courier Dispatcher
Consumes internal ETAs to score assignments and batching decisions.
Dynamic Pricing
Uses ETA and marketplace conditions to set delivery fees and surge.
CX Automation
Auto-refunds and proactive apologies triggered when actual delivery exceeds promised ETA by policy thresholds.
Merchant Health
Persistent prep delays surface in merchant dashboards for coaching and enforcement.
Key Takeaways
An ETA system is one of those quiet pieces of infrastructure whose quality shapes the entire product. Nobody says “wow, what a great ETA” — but everyone feels a broken one, immediately.
Key Takeaways
- ETA is a chain of predictions — prep, travel, wait, hand-off — fused with policy, not a single number pulled from a model.
- Signals beat models. Rich, fresh, well-fallbacked features outperform a fancier model every time.
- Ship a heuristic baseline first. It is your floor, your fallback, and your reference for every subsequent improvement.
- Emit intervals, not just a point. Serving P50, P70 and P90 lets the product tune trust vs. conversion in the UI.
- Optimise the whole quantile, not just MAE. Calibrated bias per cohort is more important than best average error.
- Smooth the display path. Never let a customer’s tracking ETA whipsaw — smoothing is worth the small accuracy cost.
- City is the natural shard. Model, feature store and inference pool per city; regional façade above.
- Degrade gracefully. Any sub-model or feature down ⇒ fall back to a safer heuristic and flag the response.
- Same source of truth for dispatch and display. One fuser, one lineage, policy transforms on top.
- Close the feedback loop. Actual delivered times, cancellations included, feed tomorrow’s model — and yesterday’s post-mortem.
A great ETA feels like a promise a friend made. It is roughly right, it is honest about what it does not know, and it updates you before you have to ask. Every design choice — signals, models, policy, smoothing, sharding — is in service of that quiet, human trust.