Aggregators take a commission on every order, and they keep the customer relationship. More restaurants want their own ordering app. The ordering screen is the easy part — the difficulty and the money live in what happens after the customer taps Place order.
I built a five-app delivery system for one restaurant: a customer app and website, a rider app, a kitchen portal and an owner panel. These are the five lessons that mattered most.
1. Price delivery on the road, not the map
Straight-line distance is never right. A customer across a river can be 800 metres away as the crow flies and a twenty-minute ride in practice. Price on straight lines and you quietly subsidise exactly the trips that cost the most — and accept addresses your kitchen can't realistically reach.
- Use real driving distance from a routing API for the fee and the delivery boundary.
- Cache the answer per address, so a regular customer costs one lookup, not one per order.
- Decide the failure mode up front: if the map service is down, fall back to the straight-line estimate. It's always shorter, so it can only ever be generous — a checkout that always works beats one that's always precise.
- Tell out-of-range customers as soon as they enter an address — not after they've built a basket.
2. Push updates; scope them to the person
An order moves: placed, accepted, cooking, ready, picked up, delivered. Polling for those changes either drains batteries or feels sluggish. A live connection (I used Socket.IO) pushes each change the moment it happens: new orders chime on the kitchen board, riders get assignments instantly, customers watch the rider on a map.
3. Solve the bag problem physically
Several identical sealed bags on a counter, several riders collecting. No amount of screen data tells a rider which bag is theirs. So every live order gets a short number the kitchen writes on the bag; the rider types it in at pickup, and a mismatch is caught at the counter instead of across town.
The detail that makes it work: the rider's app doesn't show the number until it's been typed correctly. A code displayed on screen can be typed without looking at the bag, which defeats the check. A second code, sent to the customer, confirms the handover at the door — and marks the moment cash changed hands.
4. Track cash as events, not a balance
Cash still moves in riders' pockets. Recording it as a running total tells you what someone thinks is true; recording each collection as its own entry tells you why. A settlement should name exactly which collections it covers and close only those — so money still out on the road stays open, and a delivery completed while the cash is being counted isn't swept into the wrong receipt.
This isn't theoretical: an early version of the settlement logic miscounted delivered-but-uncollected orders. Because collections were individual events, the error was visible and fixable. With only a balance, it would have surfaced weeks later as money nobody could explain.
5. Put the controls in the owner's hands
The business changes faster than a developer can be booked. Fee structure, delivery radius, tax, banners, coupons and a single switch to stop accepting orders when the kitchen is overwhelmed — all of it belongs on a settings screen that takes effect immediately. A platform that needs its builder in the room for every decision isn't really the owner's platform.
What it takes, honestly
A serious own-delivery setup is five products, not one: two ways to order, a rider app, a kitchen view and an owner view, all reading the same live data. Keep them in agreement with one API contract and generated clients, and every future feature gets cheaper instead of riskier.
- Food delivery
- Restaurants
- React Native
- Real-time

Written by Rasmiranjan Sahoo
Full-stack and React Native developer. I design and build websites, apps and business software end to end — and write about what I learn shipping them. More about me

