intermediate
ai-ops
unmet-demand
analytics

Understanding Unmet Demand

What an unmet-demand event is, how Levy AI Ops captures it from rider app sessions, and how to use the unmet-demand heatmap.

Levy Fleets TeamMay 18, 20265 min read

Understanding Unmet Demand

Unmet demand is one of the silent revenue leaks in shared mobility: a rider opens the app, looks for a vehicle, and there isn't one nearby. They close the app and don't take a ride. You never see the missed transaction in your rides table because the ride never happened — but the demand was real, and AI Ops now captures it.

What counts as an unmet-demand event

Every time a rider opens the Levy mobile app and the in-zone vehicle list returns zero rideable vehicles within 500 meters of their search location, AI Ops records an event in the unmet_demand_events table. The event includes:

FieldDescription
h3_indexThe H3 hex the search happened in
occurred_atTimestamp of the search
available_vehicles_500mCount of vehicles within 500m (always 0 for unmet events)
search_lat / search_lngWhere the rider was searching
customer_uuidThe rider, when authenticated

The instrumentation lives in POST /api/mobile/app-session-search — the rider mobile app calls it on every map-open and vehicle-list query.

Why we capture it

Two reasons:

  1. Quantify lost revenue. If you know a hex has 30 unmet-demand events per day and your average fare is $4, that's about $120 of potential daily revenue from that hex alone. The rebalance recommender uses this to dollarize its suggestions.
  2. Correct the forecast for censoring. Historical rides are a censored signal of demand — you only see the rides that happened, not the ones that would have happened if a vehicle had been there. The forecast model uses unmet-demand events to reconstruct true demand, so it doesn't underestimate hexes that have been chronically under-supplied.

The unmet-demand heatmap layer

On Dashboard > Analytics > Heat Maps, toggle the Unmet demand layer. Hexes are colored by the count of unmet-demand events in the visible window (default: last 24 hours).

Bright red hexes are where you're leaking the most revenue. They're the highest-priority destinations for the rebalance recommender — moving vehicles there has the highest projected lift.

Click any hex to see:

  • Count of unmet events in the window
  • Time-of-day distribution (when riders are searching)
  • Forecast for the next 4 hours (predicted demand on the same hex)

Comparing unmet demand to forecast

Unmet demand is observed history. Forecast is prediction. They're complementary:

  • High unmet, high forecast — chronic under-supply. The recommender will surface this first.
  • High unmet, low forecast — short-lived surge (e.g. a one-time event). The recommender treats this with caution because the forecast horizon doesn't predict it.
  • Low unmet, high forecast — you've been keeping up. Forecast says you'll need to keep doing so.
  • Low unmet, low forecast — quiet hex, leave it alone.

Retention

Unmet-demand events are stored in a TimescaleDB hypertable with a 30-day retention policy. Older rows are dropped automatically. Aggregates roll up into the forecast feature pipeline before they age out, so the model retains the signal even after individual events are deleted.

Privacy

Search locations (search_lat / search_lng) are personal data. They are covered by the existing rider Terms of Service and are stored only for the 30-day retention window. They are never included in MDS feeds or any third-party export.