Best Error Tracking Libraries for JavaScript in 2026
·PkgPulse Team
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
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>
);
}
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 },
});
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,
});
When to Choose
| Scenario | Pick |
|---|---|
| Standard error tracking | Sentry |
| Session replay + errors + logs | Highlight.io |
| Open-source, self-hostable | Highlight.io |
| Mobile apps (React Native + web) | Bugsnag or Sentry |
| Stability score / error budget | Bugsnag |
| Performance monitoring | Sentry (transactions + spans) |
| Free tier (small project) | Sentry (5K errors/mo free) |
| Enterprise SLA | Sentry or Datadog |
Compare error tracking library package health on PkgPulse.
See the live comparison
View sentry vs. bugsnag on PkgPulse →