Why MQTT and Not WebSockets for Live GPS
Swifpack — the mobility and logistics platform delivered to Tanzania Posts Corporation — needed live GPS from every active driver, surfaced on a fleet dashboard in something close to real time. The default answer to that problem is a WebSocket connection per driver, pushing coordinates to a Node process that fans them out to whoever's watching.
That's a perfectly good answer in a datacentre. It was the wrong one here, and the reason had almost nothing to do with throughput.
The constraint that actually mattered
Drivers were on mobile networks, moving, all day. Connections didn't fail cleanly — they degraded, dropped for ninety seconds in a coverage gap, and came back. Phones were on battery for a full shift with the app backgrounded for most of it.
Once you write that down, the problem stops being 'how do I stream coordinates' and becomes 'what happens in the ninety seconds when I can't.' A raw WebSocket has no opinion about that. It gives you a bidirectional pipe and leaves reconnection, buffering, delivery guarantees, and offline detection as an exercise for the reader. Every one of those is something you will end up building badly under deadline.
What MQTT gave me for free
MQTT was designed for exactly this environment — constrained devices on unreliable links — and three of its features map directly onto the problem. Quality-of-service levels let me decide per message type whether at-least-once delivery was worth the overhead: position pings are cheap and frequent, so losing one is fine, but a trip-state change isn't. Persistent sessions meant a driver coming out of a coverage gap resumed rather than restarted, without me writing reconnect-and-replay logic by hand.
The third is the one that sold it. MQTT's Last Will and Testament lets a client register, at connect time, a message the broker publishes on its behalf if it disconnects ungracefully. That means 'this driver has gone offline' is handled by the protocol itself, at the moment the broker notices the socket is gone. With raw WebSockets you build that out of heartbeats and timeouts, and you get to pick between false positives and slow detection. Here it came included.
The pub/sub model also removed a layer of coordination I'd otherwise own. Drivers publish to their own topic; the dashboard subscribes to the fleet. Neither knows the other exists, and adding a second consumer later — analytics, an ops alerting service — meant adding a subscriber, not modifying the publisher.
Why Firebase is in there too
MQTT carries the high-frequency stream. It is deliberately not the system of record. Firebase holds the durable state the apps read on cold start — last known position, current trip status — so a dispatcher opening the dashboard sees the fleet immediately instead of an empty map waiting for the next ping.
That split is the part I'd defend hardest. Using one technology for the live stream and another for durable, queryable state is not redundancy; it's the two having genuinely different jobs. Trying to make the message bus also be the database is a common way to end up with neither working well.
Where this is the wrong call
MQTT means running and operating a broker. If your clients are browsers on stable connections and you have no offline story to worry about, that's real operational cost buying you very little — use WebSockets and move on. It's also a poor fit if your traffic is mostly request/response rather than a genuine stream; you'd be reaching for pub/sub to solve a problem HTTP already solves.
The decision here came down to one question: is unreliable connectivity a core property of the system, or an edge case? For a fleet of drivers on mobile networks it's the core property, and picking a protocol that already has answers for it beat building those answers myself. Latency on real-time updates ended up around 35% lower than the baseline we started from — but the reason I'd make the same call again is the reconnection code I never had to write.
Working on something similar? I'd be glad to talk through it.
Book a Discovery Call