useSyncBroadcast
Send and receive ephemeral messages that don't persist.
Send fire-and-forget messages across clients. Broadcasts don't persist on the server and don't update shared state — ideal for reactions, typing indicators, sound effects, and one-off notifications.
Signature
function useSyncBroadcast<ClientData = unknown>(
handler: (payload: unknown, context: { client: Client<ClientData> }) => void,
key: (string | null)[]
): SyncBroadcastResult<ClientData>function useSyncBroadcast(
handler: (payload, context) => void,
key: (string | null)[]
): SyncBroadcastResult<ClientData>Parameters
| Parameter | Type | Description |
|---|---|---|
handler | (payload, { client }) => void | Callback invoked on incoming broadcasts |
key | (string | null)[] | Room key scoping which broadcasts to receive |
Return value
| Field | Type | Description |
|---|---|---|
broadcast | (payload: unknown) => void | Send to all clients watching this key |
send | (clientId: string, payload: unknown) => void | Send to a specific client |
context | SyncContext<ClientData> | Full sync context |
Basic usage
A typing indicator using broadcasts.
import { useSyncBroadcast } from '@robojs/sync'
function Chat() {
const [typingUsers, setTypingUsers] = useState<string[]>([])
const { broadcast } = useSyncBroadcast((payload, { client }) => {
if (payload.type === 'typing') {
setTypingUsers((prev) => [...new Set([...prev, client.id])])
setTimeout(() => {
setTypingUsers((prev) => prev.filter((id) => id !== client.id))
}, 2000)
}
}, ['chat', roomId])
return (
<div>
<input onKeyDown={() => broadcast({ type: 'typing' })} />
{typingUsers.length > 0 && <p>{typingUsers.length} typing...</p>}
</div>
)
}import { useSyncBroadcast } from '@robojs/sync'
function Chat() {
const [typingUsers, setTypingUsers] = useState([])
const { broadcast } = useSyncBroadcast((payload, { client }) => {
if (payload.type === 'typing') {
setTypingUsers((prev) => [...new Set([...prev, client.id])])
setTimeout(() => {
setTypingUsers((prev) => prev.filter((id) => id !== client.id))
}, 2000)
}
}, ['chat', roomId])
return (
<div>
<input onKeyDown={() => broadcast({ type: 'typing' })} />
{typingUsers.length > 0 && <p>{typingUsers.length} typing...</p>}
</div>
)
}Sending to a specific client
const { send, context } = useSyncBroadcast(handler, ['game', roomId])
// Send private message to one client
send(targetClientId, { type: 'whisper', text: 'hello' })const { send, context } = useSyncBroadcast(handler, ['game', roomId])
// Send private message to one client
send(targetClientId, { type: 'whisper', text: 'hello' })Server broadcasts
Server-side code can also send broadcasts via the Server Zone API. These arrive with client.id === '__server__'.
useSyncBroadcast((payload, { client }) => {
if (client.id === '__server__') {
console.log('Server notification:', payload)
}
}, ['game', roomId])useSyncBroadcast((payload, { client }) => {
if (client.id === '__server__') {
console.log('Server notification:', payload)
}
}, ['game', roomId])Broadcast vs state
useSyncState persists state on the server and syncs it to all clients. Late joiners get the current state.
useSyncBroadcast sends one-off messages. Late joiners miss past broadcasts. No state is stored on the server.
Use broadcasts for: reactions, typing indicators, sound triggers, cursor positions (via useSyncCursor), and notifications.
