Realtime

WebSocket events, presence & ACK

usePubSub is the client half of the pub/sub feature. It opens a single WebSocket to the events endpoint, subscribes to the topics you name, and streams server events into an h-state store you read reactively — connection status, the event log and presence all live there.

It is resilient by default: a heartbeat keeps the socket warm, drops trigger exponential-backoff reconnection, and every delivered message is acknowledged back to the server so the ACK/redelivery guarantees on the backend actually hold.

Configure it on the backend through the pubsub config block; consume it on the frontend with this one hook. No manual socket lifecycle, no reconnection loops to write.

Hook configuration#

usePubSub(config) takes the identity and topics to subscribe to, plus optional resilience tuning. userId is required — it scopes the connection and is enforced by the maxClientsPerUser guard on the server.

userIdstringRequired

The authenticated user the socket belongs to. Sent as a query param and used server-side for per-user client limits and targeted delivery.

topicsstring[]Optional

Topics to subscribe to on connect. Changing this array re-subscribes automatically. '*' receives everything you're permitted to see.

Example: ["orders", "notifications:user-42"]

Default["*"]
wsUrlstringOptional

Override the WebSocket origin. When omitted the hook derives ws://wss:// from window.location, so same-origin deployments need no URL at all.

wsPathstringOptional

The subscribe path — must match the pubsub.wsPath configured on the backend.

Default"/api/events/subscribe"
autoReconnectbooleanOptional

Reconnect automatically after an unexpected close. A clean server close (code 4001) is respected and does not retry.

Defaulttrue
maxReconnectAttemptsnumberOptional

How many backoff attempts before giving up and surfacing an error on the store.

Default10
reconnectBaseDelaynumberOptional

Base delay in ms for exponential backoff (base · 2^attempt), capped by reconnectMaxDelay.

Default1000
reconnectMaxDelaynumberOptional

Upper bound in ms on any single reconnect delay.

Default30000
heartbeatIntervalnumberOptional

How often (ms) to send a ping frame so proxies and the server keep the socket alive.

Default30000
debugbooleanOptional

Log connection lifecycle and message handling to the console.

Defaultfalse

What the hook returns#

Everything you need to render realtime UI: live connection flags, the typed event list, presence/identity and imperative controls. Reads are reactive — when a new event arrives, components re-render.

components/LiveOrders.tsx
1const { isConnected, events, subscribe } = usePubSub({2  userId: user.id,3  topics: ["orders"],4});5 6// ACK is automatic — every event with a messageId is acknowledged7return (8  <section>9    <span data-live={isConnected}>{isConnected ? "live" : "offline"}</span>10    {events.map((e) => (11      <Event key={e.id} topic={e.topic} payload={e.data} />12    ))}13  </section>14);
isConnected / isConnectingbooleanOptional

Connection status flags. isConnecting covers both initial connect and reconnect attempts so you can show one 'linking…' state.

eventsPubSubEvent[]Optional

The received events (id, topic, data, timestamp, receivedAt, messageId, isRedelivery), capped by the store's ring buffer so memory stays bounded.

clientId / subscribedTopicsstring | string[]Optional

The server-assigned client id and the topics the server confirms you're subscribed to.

error / reconnectAttemptError | numberOptional

The last connection error (or null) and the current backoff attempt count for diagnostics UI.

subscribe / unsubscribe(topics: string[]) => voidOptional

Adjust subscriptions on a live socket without reconnecting.

connect / disconnect / clearEvents / getEventsByTopicfunctionsOptional

Imperative controls: force a (re)connect, tear down cleanly, empty the buffer, or read just one topic's events.

Related sections