Skip to main content
Platform feature. Requires WANIWANI_API_KEY. Works whether your MCP server is self-hosted or on Managed Hosting. About the Platform.
Instrumentation is the mapping between your flow’s nodes and the Waniwani event taxonomy: which node emits which event, with which metadata. Get the mapping right and the dashboard shows a funnel that explains where users drop off and which conversations turn into revenue. This page gives you the placement rules, and a skill that applies them to your codebase automatically.

The taxonomy

The event set is closed and typed. Model every funnel stage with one of these; there is no custom event name. Inside a flow node, waniwani comes from the handler context and already carries the session identity. Full type shapes are in the Event schema.

Placing lead_qualified

lead_qualified is your code declaring that a person met your qualification bar: they finished the qualifying questions, requested a demo, or matched your target profile. Three rules:
  1. It fires at the qualification bar, not at flow entry. Starting a flow is activity (tool.called covers it). The event belongs in the node where qualification completes, which is often the node that pushes the lead to your CRM.
  2. It fires once per flow run.
  3. Fill every property you can. The properties are the join keys the dashboard uses to dedupe leads and connect them to your system.
Sharing an email mid-conversation is identify(userId, { email }), not a qualified lead. identify attaches identity; lead_qualified declares that your bar was met. Most flows emit both, at different nodes.

Placement rules for the rest

  • identify as early as possible. The first node where an email or user id is in state calls waniwani?.identify(state.email). This is what lets an off-platform converted find its way back to the session.
  • Price events go where the numbers are. The node that computes a single price emits priceShown; the node that presents multiple plans emits pricesCompared; the node that runs after the user picked (the selection is now in state) emits optionSelected.
  • converted only on real conversion. A confirmed booking or completed purchase inside the flow. If the sale closes later on your own site, emit it from your backend with the same externalUserId you identified during the flow. See Identify.
  • Emit from node handlers, never from validate callbacks. Validation can run several times per answer and would duplicate events.
  • Always guard with waniwani?.. The scoped client is undefined when the server is not wrapped with withWaniwani(server), and tracking throws without an API key. Optional chaining keeps keyless runs working.
  • Never pass sessionId manually inside a flow. The scoped client carries it.

A fully instrumented flow

Not every flow has every stage. A lead-gen flow can end at lead_qualified; a support flow may only ever identify. Forcing events onto nodes that do not represent that stage corrupts the funnel.

Auto-instrument with the skill

The instrument-tracking agent skill applies everything on this page to your codebase: it inventories your flows, maps every node to the taxonomy, inserts guarded tracking calls with metadata read from your flow state, wraps the server with withWaniwani if needed, and runs your typecheck.
Then ask your agent, in natural language:
  • “Instrument tracking across my flows”
  • “Track qualified leads in my demo flow”
  • “Add conversion tracking to the booking flow”
The skill also runs well as a subagent at the end of a scaffolding session, so a freshly generated flow ships instrumented from its first deploy. It reports the final node-to-event mapping as a table, so you can review every placement before committing.

Checklist

  • Exactly one leadQualified per flow run, placed at the qualification bar, with externalId when your CRM returns one.
  • identify runs at the earliest node where a stable id exists.
  • Every tracking call is guarded with waniwani?. and none passes sessionId.
  • withWaniwani(server) wraps the server.
  • Off-platform conversions send converted from your backend with the identified externalUserId.

Next

Event schema

Identify

Sessions

Agent skills