How to set up a user feedback loop for your application
Once traces are coming in, capturing user feedback is a great next step. Your users judge every response through what they click, edit, retry, or say. Capturing that on your traces gives you a quality signal grounded in real usage, where each score points at a trace you can open and learn from.
A lot of teams ask "I have traces coming in, how do I now get started with evals?". Often, these teams are better off starting with user feedback first.
This feedback gathering step generally has a very high ROI, in the AI Engineering process. We often write about this process in the Langfuse Academy, where we walk through the AI engineering loop in more detail. Gathering user feedback happens in the monitoring stage highlighted below.
Prerequisites
You already have traces coming into Langfuse. See tracing if you have not set this up yet.
Walkthrough
Choose your feedback signals
Feedback comes in two forms. Explicit feedback is a rating the user gives on purpose, like a thumbs up or down or a star rating: unambiguous, but rare and skewed toward unhappy users. Implicit feedback is derived from what users do, like retrying a query or editing a draft: you have data on every trace, but it needs interpretation.
The best signals depend heavily on your use case. Some examples as inspiration:
| Signal | What it tells you | Typically captured via |
|---|---|---|
| Thumbs up or down on a response | Direct rating of that response | Browser SDK |
| A user rephrasing the same question | The previous answer didn't land | LLM-as-a-Judge |
| A user asking to speak to a human | The user stopped trusting the assistant | LLM-as-a-Judge |
| A response copied by the user | The output was good enough to reuse | Browser SDK |
| A drafted reply edited before it is sent | What was wrong or missing in the draft | SDK / API |
| A copilot suggestion accepted or dismissed | Whether the suggestion fit the context | Browser SDK |
| An extracted field corrected in a review step | Which field was extracted incorrectly | SDK / API |
| A search query reformulated without clicking a result | The results missed the intent | SDK / API |
| A recommended item skipped right after it starts | The pick missed the user's taste | SDK / API |
Tips:
- signals combine well, no need to implement only one
- capture free-form text wherever it fits (can be as a comment on the score), as much of this analysis is now done by agents, and they work better with more context
- the academy examples show how signals are chosen for a specific application and change over its lifecycle
Capture the signals as scores
Every signal ends up as a score on the trace that produced the output. A score has a name, a value with a data type (boolean, numeric, categorical or free text), and an optional comment. Evaluators also store their results as scores, so your user feedback can land in the same filters, dashboards, and analytics.
Agent execution
User signal
Trace
Score
The route into that score depends on where the signal originates:
Ratings from your UI go straight from the browser using your public key:
import { LangfuseBrowserClient } from "@langfuse/browser";
const langfuse = new LangfuseBrowserClient({
publicKey: process.env.NEXT_PUBLIC_LANGFUSE_PUBLIC_KEY!,
});
// On a thumbs up / down click
await langfuse.score({
traceId, // returned by your backend with the response
id: `response_rating-${traceId}`, // stable id, so re-rating updates instead of duplicating
name: "response_rating", // one descriptive name per signal
value: 1, // 1 for thumbs up, 0 for thumbs down
dataType: "BOOLEAN",
});The User Feedback page has the full setup for a Next.js chatbot, including how the frontend gets the trace ID.
Events your app observes, like an accepted suggestion, an edited draft, or a closed ticket, are scored the moment they happen:
from langfuse import get_client
langfuse = get_client()
# The user edited the drafted reply before sending it
langfuse.create_score(
trace_id=trace_id, # the trace that produced the draft
name="draft_edited",
value=1,
data_type="BOOLEAN",
comment=edit_diff, # the edit itself, as context for later analysis
)import { LangfuseClient } from "@langfuse/client";
const langfuse = new LangfuseClient();
// The user edited the drafted reply before sending it
await langfuse.score.create({
traceId, // the trace that produced the draft
name: "draft_edited",
value: 1,
dataType: "BOOLEAN",
comment: editDiff, // the edit itself, as context for later analysis
});
// Flush the scores in short-lived environments
await langfuse.flush();See Scores via API/SDK for score types, updating scores, and validating them against a score config.
Signals that live in free text, like a user asking for a human or rephrasing a question, leave no event your code can catch. An LLM-as-a-Judge evaluator on your production traces reads the conversation and writes the score, with no change to your application.
Act on the feedback
Monitor how quality is trending
Score analytics and custom dashboards chart how each signal moves over time. One caveat: not every signal is a clean quality metric, e.g. thumbs feedback skews toward unhappy users.
Surface interesting traces
Filter traces by score, for example response_rating = 0, to get a concrete list of traces to investigate. Error analysis is a structured way to read and cluster them, and an annotation queue brings in more reviewers.
Use it as input for structured improvement
Add the failing cases to a dataset, test a fix with an experiment before shipping, and turn a recurring failure mode into an automated evaluator that scores every production trace from then on.
Much of this can also be handed to an agent, see Let an agent act on the feedback below.
Let an agent act on the feedback
Langfuse is built for agent access through the Langfuse CLI, the Agent Skill, and the MCP Server: point one at your project and it can interpret and act on the behavior that gets surfaced via user feedback. An example task:
Fetch the traces from the last 7 days with a response_rating score of 0.
Read the comments and outputs, cluster the failures into categories,
and propose a prompt change for the two biggest ones.Some reading material as inspiration:
Last edited