Realtime SDK

Presence

Presence

Presence lets you see who's online in a room and share custom state like user names, avatars, and activity status.

Basic Usage

import { usePresence } from '@realtime-sdk/react';
 
function OnlineUsers({ room }) {
  const { users, self, others, updatePresence } = usePresence(room);
 
  return (
    <div>
      <h3>Online ({users.length})</h3>
      <ul>
        {users.map(user => (
          <li key={user.id} style={{ color: user.color }}>
            {user.data.name ?? 'Anonymous'}
            {user.id === self?.id && ' (you)'}
          </li>
        ))}
      </ul>
    </div>
  );
}

Presence Data

Each user has:

PropertyTypeDescription
idstringUnique user ID (from JWT)
colorstringAuto-assigned color (hex)
dataobjectCustom presence data
cursorCursorPosition | nullCurrent cursor position

Setting Initial Presence

Pass initial presence when joining a room:

room.join({
  metadata: {
    name: user.name,
    avatar: user.avatarUrl,
    status: 'active',
  },
});

Updating Presence

Update your presence data at any time:

const { updatePresence } = usePresence(room);
 
// Update single field
updatePresence({ status: 'away' });
 
// Update multiple fields
updatePresence({
  name: 'New Name',
  status: 'active',
});

Listening to Changes

The hook automatically re-renders when presence changes. For more control:

useEffect(() => {
  const unsubJoin = room.on('presence:join', (user) => {
    console.log(`${user.data.name} joined`);
  });
 
  const unsubLeave = room.on('presence:leave', (userId) => {
    console.log(`User ${userId} left`);
  });
 
  return () => {
    unsubJoin();
    unsubLeave();
  };
}, [room]);

Color Assignment

Each user is automatically assigned a color from a palette of 16 distinct colors. Colors are consistent for the duration of their session but may change on reconnection.

// Access the assigned color
const { self } = usePresence(room);
console.log(self?.color); // e.g., '#E57373'

Avatar Stack Component

Common pattern for showing online users:

function AvatarStack({ room }) {
  const { others, self } = usePresence(room);
  const maxVisible = 5;
  const overflow = others.length - maxVisible;
 
  return (
    <div className="flex -space-x-2">
      {self && (
        <Avatar user={self} className="ring-2 ring-white z-10" />
      )}
      {others.slice(0, maxVisible).map((user, i) => (
        <Avatar 
          key={user.id} 
          user={user} 
          style={{ zIndex: maxVisible - i }}
        />
      ))}
      {overflow > 0 && (
        <div className="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center text-xs">
          +{overflow}
        </div>
      )}
    </div>
  );
}

On this page