Skip to content
Observability

Error Tracking with Sentry: From 'Users Are Complaining' to 'Already Fixed'

The highest-ROI observability tool for a small team. One integration, and every uncaught exception comes with a stack trace, context, and breadcrumbs.

February 27, 2025 7 min readBy ShipReady

Error tracking is the difference between "users are complaining about a bug" and "you already fixed the bug before they complained." It's the highest-ROI observability tool for a small team — one integration, and every uncaught exception gets reported with a full stack trace, request context, and user info.

Here's how to set it up right.

Why error tracking matters

Without error tracking, you learn about bugs from:

  • User support tickets (angry, delayed, missing context)
  • Reviewing logs manually (slow, reactive)
  • Not learning about them at all (worst case)

With error tracking, you learn about bugs from:

  • A real-time alert the moment an exception fires
  • A stack trace pointing to the exact line
  • Request context (URL, user, browser, payload shape)
  • A breadcrumb trail of what happened before the error

The difference is night and day. A bug that would have taken a day to reproduce takes 10 minutes when the error report lands in your inbox with everything you need.

The tools

  • Sentry — the default. Free tier (5,000 errors/month), generous paid tiers. Supports every language. The open-source standard.
  • Rollbar — similar to Sentry, slightly different UX. Free tier (5,000 events/month).
  • Bugsnag — strong on mobile, good free tier.
  • Raygun — enterprise-focused, pricier.
  • Self-hosted GlitchTip — open-source Sentry alternative, self-hostable.

For a small team: Sentry's free tier is enough to start. When you outgrow it, the paid tier is reasonable.

What to track

1. Uncaught exceptions

The baseline. Every uncaught exception — frontend or backend — should be reported. The SDK does this automatically once installed.

// Frontend (React)
Sentry.init({ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN });

// Backend (Node)
Sentry.init({ dsn: process.env.SENTRY_DSN });

2. Handled errors you care about

Not every catch block should be silent. For errors that are unexpected or indicate a real problem, manually capture:

try {
  await riskyOperation();
} catch (err) {
  Sentry.captureException(err);
  // handle gracefully
}

Don't capture expected errors (validation failures, 404s) — you'll drown in noise.

3. Performance issues (optional, later)

Most error trackers now also do performance monitoring (page load times, slow DB queries, transaction traces). Useful once you have errors under control. Start with errors; add performance later.

Frontend setup (React / Next.js)

Install the SDK, initialize it early (before your app renders), and configure source maps:

  1. Install: npm install @sentry/nextjs (or the framework-specific package).
  2. Initialize: in your app's entry point, call Sentry.init() with your DSN.
  3. Source maps: upload source maps to Sentry so stack traces show your original code, not minified. Every CI/CD pipeline should do this on deploy.
  4. Error boundary: wrap your app in an error boundary that captures uncaught render errors. Next.js's error.tsx convention does this automatically.
  5. User context: after login, call Sentry.setUser({ id, email }) so error reports include who was affected.

Backend setup (Node / Python / etc.)

  1. Install the SDK for your language.
  2. Initialize at the very start of your app — before any routes are registered.
  3. Wrap your request handler so the SDK captures the request context (URL, method, headers, user) with each error.
  4. Don't capture expected errors. A 404 or validation error isn't a bug; filter it out.
  5. Capture unhandled promise rejections and uncaught exceptions — the SDK can do this, so your process doesn't crash silently.

What good context looks like

When an error report comes in, you should be able to answer:

  • What happened? The exception type and message.
  • Where? The stack trace (with source maps).
  • When? The timestamp and how often it's happening.
  • Who? The user ID / email (if authenticated).
  • What were they doing? The URL, the request payload (sanitized), breadcrumbs (previous clicks / API calls).
  • What environment? Browser, OS, app version, server region.

Sentry captures all of this automatically once you set the user context and install the SDK. The manual part is just adding business-logic breadcrumbs ("user clicked checkout", "order created") for flows you care about.

Source maps: non-negotiable for frontend

Without source maps, your frontend stack traces look like:

at a (main.abc123.js:1:4567)
at b (main.abc123.js:1:7890)

Useless. With source maps uploaded to Sentry:

at checkout (src/components/Checkout.tsx:42:15)
at handleSubmit (src/components/Checkout.tsx:28:9)

Now you can fix it. Upload source maps in CI on every deploy — Sentry has CLI tools and GitHub Actions for this. Never ship to production without uploading maps.

PII and scrubbing

Error reports can accidentally include PII — passwords in request bodies, emails in URLs, tokens in headers. Configure scrubbing:

  • Server-side: Sentry can redact fields matching patterns (password, token, authorization).
  • Before send: use the beforeSend hook to inspect and scrub events before they're sent.

Don't skip this. Sending a user's password to Sentry is a data breach.

Alerting: don't alert on every error

A common mistake: email on every error. You'll get 500 emails at 3am and learn to ignore them. Instead:

  • Alert on new errors only — first time an error type is seen.
  • Alert on spikes — error rate for a known issue suddenly 10x's.
  • Alert on regression — an error you marked "resolved" reappears.
  • Group by issue — Sentry groups identical errors so you see "1,234 occurrences of this bug" not 1,234 separate alerts.

Route alerts to Slack/Discord/PagerDuty. Email is too slow for production issues.

Triage and resolution

When an error comes in:

  1. Acknowledge it — mark as "investigating" so your team knows someone's on it.
  2. Reproduce — use the breadcrumbs and request context to reproduce locally.
  3. Fix and deploy — then mark the error "resolved" in Sentry.
  4. Verify — Sentry will auto-resolve when the fix deploys and the error stops. If it reappears, Sentry reopens it (regression detection).

This loop — alert, investigate, fix, resolve, verify — is the core of production error handling. It's why error tracking exists.

The 80/20

If you do nothing else:

  1. Install Sentry (free tier) on frontend + backend.
  2. Upload source maps in CI.
  3. Set user context after login.
  4. Alert on new errors only, to Slack.
  5. Triage within 24 hours — every new error gets acknowledged or resolved.

That's it. An afternoon of work, and you'll never learn about a production bug from a user complaint again.

Run the ShipReady Observability checklist — error tracking is one of the 8 items in the Observability & Operations section.

Run the full checklist

Put this into practice — generate a stack-specific production readiness checklist and track your progress, free.

Open the checklist

Get new articles in your inbox

Practical production readiness guides. No spam, unsubscribe anytime.

Join developers shipping safer. We email ~2× per month.

Keep reading