name: temporal-ts-enriching-ui version: 1.0.0 description: > Use when adding metadata (summaries, details) to Temporal Workflows, Activities, or Timers in TypeScript to enrich the Temporal Web UI. Covers staticSummary, staticDetails, setCurrentDetails, activity executeWithOptions, and timer summary options. Applies to any project using @temporalio/client or @temporalio/workflow.
Temporal TypeScript SDK -- Enriching the UI
Temporal lets you attach human-readable metadata to Workflows, Activities, and Timers. This metadata appears in the Temporal Web UI, making it easier to identify and understand what each Workflow is doing without inspecting payloads.
There are three distinct mechanisms:
| Mechanism | Where Set | Mutability | Scope |
|---|---|---|---|
staticSummary |
Client, at Workflow start | Immutable after start | Workflow list view |
staticDetails |
Client, at Workflow start | Immutable after start | Workflow detail view |
setCurrentDetails() |
Inside Workflow code | Updatable at any time | Workflow detail view |
Activity staticSummary |
Inside Workflow, via executeWithOptions |
Immutable per invocation | Event history |
Timer summary |
Inside Workflow, via sleep options |
Immutable per invocation | Event history |
When to Use
- You want Workflow list views to show a short description instead of just a Workflow ID.
- You want the detail page to show context about the Workflow's current state.
- You want Activity and Timer events in the history to be self-documenting.
- You are building an operator dashboard or need better observability for non-engineers.
How to Use
Environment Context Gathering
Before implementing, determine the user's Temporal setup:
- Where is Temporal running? (local dev server via
temporal server start-dev, self-hosted cluster, or Temporal Cloud) - What is the full Temporal UI URL? Default local:
http://localhost:8233. If not local, get the full URL. - Is ingress configured for the Temporal HTTP API? This matters for Temporal Cloud or Kubernetes-hosted clusters where the HTTP API endpoint may differ from the gRPC endpoint.
These answers affect how the user views the enriched UI metadata after implementation.
Quick Reference
| API | Import | Limit |
|---|---|---|
staticSummary |
@temporalio/client (on WorkflowStartOptions) |
200 bytes |
staticDetails |
@temporalio/client (on WorkflowStartOptions) |
20,000 bytes |
getCurrentDetails() |
@temporalio/workflow |
-- |
setCurrentDetails(value) |
@temporalio/workflow |
20,000 bytes |
activity.executeWithOptions({ staticSummary }, args) |
@temporalio/workflow (on proxy) |
200 bytes |
sleep(duration, { summary }) |
@temporalio/workflow |
200 bytes |
Format: Standard Markdown (no images, no HTML, no scripts).
Implementation Patterns
1. Set Static Summary and Details at Workflow Start
Use staticSummary and staticDetails when starting a Workflow from the client. These are immutable once set.
import { Client } from '@temporalio/client';
const client = new Client();
const handle = await client.workflow.start(orderWorkflow, {
args: [orderPayload],
taskQueue: 'orders',
workflowId: `order-${orderId}`,
staticSummary: `Order #${orderId} for ${customerName}`,
staticDetails: [
`**Customer:** ${customerName}`,
`**Items:** ${itemCount}`,
`**Shipping:** ${shippingMethod}`,
].join('\n'),
});
Works identically with client.workflow.execute(...).
2. Update Current Details Inside a Workflow
Use setCurrentDetails to reflect the Workflow's progress as it runs. Call it as many times as needed.
import { getCurrentDetails, setCurrentDetails } from '@temporalio/workflow';
export async function orderWorkflow(order: Order): Promise<string> {
setCurrentDetails(`## Order ${order.id}\nStatus: **validating**`);
await validateOrder(order);
setCurrentDetails(`## Order ${order.id}\nStatus: **charging payment**`);
await chargePayment(order);
setCurrentDetails(`## Order ${order.id}\nStatus: **shipping**`);
await shipOrder(order);
setCurrentDetails(`## Order ${order.id}\nStatus: **completed**`);
return 'done';
}
3. Add Summary to Activity Calls
Use executeWithOptions on the proxied activity. Note: arguments go in an array as the second parameter.
import { proxyActivities } from '@temporalio/workflow';
import type * as activities from './activities';
const { sendEmail, chargeCard } = proxyActivities<typeof activities>({
startToCloseTimeout: '30 seconds',
});
export async function checkoutWorkflow(input: CheckoutInput): Promise<void> {
await chargeCard.executeWithOptions(
{ staticSummary: `Charge $${input.amount} to card ending ${input.lastFour}` },
[input], // arguments as array
);
await sendEmail.executeWithOptions(
{ staticSummary: `Confirmation email to ${input.email}` },
[input.email, input.receiptId],
);
}
4. Add Summary to Timers
Pass an options object with summary as the second argument to sleep.
import { sleep } from '@temporalio/workflow';
export async function trialWorkflow(userId: string): Promise<void> {
await sleep('7 days', { summary: `7-day trial period for user ${userId}` });
// trial expired, proceed
}
Common Mistakes
Exceeding the 200-byte limit on summaries. The summary silently truncates. Keep summaries short and ASCII-friendly (multi-byte characters eat the budget fast).
Passing activity args as positional parameters instead of an array.
// WRONG -- args are positional await myActivity.executeWithOptions({ staticSummary: '...' }, arg1, arg2); // CORRECT -- args in an array await myActivity.executeWithOptions({ staticSummary: '...' }, [arg1, arg2]);Using
staticSummary/staticDetailsinside the Workflow. These are client-side options only. Inside the Workflow, usesetCurrentDetails().Including images, HTML, or script tags in Markdown. These are stripped. Stick to text formatting: bold, italic, headers, lists, links.
Forgetting that
staticSummaryandstaticDetailsare immutable. If you need the detail to change over time, usesetCurrentDetails()instead of or in addition to the static fields.Calling
getCurrentDetails()expecting it to returnstaticDetails.getCurrentDetailsonly returns the value set bysetCurrentDetails. Static details are separate and read-only from the UI.
Debugging Tips
- Summary not appearing in the UI? Check the byte length. Use
Buffer.byteLength(summary, 'utf8')to verify it is under 200 bytes. - Details not rendering Markdown? Ensure you are not using images, HTML, or
<script>tags. Only standard Markdown text formatting is supported. setCurrentDetailsnot updating? The UI polls; refresh the page. Also confirm the Workflow has actually reached the line that callssetCurrentDetails.- Activity summary missing from event history? Make sure you used
executeWithOptionsand not the normal direct call syntax. The standardawait myActivity(args)call does not accept summary options. - Timer summary not showing? Verify you are passing the options object as the second argument to
sleep, not as part of the duration string.
Further Reading
If this skill does not answer your question, use Context7 to search /temporalio/sdk-typescript or /temporalio/samples-typescript for more details.