Skip to content

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.

  • 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-id header 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.

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.
  1. Add MIBO_API_KEY as a Flowise Variable

    In your Flowise instance, go to VariablesAdd Variable:

    VariableTypeValue
    MIBO_API_KEYStaticYour Mibo API key (from Project → API Keys in the dashboard)

    Optionally add MIBO_TRACES_URL if you’re pointing at a non-production Mibo environment. Defaults to https://api.mibo-ai.com/public/traces.

  2. 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.

  3. Import into Flowise

    In Flowise:

    • For a chatflow: click + Add NewLoad 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.
  4. 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.

  5. 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_api and the span name set to your chatflow’s name. If it doesn’t, see Troubleshooting.

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 externalId across turns.
  • POSTing again with the same x-request-id replaces 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.

The trace is matched to a Mibo agent using the same rule as OTLP:

  1. If your API key is scoped to a single agent, that agent is used.

  2. Otherwise, the request must include platformId at the top level or metadata.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';
  3. If neither resolves, Mibo returns 400 with a hint pointing at this rule.

See API Keys → Trace Routing for the full resolution rules.

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.

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.

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.

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.

Flowise CloudFlowise self-hosted
Mibo Trace Sender worksYesYes
OTLP native exportNot availableAvailable — prefer it if enabled
Setup stepsSame as aboveSame 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.

  • 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 that MIBO_TRACES_URL is reachable from your Flowise host.
  • Trace appears but gen_ai.response.text is empty. The Mibo Trace Sender uses its input as the response text. If your final node returns a structured object without a text field, edit the responseText extraction in the function to point at the correct property.
  • Mibo returns 400 with “API traces require a platform target”. Your API key is multi-agent but the payload doesn’t say which one. Add payload.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.name in 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.chatId is changing per turn. Either accept that, or replace it with $flow.sessionId for one trace per session.
  • It does not capture node-level execution data automatically. Flowise’s agentFlowExecutedData isn’t reachable from a Custom Function node at runtime — you populate $flow.state.miboSpans yourself 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.