Self-Hosted n8n + Langfuse Setup: Make Every LLM Call Traceable
My n8n instance runs self-hosted, with three content automation workflows on it. Last month they started misbehaving: triggered at 6 AM every day, sometimes finishing in 40 seconds, sometimes taking 3 minutes, and occasionally failing silently - the workflow showed green, but no article was ever produced downstream.
It took me a full weekend to nail down the cause. The root problem was not n8n itself - it was that I had zero observability: I had no idea which step was slow, which LLM call was retrying, or where the tokens were actually being burned.
This article is my full record of wiring Langfuse into self-hosted n8n. Every command and config comes from an environment I actually got working. There are no affiliate links or sponsored content here.
Why n8n's Default Logging Is Not Enough
n8n's built-in execution records tell you whether a workflow succeeded or failed overall, but when you call an LLM, the information left behind is extremely thin:
- You see "AI Agent node took 87 seconds" but not whether that 87 seconds was **one slow call** or **five retries**
- You cannot see the actual prompt, so you cannot review "why this output went off the rails"
- Token usage is a black box until the monthly bill arrives and shocks you
My first approach was to add a Code node after each HTTP node to manually print status codes. The problem with that hack is obvious: it pollutes the workflow structure, and every prompt change forces a matching logging change.
What I needed was a side-channel: see the input, output, latency, and tokens of every LLM call without touching business logic.
Prerequisites and Architecture Choice
Three things to confirm before starting:
1. How n8n is deployed
Mine is Docker Compose. If you use n8n Cloud, the self-hosting steps below do not apply, but the Langfuse config keys are the same.
2. Where Langfuse runs
Langfuse has Cloud and self-hosted options. I chose self-hosted from the start because my prompts contain content strategy I do not want to send off-box. Self-hosted spins up with the official Docker Compose.
3. Network connectivity
This is the most overlooked part. The n8n container must be able to reach Langfuse's address. If you, like me, put both on the same machine, Docker networking handles it - just do not use localhost, because **localhost inside a container points to the container itself**.
Step 1: Spin Up a Self-Hosted Langfuse
Langfuse's official repo provides a Docker Compose setup. I pulled the official compose file and started it on a 2C4G box:
git clone https://github.com/langfuse/langfuse.git
cd langfuse
docker compose up -d
It listens on port 3000 by default. One gotcha: if your n8n also uses 3000, change the port mapping first. In my environment n8n uses 5678, so there was no conflict.
Once it is up, open the Langfuse web UI, create an organization and a project, then generate a pair of API keys in project settings: Public Key and Secret Key. **These are shown only once - save them first.**
Step 2: Connect n8n to Langfuse
I hit my first real gotcha here. Conclusion first, then the story.
Error 1: connection refused (ECONNREFUSED)
The first time I configured it, I set LANGFUSE_HOST=http://localhost:3000 in n8n's environment variables, and the workflow immediately errored:
Error: connect ECONNREFUSED 127.0.0.1:3000
The reason is straightforward: n8n runs inside a Docker container, and localhost inside the container is the container itself, not the host. **The fix** is to use the host's name on the Docker network. If you orchestrate both services with docker-compose, use the service name directly:
LANGFUSE_HOST=http://langfuse-server:3000
Because my Langfuse runs as its own independent compose stack, I added the n8n container to the same Docker network and addressed Langfuse by container name and port. After restarting the n8n container, the connection worked immediately.
Error 2: n8n's AI nodes produce no trace
Once connected, I expected to see data in Langfuse - but it was completely empty. The workflow clearly ran, yet Langfuse had nothing.
After digging in: n8n's Langfuse integration requires tracing through the corresponding node or explicit configuration, not a global switch. Setting environment variables alone is not enough to make all AI calls report automatically. The n8n community has dedicated threads on this (source: community.n8n.io, "Capturing n8n flows with observability" and "Deep n8n observability with OpenTelemetry").
My path was to use n8n's Langfuse-specific node/integration and explicitly attach the LLM calls I wanted traced. Langfuse's official docs have a dedicated page on the n8n node (source: langfuse.com/docs/prompt-management/features/n8n-node); after configuring per it, traces appeared immediately. There is also a third-party package n8n-nodes-openai-langfuse in the community (source: github.com/rorubyy/n8n-nodes-openai-langfuse), but given maintenance activity, I ultimately chose the official path.
Step 3: Read the Traces and Find the Real Bottleneck
Once wired up, I "saw" the workflow for the first time. Three findings directly solved my original problem:
Finding 1: the slow part was not the LLM - it was retries
I always assumed the 3-minute run meant a slow model. The trace showed that run had the same call retried four times, each timing out. The root cause was my overly long prompt pushing processing past the default timeout. After raising the timeout threshold, retries disappeared and single-run latency settled at around 45 seconds.
Finding 2: token usage is highly concentrated
Sorting by tokens, I saw that one of the three workflows accounted for over 70% of token usage, yet its output quality was no better than the others. I cut a third of the redundant context from that workflow's prompt, and monthly usage dropped noticeably.
Finding 3: silent failures now leave a trail
Those "green but no output" executions now show the LLM returning an empty string in the trace. This is not an n8n bug - it is the model returning an empty response under certain inputs. Knowing this, I added an empty-value check branch to the workflow, and the problem has not reappeared.
A Checklist You Can Follow Directly
I turned this integration experience into a checklist:
- **Do not use localhost to reach cross-container services**; use the Docker service or container name
- **API keys are shown only once**; store them immediately in secret management, never commit them in the compose file
- **Environment variables are not automatic tracing**; you must explicitly attach the Langfuse node in the workflow
- **Langfuse itself needs persistence**; the default compose uses an in-container database that loses data on restart - mount a volume in production
- **Look at retry count before single-call latency**; many "slow" cases are just retries piling up
Was It Worth It
My answer is yes, with a caveat.
If you have only one or two simple workflows with few LLM calls, standing up a dedicated Langfuse instance costs more to maintain than it returns. But if your workflows meet any of these, I would recommend it:
- Multiple chained LLM calls where you need to pinpoint the slow step
- Sensitivity to token cost, where you need to know where the money goes
- Any history of "succeeded but produced wrong results" silent failures
The integration itself took me about two hours, including both gotchas - but it saves time on every future investigation. Going from "guessing what is slow" to "opening Langfuse and taking a look" is worth more than any single optimization.
👉 Join MiniMax Token Plan: AI coding acceleration for businesses
👉 Join Xiaomi MiMo Platform: Leading AI model platform with cost-effective inference
👉 Join Aliyun AI: Top AI products with exclusive coupons for business innovation
📌 This article was AI-assisted generated and human-reviewed | TechPassive — An AI-driven content testing site focused on real tool reviews
🔗 Recommended Tools
These are carefully selected tools. Using our affiliate links supports us to keep producing quality content: