Home/ Blog/ Buffer time: the invisible KPI killing your orders
Engineering 2026-04-25 · Sergei Filatov

Buffer time: the invisible KPI killing your orders

The time between "order ready" and "courier picks it up" is the KPI nobody monitors — and the one that hits quality the hardest. Here is how we instrumented it for Dodo Pizza with Spark Streaming + Delta Lake, and the 4 mistakes we made before doing it right.

SF
Sergei Filatov Founder · ex-Dodo Brands · 15 years
14 min read

The KPI nobody sees

When we start auditing a new client's delivery operation, we always ask the same question: "how long does it take from when the kitchen marks an order as ready to when the courier picks it up?". The answer, in 90% of cases, is "we don't know". Sometimes we hear "less than 2 minutes, normally" — which is the elegant way of saying the same thing.

We call that interval buffer time. And it is the silent killer of food quality and customer experience. While the order sits in the buffer, pizza loses temperature, sauce loses texture, fries lose everything that makes them worth being fries.

i
Operational definition

Buffer time = "courier picked up" timestamp − "order ready" timestamp. Measured per order, aggregated by store / hour / day.

Why it matters

There is a brutally clear correlation between buffer time and customer NPS. We analyzed ~3.2M Dodo Pizza orders over 18 months and found:

  • Buffer < 60s → average NPS +72
  • Buffer 60–180s → average NPS +58
  • Buffer 180–300s → average NPS +34
  • Buffer > 300s → average NPS −12 (annoyed customer)

The 4 mistakes we made

Before we had something decent, we failed four times. Worth documenting so you don't repeat them.

1. Trusting the POS timestamp

Our first instinct was to use order.completed_at from the POS as the "ready" event. Bad idea. In half the stores that field gets filled when the cashier rings up, not when the kitchen finished. The gap can be 90s. Your KPI inherits that bias.

!
Lesson learned

Polling is the way you don't hear about things that matter. If your system supports webhooks or events, use them. If not, instrument it yourself.

python · pyspark
from pyspark.sql import functions as F
from delta.tables import DeltaTable

events = (spark.readStream
    .format("kafka")
    .option("subscribe", "kitchen.events")
    .load()
    .select(F.from_json("value", schema).alias("e"))
    .select("e.*"))

buffer = (events
    .groupBy("order_id", F.window("event_ts", "15 minutes"))
    .agg(
        F.min(F.when(F.col("type") == "ready", F.col("event_ts"))).alias("ready_at"),
        F.min(F.when(F.col("type") == "pickup", F.col("event_ts"))).alias("pickup_at"))
    .withColumn("buffer_seconds",
        F.unix_timestamp("pickup_at") - F.unix_timestamp("ready_at")))
The most surprising thing was not the NPS impact. It was that we found 3 stores where buffer was consistently 6 minutes — same store manager, bad courier scheduling.— Operations Manager, Dodo Pizza Mexico

Results after 6 months

  • Median buffer: from 187s to 84s (−55%)
  • % of orders with buffer > 5min: from 11.2% to 1.4%
  • Average NPS: +18 points in stores with worst initial buffer
  • "Cold food" complaints: −63%
Free 30-min audit →