Build a dashboard and alert from custom metrics in a Next.js app
Turn a single custom metric into something your team actually watches: a dashboard widget and an alert that fires the moment things drift.
Before you start
SDKs & packages
- A Next.js app (v13+ with App Router recommended)
- @sentry/nextjs version
10.25.0or later (metrics are on by default from this version)
Accounts & access
- Sentry account with a Next.js project created
- A Trial, Business, or Enterprise plan if you want to use anomaly-detection alerts (open beta)
Knowledge
- Basic familiarity with Next.js Route Handlers or Server Actions
- A rough sense of when to reach for a counter, a gauge, or a distribution
1 Install the Sentry Next.js SDK
Add the Sentry SDK to your project with the wizard, which wires up the instrumentation files automatically. Run this in your project root. Metrics are on by default in @sentry/nextjs 10.25.0 and later, so there's nothing extra to enable. If you ever need to turn them off, set enableMetrics: false in your Sentry.init config.
npx @sentry/wizard@latest -i nextjs 2 Emit a custom metric from your app
Pick a signal that maps to something your team cares about, then emit it from the exact code path where it happens. Use Sentry.metrics.count() for events you tally and Sentry.metrics.distribution() for values you'll want percentiles on later.
The example below is from a Next.js conference-scheduler app: every time a user adds or removes a talk, it counts a schedule.event and attaches action and result attributes so you can slice by outcome. Both logs and metrics are high-cardinality wide events, so adding more attributes costs nothing and gives you more ways to query, group, and alert later. For values where you want a p95, emit a distribution instead, for example Sentry.metrics.distribution("ai.tokens.total", totalTokens).
import * as Sentry from '@sentry/nextjs';
export async function addTalkToSchedule(userId: string, talkId: string) {
const existing = await getScheduleEntry(userId, talkId);
if (existing.length > 0) {
Sentry.metrics.count('schedule.event', 1, {
attributes: { action: 'add', result: 'duplicate' },
});
return;
}
await db.insert(userSchedules).values({ userId, talkId });
revalidatePath('/');
Sentry.metrics.count('schedule.event', 1, {
attributes: { action: 'add', result: 'success' },
});
} 3 Explore your metric in the Metrics explorer
Trigger the code path a few times, then open the Metrics explorer. Select schedule.event, choose an aggregation like sum or per_minute, and group by the result attribute to see successes, duplicates, and failures split out.
Open the Samples tab to see individual metric events, each with a direct link to its trace, so a suspicious number is one click away from the request behind it.
Application Metrics documentation
4 Build a dashboard around your metric
Once the query in the explorer shows what you want, open the Save As menu and pin it as a dashboard widget. Head to Dashboards to add it to a new or existing dashboard, then drop in a second widget for another signal (like ai.tokens.total at p95, or page.view throughput) so related metrics sit side by side.
A good starter layout: schedule events over time grouped by result, plus a throughput or latency widget next to it.
Dashboards documentation
5 Add a threshold alert
From the metric query, use the Save As menu to turn it into a Monitor (or head to Alerts and create one). Pick Threshold as the detection method and set a number you understand: for a free AI assistant, that might be ai.tokens.total summed above a cost ceiling per hour; for the scheduler, schedule.event where result is not success above N per hour. Route the notification to Slack, PagerDuty, or email so the right people hear about it.
Static thresholds are the right call when you already know the number that means trouble, like a spend cap or an SLO you've committed to.
Alerts documentation
6 Switch to anomaly detection when you don't have a baseline
When you don't yet know what "normal" looks like, a static threshold either fires all night or sleeps through daytime spikes. Create a second alert and pick Anomaly as the detection method instead. Sentry learns your metric's seasonality and daily or weekly patterns, then flags deviations with no threshold to tune, just a sensitivity slider. Throughput metrics like page.view are a perfect fit, since traffic naturally rises and falls through the day.
Reach for anomaly detection on new metrics or anything with a strong daily rhythm, and keep static thresholds for hard limits you've explicitly agreed to.
Alerts documentation
That's it.
Your telemetry finally tells you something.
One custom metric becomes a dashboard you watch and an alert that pages you, all trace-connected so you can jump straight from a spike to the request that caused it.
- Emitted a custom counter metric from a Next.js Server Action with business-context attributes
- Explored metric values, aggregations, and trace-connected samples in the Metrics explorer
- Built a dashboard widget from a saved metric query
- Created a static threshold alert routed to your team's channels
- Compared static thresholds with anomaly detection so you know which to reach for
Pro tips
- 💡 Name metrics with a consistent, dotted convention like
schedule.eventandai.tokens.totalso they're easy to find, group, and reason about across the team. - 💡 Push business context into
attributes(action, result, plan tier) rather than baking it into the metric name. Attributes are free on high-cardinality events and give you more ways to slice, group, and alert. - 💡 Use a distribution, not a gauge, whenever you care about p95 or p99. Gauges only keep the latest snapshot, so percentiles need distributions.
- 💡 Start with a static threshold you understand, then add an anomaly alert once you have a couple of weeks of baseline data for Sentry to learn from.
Common pitfalls
- ⚠️ Baking dimensions into the metric name (
schedule.event.success,schedule.event.duplicate) instead of using one metric with aresultattribute. This explodes cardinality and makes grouping impossible. - ⚠️ Expecting percentiles from a counter or gauge. Only distributions compute p50, p95, and p99; counters aggregate by sum or rate, and gauges keep the last value.
- ⚠️ Putting a static threshold on a metric with strong daily or weekly seasonality like page views. It will page you every night or miss real daytime spikes. Use anomaly detection there instead.
- ⚠️ Running an SDK older than
10.25.0. Earlier versions silently ignoreSentry.metricscalls, so your metric never shows up.
Frequently asked questions
What's next?
Fix it, don't observe it.
Get started with the only application monitoring platform that empowers developers to fix application problems without compromising on velocity.