Skip to content
tezvyn:
Menu

How to sync state across multiple user devices?

Source: interviewMediumHow cards are made

Summary

multi-device presence and state coherence patterns.

Key points

attach userId to each socket, track active sockets per user, broadcast user state to all their sockets.

The multi-device problem

When a user opens your app on a phone and laptop, the server sees two separate WebSocket connections. If the user clicks a button on the phone, only the phone socket receives the response. The laptop socket is unaware, showing stale state. Without explicit synchronization, the devices diverge.

Socket-to-user mapping

Maintain a mapping of userId to all connected sockets. In the connection handler, extract userId from the JWT, then add the socket to a collection: usersWithSockets[userId] = usersWithSockets[userId] || []; usersWithSockets[userId].push(socket.id);. On disconnect, remove the socket from the list. This allows you to broadcast to all of a user's connections.

Central state store

For important state (user settings, document edits, presence status), store in a database or cache (Redis). When a user changes something on the phone, write to the store, then emit the updated state to all their sockets. This ensures both devices see the change. For example: user clicks settings on phone, server writes to database, server emits 'settingsUpdated' to all sockets of that user, laptop updates its UI.

Broadcast to all user sockets

Create a helper: io.to() sends to a single room. To send to all sockets of a user, join each socket to a user room on connect: socket.join('user:' + userId);. Then broadcast: io.to('user:' + userId).emit('stateChange', newState);. Both devices receive simultaneously.

Event deduplication

When a user's phone socket triggers an action, it will receive the broadcast notification too. To prevent the phone from processing its own request twice, either mark the original socket for exclusion or have the phone await the server's confirmation response before updating locally.

Clustered considerations

If you have multiple Node.js servers, each server knows only its local sockets. If the phone connects to server A and the laptop to server B, sending to the laptop via server A fails. Use a Redis adapter to broadcast room messages across all servers. Socket.IO's adapter system handles this transparently.

Interview question

A user's phone and laptop are both connected. The user changes their avatar on the phone. What's the best way to ensure the laptop also sees the new avatar?

  • a.Have the phone make a REST API call to update the avatar, then hope the laptop polls for updates eventually.
  • b.Broadcast the avatar change to all of the user's sockets via a room or user mapping.Correct
  • c.Send a direct socket.emit() only to the phone's socket; the laptop will sync next time it reconnects.
  • d.Update the database and wait for both devices to poll the server independently.
Why?

Broadcasting to a user room ensures both connected devices receive the update instantly. REST polling introduces delay and inefficiency. Direct socket.emit() to only the phone means the laptop sees nothing until reconnect. Independent polling is asynchronous and defeats real-time synchronization.

Just read this? Test yourself on what you have been reading.

Read the original → socket.io

Put your scrolling time to good use

Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Every open role lists the topics its interview covers, so you can prepare for the real thing rather than guessing.

See open roles