Day 3 of 5
⏱ ~60 minutes
WebSockets in 5 Days — Day 3

Building a Chat App

Rooms, private messages, user presence, message history.

Chat App Architecture

A real chat app needs: rooms (channels), user presence (who's online), private messages, and message history. We'll build all four today. The server is the single source of truth — it manages room membership and broadcasts messages.

Rooms

Rooms — Join and Leave
io.on('connection', (socket) => {
  // Join a room
  socket.on('joinRoom', (room) => {
    socket.join(room);
    // Tell others in the room
    socket.to(room).emit('userJoined', { 
      userId: socket.id, room 
    });
    socket.emit('joinedRoom', room);
  });

  // Send to a room
  socket.on('roomMessage', ({ room, message }) => {
    io.to(room).emit('newMessage', {
      from: socket.id,
      message,
      time: new Date().toISOString()
    });
  });

  // Leave a room
  socket.on('leaveRoom', (room) => {
    socket.leave(room);
    socket.to(room).emit('userLeft', socket.id);
  });
});

User Presence

Track who's online using a simple in-memory Map. In production you'd use Redis, but for a single-server app a Map works fine.

Presence Tracking
const onlineUsers = new Map(); // socketId -> username

io.on('connection', (socket) => {
  socket.on('setUsername', (username) => {
    onlineUsers.set(socket.id, username);
    io.emit('onlineUsers', Array.from(onlineUsers.values()));
  });

  socket.on('disconnect', () => {
    const username = onlineUsers.get(socket.id);
    onlineUsers.delete(socket.id);
    io.emit('userLeft', username);
    io.emit('onlineUsers', Array.from(onlineUsers.values()));
  });
});

Private Messages

Private Messages
socket.on('privateMessage', ({ to, message }) => {
  // Each socket automatically joins a room named by its own ID
  io.to(to).emit('privateMessage', {
    from: socket.id,
    message,
    time: new Date().toISOString()
  });
  // Also emit to sender so they see their own message
  socket.emit('privateMessage', {
    from: socket.id, to, message,
    time: new Date().toISOString()
  });
});
📝 Day 3 Exercise
Full Chat App with Rooms
  1. Build a full chat page: a username input, a room selector, a message list, and a message input.
  2. Implement: join room, leave room, send room message, see who's online.
  3. Add a typing indicator: when a user starts typing, broadcast typing to the room. Stop broadcasting after 2 seconds of no input.
  4. Persist the last 50 messages in an array on the server. Send history when a user joins a room.

Day 3 Summary

  • Rooms are named channels — sockets can join multiple rooms simultaneously.
  • Presence tracking uses an in-memory Map updated on connect/disconnect events.
  • Private messages work by emitting to a socket's own ID (which is a room).
  • Message history should be loaded on room join, not on page load.
Finished this lesson?