Skip to main content

Signals (Broadcast)

Beta

This feature is in beta. Core behavior is stable, but some APIs or configuration may change before general availability.

room.signals is the ephemeral event rail of Room.

Signals are not authoritative state. They are for events you want to deliver now without storing them as the room's source of truth.

Good Fits for Signals

  • chat events
  • typing bursts
  • cursor movement
  • read receipts
  • transient notifications
  • WebRTC offer/answer/ICE signaling

Client Surface

Assume room is an authenticated room client created with client.room(...).

room.signals.on('chat.message', (payload, meta) => {
appendMessage(payload, meta);
});

room.signals.onAny((event, payload) => {
console.log('signal', event, payload);
});

await room.signals.send('chat.message', { text: 'hello' });
await room.signals.sendTo('member-2', 'private_hint', { text: 'look left' });

The main client APIs are:

  • room.signals.send(event, payload, options?)
  • room.signals.sendTo(memberId, event, payload?)
  • room.signals.on(event, handler)
  • room.signals.onAny(handler)

Server Surface

Server-side code uses the existing Room message helpers:

  • room.sendMessage(type, data?, options?)
  • room.sendMessageTo(userId, type, data?)
handlers: {
actions: {
CHAT: (payload, room, sender) => {
room.sendMessage('chat.message', {
from: sender.userId,
text: payload.text,
});
},
},
},

Access and Hooks

Signals have their own control points:

  • access.signal(auth, roomId, event, payload) — allow/deny the signal
  • hooks.signals.beforeSend(event, payload, sender, room, ctx) — transform or reject before delivery
  • hooks.signals.onSend(event, payload, sender, room, ctx) — side effects after delivery
rooms: {
game: {
access: {
signal: (auth, roomId, event) => auth !== null,
},
hooks: {
signals: {
beforeSend: async (event, payload, sender, room, ctx) => {
// Return false to reject
if (event === 'spam') return false;
// Return transformed payload
return { ...payload, timestamp: Date.now() };
// Return undefined to pass through unchanged
},
onSend: async (event, payload, sender, room, ctx) => {
console.log(`Signal ${event} from ${sender.userId}`);
},
},
},
},
},
HookReturnBehavior
beforeSendfalseReject signal — client receives signal_error
beforeSendtransformed payloadDeliver modified payload to recipients
beforeSendundefined / voidDeliver original payload unchanged
onSendNon-blocking side effects only

Use them to reject, transform, audit, or mirror transient event traffic.

Signals vs State

  • Use State when the server must own the durable truth.
  • Use signals when the event is transient and should not become part of shared or private state.

Legacy Compatibility

Older or compatibility-oriented SDK examples may still refer to:

  • room.onMessage(...)
  • room.onAnyMessage(...)

On unified clients, room.signals.* is the preferred model.