A delivery marketplace where the two moments that matter — choosing a restaurant and watching an order arrive — both happen on a phone, often on a poor connection.
Marketplace · Real-time
Deliveroo
Restaurant delivery with live rider tracking, across the UK and Europe.
- Product
- Deliveroo — restaurant delivery across the UK and Europe
- Role
- Frontend engineer, contract
- Scope
- Next.js storefront, GraphQL data layer, real-time order tracking

The tension
Tracking is only worth showing if it is current, and search is only worth having if it answers first.
Peak demand is concentrated into a narrow window each evening. A search path that is fine at noon is the whole product at seven o'clock.
Restaurant search answering fast enough at peak that nobody reaches for a competitor, and a tracking view that updates without being asked.
Menu availability changes with kitchen capacity, so a listing that is accurate on load can be wrong by checkout.
Platform-wide, across every served market.
The product story
One field stands between arrival and a menu.
The gate
Everything depends on one postcode.
The landing view asks for a postcode and nothing else, because until it is known there is no catalogue to show — availability is entirely a function of where the visitor is.

Narrow first
Ordered from a phone, on the move.
The postcode field, the cuisine rail and the tracking prompt all reflow to one column, keeping the entry point reachable without scrolling back up.

Four audiences
The same platform, from four sides.
Below the storefront the page addresses restaurants, riders, workplaces and gift buyers in turn — each a separate funnel sharing one delivery network.

Walkthrough
The storefront in motion
Recorded from the live site.
The trust test
The happy path is only half the product.
The kitchen hits capacity mid-order
Availability is re-checked at checkout rather than trusted from the listing, so an unavailable dish is caught before payment rather than after.
The socket drops
Tracking falls back to a polled read rather than freezing, so a dropped connection degrades the update rate instead of the information.
The visitor arrives from a local search
Restaurant pages are server-rendered and self-contained, so landing directly on one from search is a complete page rather than an entry into a flow.
The decisions
Three moves carried the story.
Collapse the reads into one query
Restaurant, menu and order data arrive through a single GraphQL round trip shaped to the view, rather than several REST calls a phone network has to pay for individually.
Cache the search path, not the order path
Redis sits in front of restaurant search, where the same queries repeat constantly at peak. Order state is never cached, because a stale order is worse than a slow one.
Push rider position, do not poll for it
Live tracking runs over a socket rather than an interval, so the map is current without every open tracking screen generating steady request load.
What I would test next
