--- title: Streams hooks sidebarTitle: Streams description: Subscribe to real-time streams from your tasks in React components --- These hooks allow you to consume real-time streams from your tasks. Streams are useful for displaying AI/LLM outputs as they're generated, or any other real-time data from your tasks. To learn how to emit streams from your tasks, see our [Realtime Streams](/tasks/streams) documentation. ## useRealtimeStream (Recommended) Available in SDK version **4.1.0 or later**. This is the recommended way to consume streams in your React components. The `useRealtimeStream` hook allows you to subscribe to a specific stream by its run ID and stream key. This hook is designed to work seamlessly with [defined streams](/tasks/streams#defining-typed-streams-recommended) for full type safety. ### Basic Usage ```tsx "use client"; import { useRealtimeStream } from "@trigger.dev/react-hooks"; export function StreamViewer({ runId, publicAccessToken, }: { runId: string; publicAccessToken: string; }) { const { parts, error } = useRealtimeStream(runId, "ai-output", { accessToken: publicAccessToken, }); if (error) return
Error: {error.message}
; if (!parts) return
Loading...
; return (
{parts.map((part, i) => ( {part} ))}
); } ``` ### With Defined Streams The recommended approach is to use defined streams for full type safety: ```tsx "use client"; import { useRealtimeStream } from "@trigger.dev/react-hooks"; import { aiStream } from "@/app/streams"; export function StreamViewer({ runId, publicAccessToken, }: { runId: string; publicAccessToken: string; }) { // Pass the defined stream directly - full type safety! const { parts, error } = useRealtimeStream(aiStream, runId, { accessToken: publicAccessToken, timeoutInSeconds: 600, onData: (chunk) => { console.log("New chunk:", chunk); // chunk is typed! }, }); if (error) return
Error: {error.message}
; if (!parts) return
Loading...
; return (
{parts.map((part, i) => ( {part} ))}
); } ``` ### Streaming AI Responses Here's a complete example showing how to display streaming AI responses: ```tsx "use client"; import { useRealtimeStream } from "@trigger.dev/react-hooks"; import { aiStream } from "@/trigger/streams"; import { Streamdown } from "streamdown"; export function AIStreamViewer({ runId, publicAccessToken, }: { runId: string; publicAccessToken: string; }) { const { parts, error } = useRealtimeStream(aiStream, runId, { accessToken: publicAccessToken, timeoutInSeconds: 300, }); if (error) return
Error: {error.message}
; if (!parts) return
Loading stream...
; const text = parts.join(""); return (
{text}
); } ``` ### Options The `useRealtimeStream` hook accepts the following options: ```tsx const { parts, error } = useRealtimeStream(streamOrRunId, streamKeyOrOptions, { accessToken: "pk_...", // Required: Public access token baseURL: "https://api.trigger.dev", // Optional: Custom API URL timeoutInSeconds: 60, // Optional: Timeout (default: 60) startIndex: 0, // Optional: Start from specific chunk throttleInMs: 16, // Optional: Throttle updates (default: 16ms) onData: (chunk) => {}, // Optional: Callback for each chunk }); ``` ### Using Default Stream You can omit the stream key to use the default stream: ```tsx const { parts, error } = useRealtimeStream(runId, { accessToken: publicAccessToken, }); ``` For more information on defining and using streams, see the [Realtime Streams v2](/tasks/streams) documentation. ## useRealtimeRunWithStreams For new projects, we recommend using `useRealtimeStream` instead (available in SDK 4.1.0+). This hook is still supported for backward compatibility and use cases where you need to subscribe to both the run and all its streams at once. The `useRealtimeRunWithStreams` hook allows you to subscribe to a run by its ID and also receive any streams that are emitted by the task. This is useful when you need to access both the run metadata and multiple streams simultaneously. ```tsx "use client"; // This is needed for Next.js App Router or other RSC frameworks import { 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
Error: {error.message}
; return (
Run: {run.id}
{Object.keys(streams).map((stream) => (
Stream: {stream}
))}
); } ``` You can also provide the type of the streams to the `useRealtimeRunWithStreams` hook to get type-safety: ```tsx 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(runId, { accessToken: publicAccessToken, }); if (error) return
Error: {error.message}
; const text = streams.openai?.map((part) => part).join(""); return (
Run: {run.id}
{text}
); } ``` 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: ```tsx 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(runId, { accessToken: publicAccessToken, }); if (error) return
Error: {error.message}
; const text = streams.openai ?.filter((stream) => stream.type === "text-delta") ?.map((part) => part.text) .join(""); return (
Run: {run.id}
{text}
); } ``` ### Streaming AI responses with useRealtimeRunWithStreams Here's an example showing how to display streaming OpenAI responses using `useRealtimeRunWithStreams`: ```tsx import { useRealtimeRunWithStreams } from "@trigger.dev/react-hooks"; import type { aiStreaming, STREAMS } from "./trigger/ai-streaming"; function MyComponent({ runId, publicAccessToken }: { runId: string; publicAccessToken: string }) { const { streams } = useRealtimeRunWithStreams(runId, { accessToken: publicAccessToken, }); if (!streams.openai) { return
Loading...
; } const text = streams.openai.join(""); // `streams.openai` is an array of strings return (

OpenAI response:

{text}

); } ``` ### AI SDK with tools When using the AI SDK with tools with `useRealtimeRunWithStreams`, you can access tool calls and results: ```tsx import { useRealtimeRunWithStreams } from "@trigger.dev/react-hooks"; import type { aiStreamingWithTools, STREAMS } from "./trigger/ai-streaming"; function MyComponent({ runId, publicAccessToken }: { runId: string; publicAccessToken: string }) { const { streams } = useRealtimeRunWithStreams(runId, { accessToken: publicAccessToken, }); if (!streams.openai) { return
Loading...
; } // streams.openai is an array of TextStreamPart const toolCall = streams.openai.find( (stream) => stream.type === "tool-call" && stream.toolName === "getWeather" ); const toolResult = streams.openai.find((stream) => stream.type === "tool-result"); const textDeltas = streams.openai.filter((stream) => stream.type === "text-delta"); const text = textDeltas.map((delta) => delta.textDelta).join(""); const weatherLocation = toolCall ? toolCall.args.location : undefined; const weather = toolResult ? toolResult.result.temperature : undefined; return (

OpenAI response:

{text}

Weather:

{weatherLocation ? `The weather in ${weatherLocation} is ${weather} degrees.` : "No weather data"}

); } ``` ### Throttling updates The `useRealtimeRunWithStreams` hook accepts 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. ```tsx import { useRealtimeRunWithStreams } from "@trigger.dev/react-hooks"; export function MyComponent({ runId, publicAccessToken, }: { runId: string; publicAccessToken: string; }) { const { run, streams, error } = useRealtimeRunWithStreams(runId, { accessToken: publicAccessToken, experimental_throttleInMs: 1000, // Throttle updates to once per second }); if (error) return
Error: {error.message}
; return (
Run: {run.id}
{/* Display streams */}
); } ``` All other options (accessToken, baseURL, enabled, id) work the same as the other realtime hooks. For the newer `useRealtimeStream` hook, use the `throttleInMs` option instead (see [options above](#options)).