We Built a Real-Time Fleet-Tracking Dashboard for a 60-Truck Logistics SMB on a ₹52k/Month Cloud Bill
A 60-truck cement-haulage SMB in Nagpur replaced their 2018-era GPS tracker with a custom MQTT + TimescaleDB + WebSockets + Mapbox dashboard. Live ETAs, geofence alerts, fuel-anomaly detection. Cost: ₹52k/month.
Hrishikesh Baidya
November 22, 202515 min read
0%
A 60-truck cement-haulage SMB in Nagpur was paying ₹38,000/month to a third-party GPS-tracking SaaS that they hated. The tracker showed truck positions on a 30-second refresh map. It did not show ETAs, did not flag fuel anomalies, did not integrate with their dispatch sheet. The owner asked us a simple question: "if I am paying ₹38,000/month for a map, can I have something that actually helps me run the business?" Twelve weeks later we shipped a custom MQTT + TimescaleDB + WebSockets + Mapbox dashboard for ₹52,000/month total cloud bill. This is what we built and the cost-control choices that kept us under budget.
60
Trucks Tracked Live
12 weeks
Discovery to Cutover
₹52k/mo
Steady-State Cloud Bill
~190M
GPS Pings Stored Per Month
## The Answer in 60 Words
Each truck pings GPS + speed + fuel level every 5 seconds via an existing OBD-II tracker (we kept the hardware they had). MQTT broker on a single EMQX node receives 720 pings/min/truck — 43,200/min total. TimescaleDB stores raw, aggregates 1-min and 1-hour rollups. Next.js dashboard subscribes via WebSockets, renders Mapbox tiles. Cost: ₹52,000/month for 60 trucks.
## Why This Matters For Indian Logistics SMBs
The Indian logistics SMB market — ~250,000 firms operating fewer than 200 trucks — is the underserved middle. Enterprise GPS-tracking SaaS (KPIT, Trakzee, Webfleet) starts at ₹400/truck/month and scales linearly forever; for 60 trucks that is ₹24,000/month minimum, ₹2.88 lakh/year. Tier-1 telematics integrations (FleetX, Locus, LogiNext) offer richer dashboards at ₹650-900/truck/month. For a chain doing ₹15-30 crore annual revenue with 5-8% net margin, that ₹3-6 lakh/year is real money. Custom builds at ₹15-25 lakh upfront + ₹50,000-80,000/month run cost have a 2-3 year payback against tier-1 SaaS, plus the data and roadmap stay in-house.
The other reason: open-source telematics infrastructure has matured. EMQX is genuinely production-grade as a free MQTT broker. TimescaleDB is the right database for time-series GPS data. Mapbox's [pricing tiers](https://www.mapbox.com/pricing) at our volume are actually cheaper than Google Maps. The build cost has dropped roughly 60% since 2022.
## The Client (Specific Details)
- Sector: Cement haulage (B2B, hauling for ACC, UltraTech, Dalmia in central India)
- Location: Nagpur HQ, operations across Maharashtra + Madhya Pradesh + Chhattisgarh
- Fleet: 60 trucks (mostly Tata 4923, some Ashok Leyland 4928, all 49-tonne tractors)
- Routes: Avg 280 km, 2-day round trip, ~14 active trucks at any moment
- Drivers: 84 (rotating shift, 2 drivers per long-haul truck for the 18-hour mid-corridor leg)
- Existing trackers: Concox AT4 OBD-II devices installed in 2018, still functional, MQTT-capable on a custom firmware the previous vendor owned
- The trigger: A truck was 6 hours late delivering to a UltraTech site in Raipur in August 2025. The customer cancelled the contract for 4 weeks. The owner gave us 12 weeks and a clear brief: "I want to know when a truck is going to be late, before the customer does."
## The Architecture
📡
EMQX MQTT Broker
Single EMQX cluster on 2 c6i.large EC2 (HA pair). Receives 43,200 pings/min from 60 trucks. Persists nothing — just routes to the ingest worker. Publishes per-truck topic (truck/{vin}/telemetry).
⏱️
TimescaleDB Hypertable
Postgres + Timescale extension. Hypertable on (truck_id, ts) partitioned by 7-day chunks. Continuous aggregates compute 1-min and 1-hour rollups in real time. Compression after 14 days drops storage by 92%.
🌐
WebSocket Live Stream
Node.js + ws library. Browser subscribes to "fleet view" or "truck/{id}". Server forwards filtered MQTT messages from Redis pub-sub. ~12 ms median latency from MQTT receipt to browser render.
🗺️
Mapbox + Custom Layers
Mapbox GL JS for the base map. Custom GeoJSON layers for client geofences (cement plants, customer sites, toll plazas). 60 truck markers update without re-rendering the map. Heatmap of historical routes for planning.
## The Stack (And Why)
| Layer | Choice | Why |
|---|---|---|
| MQTT broker | EMQX 5 (open-source) | Free, handles 100K+ connections per node. We are at 60. Headroom for 1000x. |
| Time-series DB | TimescaleDB on Postgres 16 | Continuous aggregates removed 80% of dashboard query work. Compression saved storage cost meaningfully. |
| Cache + pub-sub | Redis (ElastiCache t4g.micro) | Fan-out from one MQTT message to N WebSocket subscribers. |
| Backend API | Node.js 20 + Fastify | The team knows it. Fastify outperformed Express by ~22% in our load tests. |
| WebSocket | ws library directly (no Socket.io) | Socket.io's protocol overhead was unnecessary for our use case. ws gives raw control. |
| Frontend | Next.js 14 + Mapbox GL JS | Server components for the static dashboard chrome; Mapbox handles the map layer with its own state. |
| Hosting | AWS Mumbai (ap-south-1) | Owner wanted INR billing through an Indian AWS partner; ap-south-1 keeps GPS data in-region. |
| Geocoding | Mapbox + IndianMaps fallback | Mapbox sometimes misses small Indian villages; IndianMaps fills gaps. Free for our volume. |
## The 12-Week Plan
1
Weeks 1–2: Discovery + tracker firmware audit
Two days at the Nagpur depot. Watched the dispatch supervisor work for 9 hours straight. Mapped his 14 distinct decision points (dispatch, load confirm, gate-out, mid-corridor check, ETA update, late warning, arrival, gate-in, unload confirm, return-leg dispatch, fuel-stop log, breakdown handling, customer call, payment trigger). The Concox AT4 trackers had MQTT firmware available but the previous vendor had it custom-locked. Concox confirmed they would unlock for ₹240/device. ₹14,400 well spent.
EMQX HA pair behind an internal AWS NLB. Ingest worker reads from MQTT, writes to TimescaleDB in batches of 1000 inserts (200ms windows) for write efficiency. Tested at 50K msg/sec sustained — we use 720, so 70x headroom.
4
Weeks 6–7: Live dashboard MVP
Mapbox base map, 60 truck markers, real-time updates via WebSocket. Dispatch supervisor's first reaction: "where is the ETA?" We had it on the v2 spec. Pulled it forward into v1.
5
Weeks 8–9: ETA engine + geofence alerts
ETA = current_distance_to_destination / avg_speed_last_30min, adjusted for time-of-day historical traffic on that corridor. Recomputes every 60 seconds. Geofences for 14 cement plants and 38 customer sites. Slack alert on "truck X stopped >15 min outside a known geofence."
6
Weeks 10: Fuel anomaly detection
Trucks log fuel level via OBD-II. Detect "drop > 8 litres in <2 minutes while parked" — likely siphoning. Triggered 3 alerts in pilot week; 2 were genuine, 1 was a faulty sensor. We tuned to >12 litres before it stopped firing on sensor noise. Owner's phrasing: "you may have just paid for the build in year 1."
7
Week 11: Pilot with 10 trucks (the Raipur corridor)
Soft launch on the 10 trucks running Nagpur-Raipur. The dispatch supervisor accepted ETA accuracy within ±18 minutes as the working tolerance. We hit ±9 minutes median. He started checking the new dashboard exclusively in week 2.
8
Week 12: Full rollout + cancel old tracker contract
Remaining 50 trucks switched over Tuesday-Friday. Old SaaS contract cancelled with 30-day notice on Monday week 12. Run cost from week 12: ₹52,000/month. Old SaaS bill was ₹38,000/month — we are spending more, but for a system that actually helps. Owner is fine with it.
## The Cost-Control Choices (Why ₹52k Not ₹2 Lakh)
This is the meat of the post. Below are the specific decisions that kept the cloud bill under ₹60,000/month.
### Choice 1: Single-region, no cross-AZ replication
We run the entire stack in ap-south-1a. The owner accepted that an AZ outage would cause ~30 min of dashboard downtime (the ingest queue absorbs the gap). Cross-AZ data transfer would have added ~₹6,000/month for no business value. Easy call.
### Choice 2: TimescaleDB compression after 14 days
Raw GPS pings compress 92% with TimescaleDB's columnar compression. We run "compress chunks older than 14 days" as a continuous job. Storage went from would-have-been ₹14,000/month to ₹1,800/month. Engineering cost: 4 lines of SQL.
That's it. The continuous aggregates remain uncompressed (they are queried often), the raw pings compress aggressively (they are queried rarely).
### Choice 3: EMQX self-hosted, not AWS IoT Core
AWS IoT Core charges per-message at ~$1 per million messages. At 43,200 msg/min × 1440 min/day × 30 days = 1.87 billion msg/month. That would be ~₹1.5 lakh/month on AWS IoT Core. Self-hosted EMQX on 2 c6i.large costs ₹6,400/month. Saved ₹1.4 lakh/month. The engineering cost of running EMQX: 4 hours/month for upgrades and monitoring.
### Choice 4: Mapbox pay-as-you-go, not Google Maps
Mapbox charges $0.50 per 1000 map loads above the free tier. Our dashboard generates ~120,000 loads/month. Bill: ~$32 = ₹2,700/month. Google Maps for the same volume would have been ~$280 = ₹23,500. Mapbox API is comparable in quality for Indian roads (sometimes better — they have better coverage of MP-CG industrial corridors).
### Choice 5: WebSocket through a single Node process, not Lambda
API Gateway WebSocket + Lambda would have charged per-message. At 60 connections × 100 messages/sec = 6000 msg/sec sustained, plus 80,000 GB-seconds Lambda compute, we estimated ~₹38,000/month. Self-hosted Node ws on a single t4g.medium: ₹3,200/month. The trade-off: we manage one EC2 instance. Worth it.
## The Cost Breakdown
## The Outcome (Numbers That Mattered)
±9 min
Median ETA Accuracy
~₹2.4L
Recovered (Year 1, Fuel Anomaly)
−43%
Customer Complaints (Late Delivery)
14 mo
Build Payback (vs Tier-1 SaaS)
## The Pre-Production Checklist
EMQX broker tested at 10x peak load (we did 432K msg/sec, deployed at 720)
TimescaleDB compression policy active and verified (chunk older than 14 days = compressed)
Continuous aggregates refresh every 60 seconds (not on-query — that kills performance)
WebSocket reconnect tested with 30-second internet drop on dispatch supervisor's machine
Fuel anomaly threshold calibrated against 30 days of baseline (not arbitrary)
Backup of TimescaleDB taken nightly to S3 cross-region (Mumbai → Hyderabad)
Per-truck data export pipeline for regulatory needs (we ship CSV per VIN per quarter)
Load test: 60 simultaneous browser dashboards open without degrading WebSocket fan-out
Rollback plan: re-enable old SaaS tracker for 7 days as a safety net (we kept it during pilot)
## What We Deliberately Did Not Build
1. A driver-facing mobile app. Drivers would not have used it. Owner's framing: "if I give them a screen, they will look at it instead of the road." We respected operator wisdom. The truck-level data is sufficient; no driver UI needed.
2. ML-based ETA prediction. We considered it. The simple "current speed × distance + traffic factor" model hits ±9 minutes median. ML might get to ±6 minutes. Not worth the engineering. Maybe in v3 with 18 months of training data.
3. Payment integration with cement plants. The dispatch supervisor uses WhatsApp to send arrival photos to customers, who release payment. Pulling that into the dashboard would have required a 3-month sales conversation with each of 14 cement plants. v2 candidate, not worth the upfront friction.
## Common Mistakes (Each One Costs Real Money)
Symptom: "TimescaleDB queries get slower over time." Cause: missing chunk compression policy. Without it, the hypertable grows linearly and indexes get slow at ~50 GB. Fix: add_compression_policy after 14 days. Compression rate is roughly 92% on GPS data.
Symptom: "MQTT broker memory keeps climbing." Cause: stale subscribers. Browser tabs left open for days hold connections. Fix: enable EMQX's session expiry (session.expiry_interval = 7200) and persistent-session limits. Saved us 2 broker restarts in 6 months.
Symptom: "ETA spikes to '6 hours late' when a truck stops at a fuel station." Cause: ETA engine treats 0 km/h as "stopped forever." Fix: filter known fuel stops + customer geofences from the speed-averaging window. Apply a "minimum recent moving speed" floor.
Symptom: "Dashboard freezes when 60 trucks update simultaneously." Cause: React re-rendering 60 markers per WebSocket message. Fix: debounce updates to 250ms windows, mutate the Mapbox source data directly instead of re-rendering React components on every ping.
Symptom: "GPS pings go missing in poor coverage areas." Cause: tracker buffers locally then bursts when coverage returns. Fix: timestamp-on-tracker (not on ingest). Process out-of-order pings using TimescaleDB's natural ts ordering.
## A Detail That Surprised Us
In week 8 of the pilot, the dispatch supervisor noticed his dashboard showed truck 47 was idle for 4 hours at a non-customer GPS location near Itarsi. He called the driver. Driver was at a dhaba waiting for the next load assignment from the plant — standard practice. Supervisor cancelled the alert. Two days later, same truck at the same spot for 3 hours. He called the driver again. Driver had run out of work and was unsure what to do. Supervisor reassigned the truck to a Bhopal pickup, saving 11 hours of dead time. That single conversation — enabled by the live dashboard — paid for a month of run cost.
## Where Logistics Fits In Our Wider Work
We have built variants of real-time tracking dashboards for:
- An aggregator's Insofy-style platform.
- A field-service dispatch app that uses the same MQTT + WebSocket pipeline (a smaller variant on 8 vans for an HVAC service).
- The voice-AI infrastructure pattern from TalkDrill — our in-house English app — uses similar Redis pub-sub fan-out at higher scale.
If you have a fleet, a dispatch operation, or any moving-asset tracking problem, the playbook above transfers. The only piece you need to redesign per client is the fuel-anomaly threshold and the geofence library. Everything else is identical.
## FAQ
### Why not buy FleetX or Locus?
For 60 trucks at ₹650/truck/month (FleetX's mid-tier in 2025), the annual cost is ₹4.68 lakh. Custom build at ₹18 lakh + ₹6.24 lakh/year run cost has 14-month payback. After year 2, the custom build is cheaper. Plus, we control the roadmap.
### Can the same architecture handle 1000 trucks?
Yes, with two changes: (1) shard EMQX by truck-ID-modulo to 4 broker nodes, (2) move TimescaleDB to a multi-node cluster. We have load-tested up to 4000 simulated trucks on a 3-node TimescaleDB. The Postgres scaling story for time-series is genuinely good.
### What about offline tracking when trucks lose 4G?
The Concox AT4 firmware buffers up to 12 hours of pings locally and bursts when coverage returns. We process bursts using the timestamp-on-tracker, so out-of-order pings are inserted correctly into TimescaleDB.
### Can the system support drivers' weekly trip-sheet generation?
Yes. We generate per-truck per-week summary PDFs from the continuous aggregates: distance covered, average speed, fuel consumed, time at customer sites, time idle, alerts triggered. Email out every Monday morning.
### What about integration with Tally for fuel cost reconciliation?
We export a CSV per month with truck-level fuel data, which the accountant manually loads into Tally. A direct Tally bridge is on the v2 wishlist; for now, the CSV-and-paste workflow is fast enough.
### Did the old GPS tracker contract cancel cleanly?
30-day notice in the contract. Old vendor offered a 25% discount to retain. Owner declined. Migration was clean — both systems ran in parallel for 4 weeks, no data lost.
### What is the team composition?
Two backend engineers (one on the MQTT and TimescaleDB side, one on the API and WebSocket fan-out), one frontend engineer for the Next.js + Mapbox dashboard, one DevOps engineer at 0.4 FTE for AWS setup and EMQX hardening, our project lead at 0.2 FTE. Total: 4 people, ~9 person-weeks.
Want a fleet/logistics dashboard built?
We build real-time tracking dashboards for Indian logistics SMBs running 20–500 vehicles. Typical project: ₹15–28 lakh, 10–14 weeks, fixed scope. Cloud bill stays under ₹80,000/month at our scale. The first call is technical, with the engineer who would lead your build.