Langfuse: OpenTelemetry-Based Tracing for Any Framework
Langfuse is an LLM/agent observability platform that fits multi-framework stacks well. It emphasizes open instrumentation (including OpenTelemetry-friendly paths), self-host options, and traces that are not locked to one orchestration library.
Use this page when you want portable spans across custom loops, LangGraph, CrewAI, or mixed runtimes - and when self-hosting or open standards matter.
Summary
Create a Langfuse project (cloud or self-hosted), configure public/secret keys and host URL, instrument model and tool calls via the current Langfuse SDK decorators/clients or OTEL exporters (verify package names at build), emit nested observations per agent turn, and review traces, scores, and cost in the Langfuse UI.
Recipe
- Deploy Langfuse cloud or self-host (Docker/K8s docs evolve - verify at build).
- Create a project and copy public key, secret key, and base URL.
- Set env vars in every runtime, for example:
LANGFUSE_PUBLIC_KEYLANGFUSE_SECRET_KEYLANGFUSE_HOST/ base URL for self-host
- Install the current Python SDK (
langfuseand any OTEL helpers your version requires - verify at build). - Wrap the agent entrypoint so one trace equals one user task / run.
- Create child spans/generations for model calls and spans for tools.
- Attach metadata: user id, session id, agent version, environment, tags.
- Flush on worker shutdown so short-lived jobs do not drop the last events.
- Add scores (user feedback, eval harness, or LLM-as-judge) on the same trace id.
- Redact secrets before attributes are exported.
Working Example
Conceptual host instrumentation (API names drift between SDK major versions - verify at build):
import os
import time
from uuid import uuid4
# pip install langfuse (verify version and import paths at build)
from langfuse import Langfuse
langfuse = Langfuse(
public_key=os.environ["LANGFUSE_PUBLIC_KEY"],
secret_key=os.environ["LANGFUSE_SECRET_KEY"],
host=os.environ.get("LANGFUSE_HOST", "https://cloud.langfuse.com"),
)
def run_agent(goal: str, call_model, tools: dict) -> str:
run_id = str(uuid4())
trace = langfuse.trace(
name="agent-run",
id=run_id,
input={"goal": goal},
metadata={"agent_version": "1.2.0", "env": "dev"},
tags=["agent", "demo"],
)
messages = [{"role": "user", "content": goal}]
for turn in range(5):
t0 = time.perf_counter()
generation = trace.generation(
name="model",
model=os.environ.get("AGENT_MODEL", "demo-model"),
input=messages,
)
text = call_model(messages)
generation.end(
output=text,
metadata={"turn": turn, "ms": int((time.perf_counter() - t0) * 1000)},
)
if text.startswith("FINAL:"):
answer = text.removeprefix("FINAL:").strip()
trace.update(output={"answer": answer, "stop_reason": "goal_met"})
langfuse.flush()
return answer
name, args = parse_tool(text) # your parser
span = trace.span(name=f"tool:{name}", input=args)
try:
obs = tools[name](**args)
span.end(output={"status": "ok", "preview": str(obs)[:200]})
except Exception as e:
span.end(output={"status": "error", "error": str(e)}, level="ERROR")
trace.update(output={"stop_reason": "error"})
langfuse.flush()
raise
messages.extend([
{"role": "assistant", "content": text},
{"role": "tool", "content": str(obs)},
])
trace.update(output={"stop_reason": "max_turns"})
langfuse.flush()
return ""Decorator-style instrumentation is also common in recent SDKs:
# Verify decorator names/imports for your langfuse major version at build
from langfuse.decorators import observe
@observe(name="search-tool")
def search(query: str) -> str:
return "demo result"OpenTelemetry path (when you already standardize on OTEL collectors):
# Pattern only - package and register helpers change; verify at build.
# 1) Configure OTEL exporter toward Langfuse's OTLP endpoint (if enabled for your plan/version)
# 2) Instrument HTTP/framework auto-instrumentors
# 3) Set agent attributes: run_id, tool.name, gen_ai.* fields where supportedDeep Dive
Why Langfuse for mixed stacks
LangGraph teams often start on LangSmith. Multi-runtime orgs often need one place for:
- Custom Python loops
- CrewAI / LlamaIndex / OpenAI Agents SDK
- Services that already speak OpenTelemetry
Langfuse's strength is framework neutrality plus product features (sessions, scores, datasets) without requiring LangChain types.
Trace hierarchy to mirror agent structure
Map agent concepts deliberately:
| Agent concept | Langfuse-style observation |
|---|---|
| User task / ticket | Trace |
| Model call | Generation |
| Tool / HTTP / DB | Span |
| Multi-agent specialist | Nested span or child trace linked by metadata |
| Human score / eval | Score on trace or observation |
If everything is a flat generation, you lose tool path debugging.
Self-hosting and data residency
Self-host when prompts and tool payloads cannot leave your network boundary. Budget for Postgres/storage, upgrades, auth, and backup - observability platforms are production systems.
Cloud is fine for many startups if DPA, retention, and redaction match policy.
Scores and product feedback
Attach thumbs-up/down, rubric scores, or automated eval results to the same trace id. That join is how "bad answer" becomes a filterable queue, not a Slack anecdote.
Cost and token fields
Populate model name, token usage, and estimated cost when the SDK allows. Without them, Langfuse becomes a debugger only, not a cost control surface.
Sampling and async workers
Short Lambda/job workers must flush() (or equivalent) before exit.
For high QPS, sample successful traces and keep 100% of errors and high-value tenants if volume forces trade-offs.
Gotchas
- Forgetting flush on process exit - last traces vanish in serverless.
- One giant span for the whole agent - no tool visibility.
- SDK major version import churn - pin versions and re-read upgrade notes.
- Secrets in inputs/outputs - redaction is your job at the host.
- Missing session/user metadata - cannot find customer incidents.
- Clock skew across workers - rely on ids more than wall clock alone.
- Self-host under-provisioned storage - retention deletes the evidence you need.
- Treating Langfuse as APM only - still correlate with infra metrics.
Alternatives
| Approach | Strength | Weakness |
|---|---|---|
| Langfuse | Multi-framework, self-host path | Graph nesting less automatic than LangSmith for LangGraph |
| LangSmith | Best LangGraph ergonomics | Less ideal as universal multi-framework default |
| Arize Phoenix | Eval-heavy workflows | Different product focus |
| Raw OTEL + Grafana/Tempo | Full control | Rebuild LLM-specific UX |
| Custom JSONL only | Tiny footprint | No product UI for free |
FAQs
Is Langfuse only for LangChain?
No. It is commonly used with many frameworks and custom hosts. LangChain integrations exist, but they are optional.
Do I need OpenTelemetry to use Langfuse?
No. Many teams use the Langfuse SDK directly. OTEL is valuable when you already standardize exporters and collectors.
Can I run Langfuse fully offline?
Self-host deployments target private networks. Confirm current deployment guides and dependency requirements at build.
How do sessions differ from traces?
A session groups multi-turn chat. A trace is usually one task/run. Link both so multi-turn agents stay navigable.
How should I represent handoffs?
Nest specialist work under the parent trace and tag specialist=.... Include handoff packet ids in metadata.
Where do evals live?
As scores and/or datasets tied to traces. Offline suites should write scores back with the original trace id when possible.
What about TypeScript agents?
Langfuse maintains multi-language SDKs. Apply the same hierarchy: one trace per task, children for model/tool. Verify TS package APIs at build.
How do I avoid double-billing of tokens in attributes?
Record usage once at the generation boundary from the provider response; do not re-estimate ad hoc in every child span.
Is Langfuse a replacement for Datadog?
No. Use Langfuse for agent/LLM path quality; use infra APM for hosts, queues, and databases. Join with shared ids.
What is a good first production filter set?
Environment, agent version, error level, stop reason, and user id. Add cost quantiles once usage fields are reliable.
Related
- What Agent Observability Actually Needs to Capture - field model
- Agent Observability Basics - platform-free sketches
- LangSmith for LangChain/LangGraph-Native Tracing - LangGraph-native alternative
- Arize Phoenix for Eval-Rigorous Agent Monitoring - eval-first alternative
- Building Custom Trace Logging Without a Third-Party Platform - minimal DIY
- Pairing Agent Observability with Infrastructure Monitoring - APM join
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.