Node.js API Error Tracking: Catch 5xx Errors Before Your Users Do
A 5% error rate on your Node.js API can quietly kill your product. This guide covers how to track, aggregate, and alert on API errors in Express and Fastify — without spending a day setting up error monitoring.
The Hidden Error Problem in Production APIs
Here's a scenario that happens more often than you'd think: a developer deploys a new version of their API. Everything looks fine. The deployment succeeds. The app starts. A few hours later, a user opens a support ticket: "I can't save my data."
The developer checks the logs — 100,000 lines of combined info, debug, and error messages. The 5xx errors are buried somewhere in there. The route that's broken is POST /projects, and it's been returning 500 for 3 hours to 8% of requests.
This is the error tracking problem. Not that errors happen — they always do. But that you find out about them from users instead of finding them yourself, and hours late instead of minutes after deploy.
Why console.log and Basic Error Middleware Aren't Enough
Most Node.js APIs have some version of this:
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
});
This catches unhandled errors and logs them. But it doesn't tell you:
- Which routes have the highest error rates
- How often errors are happening (1/day? 1/minute?)
- Whether error rates are increasing after a deployment
- What the 4xx breakdown looks like (auth failures? validation errors? not found?)
You need aggregated error metrics, not individual log lines.
Types of API Errors to Track
5xx Server Errors
These are your bugs. Unhandled promise rejections, DB connection failures, validation logic you missed, third-party API failures that weren't caught.
// Common sources of 5xx errors in Node.js
app.get('/users/:id', async (req, res) => {
const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
// If db is unavailable, this throws — causes 500 if not caught
res.json(user.rows[0]);
});
4xx Client Errors
These are client mistakes — but tracking them matters. A sudden spike in 401s might mean your auth tokens are expiring unexpectedly. A spike in 422s might mean a frontend deploy broke form validation. A spike in 404s might mean a route was accidentally renamed.
Error Rate Per Route
The most actionable metric is error rate per route: what % of requests to POST /checkout are returning 5xx? Even 1% on a critical path is a fire.
Setting Up Error Tracking in 60 Seconds
npm install auto-api-observe
const express = require('express');
const { observe } = require('auto-api-observe');
const app = express();
// Add monitoring before your routes
app.use(observe({ apiKey: process.env.APILENS_KEY }));
// Your routes
app.post('/checkout', async (req, res) => {
const result = await processPayment(req.body);
res.json(result);
});
// Your error handler (still needed — observe hooks into res.on('finish'))
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: 'Something went wrong' });
});
app.listen(3000);
The middleware automatically captures the status code of every response — including errors. No need to explicitly report errors; they're tracked as part of every request metric.
What Error Data You Get
Once deployed, the Errors tab in your dashboard shows:
Error rate over time: A chart of error rate (%) across all routes over the last 24h/7d. You can immediately see if a deploy caused an error rate spike.
Errors by route: Which routes are returning the most errors. POST /checkout at 8% error rate vs GET /users at 0.1% error rate — very different problems requiring different urgency.
Status code breakdown: How many 400s vs 401s vs 422s vs 500s vs 503s. Useful for distinguishing client errors from server errors.
Error volume: Total 5xx count in a time window. Useful for understanding severity — 10 errors/day on a low-traffic route is different from 100 errors/minute.
Setting Up Error Alerts
Knowing your error rate is 5% is useful. Getting notified within 5 minutes of a deploy that caused an error spike is essential.
From your APILens dashboard:
1. Go to Alerts (within your project)
2. Create a new alert: type error rate, threshold > 2%, window 5 minutes
3. Add your email address
4. Save
Now, if your error rate exceeds 2% over any 5-minute window, you get an email with the affected project and timestamp.
You can also set per-route alerts. If POST /payments — your most critical route — exceeds even 0.5% error rate, that should page you immediately.
// The alert fires based on the route pattern you're seeing in the dashboard
// e.g., "POST /api/payments" error rate > 0.5% → email notification
Error Tracking Best Practices for Node.js APIs
Always handle promise rejections
// ❌ Unhandled rejection crashes the process in Node.js 15+
app.get('/data', async (req, res) => {
const data = await riskyOperation(); // if this throws, no error handler catches it
res.json(data);
});
// ✓ Wrap async routes
app.get('/data', async (req, res, next) => {
try {
const data = await riskyOperation();
res.json(data);
} catch (err) {
next(err); // passes to Express error handler → res.status(500)
}
});
// Or use an async wrapper utility
const asyncHandler = fn => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next);
app.get('/data', asyncHandler(async (req, res) => {
const data = await riskyOperation();
res.json(data);
}));
Return consistent error shapes
// ✓ Consistent error response format
app.use((err, req, res, next) => {
const status = err.status || err.statusCode || 500;
res.status(status).json({
error: {
message: status < 500 ? err.message : 'Internal server error',
code: err.code || 'UNKNOWN_ERROR',
},
});
});
Don't log sensitive data in errors
// ❌ Leaks user data to logs
console.error('Failed to process payment', { card: req.body.cardNumber, cvv: req.body.cvv });
// ✓ Log only what's needed for debugging
console.error('Failed to process payment', { userId: req.user.id, amount: req.body.amount });
Error Tracking vs Full APM: Do You Need Both?
There's an overlap between error tracking (Sentry) and APM (Datadog, APILens). Here's how to think about it:
| Use Case | Error Tracking (Sentry) | APM (APILens) |
|---|---|---|
| Capture full stack traces | ✓ Best-in-class | ✗ |
| Group errors by type | ✓ | ✗ |
| Error rate per route | Partial | ✓ |
| Latency per route | ✗ | ✓ |
| DB query profiling | ✗ | ✓ |
| Alert on error rate spike | Partial | ✓ |
| Distributed tracing | Partial | ✓ |
Practical recommendation: Use both together. Sentry is unmatched for stack trace capture and error grouping. APILens shows you the aggregate error rate, latency, and DB query context around those errors. They're complementary.
APILens is free during beta. Sentry's free tier covers most small APIs. There's no reason to choose.
A Real Scenario: Catching a Deploy-Induced Error Spike
Here's the workflow when it works correctly:
1. You deploy version 2.3.1 at 14:00
2. At 14:07, you get an email: "Error rate alert — project: api-prod — error rate 6.2% over last 5 minutes"
3. You open the dashboard, go to Errors tab
4. POST /api/subscriptions is showing 100% error rate (all requests since 14:00)
5. You check your deploy — a new dependency broke a Stripe API call
6. You roll back at 14:12
7. Error rate drops to 0% at 14:13
Without monitoring: you find out at 14:45 when a customer emails you that they can't upgrade their plan.
With monitoring: you find it in 7 minutes, roll back in 12, total user impact is 12 minutes instead of 45+.
Summary
Error tracking for a Node.js API doesn't require Sentry Pro or Datadog. For aggregate error rates, per-route error breakdowns, and deploy regression detection, one middleware and a free dashboard is enough.
npm install auto-api-observe
app.use(observe({ apiKey: process.env.APILENS_KEY }));
Then set up an error rate alert from the dashboard — and find out about broken deploys in minutes, not hours.
- Dashboard: apilens.rest/dashboard
- GitHub: github.com/rahhuul/auto-api-observe
- Price: Free during beta
*How do you currently track errors in your Node.js API? What's your alert threshold for error rate?*