mcpbeat Sign in

Trigger Realtime And Frontend Agent Skill

> (runs.subscribeToRun and the @trigger.dev/react-hooks hook useRealtimeRun), consume metadata and AI/text streams in React (useRealtimeStream), trigger tasks from the browser (useTaskTrigger, useRealtimeTaskTrigger), and mint scoped frontend credentials with auth.createPublicToken / auth.createTriggerPublicToken. Load when wiring a frontend (React/Next.js/Remix) or backend-for-frontend to show live run progress, status badges, token streams, trigger buttons, or wait-token approval UIs. NOT for writing the backend task itself (streams.define / metadata.set is trigger-authoring-tasks territory); this is the consumer side.

3k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
15884
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/triggerdotdev/trigger.dev --skill trigger-realtime-and-frontend

The instruction itself

14 sections, as written by the author

Realtime and Frontend

The consumer side of Trigger.dev's run state and streams: read live run

updates, render AI/text streams, and trigger tasks from a browser. Hooks come

from @trigger.dev/react-hooks; token minting and backend subscription come

from @trigger.dev/sdk.

Setup

npm add @trigger.dev/react-hooks   # frontend hooks (React/Next.js/Remix)
# @trigger.dev/sdk is already installed for the backend

The flow is always: mint a scoped token in the backend, pass it to the

frontend, subscribe with a hook.

// backend (API route / server action)
import { auth } from "@trigger.dev/sdk";

const publicAccessToken = await auth.createPublicToken({
  scopes: { read: { runs: ["run_1234"] } }, // a token with no scopes is useless
});
// frontend
"use client";
import { useRealtimeRun } from "@trigger.dev/react-hooks";

export function RunStatus({ runId, publicAccessToken }: { runId: string; publicAccessToken: string }) {
  const { run, error } = useRealtimeRun(runId, { accessToken: publicAccessToken });
  if (error) return <div>Error: {error.message}</div>;
  if (!run) return <div>Loading...</div>;
  return <div>Run: {run.status}</div>;
}

There are two token kinds: Public Access Tokens (read/subscribe, from

auth.createPublicToken) and Trigger Tokens (trigger-from-browser, single-use,

from auth.createTriggerPublicToken). Both default to a 15 minute expiry.

Core patterns

1. Subscribe to a run and render metadata progress

metadata is Record<string, DeserializedJson>, so nested values need a cast.

"use client";
import { useRealtimeRun } from "@trigger.dev/react-hooks";
import type { myTask } from "@/trigger/myTask";

export function Progress({ runId, publicAccessToken }: { runId: string; publicAccessToken: string }) {
  const { run, error } = useRealtimeRun<typeof myTask>(runId, { accessToken: publicAccessToken });
  if (error) return <div>Error: {error.message}</div>;
  if (!run) return <div>Loading...</div>;
  const progress = run.metadata?.progress as { percentage?: number } | undefined;
  return <div>{run.status}: {progress?.percentage ?? 0}%</div>;
}

Pass onComplete: (run, error) => {} to react when the run finishes.

2. Status-only subscription with skipColumns

For a badge or progress bar you do not need payload/output. Skipping them

reduces wire size and avoids "Large HTTP Payload" warnings.

const { run } = useRealtimeRun(runId, {
  accessToken: publicAccessToken,
  skipColumns: ["payload", "output"],
});

You can skip any of: payload, output, metadata, startedAt, delayUntil,

queuedAt, expiredAt, completedAt, number, isTest, usageDurationMs,

costInCents, baseCostInCents, ttl, payloadType, outputType, runTags,

error.

3. Trigger from the browser with a Trigger Token

accessToken here is a Trigger Token (auth.createTriggerPublicToken), not a

Public Access Token.

"use client";
import { useTaskTrigger } from "@trigger.dev/react-hooks";
import type { myTask } from "@/trigger/myTask";

export function TriggerButton({ triggerToken }: { triggerToken: string }) {
  const { submit, handle, isLoading } = useTaskTrigger<typeof myTask>("my-task", {
    accessToken: triggerToken,
  });
  if (handle) return <div>Run ID: {handle.id}</div>;
  return (
    <button onClick={() => submit({ foo: "bar" }, { tags: ["user:123"] })} disabled={isLoading}>
      {isLoading ? "Triggering..." : "Run"}
    </button>
  );
}

submit(payload, options?) takes the same options as a backend trigger call.

4. Trigger and subscribe in one hook

"use client";
import { useRealtimeTaskTrigger } from "@trigger.dev/react-hooks";
import type { myTask } from "@/trigger/myTask";

export function Runner({ publicAccessToken }: { publicAccessToken: string }) {
  const { submit, run, isLoading } = useRealtimeTaskTrigger<typeof myTask>("my-task", {
    accessToken: publicAccessToken,
  });
  if (run) return <div>{run.status}</div>;
  return <button onClick={() => submit({ foo: "bar" })} disabled={isLoading}>Run</button>;
}

Use useRealtimeTaskTriggerWithStreams<typeof myTask, STREAMS> when you also

want the task's streams (it returns { submit, run, streams, error, isLoading }).

useRealtimeStream takes a defined stream for full type safety, or a runId

plus optional stream key. Returns { parts, error }.

"use client";
import { useRealtimeStream } from "@trigger.dev/react-hooks";
import { aiStream } from "@/trigger/streams"; // a defined stream -> typed parts

export function StreamView({ runId, publicAccessToken }: { runId: string; publicAccessToken: string }) {
  const { parts, error } = useRealtimeStream(aiStream, runId, {
    accessToken: publicAccessToken,
    timeoutInSeconds: 300, // default 60
    onData: (chunk) => console.log(chunk),
  });
  if (error) return <div>Error: {error.message}</div>;
  if (!parts) return <div>Loading...</div>;
  return <div>{parts.join("")}</div>;
}

Without a defined stream: useRealtimeStream<string>(runId, "ai-output", { accessToken }),

or omit the key to use the default stream. Other options: baseURL, startIndex,

throttleInMs (default 16). The legacy useRealtimeRunWithStreams(runId, options)

hook is still supported when you need both the run and all its streams at once.

6. Send input back into a running task

"use client";
import { useInputStreamSend } from "@trigger.dev/react-hooks";
import { approval } from "@/trigger/streams";

export function ApprovalForm({ runId, accessToken }: { runId: string; accessToken: string }) {
  const { send, isLoading, isReady } = useInputStreamSend(approval.id, runId, { accessToken });
  return (
    <button disabled={!isReady || isLoading} onClick={() => send({ approved: true })}>
      Approve
    </button>
  );
}

7. Complete a wait token from React

// backend: create the token, return id + publicAccessToken to the frontend
import { wait } from "@trigger.dev/sdk";
const token = await wait.createToken({ timeout: "10m" });
return { tokenId: token.id, publicToken: token.publicAccessToken };
"use client";
import { useWaitToken } from "@trigger.dev/react-hooks";

export function Approve({ tokenId, publicToken }: { tokenId: string; publicToken: string }) {
  const { complete } = useWaitToken(tokenId, { accessToken: publicToken });
  return <button onClick={() => complete({ approved: true })}>Approve</button>;
}

8. Subscribe from the backend (async iterators)

import { runs, tasks } from "@trigger.dev/sdk";
import type { myTask } from "./trigger/my-task";

const handle = await tasks.trigger("my-task", { some: "data" });
for await (const run of runs.subscribeToRun<typeof myTask>(handle.id)) {
  console.log(run.payload.some, run.output?.some); // typed
}

runs.subscribeToRun completes when the run finishes, so the loop exits on its own.

Common mistakes

  • CRITICAL: Triggering from the browser with a Public Access Token. The

read token from createPublicToken cannot trigger tasks.

  • Wrong: useTaskTrigger("my-task", { accessToken: publicAccessTokenFromCreatePublicToken })
  • Correct: mint a single-use Trigger Token with auth.createTriggerPublicToken("my-task") and pass that.
  • Token with no scopes. A scopeless token authorizes nothing, so every subscribe 403s.
  • Wrong: await auth.createPublicToken()
  • Correct: await auth.createPublicToken({ scopes: { read: { runs: ["run_1234"] } } })
  • Polling with useRun/SWR for live updates. useRun is the SWR-based

management-API hook (not recommended for live state); set refreshInterval: 0

to stop polling if you do use it.

  • Wrong: useRun(runId, { refreshInterval: 1000 }) to track progress
  • Correct: useRealtimeRun(runId, { accessToken }) (no polling, no WebSocket setup)
  • Forgetting "use client". Realtime/trigger hooks cannot run in a server component.
  • Wrong: a Next.js App Router server component using useRealtimeRun
  • Correct: put "use client"; at the top of any component using these hooks.
  • Shipping payload/output you do not render.
  • Wrong: useRealtimeRun(runId, { accessToken }) for a status badge (large payloads over the wire)
  • Correct: useRealtimeRun(runId, { accessToken, skipColumns: ["payload", "output"] })
  • Subscribing before the handle exists.
  • Wrong: useRealtimeRun(handle, { accessToken: handle?.publicAccessToken }) with no guard
  • Correct: add enabled: !!handle so it subscribes only once the trigger returns a handle.

References

Sibling skills:

  • trigger-authoring-tasks for the task side: streams.define(), metadata.set(), and wait.createToken.
  • trigger-authoring-chat-agent and trigger-chat-agent-advanced for chat agents, which build on these realtime streams.

Reference docs ship beside this skill in the same package, read them locally (no network), pinned to your installed version. The sources: frontmatter above lists every doc this skill draws from, all under @trigger.dev/sdk/docs/. Start with:

  • @trigger.dev/sdk/docs/realtime/react-hooks/subscribe.mdx
  • @trigger.dev/sdk/docs/realtime/react-hooks/streams.mdx
  • @trigger.dev/sdk/docs/realtime/auth.mdx
  • @trigger.dev/sdk/docs/realtime/run-object.mdx (the realtime run object differs from the management-API object returned by useRun)

Version

This skill is bundled inside @trigger.dev/sdk and read directly from node_modules, so it always matches your installed SDK version (see the adjacent package.json). The full documentation for these APIs ships alongside it under @trigger.dev/sdk/docs/.

Other skills for the same job

different authors, same section of the catalogue
MCP Builder
by anthropics
vendor ×13

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

30k tokens scripts
Changelog Generator
by frostant
×9

Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.

774 tokens
Finishing A Development Branch
by ZhanlinCui
×7

Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup

1k tokens
MCP Builder
by JayZeeDesign
×7

Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).

37k tokens scripts
Vercel React Native Skills
by vercel-labs
vendor ×6

React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.

39k tokens
Vercel React Best Practices
by ratacat
×5

React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

34k tokens
Next Best Practices
by vercel-labs
vendor ×4

Next.js best practices - file conventions, RSC boundaries, data patterns, async APIs, metadata, error handling, route handlers, image/font optimization, bundling

20k tokens
Using Git Worktrees
by ZhanlinCui
×4

Use when starting feature work that needs isolation from current workspace or before executing implementation plans - creates isolated git worktrees with smart directory selection and safety verification

1k tokens

How to use it

Copy the folder

Take triggerdotdev/trigger.dev-trigger-realtime-and-frontend from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.