useExtension for the latest
payload, and useChannel as a raw-events escape hatch.
The example below is a customer-support agent whose transformer redacts PII
(emails, phone numbers, SSNs, card numbers, IPs) from every event before it
reaches the browser, and publishes running redaction counts on a
redaction-stats channel. The side panel renders those counts live.
How custom channels work
A custom channel has two ends. On the server, aStreamTransformer opens a
named StreamChannel and pushes payloads onto it. On the client, a selector
subscribes to the matching custom:<name> channel and exposes the payloads as
reactive state.
The transformer’s process method runs for every protocol event. It can mutate
the event in place (here, scrubbing PII from messages, tools, and values
data) and push side-channel updates whenever it has something to report.
The client-side selectors (useExtension, useChannel) ship with the v1
frontend SDK packages (@langchain/react, @langchain/vue,
@langchain/svelte, @langchain/angular).
Stream transformers and
StreamChannel require langgraph>=1.2.Setting up useStream
Wire up useStream as usual. The custom-channel selectors take the same
stream handle returned here.
The code examples use
useStream<typeof myAgent> for type-safe stream state. See Type inference for Python or JavaScript backends.Read the latest payload with useExtension
useExtension subscribes to a custom:<name> channel and returns the most
recent payload the transformer pushed, already unwrapped and typed. It is the
ergonomic choice when the UI only needs the current value, such as a live
counter, progress percentage, or status badge.
Pass the bare channel name ("redaction-stats"), not the custom: prefix:
Ref in Vue (latest.value), and a signal in Angular
(latest()). The value is undefined until the first payload arrives.
An optional third target argument scopes the subscription to a namespace, the
same way useMessages(stream, node) scopes messages to a discovered graph node.
See Graph execution for namespace
targeting.
Buffer raw events with useChannel
useChannel is the raw-events escape hatch. It subscribes to one or more
channels and returns a bounded buffer of the underlying protocol events rather
than a single unwrapped value. Reach for it when you need history instead of the
latest value, such as an event log or audit trail, or when you need a channel
that no higher-level selector covers.
Pass the full channel id ("custom:redaction-stats"):
event.params.data. Unwrap it yourself:
| Option | Default | Effect |
|---|---|---|
bufferSize | "default" | Maximum number of buffered events. Older events drop once the cap is reached. |
replay | true | Replay events already seen on the channel when the selector mounts, instead of only live events. |
Prefer the higher-level selectors (
useExtension, useMessages,
useToolCalls, useValues) for common cases. They return typed, unwrapped
values and track only what you render. Use useChannel when you specifically
need the raw event stream.Choosing between useExtension and useChannel
Both read the same custom channel but differ in what they return:
useExtension | useChannel | |
|---|---|---|
| Returns | Latest payload (T | undefined) | Bounded buffer of raw events (Event[]) |
| Shape | Unwrapped, typed payload | Raw protocol events; unwrap event.params.data yourself |
| Subscribe by | Channel name ("redaction-stats") | Full channel id (["custom:redaction-stats"]) |
| Use when | You need the current value | You need history, a log, or multiple channels |
| Options | — | bufferSize, replay |
useExtension drives a
live summary (current totals), while useChannel backs a scrolling event log of
every update across the thread.
Use cases
Custom channels fit any server-side signal that does not map cleanly to messages, tool calls, or graph state:- Compliance and redaction stats: counts of scrubbed PII, blocked content, or policy hits, as in the example above.
- Progress reporting: percentage complete or step labels emitted by a long-running tool.
- Live metrics: token usage, latency, or cost accumulating during a run.
- Sources and citations: retrieved documents pushed to a side panel as the agent grounds its answer.
- Domain events: any structured update your backend wants to surface without changing the message transcript.
Related
- Overview — the LangGraph frontend stream API and architecture.
- Graph execution — namespace-scoped selectors for multi-node pipelines.
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

