A driver is halfway through a trip when the phone drops into a dead zone under a flyover. Ninety seconds later it’s back. What happened to the trip in between decides whether your dispatch system is trustworthy. If the server took that silence to mean “driver gone” and reassigned the ride, you now have two cars heading for one passenger. MQTT live location tracking handles the location part well. Keeping dispatch state correct through the drop is a separate job, and it’s the one teams usually get wrong.

We built a taxi dispatch platform with a Laravel backend, separate Flutter apps for drivers and riders, and an admin panel. Driver location runs over MQTT, routing uses Google APIs, push goes through OneSignal, and the dispatch state survives a driver’s connection dropping mid-trip. Here’s how we’d design that again.

Why pick MQTT live location tracking

You could stream locations over WebSockets or poll an HTTP endpoint. MQTT earns its place because of features it already has that you’d otherwise build yourself:

  • Small overhead. A location update is a tiny payload, and MQTT’s fixed header is tiny too. That matters on patchy mobile data, multiplied across a fleet sending every few seconds.
  • QoS levels. QoS 0 is fire-and-forget, QoS 1 guarantees at least once delivery, QoS 2 exactly once. Different messages in a dispatch system need different guarantees, and you get to choose per message.
  • Retained messages. The broker keeps the last retained message on a topic and hands it to new subscribers immediately. A dispatcher opening the map sees every driver’s last known position at once, without waiting for the next update.
  • Last Will and Testament. A client registers a message when it connects. If it disappears without a clean disconnect, the broker publishes that message for it. That’s your offline signal, for free.

MQTT can run over WebSockets as well, which is handy for a browser-based admin panel that needs to read the same topics.

Topics, QoS and the offline signal

A topic layout that keeps permissions and subscriptions simple:

drivers/{driverId}/location   QoS 0, retained
drivers/{driverId}/status     QoS 1, retained (online / offline)
trips/{tripId}/events         QoS 1, not retained

Location goes at QoS 0 on purpose. If one update is lost, the next one arrives in a few seconds and makes it irrelevant. Paying for acknowledgements and redelivery on data that’s stale in five seconds just adds traffic. Trip events (accepted, arrived, started, completed) are the opposite: losing one breaks the trip, so they’re QoS 1, and the receiving side must handle duplicates.

For status, the driver app connects with a will message of offline on its status topic, retained, then publishes online, retained, as soon as it’s connected. Now anyone subscribed to status always sees the current value, and an ungraceful drop flips it automatically once the broker notices. How fast it notices depends on the keep-alive interval: the broker treats a client as gone after about one and a half keep-alive periods with no traffic. Too short and every tunnel looks like a disconnect. Too long and a dead phone looks alive. Tune it against real network conditions in the cities you serve.

Lock topics down at the broker. Each driver authenticates with its own credentials, and the ACL lets it publish only under its own drivers/{driverId}/ prefix. Otherwise any driver app can report any other driver’s position.

Sessions that survive reconnects

Connect with a persistent session (clean session off in MQTT 3.1.1, or a session expiry interval in MQTT 5). The broker then remembers the driver’s subscriptions and queues QoS 1 messages while they’re away. When the phone comes back, it gets the trip event it missed, such as a rider cancellation, without any extra code.

Dispatch state is not connection state

This is the part that keeps the flyover scenario from turning into a double booking. MQTT tells you a driver’s connection dropped. It doesn’t tell you the trip is over. Treat them as two different things.

  1. The trip is a state machine in the database. Laravel owns it: requested, assigned, arriving, in progress, completed, cancelled. Transitions happen only through explicit events, never as a side effect of a connection changing.
  2. An offline status starts a timer, not a reassignment. For a driver with no active trip, going offline removes them from the dispatch pool. For a driver mid-trip, it marks the trip as “driver unreachable” and starts a grace period. Only if the grace period runs out does a human or a rule decide what happens next.
  3. The driver app keeps its own copy of the trip. Current trip ID, state and the last transition it sent, stored locally. If the app is killed and reopened, it restores the screen from local state and then confirms with the server.
  4. Reconnect means resync, over HTTP. After reconnecting, the app fetches the authoritative trip state with an ordinary API call and reconciles. MQTT is great for streams. For “what’s the truth right now”, a request and response is simpler to reason about.
  5. Transitions are idempotent and versioned. Every trip event carries the trip’s version number. “Mark arrived, expecting version 4” either applies once or gets rejected as stale. QoS 1 can deliver the same message twice, and a retrying app can send it twice, so duplicate handling isn’t optional.

The rider app benefits as well. During the grace period it can say “Driver’s connection is weak, last seen 40 seconds ago” with the last retained location on the map, which is honest and much better than a spinner or a silent reassignment.

Background behaviour on the driver’s phone

None of this works if the driver app stops sending when the screen locks. On Android that means a location foreground service with its persistent notification. On iOS, the location background mode, started while the app is in the foreground. Buffer points locally when the connection is down and publish the latest on reconnect. The full trail can go up later in a batch if you need it for fare disputes.

At orithLabs, we’ve built dispatch and live tracking systems end to end, from the broker topics to the driver app to the admin panel. If you’re building something in logistics or mobility, see our mobile development service and the taxi dispatch case study.