In this lesson, you will learn how to build a collaborative cursor tracking system by balancing real-time responsiveness with server-side bandwidth constraints.
When multiple users track their mouse movements on a shared canvas, sending every single pixel coordinate would overwhelm your WebSocket server. A typical mouse can trigger over 100 events per second; if you have 50 active users, that’s 5,000 messages per second, leading to severe network bottlenecks.
The Throttling Strategy
To manage this, we employ event throttling. Instead of emitting a packet on every mousemove event, we use a controlled interval or a request-animation-frame loop to "sample" the cursor position.
On the client side, we store the current coordinates in a local variable and only broadcast them to the server if a specific time threshold has passed (e.g., every 30ms).
// Client-side: Throttled broadcast
let lastCursorPos = { x: 0, y: 0 };
let lastEmitTime = 0;
window.addEventListener('mousemove', (e) => {
lastCursorPos = { x: e.clientX, y: e.clientY };
const now = Date.now();
if (now - lastEmitTime > 30) { // Limit to ~33 broadcasts per second
socket.emit('cursor-move', lastCursorPos);
lastEmitTime = now;
}
});
Server-Side Efficiency
On the backend, you shouldn't broadcast every incoming coordinate to every connected client individually. If you have 100 users, broadcasting each update to everyone creates an traffic complexity. Instead, use a broadcast buffer. Every 50ms, the server collects all pending cursor updates and sends them as a single "batch" array to all clients. This reduces the number of WebSocket frames significantly while maintaining a smooth visual experience for your users.
To further save bandwidth, represent cursor positions as simple integer arrays [x, y] instead of verbose JSON objects like {"x": 100, "y": 200}. Over thousands of updates, stripping those extra characters adds up to substantial savings in your monthly egress costs.
Key Takeaway: Never stream raw mouse events directly; always throttle client-side broadcasts and batch server-side payloads to maintain scalability without sacrificing visual fluidity.