Overview
If your agent is already instrumented with Langfuse, calado can consume the traces Langfuse is already collecting. You do not re-instrument your app and you do not add the calado SDK. Langfuse posts each finished trace to calado, and theformat: "langfuse" adapter normalizes it into the canonical conversation and per-step structure the rest of calado uses.
Use this page if your agent runs on Langfuse. For provider clients with no tracer, see the Node.js SDK or Direct API. For LangChain or LangGraph agents, see LangChain and LangSmith.
There are two ways in:
Webhook
Langfuse’s built-in webhook posts every finished trace to calado in real time. Zero code in your runtime. Recommended.
Forwarder script
A small script paginates Langfuse traces on a cursor and POSTs each batch. Use it for backfill or where webhooks are not an option.
POST /api/ingest with the same payload shape. Pick one.
Webhook setup
LangFuse only sends a webhook when a trigger fires. Pointing the URL at calado does nothing on its own. This is the step customers most often miss.Get your calado API key
In the calado dashboard, open your agent’s Settings page and create an API key. It is prefixed with
cl_. You paste it into Langfuse in the next step.Create the webhook
In Langfuse, open your project and go to Settings → Webhooks → Create webhook.
- URL —
https://app.calado.ai/api/ingest - HTTP headers — add
Authorization: Bearer cl_<your_calado_api_key> - Body format — JSON, using Langfuse’s full trace payload option.
Add a trigger
Create a trigger on Trace finished. Without a trigger the webhook stays silent. Optionally add filters (project, environment tag,
release) so noisy dev traces are not forwarded.Payload envelope
calado expects the trace wrapped in an envelope:{trace, observations} directly, without the outer format and conversations envelope, put a small relay in front of calado that wraps the body. A single Cloudflare Worker or Vercel function is enough. The forwarder script below also does this and can run as the relay.
Verifying it works
In calado, open Agents → (your agent) → Conversations. A forwarded trace shows up as a conversation whoseexternalId is the Langfuse trace.id. Any system prompt or tool schema Langfuse captured appears under Agent definitions.
Raw conversations appear immediately. Analysis does not start automatically — click Run Analysis on the agent page when you are ready to classify.
Multi-agent traces
Langfuse traces with nested observations (an orchestrator and its sub-agents, linked viaparentObservationId) map cleanly onto calado’s step model. Each sub-agent span becomes a step on one conversation, and the dashboard renders the orchestrator and its sub-agents as a tree.
For aggregation to work, every step of one trace has to share a session id. The adapter uses trace.sessionId when Langfuse has one, and falls back to trace.id when it does not, so multi-agent traces collapse into a single conversation row either way. You do not need to set anything.
What gets captured
| calado field | Langfuse source |
|---|---|
conversation.externalId | trace.id |
conversation.sessionId | trace.sessionId, falling back to trace.id |
conversation.messages | GENERATION observation input and output messages |
| Step name and hierarchy | Observation name, id, parentObservationId |
| System prompt | System-role messages in a GENERATION input |
| Tool schemas | GENERATION input.tools and modelParameters.tools |
| Per-step inline definition | A child observation’s system-role input message, attached as that step’s inlineDefinition so the sub-agent is analyzed against its own prompt |
| Tool calls | SPAN observations with tool execution |
| Trace events | All observations, with timestamps and durations |
| Token usage and model | GENERATION usage and model metadata |
| Tags, release, version, user id | conversation.metadata |
Forwarder script
Use the forwarder for backfills, or where the webhook route is not viable. It polls the Langfuse API on a cursor and POSTs each batch to calado..langfuse-cursor.json) so re-runs forward only new traces. The first run backfills everything; later runs are incremental. The full script is in the examples/langfuse-forwarder/ directory of the calado repo, ready to copy.
Caps
| Limit | Value |
|---|---|
| Request body size | 5 MB |
| Observations per trace | 950 |
| Conversations per request | 1,000 |
| Message content | 1 MB |
400 too_many_child_runs naming the trace. The practical limit is usually the 5 MB body cap, which a verbose trace reaches well before 950 observations. If you hit either, reduce trace verbosity (drop noisy EVENT observations) or split long-running work into shorter sessions.
Security
The webhook setup puts your calado API key into Langfuse’s webhook configuration UI, as a header value. Anyone with access to your Langfuse project settings can read it. That is a slightly wider exposure surface than the direct-SDK path, where the key only ever lives in your runtime environment. Webhook-scoped sub-keys, where a leaked webhook key cannot be used for anything else, are on the calado roadmap. Until then, the rotation discipline above is the mitigation.Troubleshooting
The webhook returns400 too_many_child_runs. One trace exceeded the per-trace observation cap. Reduce verbosity or split the trace into shorter sessions.
The webhook returns 401. The bearer token was rejected. Re-paste the key into the Langfuse webhook header. The usual cause is a stray space or a missing Bearer prefix.
No webhook activity at all. The trigger is not configured. A webhook URL with no trigger never fires. See Webhook setup, step 3.
Next: redacting sensitive data
Strip PII before traces leave your infrastructure.