Langfuse in depth
← All modules Langfuse in depth

Module 5 · Langfuse in depth · about 25 minutes

Langfuse in depth: find out what your AI app actually did

Module 2 introduced Langfuse as the "camera and receipts" for an AI app. This module opens it up. We'll keep the same example, a research assistant that takes a question, searches the web, reads the results and writes a short cited report, and use Langfuse to debug a real-feeling customer complaint.

TracingCost and latencyPrompt managementEvaluation

Words with a dotted underline, like , are technical terms. Tap one for a plain-English definition.

Interactive demo

Debug a complaint

A customer says a report was wrong and slow. Use a Langfuse-style screen to find the run, work out what went wrong, then test and ship a fix. Hints guide you, and every step has a "Show me" button.

Simulation:not the real Langfuse app; traces, users, prices and timings are scripted and illustrative.
Support ticket #4821 · from priya@acme.example · Thursday

"Tuesday's index-fund report cited a dodgy source and took ages."

Hint · step 1 of 6

Traces one row per run · click a question to open it · click a column name to sort
Question Tags

Score = citation_accuracy from an automatic judge, 0 to 1.

No trace open. Click a question in the table to open its trace here.

1 · What Langfuse is

An open-source platform for seeing inside LLM apps

Langfuse records what your app does, stores and versions its prompts, and scores the quality of its answers. Engineers, PMs and reviewers all work from the same screens.

Open source

The code is public. Its GitHub repository says it is , except for folders marked as enterprise. A few add-on features need a paid licence key.

Cloud or self-hosted

Use Langfuse Cloud, which offers EU and US , or it on your company's servers. Section 9 covers what that means for data.

Separate company

Langfuse is not made by LangChain Inc, the company behind LangChain and LangGraph. The Langfuse GitHub README says the team has been part of ClickHouse since January 2026.

Works with any stack

It has a ready-made connector for LangChain and LangGraph, and works just as well without them: with plain provider , other frameworks, or anything that speaks .

Langfuse compared with LangSmith

is LangChain's own product for the same job. Both cover tracing, prompts and evals. The differences are mostly about who makes it, where it runs and how open it is.

LangfuseLangSmith
Made byThe Langfuse team, separate from LangChainLangChain Inc
Source codeOpen source (MIT core, some paid add-ons)Commercial product; its SDKs are open source, the platform is not
HostingLangfuse Cloud, or self-host for freeLangChain's cloud; self-hosting is offered on enterprise plans
FrameworksFramework-neutral, with many integrations including LangChain and LangGraphDeepest fit with LangChain and LangGraph; also works without them
Typical reason to pick itYou want open source, self-hosting, or you mix frameworksYour team is all-in on LangChain and LangGraph and wants one vendor

Both products change fast. Check current features, plans and pricing on each vendor's site before deciding.

Other tools your engineers may suggest

LangSmith isn't the only alternative. These cover the same ground with different trade-offs.

ToolIn shortOften picked when…
Arize PhoenixOpen-source tracing and evals, built on OpenTelemetry. Arize also sells a hosted platform.The team wants open source with a strong evaluation focus
BraintrustA commercial platform centred on evals, datasets and prompt experimentsEvaluation is the main need, and a hosted product is fine
HeliconeOpen source. Sits between your app and the model provider as a proxy, logging every call.You want logging and cost tracking with almost no code changes
W&B WeaveTracing and evals from Weights & BiasesThe company already uses W&B for machine-learning work
Datadog LLM Observability, and similarLLM tracing inside a general monitoring platformThe company wants one place for all monitoring, and needs less prompt management

Because Langfuse and most of these accept OpenTelemetry, switching later is easier than it used to be. Try two on a week of your own traces before choosing.

PM takeaway

Langfuse is the open, framework-neutral choice for tracing, prompts and evals. LangSmith is the in-house option if you're fully on LangChain.

2 · The data model

Traces, observations, and the labels that make them findable

Everything Langfuse shows is built from a few kinds of record. Knowing them helps you ask engineers for the right things.

USER priya@acme.example SESSION chat-118 (one conversation) TRACE "How do index funds work…" tags: finance, report · metadata: app_version 2.3 SPANplan GENERATIONchat-large · tokens · cost SPANsearch TOOLweb_search SPANread → 3 × TOOL fetch_page SPANwrite → GENERATION EVENT"report sent" TRACE Follow-up question "Which source is [3]?" same session, next turn SCORE citation_accuracy 0.33 attached to a trace or to one observation
A user can have many sessions. A session groups the traces of one conversation. Each trace holds a tree of observations, and scores can be attached at either level.
Trace

A is the full record of one run: one question in, one report out, with total time and cost.

Observation

An is one piece of work inside a trace. Observations nest, so a step can contain the LLM call and tool calls it made.

Session

A groups traces that belong together, such as every turn of one chat. Replay a whole conversation in order.

User

A user ID ties traces to a customer. That's how you go from "Priya complained" to Priya's runs in seconds.

Tags and metadata

are short labels for filtering, such as finance or report. is extra detail, such as the app version.

Scores

A is a quality grade on a trace or observation: a number, a category or yes/no, with an optional comment.

Observation types

The first three are the classics. Recent SDKs add more specific types so the screen can show what each step is. The docs list these for Python SDK 3.3.1 and later and JS/TS SDK 4 and later.

TypeWhat it recordsIn the research assistant
SPANA generic timed piece of work, as a Each step: plan, search, read, write
GENERATIONOne LLM call, as a : prompt, reply, model, , costThe model call inside plan, grade and write
EVENTA moment with no duration, as an "Report sent to user"
TOOLOne action, such as a function or API callweb_search, fetch_page
AGENTA step where an LLM decides what to do next and may use toolsThe whole assistant, if it chose its own steps
CHAINA fixed sequence linking stepsprompt → model → clean up output
RETRIEVERA read-only lookup in a database or document storeSearching the company's own research notes
EVALUATORA step that grades another step's outputThe grade step
EMBEDDINGA call that turns text into numbers for search, with tokens and costIndexing fetched pages
GUARDRAILA safety check that blocks harmful or off-limits contentBlocking a report that promises returns

Check your understanding · Data model

Priya complains about Tuesday's report. Tracing is on, but nobody can find her run among 40,000 traces. What was missing?

PM takeaway

Ask for user IDs, session IDs and tags from day one. Without them you can't find a customer's run when they complain.

3 · Getting data in

Four ways to send traces to Langfuse

Engineers add a little code to the app, and the app sends records to Langfuse in the background. Which way they choose depends on how the app is built.

The @observe decorator

A is a one-line label above a function. @observe records that function as an observation, with its input, output and timing. Functions called inside it nest automatically.

LangChain / LangGraph handler

If the app uses LangChain or LangGraph, a handler records every step, LLM call and tool call without decorating each function.

OpenTelemetry

Langfuse accepts traces in the OpenTelemetry standard. The current SDKs are built on it too. Any tool that already emits OpenTelemetry data can send to Langfuse.

Other integrations

Ready-made cover many providers and frameworks, such as a drop-in wrapper for the OpenAI SDK, LlamaIndex, LiteLLM and the Vercel AI SDK. The docs keep the full list.

Without a framework

# Simplified. Names from the v3+ Python SDK docs.
from langfuse import observe, get_client, propagate_attributes

@observe()                         # this run becomes the trace
def research(question, user_id, session_id):
    with propagate_attributes(user_id=user_id,
                              session_id=session_id):
        notes = read(search(question))
        return write_report(question, notes)

@observe(as_type="tool")
def fetch_page(url): ...

@observe(as_type="generation")
def write_report(question, notes): ...

With LangChain or LangGraph

# Simplified.
from langfuse.langchain import CallbackHandler

handler = CallbackHandler()
app.invoke({"question": q}, config={
  "callbacks": [handler],
  "metadata": {
    "langfuse_user_id": "priya@acme.example",
    "langfuse_session_id": "chat-118",
    "langfuse_tags": ["finance", "report"]}})

get_client().flush()  # short scripts: send before exit

The SDK sends records in batches in the background, so tracing adds little delay for users. Exact names vary by SDK version: the current docs describe a newer major version than v3, and older code may use update_current_trace(...) instead of propagate_attributes. Ask engineers which version you're on.

PM takeaway

Adding tracing is usually a small code change, not a project. If engineers say it's hard, ask which of these four routes they looked at.

4 · Cost and token tracking

What one report costs, and who is spending it

Model providers charge per token. Langfuse turns the tokens in each LLM call into a dollar figure, then adds it up per trace, user, tag or model.

Where the numbers come from

Token counts usually come straight from the provider's reply. Langfuse multiplies them by the model's price from a . If the app sends a cost itself, that wins.

Custom prices

Langfuse ships prices for popular OpenAI, Anthropic and Google models. Teams add their own for fine-tuned, self-hosted or discounted models. Price changes apply to new calls only.

Only model calls cost money

Cost sits on generation and embedding observations. A slow web fetch costs time, not tokens, unless its text is later sent to a model.

Slice it

Because every trace carries a user ID and tags, a can show cost per customer, per feature tag or per model. The Metrics API exports the same numbers to other tools.

Worked example: one research report

StepModelTokens in → outPrice per 1M tokens (in / out)Cost
planchat-large610 → 170$3 / $15$0.0044
gradechat-small1,150 → 40$0.25 / $1.25$0.0003
read (notes)chat-small2,600 → 210$0.25 / $1.25$0.0009
writechat-large1,900 → 300$3 / $15$0.0102
Total6,980$0.0158

Illustrative prices. The write step is about two thirds of the bill because it uses the large model, which costs 12 times more per token than the small one, on a long input. Its 1,900 input tokens ($0.0057) cost more than its 300 output tokens ($0.0045). At 10,000 reports a month that's about $158, or roughly ₹13,400 at ₹85 to the dollar.

PM takeaway

Ask for cost per run and per feature, not just the monthly bill. Tags on every trace are what make that breakdown possible.

5 · Latency analysis

Where the waiting time goes

is how long the user waits. Langfuse shows it two ways: inside one trace as a timeline, and across many traces as percentiles.

Inside one trace

The timeline draws each observation as a bar. Long bars are slow steps. Bars that overlap ran at the same time. Bars in a staircase ran one after another and might be sped up.

Across many traces

Averages hide bad experiences. is the time that 95% of runs beat. If p95 is 22 s, one user in twenty waits longer than that.

20 runs sorted from fastest to slowest. The typical run (p50) takes about 9 s and the average is 11 s, but p95 is 22.6 s. Those slow runs are the ones customers complain about.

Common causes in an agent like ours

  • One slow tool call, such as fetching a huge page. The demo's 18-second PDF is this.
  • Steps running one after another when they could run in parallel.
  • Retries after a tool times out.
  • A large model used for a small job, or a very long prompt.
PM takeaway

Track p95, not the average. It's the wait your unluckiest users feel, and the timeline shows which step to fix.

6 · Prompt management

Change prompts without a code release

Instead of hard-coding prompts, the app fetches them from Langfuse by name. Every edit becomes a new numbered version, and labels decide which version is live.

Versions

Every save creates a new version: v1, v2, v3. Old versions are kept, so you can always see what changed and when.

Labels

A is a movable pointer to one version. production is what the app fetches by default. Teams add their own, such as staging.

Rollback

To , move the production label to the previous version. No deploy needed.

Playground

The lets you try a prompt against a model in the browser, and compare versions side by side, before saving.

Linked to traces

When the app records which prompt it used, each trace shows the version, for example research-report v3. You can compare cost, latency and scores by version.

Change alerts

can notify Slack or another system whenever a prompt version is created or changed.

Fetching a prompt in code

# Simplified.
langfuse = get_client()
prompt = langfuse.get_prompt("research-report", label="production")
text = prompt.compile(question=q, notes=notes)   # fills {{question}} and {{notes}}
# Pass the prompt along when recording the LLM call, so the trace shows its version.

The SDK keeps a of prompts in memory, so fetching adds almost no delay, and the app keeps working with the cached copy if Langfuse is briefly unreachable.

Who may move the production label?

Moving a label changes what every user sees, without a code release or a code review. Treat it like a release.

Limit who can do it

Use project roles so most people can draft and test prompts, but only a few can move production. Langfuse can protect chosen labels so only certain roles may change them; check which plan includes this.

Require evidence

No label move without an experiment on the dataset, with the scores written down. In regulated products, add a recorded sign-off (module 6 calls this release sign-off coverage).

Announce and watch

Send a webhook to the team channel on every change, and watch live scores for a day after. Know who rolls back, and how fast.

Check your understanding · Prompts

A colleague improved the report prompt and tried it on two questions. They want to move the production label now. What do you ask for?

PM takeaway

Prompt management lets you ship and undo wording changes in minutes. Pair it with an eval so "ship" isn't a guess, and limit who can move the production label.

7 · Evaluation

Turning "it seems better" into numbers

An measures answer quality. Langfuse supports several sources of scores, and a way to test changes before they ship.

Scores from many sources

Code checks (does every [n] match a real source?), user feedback (thumbs up or down), human reviewers, and LLM judges all write scores in the same format.

LLM-as-judge evaluators

An evaluator is set up in Langfuse with a judging prompt. Langfuse runs it, not your app, on a sample of live observations or experiment items, and stores a score with the judge's reasoning.

Annotation queues

An is a to-do list of traces for people to review and score, such as every report with a low judge score.

Datasets and experiments

A is a saved set of test questions. An runs a version of your app on every item and scores the results, so you can compare versions side by side.

The improvement loop

  1. SpotA complaint, low score or alert points to bad traces.
  2. SaveAdd those cases to the dataset, with what a good answer looks like.
  3. ChangeWrite a new prompt version, or try a new model.
  4. TestRun an experiment: old vs new on the whole dataset.
  5. ShipMove the production label. Watch scores on live traffic.

An experiment in code

# Simplified. Names from the current Python SDK docs.
dataset = langfuse.get_dataset("research-questions")
result = dataset.run_experiment(
    name="research-report v4",
    task=run_assistant_with_v4,              # answers one item
    evaluators=[citation_accuracy, clarity_judge])

Experiments can also be run from the Langfuse screen, and a GitHub Action can fail a code change if scores drop below a threshold.

How big should the dataset be?

Small datasets are good for catching a specific bug, and bad at proving one version is better overall. A rough rule: on a dataset of n items, a pass rate can be off by about 1 ÷ √n just by chance.

Dataset sizePass rate could be off by aboutGood enough to…
10 items± 30 pointsConfirm a specific fix, such as Priya's case, and catch obvious breakage
100 items± 10 pointsSpot a big improvement or a big drop
400 items± 5 pointsCompare two good versions with some confidence

Two things help a lot. Compare versions on the same items, item by item, and count where they differ. And run each item more than once, because the model's answer varies between runs. The demo's 10-item experiment shows the workflow; a real decision needs a bigger dataset.

PM takeaway

Every complaint should end up as a dataset item. Then each fix is tested against every past failure, not just the latest one.

8 · Dashboards and alerts

See trends, and get told when something breaks

Traces answer "what happened in this run?". Dashboards answer "how are we doing this week?". Alerts make sure someone notices without checking.

Built-in dashboards

Ready-made views of cost, usage, latency and scores over time, broken down by model, user or tag.

Custom dashboards

Build your own charts with filters, such as "cost of finance reports per day" or "average citation score by prompt version".

Alerts

An watches a metric over a time window, with a warning level and an alert level. It can post to Slack, call a webhook, or start a GitHub Action.

Alerts worth setting for the research assistant

MetricWarn atAlert atWindowWhy
p95 latency> 15 s> 20 s1 hourCatches slow tools before complaints arrive
Average citation_accuracy< 0.8< 0.71 dayQuality drop, such as after a prompt change
Total cost> $40> $601 dayA runaway loop or a traffic spike
Error count> 10> 501 hourSearch provider outage

Alert limits depend on the Langfuse Cloud plan. Thresholds here are examples to tune.

Which numbers? Module 6 lists the metrics for a regulated assistant by priority, and shows which Langfuse scores, tags and alerts each one comes from.

Check your understanding · Latency

The average report takes 11 seconds, but customers still complain it's slow. Which number should you look at?

PM takeaway

Pick three or four numbers you care about and put alerts on them. A dashboard nobody opens doesn't protect users.

9 · Privacy and data

Traces contain whatever users type

A trace stores prompts and replies. If a user types a name, email or account number, it ends up in Langfuse unless you stop it. Decide this before launch.

Hide sensitive data

runs inside your app and replaces before anything is sent. Engineers can also switch off recording a function's input or output entirely.

Where data lives

On Langfuse Cloud, data stays in the region you pick, EU or US. Self-hosted, everything stays on your servers: a database, an analytics store, a cache and file storage, all run by your team.

Separate environments

Tag traces with an , such as production or development, so test data doesn't mix with real customer data.

Who can see what

Projects and roles control who sees traces. Keep access to people who need it, and agree how long traces are kept.

Masking in code

# Simplified. Runs in your app, before data leaves it.
EMAIL = re.compile(r"[\w.+-]+@[\w-]+\.[\w.]+")

def hide_emails(data, **kwargs):
    if isinstance(data, str):
        return EMAIL.sub("[email]", data)
    return data

langfuse = Langfuse(mask=hide_emails)

@observe(capture_input=False)        # don't record this input at all
def lookup_account(account_id): ...

Newer SDK versions also offer a masking hook that runs at export time. The parameter names depend on the version.

Questions to ask before launch

  • What personal or client data could appear in prompts and replies?
  • What do we mask, and has someone checked real traces to confirm it works?
  • Cloud or self-hosted? If cloud, which region, and is that in our data agreements?
  • Who has access to production traces?
  • How long are traces kept, and how do we delete a user's data on request?
  • Is test data kept apart from real customer data?
PM takeaway

Tracing records what users type. Agree on masking, region and access with your security team before the first real user.

Keep this

One-page cheat sheet

TracingEvery run as a trace: steps, LLM calls, tools, time, tokens, cost.
PromptsVersioned prompts. Labels pick what's live. Roll back without a release.
EvalsScores, LLM judges, review queues, datasets and experiments.
MonitoringDashboards for cost, latency and quality, with alerts.

The data model

  • User has many sessions
  • Session groups the traces of one conversation
  • Trace is one run, a tree of observations
  • Observation: span, generation, event, tool, agent and more
  • Tags and metadata make traces filterable
  • Scores grade a trace or one observation

Names you'll see in code (simplified)

  • @observe(): record a function
  • CallbackHandler(): record LangChain or LangGraph
  • get_prompt(name, label=…): fetch a prompt
  • run_experiment(…): test a version on a dataset
  • mask=…: hide data before it's sent

PM takeaways

  1. Open, framework-neutral alternative to LangSmith.
  2. User IDs, session IDs and tags from day one.
  3. Adding tracing is a small code change.
  4. Cost per run and per feature, not the monthly bill.
  5. Track p95 latency, not the average.
  6. Ship and undo prompts in minutes, with an eval.
  7. Every complaint becomes a dataset item.
  8. Alerts on three or four numbers that matter.
  9. Agree on masking, region and access before launch.

Numbers to ask for

  • Cost per run, per user and per feature tag
  • p50 and p95 latency, and the slowest step
  • Average judge score, and its trend after each prompt change
  • Share of traces reviewed by a person
  • Dataset size, and how many items came from real complaints

Glossary

Learn from others

3 common mistakes teams make with Langfuse

1

Traces nobody can find

What it looks like
Tracing is on, but traces have no user ID, session ID or tags. When a customer complains, someone scrolls through thousands of identical rows.
Fix
Set user, session and a feature tag on every trace from the first release. Test it by finding one named user's runs in under a minute.
2

Moving labels on a hunch

What it looks like
Because prompt changes no longer need a release, people edit and promote prompts after trying two examples. Quality quietly drops on cases nobody checked.
Fix
Require an experiment on the dataset before moving the production label. Write the scores down next to the release, where the team can see them.
3

Trusting the LLM judge blindly

What it looks like
An LLM-as-judge score goes on the dashboard and becomes the quality number. Nobody checks whether the judge agrees with people, so its blind spots become yours.
Fix
Have humans score a sample in an annotation queue and compare with the judge. Rewrite the judging prompt until they mostly agree, and recheck now and then.
Previous · Module 4 ← LangGraph in depth