Yavio

Traces

Cross-layer correlation with trace IDs and combined funnels

The trace ID is the correlation key that stitches server-side and widget-side events into a single end-to-end journey. This cross-layer visibility is what makes Yavio unique — you can follow a user's journey from the initial tool call on the server through to the final conversion in the widget UI.

Trace Lifecycle

Here's what happens when a user interacts with your MCP app:

  1. User sends a prompt to the AI platform (ChatGPT, Claude, Cursor, etc.)
  2. The AI platform invokes an MCP tool — withYavio() intercepts the call
  3. The proxy generates a trace_id (e.g., tr_ + a random ID) and inherits the session_id from the current MCP connection
  4. The tool handler executes — any yavio.step() calls inherit the trace ID
  5. If the tool returns a widget response, the proxy mints a short-lived widget JWT
  6. The proxy injects window.__YAVIO__ with the trace ID, session ID, widget JWT, and endpoint
  7. The widget renders and initializes useYavio(), which reads the injected config
  8. Widget events are sent directly to the ingestion API with the same trace ID
  9. In the dashboard, the trace ID ties the tool call to the widget it rendered; a funnel follows the whole conversation (the session ID), across its traces

Combined Funnel Example

A single trace might contain events from both server and widget:

StepSourceEvent TypeData
1Server (auto)tool_calltool: "search_rooms", latency: 234ms
2Server (explicit)stepname: "rooms_found", count: 12
3Server (auto)widget_responsewidget token minted
4Widget (auto)widget_renderviewport: 400x600
5Widget (explicit)stepname: "room_selected"
6Widget (explicit)stepname: "details_completed"
7Widget (explicit)conversionname: "booking_completed", value: 567 EUR

Session vs Trace Hierarchy

Sessions and traces have a one-to-many relationship. A single conversation (session) typically holds multiple tool invocations, each with its own trace:

Session (ses_xxx) ← one conversation
  ├── Trace 1 (tr_aaa) ← tool_call "search_rooms"
  │   ├── step: "rooms_found"              (server)
  │   ├── widget_render                    (widget)
  │   ├── step: "room_selected"            (widget)
  │   └── conversion: "booking_completed"  (widget)
  ├── Trace 2 (tr_bbb) ← tool_call "check_availability"
  │   └── step: "availability_checked"     (server)
  └── Trace 3 (tr_ccc) ← tool_call "cancel_booking"

Both server and widget events share the same session_id. The trace_id provides the finer-grained correlation between a specific tool call and the widget it spawned.

Step Sequencing

When you call yavio.step() or useYavio().step(), the step gets a step_sequence number. On the server it is a counter per session in each server process, starting at 1: it starts again on every instance of a stateless fleet that serves the conversation, and after the SDK's session cache evicts it. The widget keeps its own counter per widget load, starting at 1; it does not continue from the server.

The dashboard's funnels therefore number a conversation's steps by time: steps are ordered by their timestamp, and step_sequence only breaks a tie between steps in the same millisecond. One conversation is one attempt however many instances served it; widget steps are placed among the server's by the browser's clock.

Funnel Analytics (Coming Soon)

The dashboard's funnel view will use sessions and trace IDs to:

  • Visualize step progression — see how conversations move through your defined funnel steps
  • Calculate drop-off rates — identify where users abandon the journey
  • Inspect individual traces — drill into a specific trace to see every event that occurred
  • Compare funnels across platforms — see if ChatGPT users convert differently than Claude users

The Funnels and Paths dashboard views are coming soon. Event data is already being collected — once the views launch, you'll have full historical visibility.

On this page