track() API for emitting custom business events that power real-time dashboards.
Automatic Tracing (Agent)
Automatic Tracing (Workflow)
Workflows automatically trace every step with full hierarchy:function, agent, connector, condition, switch, foreach, parallel) is traced with its own color and label in the portal.
Verbose Tracing Mode
Control how much data is saved in traces. Works identically for Agent and Workflow. Modes:full: Complete data including prompts and responses (default)standard: Balanced metadata with truncationminimal: Disables tracing entirely (no traces sent)
Trace Interceptor (onTrace)
Intercept, modify, or cancel traces before they are sent. Available in Agent, Workflow, and standalone logging.- Return the trace (modified or not) to send it
- Return
nullto cancel (trace is not sent) - Return
voidto send unchanged
Trace Hierarchy (startSpan)
Create parent-child relationships between custom logs for structured traces:Custom Executions (Non-Agent Flows)
For scenarios withoutagent.process() (document analysis, batch processing, etc.):
Custom Logging
Log custom events within any execution:Conversation Messages
Available since
@runflow-ai/sdk@1.1.10.message() to record a turn of a conversation. Each call emits a conversation_message trace that the Runflow portal renders as a chat bubble: user inbound on the left, assistant outbound on the right.
The portal switches automatically to chat view when an execution has at least one conversation_message trace — no flag, no channel hint. The thread sidebar preview also updates to show the latest user/assistant text instead of raw envelope JSON.
When to use
- Custom workflows (WhatsApp handlers, webhook routers) where you control the message flow without
agent.process(). - LLM agents when you want to also expose the conversation as chat (wrap
agent.process()calls). - Anywhere you want the execution to render as a conversation in the portal.
message(), nothing changes — your existing traces and rendering keep working exactly as before.
Wrapping an agent call (LLM)
Custom workflow (no LLM)
startSpan call is optional but recommended — it groups the technical traces under the turn so the drill-down drawer in the portal stays organized.
Multiple assistant messages per turn
A turn can emit any number of assistant messages — they render as consecutive bubbles in chronological order, exactly like WhatsApp:Structured content (buttons, audio, image)
content accepts a string OR an object with a type field. The portal renders text natively and falls back to a JSON view for structured content (buttons / media renderers are on the roadmap):
Hierarchy and grouping
Messages follow the same parenting rules aslog() and startSpan():
In the portal, clicking any bubble of a turn opens the drill-down with all traces of that execution — the hierarchy you create only affects how the trace tree looks in the drawer.
Parameters
Business Event Tracking
Usetrack() to emit custom business events from your agent. These events power the Metrics dashboard in the portal, where you can build KPI cards, charts, and real-time feeds without writing any backend code.
Events are buffered and sent in batches automatically (up to 50 events or every 2 seconds). No manual flushing needed during normal execution.
How It Works
- Call
track(eventName, properties)anywhere in your agent code - The SDK buffers events and sends them in batches to the Runflow API
- Open the Metrics tab in the portal to create dashboard cards
- Cards auto-discover your event names and properties — no configuration needed
Parameters
Options
Flushing Before Exit
For short-lived scripts or CLI tools, callflushTrackEvents() before exiting to ensure all events are sent:
Dashboard Cards
In the portal, navigate to your agent’s Metrics tab to create cards:- Number — KPI with a single aggregated value (count, sum, avg)
- Rate — Percentage based on a filtered property value
- Line / Bar — Time-series charts grouped by hour, day, week, or month
- Pie — Distribution chart over time periods
Best Practices
Use descriptive event names
Use descriptive event names
Use
snake_case names that describe what happened: alert_received, ticket_resolved, payment_processed. Avoid generic names like event or action.Keep properties flat
Keep properties flat
Properties are stored as JSON and queried via keys. Flat key-value pairs work best for dashboard aggregations:
Use consistent property types
Use consistent property types
Keep the same property as the same type across events. If
duration is a number in one event, don’t send it as a string in another — aggregations like sum and avg rely on numeric values.Execution Reviews
Available since
@runflow-ai/sdk@1.1.13. Requires an API client that exposes the reviews namespace. Ownership/SLA fields (assignedToUserId, dueAt, disposition) and the queue/source filters require 1.5.1+.Reviews exposes the execution-review feedback loop programmatically — the same surface used by the portal QA queue and the MCP tools (create_execution_review, list_execution_reviews, …). Use it from LLM-judge agents, KB curators, or scheduled jobs to flag bad executions, triage them, and feed corrected outputs back into training datasets.
checkHasReview first if you don’t want a 409 surfaced to the caller. Authentication uses your RUNFLOW_API_KEY; reviewedBy is auto-populated from the API key label on the backend.
Methods
Feedback loop pattern
Errors
Reviews throws typed errors so callers can branch cleanly:
ReviewAlreadyExistsError(HTTP 409) — the execution already has a review.ReviewNotFoundError(HTTP 404) — the reviewId doesn’t exist or belongs to another tenant.ReviewsError(any other status) — generic error withstatus+body.
Proactive review policies
Portal feature: Agent → Reviews → Policies. Policies have no public API surface yet — the reviews they create flow through the same
Reviews SDK/REST surface above, tagged with source: 'policy'.
Conversation grouping is chosen per policy:
- Whole thread — the entire thread is one conversation (in the SDK, the thread is derived from the customer identity).
- Sessions by time gap — the customer’s stream is sliced into separate conversations whenever the gap between messages exceeds a configurable window. Recommended for WhatsApp-style channels where a single customer accumulates a long-lived thread.
- Test before saving — dry-run the criteria against the agent’s latest real conversations straight from the policy editor (no reviews are created).
- Behavior analysis (opt-in) — include each turn’s connector/tool calls in the judge context (
[actions: patch-lead ✓, run-salesbot ✗]) so it can evaluate what the agent did, not just what it replied. - Health at a glance — each policy row shows its last run, reviews created, evaluation errors and judge token spend over the last 7 days.
Reading traces from the SDK (with pagination)
The cross-agent SDK’sExecutions.getDetails(executionId) returns the same hierarchical trace tree the portal shows on the “execution detail” page — but bounded to protect the DB. See Cross-Agent SDK → Executions for the full surface.
Two modes, depending on the caller:
ObservabilityController.getExecutionDetails keeps returning the entire trace array, with the new pagination fields ignored. The 10 000 cap only kicks in if an execution actually generates that many traces (which would be a bug to investigate, not a regression).
Observability Comparison
Next Steps
Workflows
Workflow tracing and step types
Configuration
Configure observability