Cloud & Infrastructure · Observability
Error Tracking in 2026: What Sentry Catches That Your Logs Don't
Logs say what happened. Error tracking says what broke, for which users, in what context. Setting up Sentry properly, without the alert fatigue.
Anurag Verma
6 min read
Sponsored
Your logs tell you that something happened. An error tracking system tells you what broke, where in the code, who it affected, how many times, and what the user was doing when it happened. They’re not the same thing, and running one without the other leaves gaps.
Sentry is the most widely deployed error tracking platform for web applications. This is a practical setup guide, what to instrument, what to skip, and how to avoid the noise that makes most teams stop looking at their error dashboard within a month.
The Setup
For a Next.js app:
npm install @sentry/nextjs
npx @sentry/wizard@latest -i nextjs
The wizard creates sentry.client.config.ts, sentry.server.config.ts, and sentry.edge.config.ts. It also wraps your next.config.js. For new projects, run the wizard. For existing projects, be careful about the config merge, check what it writes before committing.
Minimal client config:
// sentry.client.config.ts
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 0.1, // 10% of transactions for performance monitoring
replaysSessionSampleRate: 0.05, // 5% of sessions recorded
replaysOnErrorSampleRate: 1.0, // 100% of sessions that contain an error
integrations: [
Sentry.replayIntegration({
maskAllText: true, // mask PII in session replays
blockAllMedia: false,
}),
],
});
The tracesSampleRate deserves attention. At high traffic, 100% tracing generates significant data volume and cost. 10% is a reasonable default for most apps. If you care more about detecting latency regressions than individual traces, 5% is fine. If you’re debugging a specific slow path, bump it to 100% temporarily and bring it back down.
Source Maps
Without source maps, your stack traces show minified production code. Line 1, column 47832 doesn’t help anyone debug.
Sentry uploads source maps during the build via the Next.js plugin:
// next.config.ts
import { withSentryConfig } from "@sentry/nextjs";
export default withSentryConfig(nextConfig, {
org: "your-org",
project: "your-project",
silent: true,
widenClientFileUpload: true,
hideSourceMaps: true, // don't serve maps to the browser
disableLogger: true,
});
Set SENTRY_AUTH_TOKEN in your CI environment. Maps upload automatically during next build. They’re stored on Sentry’s servers for symbolicating stack traces, not exposed in your deployed bundle.
Capturing the Right Errors
Sentry automatically captures unhandled exceptions and unhandled promise rejections. What it doesn’t do automatically: capture handled errors you decide to track, add user context, or distinguish between “expected and recoverable” and “something is wrong.”
For explicit error capture with context:
import * as Sentry from "@sentry/nextjs";
async function createPayment(userId: string, amount: number) {
try {
const result = await stripe.charges.create({ amount, currency: "usd" });
return result;
} catch (error) {
Sentry.captureException(error, {
extra: {
userId,
amount,
stripeVersion: stripe.VERSION,
},
tags: {
feature: "payments",
severity: "high",
},
});
throw error; // re-throw so the caller handles it
}
}
Adding user context globally so every error includes who it affected:
// In your auth middleware or session setup
Sentry.setUser({
id: session.userId,
email: session.email,
});
For React error boundaries:
import * as Sentry from "@sentry/nextjs";
export function ComponentWithBoundary({ children }: { children: React.ReactNode }) {
return (
<Sentry.ErrorBoundary
fallback={<div>Something went wrong. We've been notified.</div>}
beforeCapture={(scope) => {
scope.setTag("component", "ComponentWithBoundary");
}}
>
{children}
</Sentry.ErrorBoundary>
);
}
Avoiding Alert Fatigue
The reason most teams stop checking their error dashboards: they alert on every error and get buried in noise from expected, unactionable events, bot traffic, crawlers hitting 404s, users typing invalid URLs, browser extensions throwing errors on your pages.
Filter them out at the source:
Sentry.init({
// ...
beforeSend(event, hint) {
const error = hint.originalException;
if (error instanceof Error) {
// Known browser noise — not your bugs
if (error.message.includes("ResizeObserver loop limit exceeded")) return null;
if (error.message.includes("Non-Error promise rejection")) return null;
if (error.message.includes("Loading chunk")) return null;
}
// Skip crawler traffic
const ua = event.request?.headers?.["user-agent"] ?? "";
if (ua.includes("Googlebot") || ua.includes("bingbot")) return null;
return event;
},
});
At the alert level, create separate rules for different error rates. A 5% error rate on your payment flow deserves an immediate page. A 0.1% rate on your search page can wait for the morning standup.
Use Sentry’s issue grouping rules to collapse variants of the same underlying error into one issue. Without this, a spike in one error type produces dozens of separate issues with slightly different messages, all pointing to the same root cause.
Performance Monitoring
Sentry’s performance tab shows slowest transactions, P75 and P99 latency, and throughput. For Next.js, it automatically instruments page loads, API routes, and database queries for supported ORMs.
For manual spans around code you care about:
async function fetchUserData(userId: string) {
return Sentry.startSpan(
{ name: "fetchUserData", op: "db.query" },
async () => {
return db.query.users.findFirst({
where: eq(users.id, userId),
});
}
);
}
The span shows up in transaction traces, making it straightforward to see if a specific function is responsible for latency spikes, and exactly how often it’s called per request.
What Sentry Won’t Do
Error tracking is not a replacement for structured logging. Sentry captures exceptions and their context; it doesn’t capture “this request processed 47 items at 12:03:21.” For event-level logs, you need a log aggregation tool (Axiom, Datadog Logs, Loki, or CloudWatch depending on your stack).
It’s also not an uptime monitor. A server crash produces no Sentry errors if no requests are reaching the server to throw one. Pair Sentry with a basic uptime monitor (Checkly, UptimeRobot, or a simple health check pinger) so you catch the “site is down” case separately from the “site is up but throwing errors” case.
The combination that covers most applications up to mid-scale: Sentry for error tracking and session context, a log aggregator for structured events, and an uptime monitor for availability. You don’t need all three immediately, but you’ll want all three before you’re responsible for a production system that has real users depending on it.
Cost
Sentry’s free tier covers 5,000 errors per month, enough to validate the setup and get comfortable with the interface. After that, the Starter plan at $26/month covers 50,000 errors and 100,000 performance transactions, which works for most early-stage products. The Team plan at $80/month per project adds alerting rules and longer data retention.
If self-hosting is preferred, GlitchTip is an open source Sentry-compatible alternative. It accepts the same SDKs and supports most Sentry features. It requires operational overhead (you’re running the service), but eliminates usage-based billing and keeps error data in your own infrastructure.
Frequently asked questions
- What does Sentry catch that my logs don't?
- Context around a failure, assembled automatically. A log line records that an exception occurred; Sentry records the stack trace against your original source, which user hit it, what they were doing, how many others hit the same thing, and whether it started after a particular release. Reconstructing that from logs means correlating across several systems by hand, which is exactly the work nobody does at 2am.
- How do I stop the error dashboard becoming noise?
- Filter before the events arrive rather than after. Most of the noise is unactionable by definition: crawlers hitting dead URLs, browser extensions throwing on your pages, users typing malformed URLs. Drop those in beforeSend or via ignoreErrors. Then use issue grouping rules so variants of one underlying error collapse into a single issue instead of producing dozens with slightly different messages.
- What should tracesSampleRate be set to?
- 10% is a sensible default. Performance data volume drives cost, and at real traffic 100% tracing generates a lot of it for little extra insight, because latency regressions show up clearly in a sample. Drop to 5% if you only care about aggregate P75 and P99. Raise to 100% temporarily when you are chasing a specific slow path, then put it back.
- Do I still need structured logging if I have Sentry?
- Yes. Sentry captures exceptions and their context; it does not capture "this request processed 47 items at 12:03:21". That is a log aggregator's job, whether that is Axiom, Datadog Logs, Loki, or CloudWatch. The combination that covers most applications is error tracking, log aggregation, and a separate uptime monitor, because each one is blind to what the other two see.
- When is GlitchTip worth it over hosted Sentry?
- When usage-based billing is a real problem or error data cannot leave your infrastructure. It accepts the same SDKs and covers most Sentry features, so the migration is mostly a DSN change. What you take on is running the service yourself, which is a fair trade at high error volume or under strict data residency rules, and a poor one if you just want error tracking to work.
Sponsored
More from this category
More from Cloud & Infrastructure
Sponsored
Discussion
Join the conversation.
Comments are powered by GitHub Discussions. Sign in with your GitHub account to leave a comment.
Sponsored