Feedback
Feedback records capture human-in-the-loop signals such as thumbs, ratings, comments, and corrections. Use feedback when you need to attach user, QA, Studio, or system review data to a trace or span and query that data alongside other observability signals.
Unlike metrics and scores, feedback is usually supplied by a person or review workflow. Numeric feedback values can be aggregated, grouped, charted over time, and queried for percentiles.
When to use feedbackDirect link to When to use feedback
- Collect user satisfaction ratings for agent responses.
- Store QA comments or corrections next to the trace they review.
- Build dashboards for ratings by agent, environment, or experiment.
Add feedbackDirect link to Add feedback
Use mastra.observability.addFeedback() when you want to annotate a persisted trace or span from app code. The helper is optional on the observability entrypoint, so check that the active observability implementation supports it. See the client SDK observability reference for all client methods.
if (!mastra.observability.addFeedback) {
throw new Error('Feedback is not supported by the active observability implementation')
}
await mastra.observability.addFeedback({
traceId: 'trace-123',
spanId: 'span-456',
feedback: {
feedbackSource: 'user',
feedbackType: 'rating',
value: 1,
comment: 'The answer solved my issue.',
},
})
Find the trace for a messageDirect link to Find the trace for a message
Feedback is usually collected against a message a user has already read, so you need the traceId for that message. Assistant messages carry it in content.metadata, both in the stream result and when the message is recalled later from memory:
const agent = mastra.getAgent('weatherAgent')
const memory = await agent.getMemory()
const { messages } = await memory!.recall({ threadId, perPage: false })
const message = messages.find(m => m.id === messageId)
const traceId = message?.content.metadata?.traceId
The value is the same trace the run reports as traceId on its result, so feedback collected at generation time and feedback collected later against a stored message anchor to the same trace. Messages produced while tracing is disabled have no traceId.
Create feedbackDirect link to Create feedback
Every createFeedback() requires feedbackType and value. Add traceId or spanId when the feedback should be anchored to a trace or a specific span. Use feedbackSource as optional string metadata, such as user, qa, studio, or system.
For storage-level writes, include timestamp because the method writes directly to the store.
const observability = await mastra.getStorage()!.getStore('observability')
await observability!.createFeedback({
feedback: {
feedbackId: 'feedback-rating-1',
timestamp: new Date(),
traceId: 'trace-123',
spanId: 'span-456',
feedbackSource: 'user',
feedbackType: 'rating',
value: 1,
comment: 'The answer solved my issue.',
tags: ['production'],
},
})
await observability!.createFeedback({
feedback: {
feedbackId: 'feedback-comment-1',
timestamp: new Date(),
feedbackSource: 'qa',
feedbackType: 'comment',
value: 'Needs a citation before shipping.',
experimentId: 'support-agent-eval',
},
})
List feedbackDirect link to List feedback
Use listFeedback() to page through raw records or poll with delta mode.
const result = await observability!.listFeedback({
filters: {
feedbackType: 'rating',
feedbackSource: 'user',
timestamp: { start: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000) },
},
pagination: { page: 0, perPage: 20 },
orderBy: { field: 'timestamp', direction: 'DESC' },
})
console.log(result.feedback, result.pagination?.hasMore)
Filters include target fields such as traceId and spanId, feedback fields such as feedbackType, feedbackSource, and feedbackUserId, and shared context fields such as entityName, environment, experimentId, and tags.
await observability!.listFeedback({
filters: {
traceId: 'trace-123',
feedbackType: ['rating', 'thumbs'],
tags: ['production'],
},
})
Query feedback analyticsDirect link to Query feedback analytics
OLAP feedback queries operate on numeric value fields. Use them for ratings, thumbs encoded as 1 and -1, numeric QA scores, or other numeric feedback types.
const rating = await observability!.getFeedbackAggregate({
feedbackType: 'rating',
feedbackSource: 'user',
aggregation: 'avg',
comparePeriod: 'previous_day',
})
const byAgent = await observability!.getFeedbackBreakdown({
feedbackType: 'rating',
groupBy: ['entityName'],
aggregation: 'avg',
filters: { environment: 'production' },
})
const ratingsOverTime = await observability!.getFeedbackTimeSeries({
feedbackType: 'rating',
aggregation: 'avg',
interval: '1h',
groupBy: ['feedbackSource'],
})
See the feedback reference for all fields, filters, return types, and percentile query parameters.
Export feedback to external platformsDirect link to Export feedback to external platforms
Feedback flows through the observability event bus, so exporters that support feedback forward it automatically. The PostHog exporter sends feedback as native $ai_feedback events that appear on the linked trace in PostHog.