Realtime
Subscribe to run status changes and stream data from tasks to your frontend in real-time using SSE (Server-Sent Events).
Overview
Trigger.dev Realtime enables:
- Live run status subscriptions
- Streaming output from AI models
- Progress updates with metadata
- Multi-run monitoring
React Hooks
Install the React hooks package:
bash
npm i @trigger.dev/react-hooksuseRealtimeRun
Subscribe to a single run's status and output:
tsx
"use client";
import { useRealtimeRun } from "@trigger.dev/react-hooks";
import type { myTask } from "@/trigger/my-task";
export function RunStatus({ runId, accessToken }: { runId: string; accessToken: string }) {
const { run, error } = useRealtimeRun<typeof myTask>(runId, {
accessToken,
onComplete: (run) => console.log("Done!", run.output),
});
if (error) return <div>Error: {error.message}</div>;
if (!run) return <div>Loading...</div>;
return (
<div>
<p>Status: {run.status}</p>
{run.output && <p>Output: {JSON.stringify(run.output)}</p>}
</div>
);
}useRealtimeRunsWithTag
Subscribe to all runs matching a tag:
tsx
import { useRealtimeRunsWithTag } from "@trigger.dev/react-hooks";
export function UserRuns({ userId, accessToken }: { userId: string; accessToken: string }) {
const { runs } = useRealtimeRunsWithTag(`user_${userId}`, {
accessToken,
});
return (
<ul>
{runs?.map(run => (
<li key={run.id}>{run.status}</li>
))}
</ul>
);
}useRealtimeBatch
Monitor all runs in a batch:
tsx
import { useRealtimeBatch } from "@trigger.dev/react-hooks";
export function BatchProgress({ batchId, accessToken }: { batchId: string; accessToken: string }) {
const { runs } = useRealtimeBatch(batchId, { accessToken });
const completed = runs?.filter(r => r.isCompleted).length ?? 0;
const total = runs?.length ?? 0;
return <div>{completed}/{total} complete</div>;
}useRealtimeStream
Subscribe to a typed stream from a task:
tsx
import { useRealtimeStream } from "@trigger.dev/react-hooks";
import { aiStream } from "@/app/streams";
export function AIOutput({ runId, accessToken }: { runId: string; accessToken: string }) {
const { parts, error } = useRealtimeStream(aiStream, runId, {
accessToken,
timeoutInSeconds: 600,
throttleInMs: 50, // limit re-renders
});
return (
<div>
{parts?.map((part, i) => <span key={i}>{part}</span>)}
</div>
);
}Backend Subscriptions
Use the SDK directly without React hooks:
ts
import { runs } from "@trigger.dev/sdk";
// Subscribe to a single run
for await (const run of runs.subscribeToRun(runId)) {
console.log(run.status, run.output);
if (run.isCompleted) break;
}
// Subscribe to runs by tag
for await (const run of runs.subscribeToRunsWithTag("user_123")) {
console.log(run.id, run.status);
}Access Tokens (Public)
Generate short-lived public access tokens for frontend clients — never expose your secret key:
ts
import { auth } from "@trigger.dev/sdk";
// In a server action or API route:
const publicToken = await auth.createPublicToken({
scopes: {
read: {
runs: [runId], // limit to specific runs
},
},
expirationTime: "1h",
});
// Pass token to client
return { accessToken: publicToken };Connection Limits
| Tier | Concurrent connections |
|---|---|
| Free | 10 |
| Hobby | 50 |
| Pro | 500+ |
Extra: $10/month per 100 concurrent connections.
See Also
- Realtime Streams — streaming typed data from tasks
- Run Metadata — attach structured data to runs