Skip to main content

Best Error Tracking Libraries for JavaScript in 2026

·PkgPulse Team
0

TL;DR

Sentry for the best developer experience and ecosystem; Highlight.io for session replay + errors in one tool. Sentry (~4M weekly downloads) is the industry standard — integrations for every framework, source maps, performance monitoring, and a generous free tier (5K errors/mo). Highlight.io (~50K downloads) is newer and open-source — it combines error tracking with full session replay at a lower price. For most projects, Sentry is the safe bet.

Key Takeaways

  • Sentry: ~4M weekly downloads — full-featured, 5K errors/mo free, every framework
  • Highlight.io: ~50K downloads — open-source, session replay + errors + logs bundled
  • Bugsnag: ~200K downloads — stability monitoring focus, good mobile support
  • Sentry source maps — upload during build to see original TypeScript code in errors
  • @sentry/nextjs — automatic route instrumentation, server + client errors unified

Why Error Tracking Is Non-Negotiable

Every web application has bugs that make it into production. Some you know about from user reports; most you don't. Error tracking services automatically capture JavaScript exceptions, server errors, and performance issues the moment they occur — before users file bug reports or (worse) silently leave.

Without error tracking, debugging production issues is detective work: you look at logs hoping to find something relevant, try to reproduce bugs locally, and often can't. With error tracking, you have: the exact error message and stack trace, the user's browser and OS, the page they were on, the sequence of actions that led to the error (breadcrumbs), and a recording of exactly what happened on their screen (session replay).

The gap between "debugging with error tracking" and "debugging without" is enormous. For any application with real users, error tracking is among the highest-ROI tools you can add.


Sentry (Industry Standard)

// Sentry — Next.js setup
// npm install @sentry/nextjs
// npx @sentry/wizard@latest -i nextjs

// 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: process.env.NODE_ENV === 'production' ? 0.1 : 1.0,
  replaysSessionSampleRate: 0.1,     // 10% of sessions
  replaysOnErrorSampleRate: 1.0,     // 100% of error sessions
  integrations: [
    Sentry.replayIntegration({
      maskAllText: true,             // Privacy: mask all user text
      blockAllMedia: true,
    }),
  ],
});
// sentry.server.config.ts
import * as Sentry from '@sentry/nextjs';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 0.1,
  // Profiling (requires plan)
  profilesSampleRate: 0.1,
});
// Sentry — manual error capture and context
import * as Sentry from '@sentry/nextjs';

// Capture specific errors with context
async function processPayment(userId: string, amount: number) {
  try {
    await chargeCard(userId, amount);
  } catch (error) {
    Sentry.captureException(error, {
      tags: {
        feature: 'payments',
        userId,
      },
      extra: {
        amount,
        timestamp: new Date().toISOString(),
      },
      level: 'error',
    });
    throw error;
  }
}

// Set user context (shows in Sentry UI)
Sentry.setUser({
  id: user.id,
  email: user.email,
  username: user.name,
});

// Custom breadcrumbs
Sentry.addBreadcrumb({
  category: 'ui.click',
  message: 'User clicked checkout button',
  level: 'info',
});

// Performance spans
const transaction = Sentry.startTransaction({ name: 'processOrder' });
const span = transaction.startChild({ op: 'validateInventory' });
await checkInventory(items);
span.finish();
transaction.finish();
// Sentry — error boundary (React)
import * as Sentry from '@sentry/react';

export function ErrorBoundaryWrapper({ children }) {
  return (
    <Sentry.ErrorBoundary
      fallback={({ error, resetError }) => (
        <div>
          <h2>Something went wrong</h2>
          <pre>{error.message}</pre>
          <button onClick={resetError}>Try again</button>
        </div>
      )}
      beforeCapture={(scope, error, componentStack) => {
        scope.setTag('react_component', 'App');
      }}
    >
      {children}
    </Sentry.ErrorBoundary>
  );
}

Sentry's wizard (npx @sentry/wizard) automates the entire setup: installs the SDK, creates config files, adds the webpack/Vite plugin for source maps, and configures environment variables. For Next.js, it instruments both the client and server automatically, including API routes, middleware, and server actions.

The breadcrumb system is particularly valuable for debugging: Sentry automatically records DOM clicks, navigation events, network requests, and console.log calls in the sequence they occurred. When an error triggers, you see exactly what the user was doing for the previous 30 seconds.


Highlight.io (Open-Source, Session Replay)

// Highlight.io — setup with React
import { H } from 'highlight.run';

H.init(process.env.NEXT_PUBLIC_HIGHLIGHT_PROJECT_ID!, {
  environment: 'production',
  version: process.env.NEXT_PUBLIC_APP_VERSION,
  networkRecording: {
    enabled: true,
    recordHeadersAndBody: true,   // Record network requests
  },
  privacySetting: 'strict',        // Mask PII by default
});

// Identify user
H.identify(user.email, {
  id: user.id,
  name: user.name,
  plan: user.plan,
});

// Manual error
try {
  await riskyOperation();
} catch (err) {
  H.consumeError(err as Error, {
    payload: { operation: 'riskyOperation' },
  });
}

// Track custom events
H.track('Checkout Started', { items: cart.length, total: cart.total });
// Highlight.io — Node.js backend
import { H } from '@highlight-run/node';

H.init({ projectID: process.env.HIGHLIGHT_PROJECT_ID! });

// Express middleware
app.use(H.Handlers.errorHandler());

// Manual capture
H.consumeError(new Error('Payment failed'), 'user@example.com', {
  payload: { amount: 99.99 },
});

Highlight.io's key differentiator is that it bundles session replay, error tracking, and structured logging in a single product. When an error occurs, you can immediately replay the user's session to see exactly what happened — no switching between tools.

Being open-source (Apache 2.0 licensed), Highlight.io can be self-hosted. For companies with data sovereignty requirements, self-hosting means error data never leaves your infrastructure.

The pricing model is also different: Highlight.io's hosted pricing is session-based rather than event-based, which often works out cheaper for applications with many small errors per session.


Source Maps (Critical for Any Tool)

// next.config.js — automatic source map upload with Sentry
const { withSentryConfig } = require('@sentry/nextjs');

module.exports = withSentryConfig({
  /* next.js config */
}, {
  // Sentry webpack plugin options
  silent: true,
  org: 'my-org',
  project: 'my-project',
  // Automatically upload source maps after each build
  widenClientFileUpload: true,
  // Delete source maps from bundle (don't expose to users)
  hideSourceMaps: true,
});

Source maps transform minified production JavaScript stack traces back into original TypeScript code. Without source maps, an error shows app.js:1:45892 — with source maps, it shows src/components/checkout/PaymentForm.tsx:142:5. Source map upload should be configured for any error tracking tool on day one.


Comparing Features

FeatureSentryHighlight.ioBugsnag
Session Replay✅ (addon)✅ (included)
Performance MonitoringLimited
Open SourcePartial
Self-Hosting✅ (Sentry self-hosted)
Free Tier5K errors/mo500 sessions/moTrial only
Logging Integration
Mobile SDKLimited

Pricing in 2026

Sentry: Free tier includes 5,000 errors/month. Team plan starts at $26/month for 50K errors. Business plan for custom volumes and SLAs.

Highlight.io: Free tier for 500 monthly sessions. Growth plan starts at $50/month. Self-hosted is free with no limits.

Bugsnag: No permanent free tier. Starts at $59/month for basic plans.

For startups and side projects, Sentry's free tier (5K errors/mo) is usually sufficient. For high-traffic applications generating millions of events, Highlight.io's session-based pricing can be more predictable.


When to Choose

ScenarioPick
Standard error trackingSentry
Session replay + errors + logs bundledHighlight.io
Open-source, self-hostableHighlight.io
Mobile apps (React Native + web)Bugsnag or Sentry
Stability score / error budgetBugsnag
Performance monitoringSentry (transactions + spans)
Free tier (small project)Sentry (5K errors/mo free)
Enterprise SLASentry or Datadog
Data sovereignty / self-hostingHighlight.io

Common Error Tracking Mistakes

Deploying an error tracking library is straightforward. Getting the most value out of it requires avoiding a set of common pitfalls.

Mistake 1: Not configuring sample rates. The default tracesSampleRate: 1.0 captures 100% of transactions for performance monitoring. For any application with real traffic, this generates enormous volume quickly. Sentry's free tier is 5,000 errors per month — performance transactions exhaust it much faster than errors. Set tracesSampleRate to 0.05–0.1 (5–10%) in production from the start.

Mistake 2: Not uploading source maps. Without source maps, production stack traces show minified code (app.js:1:23872). This makes Sentry essentially useless for debugging. Source map upload takes 5 minutes to configure but transforms every future error from undebuggable to immediately actionable. Set it up before your first production deploy.

Mistake 3: Not setting user context. Sentry's setUser() call associates errors with specific users. Without it, you can see that 50 users hit an error but you can't identify which users to contact or reproduce their session. Set user context when the user authenticates, and clear it on logout.

Mistake 4: Sending too much PII. The inverse problem: capturing user context without privacy controls. Sentry's session replay can capture keystrokes including passwords if not configured correctly. Always set maskAllText: true and blockAllMedia: true in replay configuration, and review what's being captured in your privacy policy and Sentry settings. GDPR and CCPA compliance requires careful configuration.

Mistake 5: Ignoring error volume and not setting up alerts. Installing an error tracker and never looking at it provides false confidence. Configure alert rules: notify on Slack or email when a new error occurs, when an error rate spikes above baseline, or when error volume crosses a threshold. Sentry's alert rules are powerful but require manual setup — they don't work out of the box.

Mistake 6: Not grouping errors correctly (fingerprinting). Sentry automatically groups similar errors. Sometimes it groups too aggressively (different errors with the same message look like one issue) or too granularly (the same error appears as hundreds of separate issues). Configure custom fingerprinting for errors that need specific grouping:

Sentry.captureException(error, {
  fingerprint: ['database-connection-error', error.code],
});

Setting Up Alerting and Workflows

Capturing errors is only half the value of error tracking. The other half is getting the right people notified at the right time. A good alerting setup reduces mean time to detection (MTTD) from hours to minutes.

Sentry's alert system supports multiple trigger conditions, delivery channels, and routing rules. The most useful configurations for development teams:

New issue alerts. Trigger when a completely new error is seen for the first time. This is the highest-priority alert — new errors indicate a regression, often from a recent deploy. Route these to your team's primary channel (Slack #alerts) immediately.

Regression alerts. Trigger when a previously resolved issue reappears. Essential for catching when a fix didn't hold, or when a deploy reverted a bug fix unintentionally. Route to the engineer who resolved the original issue if possible.

Error rate alerts. Trigger when a specific error's occurrence rate increases by X% or exceeds Y errors per hour. Useful for catching gradual degradation before it becomes critical. A 10x spike in 404 errors, for example, might indicate a broken link or failed deploy.

# Sentry alert configuration (via UI or Sentry CLI)
# Example: Alert on payment errors
name: Payment Errors Alert
conditions:
  - type: EventFrequency
    value: 10
    interval: 1h
    comparison_type: count
filters:
  - type: TaggedEventFilter
    key: feature
    value: payments
actions:
  - type: SlackNotifyServiceAction
    channel: "#payments-oncall"
    workspace: YOUR_WORKSPACE_ID

Pair alerts with ownership rules that route errors to the right team based on file path or tags. If an error originates in src/payments/, Sentry can automatically assign it to the payments team's Sentry queue and Slack channel. This removes the manual triage step of figuring out who owns an error.


Observability Beyond Error Tracking

Error tracking is one pillar of observability. A production-ready application needs all three: logs, metrics, and traces. Understanding how error tracking fits into the larger observability picture helps you avoid over-relying on a single tool.

Structured logging. Console.log statements aren't structured or searchable in production. A logging library like Pino (Node.js) or Winston emits JSON logs that can be shipped to Datadog, Logtail, or Highlight.io's log ingestion. Structured logs let you query level:error AND userId:abc123 rather than grepping through text. See our Node.js logging libraries guide for setup.

Metrics and uptime monitoring. Error tracking catches errors when they happen. Uptime monitoring catches when your service is entirely unreachable. Tools like Better Stack, Checkly, or Datadog synthetic monitoring send probes to your endpoints every minute and alert if they go down. This is distinct from error tracking — a server can be up but throwing exceptions (Sentry catches it) or completely down (uptime monitor catches it).

Distributed tracing. For microservices architectures, tracing follows a request across service boundaries. Sentry supports distributed tracing — a span in your frontend connects to a span in your API which connects to a span in your database query. When a slow page load occurs, distributed traces show exactly which service or query caused the latency. OpenTelemetry is the open standard that most tools now support, enabling you to switch between trace backends without rewriting instrumentation.

The practical recommendation for 2026: start with Sentry (error tracking + basic traces), add Pino structured logging to your Node.js backend, and use Better Stack or Checkly for uptime monitoring. This three-tool combination covers the most critical observability needs without the complexity of a full Datadog or New Relic deployment.


FAQ: JavaScript Error Tracking

Q: Does Sentry's session replay capture passwords or sensitive form fields?

By default with maskAllText: true, Sentry masks all text content including form inputs. Without this setting, session replay can capture text typed into input fields, including passwords. Always configure maskAllText: true in production. You can use data attributes to selectively unmask non-sensitive fields: data-sentry-unmask. Review what's being captured and document your privacy controls.

Q: How do I filter out noise from browser extensions and bot traffic?

Browser extension errors often show up as unhandled errors with unhelpful messages like "Script error." or errors from chrome-extension:// URLs. Filter them in Sentry's beforeSend hook:

Sentry.init({
  beforeSend(event) {
    // Filter extension errors
    if (event.request?.url?.startsWith('chrome-extension://')) return null;
    // Filter known bot user agents
    if (navigator.userAgent.includes('Googlebot')) return null;
    return event;
  },
});

Q: Should I use Sentry's performance monitoring or a dedicated APM?

Sentry's performance monitoring is excellent for frontend performance (Core Web Vitals, page load times) and basic backend traces. For complex backend performance analysis — database query optimization, deep service-to-service tracing, infrastructure metrics — a dedicated APM like Datadog or New Relic provides more depth. For most applications that aren't at hyperscale, Sentry's built-in performance monitoring is sufficient and cheaper than adding a separate APM.

Q: How do I handle error tracking in development without polluting production data?

Use Sentry's environment configuration and filter dev environments in your Sentry project settings. Set environment: process.env.NODE_ENV in your Sentry config. In the Sentry UI, create separate alert rules for production only. Alternatively, don't initialize Sentry at all in development — set enabled: process.env.NODE_ENV === 'production' in your Sentry config. Local errors should go to the console, not to Sentry.

Q: What's the difference between captureException and captureMessage?

captureException should be called with an actual JavaScript Error object — it preserves the stack trace. captureMessage sends a custom message without a stack trace, useful for tracking non-error events (a payment succeeded, a user completed onboarding). For debugging, captureException is almost always more useful because the stack trace tells you exactly where the problem originated. Use captureMessage for business metrics and audit trails, not for debugging errors.


Compare error tracking library package health on PkgPulse. Also see our best Node.js logging libraries for observability tooling and how to set up CI/CD for a JavaScript monorepo.

Related: OpenStatus vs Better Stack vs Instatus.

The 2026 JavaScript Stack Cheatsheet

One PDF: the best package for every category (ORMs, bundlers, auth, testing, state management). Used by 500+ devs. Free, updated monthly.