Skip to content
Skip to main content
The n8n, Langfuse and OpenTelemetry logos on frosted tiles over a dark field of glowing connected trace lines
9 min readBy Carlos Aragon

How to Trace an n8n AI Agent with Langfuse

n8n's execution view shows you what every node received and returned. That is not a trace. A trace is one searchable timeline where a single agent run, its tool calls, its retries and its token cost sit under one parent span. To get that out of n8n, you send its execution data to Langfuse — and there are two ways. The one that ships today is an HTTP Request node at the end of your workflow. The thorough one is OpenTelemetry instrumentation of the n8n process itself.

What n8n's Execution View Hides

The execution list is genuinely good for what it is. Something broke, you open the run, you click the red node, you read the error. For a deterministic workflow that's the whole job.

An AI Agent node is not deterministic. One execution might loop six times, call three different tools, get a 429 from one of them, retry, and produce an answer that's subtly wrong. The execution view collapses that into a node you can click. You get the final input and output. What you don't get is the shape of the run — which tool it reached for first, what arguments it invented, what came back, and how many tokens the whole detour cost.

I hit the wall on this with a Retell call-summary workflow. Calls were coming in, summaries were going out to Telegram, and roughly one in fifteen summaries mentioned a detail that never happened in the call. The bug turned out to be an over-eager tool argument — the agent was passing a truncated call ID and cheerfully summarizing the wrong record. Finding it took two evenings of opening executions one at a time and reading JSON. With a trace tree it would have taken one search: filter by workflow, sort by tool-call count, read the outlier.

The difference in one line:

n8n answers “what did this node do?” A trace answers “across every run this week, which prompt version, which tool, and which customer is producing bad answers — and what did it cost?”

There's a second, quieter problem: executions are pruned. Whatever retention you've set is your entire memory of what the agent has ever done. A trace store is built to keep that history and let you query across it, which is the difference between debugging an incident and debugging a pattern.

Why Langfuse and Not LangSmith

LangSmith's real advantage is depth of integration with LangChain and LangGraph. Here's the twist people miss: n8n's AI nodes arebuilt on LangChain JS, so in theory LangSmith should be the natural fit. In practice n8n doesn't expose the callback handler config where you'd hand LangSmith a tracer, so you can't just drop in an API key. That erases the one thing LangSmith was winning on, and what's left is the pricing and deployment model.

 LangfuseLangSmith
LicenseMIT core, EE key for a few featuresProprietary
Self-hostingFirst-class, free, no user capEnterprise add-on only
Seat costNone on any tier$39 / seat / month
Wire formatOpenTelemetry-native + SDKsOwn protocol, LangChain-first
Free tier50k units/mo, 30-day retentionFree dev tier, then per seat

For an agency running client workflows, the seat line is the one that decides it. Every person who might need to look at a trace — you, a VA, the client — is free on Langfuse and $39 a month on LangSmith. And because Langfuse speaks OpenTelemetry, the n8n instrumentation route below has a supported wire format to aim at instead of a bespoke SDK.

Option 1: One HTTP Request Node (ship this today)

Langfuse's ingestion API takes a batch of events. You don't need a node package, a sidecar, or self-hosted n8n — you need one HTTP Request node at the end of the agent branch and a Header Auth credential holding Basic base64(public_key:secret_key).

POST https://cloud.langfuse.com/api/public/ingestion
Authorization: Basic <base64 pk:sk>
Content-Type: application/json

{ "batch": [
  { "type": "trace-create",
    "id": "{{ $execution.id }}-evt",
    "body": {
      "id": "{{ $execution.id }}",
      "name": "retell-call-summary",
      "userId": "{{ $json.customer_id }}",
      "tags": ["n8n", "prod"],
      "metadata": { "workflowId": "{{ $workflow.id }}" },
      "input":  {{ JSON.stringify($('Agent').first().json.input) }},
      "output": {{ JSON.stringify($json.output) }}
  } },
  { "type": "generation-create",
    "id": "{{ $execution.id }}-gen",
    "body": {
      "traceId": "{{ $execution.id }}",
      "name": "agent-llm",
      "model": "claude-sonnet-5",
      "usage": { "input": {{ $json.tokens.in }},
                 "output": {{ $json.tokens.out }} }
  } }
] }

Two details save you a support thread. Use $execution.idas the trace ID — it makes any Langfuse trace one click from the matching n8n execution, which you will want at 11pm. And put the auth string in a credential, not in the node's header field, because workflow JSON gets exported, shared, and pasted into chats.

What you give up is automation: you're choosing the fields, so a tool call you forgot to send simply isn't there. That's a fair trade for a setup that survives every n8n upgrade because it only uses public, documented surfaces.

Option 2: OpenTelemetry, for a Span per Node

The community route wraps the whole n8n Node process. You mount a tracing bootstrap, load it with NODE_OPTIONS=--require, and it patches n8n's workflow execution internals so every node emits a span — AI model calls mapped to Langfuse generations, Agent nodes to agents, HTTP and utility nodes to tools. Then you point the exporter at Langfuse:

# docker-compose env for the n8n container
NODE_OPTIONS=--require /opt/otel/tracing.js
OTEL_SERVICE_NAME=n8n
OTEL_EXPORTER_OTLP_ENDPOINT=https://cloud.langfuse.com/api/public/otel
OTEL_EXPORTER_OTLP_HEADERS=Authorization=Basic <base64 pk:sk>,\
  x-langfuse-ingestion-version=4
# self-hosted Langfuse: swap the host for your own origin

The x-langfuse-ingestion-version=4 header is the one people leave off, and without it you lose real-time ingestion on Langfuse v4. Also note the signal-specific form (OTEL_EXPORTER_OTLP_TRACES_ENDPOINT) needs the full /v1/tracespath while the generic one does not — a mismatch there is the usual cause of “traces send successfully and never appear.”

Be clear-eyed about what this is. The n8n community thread that documents it calls it a proof of concept, and it earns that label: it depends on internal execution hooks that n8n has no obligation to keep stable. Treat an n8n upgrade as something that can silently stop your tracing, and add a check that alerts when no traces have landed in an hour. It also can't run on n8n Cloud at all, since you can't set NODE_OPTIONSon someone else's container.

If you're already running self-hosted n8n in queue mode with separate workers, remember the bootstrap has to load on the workers too — that's where the executions actually happen, and instrumenting only the main process gets you an empty dashboard.

What Self-Hosted Langfuse Actually Costs

“Free and open source” is true about the license and misleading about the bill. A production Langfuse deployment is six moving parts: the web container, an async worker, Postgres for transactional data, ClickHouse for the analytical trace store, Redis or Valkey for queueing, and S3-compatible object storage for large payloads.

ClickHouse is the whole decision. It's what makes trace search fast, and it's the component that dictates your memory footprint and your on-call surface. Docker Compose on one box is fine for a single-operator setup and explicitly not highly available — no failover, no built-in backup story. If tracing is going to inform client billing, plan for real backups from day one.

The gotcha that costs an evening: every component must run with its timezone set to UTC. Postgres and ClickHouse both. Get that wrong and traces land with skewed timestamps that make the waterfall view nonsense, and nothing tells you why.

Honest recommendation: start on Langfuse Cloud's free tier — 50,000 units a month with 30-day retention is plenty to prove the setup earns its keep. Move to self-hosted when either retention or data residency forces it, not before. Paid cloud tiers get expensive in the same shape everything else does (SSO sits behind a $499/mo total, enterprise controls at $2,499/mo), which is exactly when self-hosting starts paying for itself.

The Three Things Worth Tracing First

Don't try to capture everything on day one. Three fields carry most of the value:

  • The prompt version. Tag every trace with the version or hash of the system prompt. Without it, a regression has no suspect and you're guessing.
  • Full tool call arguments and the raw result. In production, agent failures are overwhelmingly bad arguments, not bad models — the truncated ID that summarized the wrong call is the canonical example.
  • Token counts plus a tag for the customer or workflow. Cost with no owner never gets fixed; cost with a name on it gets fixed the same week.

One warning before you turn it on for client work: traces capture inputs verbatim. If the workflow touches call transcripts, emails or anything a customer would consider private, mask or drop those fields before they leave n8n. A trace store quietly becomes a second copy of your most sensitive data, and it's the copy nobody put in the security review.

Once traces are landing, they become the input to something more useful than debugging. Scoring those runs is how you get from “it feels better” to a number — which is the whole subject of running evaluations on n8n AI agents.

The Short Version

  • n8n's execution view answers “what did this node do?” A trace answers “what is this agent doing across every run, and what does it cost?”
  • Start with one HTTP Request node posting to the Langfuse ingestion API. Works on n8n Cloud, survives upgrades, done in an afternoon.
  • Use $execution.id as the trace ID so every Langfuse trace links back to the matching n8n execution.
  • OpenTelemetry gives you a span per node automatically, but it's a community proof of concept on n8n internals — alert on trace silence and re-verify after upgrades.
  • In queue mode, instrument the workers, not just the main process.
  • Pick Langfuse over LangSmith here: n8n doesn't expose LangChain callbacks anyway, and Langfuse has no per-seat cost and real self-hosting.
  • Self-hosting means owning ClickHouse. Everything in UTC, or your waterfalls lie to you.
  • Trace the prompt version, the tool arguments, and tokens-per-customer first. Mask anything private on the way out.

Tracing tends to pay for itself twice: once in debugging time, once on the invoice. If the second one is what you're after, I wrote up the guardrails in cost controls for autopilot agents and the broader math in AI agent cost optimization. And if your agent's memory is the part that's misbehaving, that's a different fix — Postgres vs Redis for agent memory covers it. The official docs worth bookmarking are Langfuse's OpenTelemetry reference and the self-hosting guide.

Running Agents You Can't See Into?

I build n8n and AI agent systems that come with observability attached — traces, cost per client, alerts when the thing goes quiet. If you've got workflows in production and no idea what they're actually doing, that's a solvable problem and usually a fast one.

Related Posts

n8n

How to Evaluate n8n AI Agents Before Production

An n8n AI agent evaluation is four pieces: a dataset of real test cases in a Data Table or Google Sheet, an Evaluation Trigger node that replays every row through the live workflow, an Evaluation node that scores the answer, and a threshold you refuse to ship below. n8n gives you five built-in metrics — Correctness and Helpfulness are LLM-judged on a 1–5 scale, while String Similarity, Categorization, and Tools Used are deterministic and effectively free — plus custom metrics from a Code node. The critical detail is testing the real workflow, not a copy: the Check If Evaluating operation branches side effects out of a test run so nothing emails a real customer. Track two metrics per agent, baseline before you tune, and turn every production incident into a test case the same day.

n8n

Scaling Self-Hosted n8n: When to Switch to Queue Mode (2026)

Default n8n runs the editor, webhooks, and every execution in one Node process — it works until the UI crawls during runs and webhooks drop under load. The signal to move is the main process pinned near 80% CPU; the fix is queue mode: a main instance, a Redis broker, and dedicated workers on Postgres. The exact signals I watch, the env vars I set, and the mistakes that cost me a night of dropped executions.

n8n

n8n AI Agent Memory: Postgres vs Redis (What I Run in Production)

Postgres or Redis for n8n AI agent memory? Default to Postgres Chat Memory for durable, queryable history; add Redis only when you truly need fast session context at concurrency. My decision rule, a head-to-head table, and the session-key bug that breaks memory more often than the database ever does.