trigger-realtime
SkillProductivityTeaches your agent how to add realtime updates to Trigger.dev tasks and frontend apps.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the trigger-realtime skill
About this capability
How to use realtime in your Trigger.dev tasks and your frontend
What this skill tells your AI
The instructions your AI receives, as published by trycompai/comp in .agents/skills/trigger-realtime/SKILL.md and read by ahel’s review.
Source Cursor rule: .cursor/rules/trigger.realtime.mdc.
Original file scope: **/trigger/**/*.ts.
Original Cursor alwaysApply: false.
Trigger.dev Realtime (v4)
Real-time monitoring and updates for runs
Core Concepts
Realtime allows you to:
- Subscribe to run status changes, metadata updates, and streams
- Build real-time dashboards and UI updates
- Monitor task progress from frontend and backend
Authentication
Public Access Tokens
import { auth } from "@trigger.dev/sdk";
// Read-only token for specific runs
const publicToken = await auth.createPublicToken({
scopes: {
read: {
runs: ["run_123", "run_456"],
tasks: ["my-task-1", "my-task-2"],
},
},
expirationTime: "1h", // Default: 15 minutes
});
Trigger Tokens (Frontend only)
// Single-use token for triggering tasks
const triggerToken = await auth.createTriggerPublicToken("my-task", {
expirationTime: "30m",
});
Backend Usage
Subscribe to Runs
import { runs, tasks } from "@trigger.dev/sdk";
// Trigger and subscribe
const handle = await tasks.trigger("my-task", { data: "value" });
// Subscribe to specific run
for await (const run of runs.subscribeToRun<typeof myTask>(handle.id)) {
console.log(`Status: ${run.status}, Progress: ${run.metadata?.progress}`);
if (run.status === "COMPLETED") break;
}
// Subscribe to runs with tag
for await (const run of runs.subscribeToRunsWithTag("user-123")) {
console.log(`Tagged run ${run.id}: ${run.status}`);
}
// Subscribe to batch
for await (const run of runs.subscribeToBatch(batchId)) {
console.log(`Batch run ${run.id}: ${run.status}`);
}
Streams
import { task, metadata } from "@trigger.dev/sdk";
// Task that streams data
export type STREAMS = {
openai: OpenAI.ChatCompletionChunk;
};
export const streamingTask = task({
id: "streaming-task",
run: async (payload) => {
const completion = await openai.chat.completions.create({
model: "gpt-4",
messages: [{ role: "user", content: payload.prompt }],
stream: true,
});
// Register stream
const stream = await metadata.stream("openai", completion);
let text = "";
for await (const chunk of stream) {
text += chunk.choices[0]?.delta?.content || "";
}
return { text };
},
});
// Subscribe to streams
for await (const part of runs.subscribeToRun(runId).withStreams<STREAMS>()) {
switch (part.type) {
case "run":
console.log("Run update:", part.run.status);
break;
case "openai":
console.log("Stream chunk:", part.chunk);
break;
}
}
React Frontend Usage
Installation
bun add @trigger.dev/react-hooks
Triggering Tasks
"use client";
import { useTaskTrigger, useRealtimeTaskTrigger } from "@trigger.dev/react-hooks";
import type { myTask } from "../trigger/tasks";
function TriggerComponent({ accessToken }: { accessToken: string }) {
// Basic trigger
const { submit, handle, isLoading } = useTaskTrigger<typeof myTask>("my-task", {
accessToken,
});
// Trigger with realtime updates
const {
submit: realtimeSubmit,
run,
isLoading: isRealtimeLoading,
} = useRealtimeTaskTrigger<typeof myTask>("my-task", { accessToken });
return (
<div>
<button onClick={() => submit({ data: "value" })} disabled={isLoading}>
Trigger Task
</button>
<button onClick={() => realtimeSubmit({ data: "realtime" })} disabled={isRealtimeLoading}>
Trigger with Realtime
</button>
{run && <div>Status: {run.status}</div>}
</div>
);
}
Subscribing to Runs
"use client";
import { useRealtimeRun, useRealtimeRunsWithTag } from "@trigger.dev/react-hooks";
import type { myTask } from "../trigger/tasks";
function SubscribeComponent({ runId, accessToken }: { runId: string; accessToken: string }) {
// Subscribe to specific run
const { run, error } = useRealtimeRun<typeof myTask>(runId, {
accessToken,
onComplete: (run) => {
console.log("Task completed:", run.output);
},
});
// Subscribe to tagged runs
const { runs } = useRealtimeRunsWithTag("user-123", { accessToken });
if (error) return <div>Error: {error.message}</div>;
if (!run) return <div>Loading...</div>;
return (
<div>
<div>Status: {run.status}</div>
<div>Progress: {run.metadata?.progress || 0}%</div>
{run.output && <div>Result: {JSON.stringify(run.output)}</div>}
<h3>Tagged Runs:</h3>
{runs.map((r) => (
<div key={r.id}>
{r.id}: {r.status}
</div>
))}
</div>
);
}
Streams with React
"use client";
import { useRealtimeRunWithStreams } from "@trigger.dev/react-hooks";
import type { streamingTask, STREAMS } from "../trigger/tasks";
function StreamComponent({ runId, accessToken }: { runId: string; accessToken: string }) {
const { run, streams } = useRealtimeRunWithStreams<typeof streamingTask, STREAMS>(runId, {
accessToken,
});
const text = streams.openai
.filter((chunk) => chunk.choices[0]?.delta?.content)
.map((chunk) => chunk.choices[0].delta.content)
.join("");
return (
<div>
<div>Status: {run?.status}</div>
<div>Streamed Text: {text}</div>
</div>
);
}
Wait Tokens
"use client";
import { useWaitToken } from "@trigger.dev/react-hooks";
function WaitTokenComponent({ tokenId, accessToken }: { tokenId: string; accessToken: string }) {
const { complete } = useWaitToken(tokenId, { accessToken });
return <button onClick={() => complete({ approved: true })}>Approve Task</button>;
}
SWR Hooks (Fetch Once)
"use client";
import { useRun } from "@trigger.dev/react-hooks";
import type { myTask } from "../trigger/tasks";
function SWRComponent({ runId, accessToken }: { runId: string; accessToken: string }) {
const { run, error, isLoading } = useRun<typeof myTask>(runId, {
accessToken,
refreshInterval: 0, // Disable polling (recommended)
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>Run: {run?.status}</div>;
}
Run Object Properties
Key properties available in run subscriptions:
id: Unique run identifierstatus:QUEUED,EXECUTING,COMPLETED,FAILED,CANCELED, etc.payload: Task input data (typed)output: Task result (typed, when completed)metadata: Real-time updatable datacreatedAt,updatedAt: TimestampscostInCents: Execution cost
Best Practices
- Use Realtime over SWR: Recommended for most use cases due to rate limits
- Scope tokens properly: Only grant necessary read/trigger permissions
- Handle errors: Always check for errors in hooks and subscriptions
- Type safety: Use task types for proper payload/output typing
- Cleanup subscriptions: Backend subscriptions auto-complete, frontend hooks auto-cleanup
Signals
- GitHub stars
- 2k
- Forks
- 412
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
trigger-realtime- Source
- github.com/trycompai/comp