The useRealtimeRun hook allows you to subscribe to a run by its ID.
"use client"; // This is needed for Next.js App Router or other RSC frameworksimport { useRealtimeRun } from "@trigger.dev/react-hooks";export function MyComponent({ runId, publicAccessToken,}: { runId: string; publicAccessToken: string;}) { const { run, error } = useRealtimeRun(runId, { accessToken: publicAccessToken, }); if (error) return <div>Error: {error.message}</div>; return <div>Run: {run.id}</div>;}
To correctly type the run’s payload and output, you can provide the type of your task to the useRealtimeRun hook:
import { useRealtimeRun } from "@trigger.dev/react-hooks";import type { myTask } from "@/trigger/myTask";export function MyComponent({ runId, publicAccessToken,}: { runId: string; publicAccessToken: string;}) { const { run, error } = useRealtimeRun<typeof myTask>(runId, { accessToken: publicAccessToken, }); if (error) return <div>Error: {error.message}</div>; // Now run.payload and run.output are correctly typed return <div>Run: {run.id}</div>;}
You can supply an onComplete callback to the useRealtimeRun hook to be called when the run is completed or errored. This is useful if you want to perform some action when the run is completed, like navigating to a different page or showing a notification.
The useRealtimeRunsWithTag hook allows you to subscribe to multiple runs with a specific tag.
"use client"; // This is needed for Next.js App Router or other RSC frameworksimport { useRealtimeRunsWithTag } from "@trigger.dev/react-hooks";export function MyComponent({ tag }: { tag: string }) { const { runs, error } = useRealtimeRunsWithTag(tag); if (error) return <div>Error: {error.message}</div>; return ( <div> {runs.map((run) => ( <div key={run.id}>Run: {run.id}</div> ))} </div> );}
To correctly type the runs payload and output, you can provide the type of your task to the useRealtimeRunsWithTag hook:
import { useRealtimeRunsWithTag } from "@trigger.dev/react-hooks";import type { myTask } from "@/trigger/myTask";export function MyComponent({ tag }: { tag: string }) { const { runs, error } = useRealtimeRunsWithTag<typeof myTask>(tag); if (error) return <div>Error: {error.message}</div>; // Now runs[i].payload and runs[i].output are correctly typed return ( <div> {runs.map((run) => ( <div key={run.id}>Run: {run.id}</div> ))} </div> );}
If useRealtimeRunsWithTag could return multiple different types of tasks, you can pass a union of all the task types to the hook:
import { useRealtimeRunsWithTag } from "@trigger.dev/react-hooks";import type { myTask1, myTask2 } from "@/trigger/myTasks";export function MyComponent({ tag }: { tag: string }) { const { runs, error } = useRealtimeRunsWithTag<typeof myTask1 | typeof myTask2>(tag); if (error) return <div>Error: {error.message}</div>; // You can narrow down the type of the run based on the taskIdentifier for (const run of runs) { if (run.taskIdentifier === "my-task-1") { // run is correctly typed as myTask1 } else if (run.taskIdentifier === "my-task-2") { // run is correctly typed as myTask2 } } return ( <div> {runs.map((run) => ( <div key={run.id}>Run: {run.id}</div> ))} </div> );}
The useRealtimeRunWithStreams hook allows you to subscribe to a run by its ID and also receive any streams that are emitted by the task. See our Realtime documentation for more information about emitting streams from a task.
"use client"; // This is needed for Next.js App Router or other RSC frameworksimport { useRealtimeRunWithStreams } from "@trigger.dev/react-hooks";export function MyComponent({ runId, publicAccessToken,}: { runId: string; publicAccessToken: string;}) { const { run, streams, error } = useRealtimeRunWithStreams(runId, { accessToken: publicAccessToken, }); if (error) return <div>Error: {error.message}</div>; return ( <div> <div>Run: {run.id}</div> <div> {Object.keys(streams).map((stream) => ( <div key={stream}>Stream: {stream}</div> ))} </div> </div> );}
You can provide the type of the streams to the useRealtimeRunWithStreams hook:
import { useRealtimeRunWithStreams } from "@trigger.dev/react-hooks";import type { myTask } from "@/trigger/myTask";type STREAMS = { openai: string; // this is the type of each "part" of the stream};export function MyComponent({ runId, publicAccessToken,}: { runId: string; publicAccessToken: string;}) { const { run, streams, error } = useRealtimeRunWithStreams<typeof myTask, STREAMS>(runId, { accessToken: publicAccessToken, }); if (error) return <div>Error: {error.message}</div>; const text = streams.openai?.map((part) => part).join(""); return ( <div> <div>Run: {run.id}</div> <div>{text}</div> </div> );}
As you can see above, each stream is an array of the type you provided, keyed by the stream name. If instead of a pure text stream you have a stream of objects, you can provide the type of the object:
import type { TextStreamPart } from "ai";import type { myTask } from "@/trigger/myTask";type STREAMS = { openai: TextStreamPart<{}> };export function MyComponent({ runId, publicAccessToken,}: { runId: string; publicAccessToken: string;}) { const { run, streams, error } = useRealtimeRunWithStreams<typeof myTask, STREAMS>(runId, { accessToken: publicAccessToken, }); if (error) return <div>Error: {error.message}</div>; const text = streams.openai ?.filter((stream) => stream.type === "text-delta") ?.map((part) => part.text) .join(""); return ( <div> <div>Run: {run.id}</div> <div>{text}</div> </div> );}
This allows you to change the ID of the subscription based on some state. Passing in a different ID will unsubscribe from the current subscription and subscribe to the new one (and remove any cached data).
The *withStreams variants of the Realtime hooks accept an experimental_throttleInMs option to throttle the updates from the server. This can be useful if you are getting too many updates and want to reduce the number of updates.
import { useRealtimeRunsWithStreams } from "@trigger.dev/react-hooks";export function MyComponent({ runId, publicAccessToken,}: { runId: string; publicAccessToken: string;}) { const { runs, error } = useRealtimeRunsWithStreams(tag, { accessToken: publicAccessToken, experimental_throttleInMs: 1000, // Throttle updates to once per second }); if (error) return <div>Error: {error.message}</div>; return ( <div> {runs.map((run) => ( <div key={run.id}>Run: {run.id}</div> ))} </div> );}