Send traces from Flowise
Flowise doesn’t have a dedicated Mibo node, but it ships a Custom JS Function primitive every flow can use. This guide drops a pre-built Mibo Trace Sender function into your flow that posts the canonical Your API trace to Mibo after every interaction. Works on Flowise Cloud and self-hosted — no backend changes, no OpenTelemetry exporter to configure.
If your self-hosted Flowise has native OpenTelemetry export enabled, use OTLP instead — same endpoint, same passive testing.
What you get
Section titled “What you get”- One canonical span per chatflow run, carrying the assistant’s final answer.
- Optional per-node spans built from
$flow.state.miboSpans(see Adding per-node spans). - Identity via the
x-request-idheader so re-runs of the same chat overwrite their previous trace. - Fire-and-forget POST — flow latency and end-user response are not affected by Mibo being slow or unreachable.
Before you start
Section titled “Before you start”You need:
- A Mibo project with a Flowise agent and an API key. See API Keys.
- Flowise 2.x (Cloud or self-hosted).
- Permission to edit your chatflow and add Variables in your Flowise instance.
-
Add
MIBO_API_KEYas a Flowise VariableIn your Flowise instance, go to Variables → Add Variable:
Variable Type Value MIBO_API_KEYStatic Your Mibo API key (from Project → API Keys in the dashboard) Optionally add
MIBO_TRACES_URLif you’re pointing at a non-production Mibo environment. Defaults tohttps://api.mibo-ai.com/public/traces. -
Download the template
Download
flowise-template-mibo-tracing.json. It contains a single Custom JS Function node named Mibo Trace Sender pre-loaded with the trace-posting code. -
Import into Flowise
In Flowise:
- For a chatflow: click + Add New → Load Chatflow → pick the downloaded JSON. Flowise opens the node in a blank canvas. Right-click the Mibo Trace Sender node → Duplicate to copy it into your existing flow, or drag it across tabs.
- For an agentflow: open your agentflow, then drag a Custom JS Function node onto the canvas and paste the code from the Javascript Function field of the template into your new node.
-
Wire it in after your final answer node
Connect the output of your last node to the input of Mibo Trace Sender. Connect the sender’s output to whatever your flow currently terminates with — the function returns its input unchanged, so adding it doesn’t alter the response your user sees.
-
Run a test interaction and verify
Trigger a chat through your Flowise flow as a user would. Within a few seconds, the trace should appear under Traces in your Mibo project with
source: custom_apiand the span name set to your chatflow’s name. If it doesn’t, see Troubleshooting.
How identity works
Section titled “How identity works”Mibo reads the trace’s externalId from the x-request-id HTTP header — never from the body. The template sets it to $flow.chatId (falling back to $flow.sessionId, then a generated id), which means:
- Each end-user conversation has one stable
externalIdacross turns. - POSTing again with the same
x-request-idreplaces the existing trace — useful if you re-run a chat or correct a previous payload.
If you want every turn to land as a separate trace, replace $flow.chatId with a per-turn id in the template.
How agent resolution works
Section titled “How agent resolution works”The trace is matched to a Mibo agent using the same rule as OTLP:
-
If your API key is scoped to a single agent, that agent is used.
-
Otherwise, the request must include
platformIdat the top level ormetadata.mibo.platform_id. Add this to the payload in the Custom Function if you have multiple Flowise agents behind one API key:payload.platformId = 'YOUR_PLATFORM_UUID'; -
If neither resolves, Mibo returns
400with a hint pointing at this rule.
See API Keys → Trace Routing for the full resolution rules.
Span naming convention
Section titled “Span naming convention”The Mibo Trace Sender sets span.name to your chatflow name (the user-facing label you see in Flowise). The node_call assertion does case-insensitive substring matching against span.name, so:
- Write assertions against the display name you see in Flowise — not the internal node id.
- If you want assertions on individual components like an Agent, a Tool, or a Retriever, add per-node spans using the user-facing label of each step as the span’s
name.
Adding per-node spans
Section titled “Adding per-node spans”By default the template emits a single root span carrying the final response. To enable richer assertions (node_call, per-tool checks, stage analysis), populate $flow.state.miboSpans from earlier nodes in your flow.
In any node that updates state, push a span entry. For example, after a retrieval step:
const miboSpans = $flow.state.miboSpans || [];miboSpans.push({ name: 'Knowledge Base Retrieval', start_time_unix_nano: ($flow.state.kbStart || (BigInt(Date.now()) * 1000000n)).toString(), end_time_unix_nano: (BigInt(Date.now()) * 1000000n).toString(), attributes: { 'flowise.component.type': 'retriever', 'flowise.component.status': 'success', 'flowise.component.output': JSON.stringify({ count: results.length }) }, status: { code: 1 }});return { miboSpans };For a tool call, set gen_ai.tool.name and gen_ai.tool.call.arguments so it shows up under the parent span as a tool:
miboSpans.push({ name: 'search_flights', attributes: { 'gen_ai.tool.name': 'search_flights', 'gen_ai.tool.call.arguments': JSON.stringify({ origin: 'NYC', destination: 'MAD' }) }});The Trace Sender picks these up automatically and parents them under the chatflow’s root span. Use the display label you see in Flowise — never the technical component id.
Token usage
Section titled “Token usage”If your flow has access to token counts (e.g. from an LLM node’s usageMetadata or OpenAI’s usage), put them on the root span so token_limit assertions work. Edit the template’s root span block:
rootSpan.attributes['gen_ai.usage.input_tokens'] = $flow.state.inputTokens;rootSpan.attributes['gen_ai.usage.output_tokens'] = $flow.state.outputTokens;When the attributes are missing, token_limit assertions return missing instrumentation in the dashboard rather than passing or failing silently. See the Assertion Reference.
Full payload shape
Section titled “Full payload shape”For reference, the canonical API payload the template posts looks like:
{ "spans": [ { "span_id": "a3f1...", "parent_span_id": null, "name": "Restaurant Reservations Agentflow", "start_time_unix_nano": "1717689600000000000", "end_time_unix_nano": "1717689602450000000", "attributes": { "gen_ai.response.text": "Your table for 4 is booked at 8pm.", "gen_ai.output.messages": [ { "role": "assistant", "parts": [{ "type": "text", "content": "Your table for 4 is booked at 8pm." }] } ], "flowise.component.type": "chatflow", "flowise.component.status": "success", "flowise.chatflow.id": "cf-abc-123", "flowise.session.id": "sess-xyz" }, "status": { "code": 1 } } ], "metadata": { "chatflowId": "cf-abc-123", "sessionId": "sess-xyz", "chatId": "chat-001" }}Posted to POST /public/traces with headers x-api-key and x-request-id. See the HTTP API trace format reference for the full schema.
Cloud vs. self-hosted
Section titled “Cloud vs. self-hosted”| Flowise Cloud | Flowise self-hosted | |
|---|---|---|
| Mibo Trace Sender works | Yes | Yes |
| OTLP native export | Not available | Available — prefer it if enabled |
| Setup steps | Same as above | Same as above |
The whole point of the API path is to give Cloud users a first-class option that doesn’t require host-level OTel configuration. If you’re on self-hosted Flowise with OTel already wired up, use OTLP instead — fewer moving parts.
Troubleshooting
Section titled “Troubleshooting”- No trace appears in Mibo. Open the Flowise execution log. If you see
[mibo] trace POST failed, the network call is failing — check the API key and thatMIBO_TRACES_URLis reachable from your Flowise host. - Trace appears but
gen_ai.response.textis empty. The Mibo Trace Sender uses its input as the response text. If your final node returns a structured object without atextfield, edit theresponseTextextraction in the function to point at the correct property. - Mibo returns
400with “API traces require a platform target”. Your API key is multi-agent but the payload doesn’t say which one. Addpayload.platformId = '<uuid>'in the function, or scope the API key to a single agent in Project → API Keys. - Assertions matching on node names fail. Check that
span.namein the trace matches the display label you reference in your assertion — case-insensitive substring matching is used. - Every turn creates a new trace instead of overwriting.
$flow.chatIdis changing per turn. Either accept that, or replace it with$flow.sessionIdfor one trace per session.
What this does NOT do
Section titled “What this does NOT do”- It does not capture node-level execution data automatically. Flowise’s
agentFlowExecutedDataisn’t reachable from a Custom Function node at runtime — you populate$flow.state.miboSpansyourself where it matters. - It does not retry on failure. Trace POST is best-effort; one missed trace won’t break your flow.
- It does not modify the chat response shown to your end user — the function returns its input unchanged.