← Back
February 20269 min readReal-Time Systems

Real-Time GPS Tracking with Socket.io and Leaflet.js: Lessons from Production

Real-Time GPS Tracking with Socket.io and Leaflet.js: Lessons from Production

Building real-time vehicle tracking for FAMS V5 was one of the most technically demanding features I've implemented. Handling thousands of GPS-enabled vehicles broadcasting their positions every few seconds, and rendering them live on a map — here's how I did it and what I learned.

The Architecture

The system has three main layers:

  • Data ingestion — GPS devices send coordinates via TCP/MQTT to a Node.js ingestion server
  • Real-time distribution — Socket.io broadcasts position updates to connected web clients
  • Map rendering — Leaflet.js displays vehicles as interactive markers on the map

Why Socket.io Over Raw WebSockets

While raw WebSockets have lower overhead, Socket.io provides critical production features:

  • Automatic reconnection — When a user's connection drops (common on mobile), Socket.io reconnects seamlessly
  • Room-based broadcasting — Each fleet/organization subscribes to their own "room," so vehicles only broadcast to their owner
  • Fallback transports — Some corporate firewalls block WebSockets; Socket.io falls back to long-polling automatically
  • Binary support — GPS data can be sent as compressed binary for lower bandwidth

Optimizing Leaflet.js for Thousands of Markers

Rendering 5,000+ markers on a Leaflet map will destroy performance if you use default markers. Here's what I did:

  • Marker clustering — Used Leaflet.markercluster to group nearby vehicles at lower zoom levels
  • Canvas renderer — Switched from SVG to Canvas rendering for 10x better performance with many markers
  • Viewport culling — Only render markers visible in the current map bounds
  • Throttled updates — Batch position updates and render at 30fps instead of on every incoming event

Handling Scale: Connection Management

With thousands of concurrent Socket.io connections, memory and CPU become real concerns:

// Use Redis adapter for horizontal scaling
const { createAdapter } = require("@socket.io/redis-adapter");
const pubClient = createClient({ url: REDIS_URL });
const subClient = pubClient.duplicate();

io.adapter(createAdapter(pubClient, subClient));

The Redis adapter allows multiple Node.js processes (or servers) to share Socket.io state, enabling horizontal scaling behind a load balancer.

Geofencing: Server-Side Efficiency

Geofence calculations (is this vehicle inside this polygon?) are done server-side using the point-in-polygon algorithm. Processing this on the client would be too slow and insecure. When a vehicle crosses a geofence boundary, the server emits an alert event to the relevant dashboard users.

Key Takeaways

Real-time systems require thinking differently about state management, rendering performance, and network resilience. The combination of Socket.io for reliable real-time communication and Leaflet.js for efficient map rendering gives you a solid, production-ready stack for any tracking or logistics application.