22name : realtime-and-frontend
33description : >
44 Trigger.dev client/frontend surface: subscribe to runs in realtime
5- (runs.subscribeToRun and the @trigger.dev/react-hooks hooks useRealtimeRun,
6- useRealtimeRunsWithTag, useRealtimeBatch), consume metadata and AI/text
7- streams in React (useRealtimeStream ), trigger tasks from the browser
8- (useTaskTrigger, useRealtimeTaskTrigger), and mint scoped frontend
9- credentials with auth.createPublicToken / auth.createTriggerPublicToken.
5+ (runs.subscribeToRun and the @trigger.dev/react-hooks hook useRealtimeRun) ,
6+ consume metadata and AI/text streams in React (useRealtimeStream), trigger
7+ tasks from the browser (useTaskTrigger, useRealtimeTaskTrigger ), and mint
8+ scoped frontend credentials with auth.createPublicToken /
9+ auth.createTriggerPublicToken.
1010 Load when wiring a frontend (React/Next.js/Remix) or backend-for-frontend to
1111 show live run progress, status badges, token streams, trigger buttons, or
1212 wait-token approval UIs. NOT for writing the backend task itself (streams.define
@@ -108,27 +108,9 @@ const { run } = useRealtimeRun(runId, {
108108You can skip any of: ` payload ` , ` output ` , ` metadata ` , ` startedAt ` , ` delayUntil ` ,
109109` queuedAt ` , ` expiredAt ` , ` completedAt ` , ` number ` , ` isTest ` , ` usageDurationMs ` ,
110110` costInCents ` , ` baseCostInCents ` , ` ttl ` , ` payloadType ` , ` outputType ` , ` runTags ` ,
111- ` error ` . ` useRealtimeRunsWithTag ` accepts ` skipColumns ` too.
111+ ` error ` .
112112
113- ### 3. Subscribe to many runs by tag or batch
114-
115- ``` tsx
116- " use client" ;
117- import { useRealtimeRunsWithTag } from " @trigger.dev/react-hooks" ;
118- import type { myTask } from " @/trigger/myTask" ;
119-
120- export function TaggedRuns({ tag }: { tag: string }) {
121- const { runs, error } = useRealtimeRunsWithTag <typeof myTask >(tag );
122- if (error ) return <div >Error: { error .message } </div >;
123- return <div >{ runs .map ((run ) => <div key = { run .id } >{ run .status } </div >)} </div >;
124- }
125- ```
126-
127- ` useRealtimeBatch(batchId) ` works the same way for a batch. Pass a union
128- (` <typeof taskA | typeof taskB> ` ) and narrow on ` run.taskIdentifier ` when a tag
129- spans multiple task types.
130-
131- ### 4. Trigger from the browser with a Trigger Token
113+ ### 3. Trigger from the browser with a Trigger Token
132114
133115` accessToken ` here is a Trigger Token (` auth.createTriggerPublicToken ` ), not a
134116Public Access Token.
@@ -153,7 +135,7 @@ export function TriggerButton({ publicAccessToken }: { publicAccessToken: string
153135
154136` submit(payload, options?) ` takes the same options as a backend ` trigger ` call.
155137
156- ### 5 . Trigger and subscribe in one hook
138+ ### 4 . Trigger and subscribe in one hook
157139
158140``` tsx
159141" use client" ;
@@ -172,7 +154,7 @@ export function Runner({ publicAccessToken }: { publicAccessToken: string }) {
172154Use ` useRealtimeTaskTriggerWithStreams<typeof myTask, STREAMS> ` when you also
173155want the task's streams (it returns ` { submit, run, streams, error, isLoading } ` ).
174156
175- ### 6 . Consume an AI/text stream (SDK 4.1.0+, recommended)
157+ ### 5 . Consume an AI/text stream (SDK 4.1.0+, recommended)
176158
177159` useRealtimeStream ` takes a defined stream for full type safety, or a ` runId `
178160plus optional stream key. Returns ` { parts, error } ` .
@@ -199,7 +181,7 @@ or omit the key to use the default stream. Other options: `baseURL`, `startIndex
199181` throttleInMs ` (default 16). The legacy ` useRealtimeRunWithStreams(runId, options) `
200182hook is still supported when you need both the run and all its streams at once.
201183
202- ### 7 . Send input back into a running task
184+ ### 6 . Send input back into a running task
203185
204186``` tsx
205187" use client" ;
@@ -216,7 +198,7 @@ export function ApprovalForm({ runId, accessToken }: { runId: string; accessToke
216198}
217199```
218200
219- ### 8 . Complete a wait token from React
201+ ### 7 . Complete a wait token from React
220202
221203``` ts
222204// backend: create the token, return id + publicAccessToken to the frontend
@@ -235,7 +217,7 @@ export function Approve({ tokenId, publicToken }: { tokenId: string; publicToken
235217}
236218```
237219
238- ### 9 . Subscribe from the backend (async iterators)
220+ ### 8 . Subscribe from the backend (async iterators)
239221
240222``` ts
241223import { runs , tasks } from " @trigger.dev/sdk" ;
@@ -247,8 +229,7 @@ for await (const run of runs.subscribeToRun<typeof myTask>(handle.id)) {
247229}
248230```
249231
250- ` runs.subscribeToRun ` completes when the run finishes. ` runs.subscribeToRunsWithTag `
251- and ` runs.subscribeToBatch ` never complete on their own; you must ` break ` .
232+ ` runs.subscribeToRun ` completes when the run finishes, so the loop exits on its own.
252233
253234## Common mistakes
254235
@@ -267,19 +248,15 @@ and `runs.subscribeToBatch` never complete on their own; you must `break`.
267248 - Wrong: ` useRun(runId, { refreshInterval: 1000 }) ` to track progress
268249 - Correct: ` useRealtimeRun(runId, { accessToken }) ` (no polling, no WebSocket setup)
269250
270- 4 . ** Infinite tag/batch loops that never break.**
271- - Wrong: ` for await (const run of runs.subscribeToRunsWithTag("user:1234")) { ... } ` with no exit (hangs forever)
272- - Correct: ` break ` once you have seen what you need. Only ` subscribeToRun ` auto-completes.
273-
274- 5 . ** Forgetting ` "use client" ` .** Realtime/trigger hooks cannot run in a server component.
251+ 4 . ** Forgetting ` "use client" ` .** Realtime/trigger hooks cannot run in a server component.
275252 - Wrong: a Next.js App Router server component using ` useRealtimeRun `
276253 - Correct: put ` "use client"; ` at the top of any component using these hooks.
277254
278- 6 . ** Shipping ` payload ` /` output ` you do not render.**
255+ 5 . ** Shipping ` payload ` /` output ` you do not render.**
279256 - Wrong: ` useRealtimeRun(runId, { accessToken }) ` for a status badge (large payloads over the wire)
280257 - Correct: ` useRealtimeRun(runId, { accessToken, skipColumns: ["payload", "output"] }) `
281258
282- 7 . ** Subscribing before the handle exists.**
259+ 6 . ** Subscribing before the handle exists.**
283260 - Wrong: ` useRealtimeRun(handle, { accessToken: handle?.publicAccessToken }) ` with no guard
284261 - Correct: add ` enabled: !!handle ` so it subscribes only once the trigger returns a handle.
285262
0 commit comments