Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.runflow.ai/llms.txt

Use this file to discover all available pages before exploring further.

The Metrics Registry lets agent code declare its own dashboard tabs and cards, then sync them to the platform with a single call. It mirrors the canonical shape used by the CLI’s rf metrics sync command — same validation, same idempotency — so the same definitions work whether you sync at deploy time or from inside the agent process.
Available since @runflow-ai/sdk@1.1.12. The portal-based dashboard editor still works — Metrics Registry is a code-first alternative for teams that want metrics tracked as code.

When to use

  • You want dashboard definitions in version control next to the agent code.
  • You’re rolling out the same dashboard across many agents and want the definitions reusable.
  • You’re migrating an existing portal-built dashboard into code (legacy field shapes like tableMode are auto-normalized).
If a one-off card is fine, the portal Metrics tab is faster — see Business Event Tracking for that flow.

Quick start

import { metrics } from '@runflow-ai/sdk/observability';

// 1. Declare a tab (idempotent on `name`)
metrics.defineTab({ name: 'Vendas' });

// 2. Declare a card on that tab
metrics.defineCard({
  tab: 'Vendas',
  title: 'Funil de checkout',
  cardType: 'funnel',
  config: {
    funnelMode: 'multi_event',
    steps: [
      { eventName: 'cart_open',        label: 'Carrinho aberto' },
      { eventName: 'checkout_started', label: 'Início checkout' },
      { eventName: 'sale',             label: 'Pagamento' },
    ],
  },
  gridLayout: { x: 0, y: 0, w: 6, h: 5 },
});

// 3. Push to the platform
await metrics.sync();
The registry is a process-wide singletonimport { metrics } returns the same instance from every module, so you can split declarations across files freely.

Validation is synchronous

defineCard() validates against the shared Zod schemas at registration time. Shape mistakes throw immediately:
metrics.defineCard({
  tab: 'Vendas',
  title: 'My card',
  cardType: 'funnel',
  config: { /* missing required `steps` */ },
});
// ❌ Throws: metrics.defineCard("My card"): config.steps: Required
Legacy aliases used by the portal editor are auto-normalized before validation (for example, the old tableMode field maps to the new mode field), so migrating an old definition usually doesn’t require any changes. Each (cardType, title) pair must be unique in the registry — registering twice throws to prevent silent dupes.

sync() is two-phase

Tabs are upserted first, then cards. The platform resolves each tab name to a tabId before the card upsert, so cards always land on the right tab:
const result = await metrics.sync();
// {
//   agentId: 'agent-uuid',
//   tabs:  { created: 1, updated: 2, total: 3 },
//   cards: { created: 4, updated: 1, failed: 0, total: 5 },
// }
Per-card idempotency uses a deterministic key (${cardType}:${title}:${tab ?? ''}), so repeated syncs only update — they never duplicate. By default failures are logged and skipped; pass { strict: true } to make any failure throw.

Configuration

sync() reads credentials from these in order:
SourceVariable
Explicit optionmetrics.sync({ agentId, baseUrl, apiKey })
EnvironmentRUNFLOW_API_URL, RUNFLOW_API_KEY, RUNFLOW_AGENT_ID
Runtime context (SDK)Set by the platform when running inside a deployed agent.
Missing any of the three throws — surface them in your config before calling sync().

CLI parity

The CLI command rf metrics sync posts the exact same shape to the same endpoints. You can switch between code-first and CLI-driven dashboards without recomputing anything — the platform dedupes by the same idempotency key on both sides.

Card types

defineCard() supports the same card catalog as the portal editor — number, rate, line, bar, pie, funnel, table, gauge, etc. Each type expects its own config shape; see the portal Metrics tab for the canonical UI of every card type.

Listing and consuming cards

You can read back what’s published — and even drive your own renderer — over the runtime REST API:
  • GET /api/v1/runtime/observability/dashboard-cards?agentId= — list every card configured for an agent (returns cardType, config, gridLayout, tabId).
  • POST /api/v1/runtime/observability/dashboard-cards — the same endpoint metrics.sync() calls. Safe to invoke directly from server-to-server jobs.
  • GET /api/v1/runtime/observability/dashboard-tabs?agentId= — list configured tabs.
  • POST /api/v1/runtime/observability/dashboard-tabs — idempotent upsert (used by metrics.defineTab(...) → metrics.sync()).
  • POST /api/v1/runtime/v1/observability/events — push events from outside the SDK.
  • GET /api/v1/runtime/v1/observability/events/feed — most-recent-first event feed (filter by agentId, eventName, paginated).
  • POST /api/v1/runtime/v1/observability/events/query — table-style query, mode: 'raw' for individual rows or mode: 'aggregate' with groupBy + metrics for grouped reports.
For KPI-style aggregation (single-number queries — sum, avg, count, rate, distinct_count, group_by with optional dateGrouping for time series), use the MCP surface:
  • aggregate_events — returns the raw value or series. Same shape the portal Metrics tab uses.
  • query_events — same as the REST endpoint, also available via MCP.
  • render_dashboard_card — pass a cardId and get back the current value, dispatching on cardType + config (supports number / rate / line / bar / pie / gauge / table / funnel).
See REST Endpoints → Dashboards & Events and MCP → Available MCP Tools for the full shapes.
Discovery endpoints (event_names, event_properties, property-values) remain portal-only over REST. They’re also exposed as MCP tools (get_event_names, get_event_properties) for AI clients.

Next Steps

Business Event Tracking

Emit the events your cards aggregate

Metrics API Reference

Signatures and options