# Trace sample rates that do not bankrupt you

> Errors are cheap and spans are not. How to pick tracesSampleRate, why the edge runtime needs a lower one, and how to keep the traces you actually need while dropping 95% of the rest.

You follow the setup guide, it says `tracesSampleRate: 1.0`, you ship. Traffic
grows. A month later the bill has a line item for spans that dwarfs the errors,
and nobody has opened the Performance tab since the first week.

The mistake is treating one number as a setting rather than a budget. Errors
and traces are priced differently and used differently, and the sample rate is
where that difference gets decided.

## The unit economics

**Errors** are rare by definition. A healthy app produces a handful per
thousand requests, and each one is individually valuable: you want all of
them.

**Transactions and spans** are produced by *every* request, whether anything
interesting happened or not. Each page load is a transaction; each fetch,
database query and component render inside it is a span. One request can easily
be twenty spans.

So at `tracesSampleRate: 1.0`, an app doing a million requests a month produces
a million transactions and perhaps twenty million spans. That is the number
that shows up on the invoice, and 99.9% of it describes requests that were
completely fine.

## The wrong way

```ts
Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  tracesSampleRate: 1.0,
});
```

Copied from a quickstart, shipped to production, never revisited. Two problems
beyond cost: at full sampling the SDK does measurably more work per request,
and the Performance tab becomes an undifferentiated wall that nobody reads.

## The right way: a small constant, raised deliberately

```ts
// sentry.server.config.ts
tracesSampleRate: process.env.NODE_ENV === "production" ? 0.1 : 1,
```

10% in production is a good starting point for a normal web app. It is enough
to see p95 latency and to spot a slow route, and it costs a tenth of the naive
setting.

Then adjust with two facts:

- **Traffic volume.** Under ~10k requests/day, 10-20% is fine. Over ~1M/day,
  you want 1% or less; you have plenty of samples either way.
- **What you actually look at.** If nobody has opened Performance in a month,
  go to 0.01 or turn tracing off. You can raise it in an afternoon when you
  need it.

## The edge runtime needs its own, lower number

```ts
// sentry.edge.config.ts
tracesSampleRate: process.env.NODE_ENV === "production" ? 0.02 : 1,
```

Edge code (proxy, middleware, edge routes) runs on far more requests than
your page views. A matcher that is slightly too broad puts it in front of every
static asset, prefetch and health check. Sampling edge transactions at the same
rate as page transactions can easily produce ten times the volume for a tenth
of the insight.

## Sample by route, not uniformly

The real win is `tracesSampler`, which decides per transaction. Now you can
keep 100% of the things you care about and almost none of the rest:

```ts
Sentry.init({
  tracesSampler: (samplingContext) => {
    const name = samplingContext.name;

    // Never trace health checks or the Sentry tunnel itself.
    if (name.includes("/api/health") || name.includes("/monitoring")) return 0;

    // Checkout is where latency costs money. Keep all of it.
    if (name.includes("/checkout") || name.includes("/api/webhooks")) return 1;

    // Inherit the parent's decision on distributed traces, so a sampled
    // request is not half-recorded.
    if (typeof samplingContext.parentSampleRate === "number") {
      return samplingContext.parentSampleRate;
    }

    return 0.05;
  },
});
```

Three rules of thumb encoded there:

1. **Drop what is never interesting.** Health checks, uptime pollers, the
   tunnel route, static asset requests. These are pure volume.
2. **Keep everything on the paths that matter.** Checkout, signup, payment
   webhooks: the handful of routes where a latency regression has a cost you
   can name.
3. **Respect the parent decision.** A partially sampled distributed trace is
   worse than no trace: the waterfall has holes and you draw wrong conclusions.

## Errors are never sampled by this

A frequent misunderstanding: `tracesSampleRate: 0.1` does **not** mean you lose
90% of your errors. It only affects performance transactions. Error events have
their own control, `sampleRate`, which should stay at `1.0`: errors are the
cheap, high-value data.

If your error volume is genuinely too high, the fix is filtering the noise
(`ignoreErrors`, `denyUrls`, better fingerprints), not sampling away real bugs
at random.

## Session Replay is the expensive one

Replay is priced separately and is heavier than everything else: it records
the DOM, uploads it, and adds substantially to the client bundle. This battery
ships with both replay rates at `0` deliberately.

If you enable it:

```ts
replaysSessionSampleRate: 0,     // do not record ordinary sessions
replaysOnErrorSampleRate: 0.1,   // record a fraction of sessions that errored
```

Error-triggered replay is the only variant that pays for itself: you get the
recording for the sessions you actually want to watch. And configure masking
before you enable anything: replay records what users type.

## Monitoring the budget

- Set a **spend cap** in Sentry's billing settings, and per-category limits if
  your plan supports them. Without one, a retry storm can burn a month's quota
  overnight.
- Check the Stats page monthly: accepted vs dropped events per category. A
  spike in transactions is usually a new route with a chatty client, not real
  growth.
- When you hit a limit, Sentry drops events, and it does not preferentially
  keep the errors. A transaction flood can cost you the error you needed.

## The starting point to copy

For a normal app, before you have data:

| Setting | Server | Edge | Client |
|---|---|---|---|
| `sampleRate` (errors) | 1.0 | 1.0 | 1.0 |
| `tracesSampleRate` | 0.1 | 0.02 | 0.1 |
| `replaysSessionSampleRate` | none | none | 0 |
| `replaysOnErrorSampleRate` | none | none | 0 |

Then, one month in: look at what you have opened. Raise the rate on the two
routes you investigated, drop it everywhere else, and delete the tracing you
never read.

---

Agentic Boilerplate: A Next.js repo your agent already knows. Free during launch, then $99 once.

- Site map for agents: https://agenticboilerplate.com/llms.txt
- Public API: https://agenticboilerplate.com/openapi.json
- Contact: agenticstudio@gmail.com
