Laayo Blog

How we estimate when your food will arrive

A delivery time is a promise. Here is how Laayo turns kitchen history, rider GPS and road distance into an honest ETA that updates while your order is on its way.

“30 minutes” is the most important number in a delivery app. It is the first thing you look at on a restaurant card and the last thing you check before you put on your shoes to meet the rider at the gate. When it is wrong, everything else feels wrong too.

For a long time, the number you saw on Laayo was a string the restaurant typed into its settings once, usually something like “20-30 min”. It never changed. It did not know whether the kitchen had ten orders waiting, whether it was raining, or whether you lived around the corner or across town. When we finally measured it against real deliveries, the typed range and reality were far apart. The range was a hope, not an estimate.

So we replaced it, in two parts: an estimate before you order, and a live ETA after you do.

Before you order: a range per store#

The delivery time on a store card is now computed, not typed. It adds up three pieces:

  1. Preparation. How long this kitchen has really taken, measured from “accepted” to “picked up” on its recent orders. Using the time until pickup, rather than just cooking time, means the wait for the rider at the counter is already included.
  2. Getting a rider there. For every rider in the zone we work out when they could reach the store, given where they are and how much of their current work is left. A rider holding a bag that is two minutes from its door is closer to free than one who just accepted an order. We take the best rider.
  3. The ride to you. The road distance from the store to your address, turned into minutes.

The result is rounded to five minutes and shown as a range. It is cached for one minute per store and per small patch of the map, so the card, the store page, the cart and checkout all show the same number, and nobody’s phone pays for a fresh calculation on every scroll.

If something is missing, such as no rider online or a store without a map pin, the estimator steps aside and the restaurant’s own text comes back. A plain honest fallback is better than a confident wrong number.

A small model on top#

The formula gets the shape right. A small regression model, trained offline on our own past deliveries, corrects it. It looks at things the formula does not: time of day and day of week, lunch and dinner peaks, weekends, how busy the kitchen was when the order came in, whether it was raining, road distance, and how a given store tends to run compared to its own average. Running it costs a single dot product per store, so it can run on every request. We tried a gradient boosted tree model too. It was not better, so we kept the simple one.

After you order: a live ETA#

Once you place an order, the question changes from “how long does this store usually take?” to “how long is left on this order?”. The live ETA splits the order into stages: waiting to start, cooking, waiting for pickup, and the ride.

The four stages of an order and the signals that drive each one
The four stages of an order and the signals that drive each one

For each stage we keep a curve of how long that stage has taken in the past, per zone. The trick is that we ask a conditional question. If cooking usually takes 15 minutes, but this order has already been cooking for 12, the answer is not “3 minutes left”. Some kitchens are slow today. The curve tells us the typical remaining time given that the stage has already run this long, and that is what we show.

Cooking time is adjusted per store, per hour and per day of the week, because the same kitchen at 1 PM on a Saturday is a different kitchen from 4 PM on a Tuesday.

Trusting GPS over taps#

The ride is where live data helps most, and also where we learned the most humbling lessons.

Riders mark their progress by swiping in the rider app: arrived at the store, picked up, arrived at the customer, delivered. We assumed those swipes were accurate. They often are not, and for understandable reasons. The app only unlocked the “Delivered” swipe after “Arrived”, so many riders swiped “Arrived” while still standing at the restaurant, just to have it out of the way. Some marked “Picked up” at the customer’s door.

If we believed those swipes, your app would say “Rider has reached your location” while the rider was still waiting for your momo. So the live ETA now treats GPS as the truth and swipes as hints:

  • Arrival at your door counts when the rider’s location is actually close to it, not when the swipe happens.
  • “Picked up” is confirmed by the rider having really been near the store.
  • A swipe that would have needed a superhero ride speed to be true is ignored.
  • Location fixes that are too old, or obviously broken, are left out.

A promise, and a straight answer when we miss it#

When you place an order we save the time we quoted. If the live prediction later moves more than three minutes past that promise, the app says so plainly: “Delayed by 6 min”. An order that is badly stuck says “Taking longer than usual” instead of counting down a number nobody believes.

Learning every night#

Every night, the system looks back at finished deliveries and refreshes its curves and its ride model. It learns on the older part of the history and tests itself on the most recent part it has not seen, so we always know how good the estimate really is instead of how good it looks on data it memorised.

Two details make that learning honest. The arrival time it learns from comes from GPS, not from the “Delivered” swipe, which is often minutes late. And road distance is used as road distance. An early version multiplied it again as if it were a straight line, which quietly padded longer rides.

Today, at the moment you place an order, our median error is around ten minutes, much of it the kitchen’s to own. Once the rider has your food, the median error drops to a few minutes, and most orders land within ten minutes of the estimate.

Smooth on the map, too#

An ETA that is right but a rider icon that jumps around still feels wrong. In our upcoming app update, the rider marker on the tracking map glides between location updates instead of hopping. The glide speed adapts to how often updates are arriving, so the marker is always moving. It follows the road line when it is close to the route, and the route line shrinks behind it as the rider gets closer.

What we are working on#

The biggest source of error left is not the ride. It is the time food waits at the counter for a rider. That is a supply problem as much as a prediction problem, and it is where most of our effort is going next. A better estimate tells you the truth. A shorter wait changes it.

ETAMachine learningMapsRiders

Laayo Engineering

Backend, apps and infrastructure

The team that keeps orders, riders, payments and the apps running across Birtamod and Damak.