Add streaming to your app
Connect your application server and browser to the same Cereal session.
Build these three pieces in order. The chat tutorial contains complete working source for all of them.
The token exchange
Your application authenticates the customer and authorizes access to the requested
session. It then calls sessions.streamToken with a server credential holding data
scope and returns the result with Cache-Control: no-store.
The token is short-lived, read-only, and scoped to one session. Pin its format to the consumer you use. Keep your Cereal API key on the server.
In the page
Use subscribe from @trycereal/sdk/browser with an explicit format and a tokenSource
function that calls your token endpoint. The helper asks for a new token on expiry and
reconnects using its last cursor. Close the subscription when the view is disposed.
Render durable messages once per sequence number. On a fresh page load, either restore the transcript and its cursor together or replay from the beginning. Saving only a cursor leaves the earlier conversation invisible.
Sending messages and answering approvals
Both actions go to your application server. Authorize customer ownership again before
calling sessions.send or sessions.decide. The browser stream token cannot write.
Use stable idempotency keys for retried messages and handle stale approval decisions.
The three formats
Use cereal for client-safe events, ai-sdk for AI SDK chunks, and ag-ui for AG-UI
consumers. The browser reference owns the helper options and adapters;
streaming protocol owns wire frames, credentials, and cursors.
Resume
A connection's durable event IDs let it resume. Ephemeral deltas are not a durable history. See protocol resume and the recovery exercises.
Server-side
client.sessions.stream(id, options) first mints a token and reads SSE. It requires
data scope and yields projected events; it is not a raw RPC event stream. Unlike the
browser subscriber, it consumes one connection and does not automatically reconnect.
See client streaming.