# Build a dashboard and alert from Next.js custom metrics

> Emit a custom metric from your Next.js app, build a dashboard around it, and add a threshold or anomaly-detection alert that fires the moment it drifts.

**URL:** https://sentry.io/cookbook/custom-metrics-dashboard-alerts-nextjs/

---

Emit one custom metric from a Next.js Server Action, then turn it into a dashboard widget and a threshold or anomaly alert that fires the moment things drift — trace-connected, so a spike is one click from the request behind it.

**Time:** 20-25 minutes | **Difficulty:** Intermediate

## What You'll Learn

- 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

**Topics:** Metrics, Dashboards, Alerts

**SDKs:** Next.js

## Before you start

**SDKs & packages**

- A [Next.js](https://nextjs.org) app (v13+ with App Router recommended)

- [@sentry/nextjs](https://docs.sentry.io/platforms/javascript/guides/nextjs/) version `10.25.0` or later (metrics are on by default from this version)

**Accounts & access**

- [Sentry account](https://sentry.io/signup/) 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

## Steps

### 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.

```bash
npx @sentry/wizard@latest -i nextjs
```

[Next.js SDK setup guide](https://docs.sentry.io/platforms/javascript/guides/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)`.

```typescript
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' },
  });
}
```

[Next.js metrics setup](https://docs.sentry.io/platforms/javascript/guides/nextjs/metrics/)

### 3. Explore your metric in the Metrics explorer

Trigger the code path a few times, then open the [Metrics explorer](https://sentry.io/orgredirect/organizations/:orgslug/explore/metrics/). 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](https://docs.sentry.io/product/metrics/)

### 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](https://sentry.io/orgredirect/organizations/:orgslug/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](https://docs.sentry.io/product/dashboards/)

### 5. Add a threshold alert

From the metric query, use the **Save As** menu to turn it into a Monitor (or head to [Alerts](https://sentry.io/orgredirect/organizations/:orgslug/monitors/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](https://docs.sentry.io/product/monitors-and-alerts/alerts/)

### 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](https://docs.sentry.io/product/monitors-and-alerts/alerts/)

## Summary

**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.

## Pro Tips

- Name metrics with a consistent, dotted convention like `schedule.event` and `ai.tokens.total` so 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 a `result` attribute. 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 ignore `Sentry.metrics` calls, so your metric never shows up.

## FAQ

**Do I need to configure anything to turn metrics on?**

No. Metrics are on by default in @sentry/nextjs version 10.25.0 and later. If you want to turn them off, set enableMetrics: false in your Sentry.init config.

**Counter, gauge, or distribution: which should I use?**

Use a counter for things you tally, like schedule events or requests. Use a gauge for a point-in-time value that goes up and down, like queue depth. Use a distribution for values you want percentiles on, like token usage or request latency.

**Should I use a static threshold or anomaly detection?**

Use a static threshold when you already know the number that means trouble, like a spend cap or an SLO. Use anomaly detection when you don't have a baseline yet or the metric has strong daily or weekly seasonality. Sentry learns the pattern and flags deviations without a fixed threshold.

**How much does this cost in Sentry?**

Metrics are billed by volume, and Sentry's free tier includes enough to get started. Anomaly-detection alerts are in open beta for Trial, Business, and Enterprise plans.

**Can alerts notify Slack or PagerDuty?**

Yes. Both threshold and anomaly alerts can route notifications to Slack, PagerDuty, or email, so they reach your team through the channels you already use.

## Next Steps

- [product/tracing](https://sentry.io/product/tracing/)

- [product/logs](https://sentry.io/product/logs/)

- [Explore the workshop app](https://github.com/getsentry/nextjs-conf-scheduler): See these metrics emitted in a real Next.js app: the conference-scheduler used in the Sentry workshop this recipe is based on.

- [Application Metrics caught my broken size estimator](https://blog.sentry.io/metrics-caught-ai-size-estimate/): See how a browser video converter used counters, gauges, and distributions to track KPIs and catch a broken size estimator.

---

*Source: [sentry.io/cookbook/custom-metrics-dashboard-alerts-nextjs/](https://sentry.io/cookbook/custom-metrics-dashboard-alerts-nextjs/)*
