![]()
Effective production monitoring for React applications requires a comprehensive approach that covers performance, errors, user experience, and business metrics. Here’s a complete guide to implementing professional-grade monitoring:
Core Monitoring Components
1. Error Tracking
// Using Sentry
import * as Sentry from '@sentry/react';
import { BrowserTracing } from '@sentry/tracing';
Sentry.init({
dsn: process.env.REACT_APP_SENTRY_DSN,
integrations: [new BrowserTracing()],
tracesSampleRate: 0.2,
environment: process.env.NODE_ENV,
release: process.env.REACT_APP_VERSION,
beforeSend(event) {
// Filter out sensitive data
if (event.request?.url) {
event.request.url = event.request.url.replace(/password=[^&]*/, 'password=[REDACTED]');
}
return event;
}
});
// Error boundary component
const ErrorBoundary = ({ children }) => (
<Sentry.ErrorBoundary
fallback={<ErrorScreen />}
onError={(error, componentStack) => {
// Custom error handling
}}
>
{children}
</Sentry.ErrorBoundary>
);
2. Performance Monitoring
// Using web-vitals library
import { getCLS, getFID, getLCP, getTTFB, getFCP } from 'web-vitals';
function sendToAnalytics(metric) {
const body = JSON.stringify(metric);
navigator.sendBeacon('/analytics', body);
// Also send to your monitoring service
if (window.monitoringTool) {
window.monitoringTool.trackPerformance(metric);
}
}
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getLCP(sendToAnalytics);
getFCP(sendToAnalytics);
getTTFB(sendToAnalytics);
Advanced Monitoring Setup
3. Real User Monitoring (RUM)
// Custom performance metrics collector
const startTime = performance.now();
let routeChangeStartTime;
export const initRouteMonitoring = (history) => {
history.listen(() => {
const now = performance.now();
const routeLoadTime = now - routeChangeStartTime;
trackMetric('route_change_time', routeLoadTime);
routeChangeStartTime = now;
});
};
export const trackPageLoad = () => {
const loadTime = performance.now() - startTime;
trackMetric('page_load_time', loadTime);
// Capture resource timing
const resources = performance.getEntriesByType('resource');
trackMetric('resource_load_stats', resources);
};
4. Custom Business Metrics
// E-commerce tracking example
export const trackProductView = (product) => {
trackEvent('product_view', {
product_id: product.id,
category: product.category,
price: product.price
});
};
export const trackCheckoutStep = (step) => {
trackEvent('checkout_progress', {
step,
cart_value: getCartTotal()
});
};
Backend Integration
5. Node.js Monitoring Setup
// Express middleware for frontend monitoring
app.use((req, res, next) => {
const start = Date.now();
const { originalUrl, method } = req;
res.on('finish', () => {
const duration = Date.now() - start;
trackApiMetric({
route: originalUrl,
method,
status: res.statusCode,
duration,
userAgent: req.headers['user-agent']
});
});
next();
});
6. Distributed Tracing
// OpenTelemetry setup
import { WebTracerProvider } from '@opentelemetry/web';
import { SimpleSpanProcessor } from '@opentelemetry/tracing';
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';
const provider = new WebTracerProvider();
const exporter = new ZipkinExporter({
url: 'https://your-collector.com/api/v2/spans'
});
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();
Dashboard and Alerting
7. Grafana Dashboard Configuration
# Sample dashboard JSON for React metrics
{
"panels": [
{
"title": "Page Load Time",
"type": "graph",
"datasource": "Prometheus",
"targets": [
{
"expr": "avg(frontend_page_load_time_seconds)",
"legendFormat": "Avg Load Time"
}
],
"thresholds": [
{
"value": 2.5,
"color": "red",
"op": "gt"
}
]
},
{
"title": "JS Errors",
"type": "stat",
"datasource": "Sentry",
"targets": [
{
"query": "count:error{environment:production}"
}
],
"alert": {
"conditions": [
{
"evaluator": {
"params": [10],
"type": "gt"
}
}
]
}
}
]
}
8. Alerting Rules
# Prometheus alerting rules
groups:
- name: frontend.rules
rules:
- alert: HighErrorRate
expr: rate(frontend_errors_total[5m]) > 0.1
for: 10m
labels:
severity: critical
annotations:
summary: "High error rate detected in frontend"
description: "Error rate of {{ $value }} exceeds threshold"
- alert: SlowPageLoad
expr: frontend_page_load_time_seconds > 3
for: 30m
labels:
severity: warning
annotations:
summary: "Slow page load detected"
description: "Average load time of {{ $value }} seconds"
Synthetic Monitoring
9. Playwright Test Scripts
// smoke-test.spec.js
const { test, expect } = require('@playwright/test');
test('Homepage load', async ({ page }) => {
const response = await page.goto('https://your-app.com');
expect(response.status()).toBe(200);
await expect(page.locator('text=Welcome to our app')).toBeVisible();
const perf = await page.evaluate(() =>
JSON.parse(JSON.stringify(performance.timing))
);
console.log('Page load time:', perf.loadEventEnd - perf.navigationStart);
});
test('Checkout flow', async ({ page }) => {
await page.goto('https://your-app.com/products/1');
await page.click('text=Add to Cart');
await page.click('text=Checkout');
// Measure checkout rendering time
const start = Date.now();
await expect(page.locator('text=Payment Method')).toBeVisible();
const renderTime = Date.now() - start;
trackMetric('checkout_render_time', renderTime);
});
Log Management
10. Structured Frontend Logging
// Enhanced logger with context
class FrontendLogger {
constructor() {
this.context = {
appVersion: process.env.REACT_APP_VERSION,
userId: null,
sessionId: this.generateSessionId()
};
}
log(level, message, metadata = {}) {
const logEntry = {
timestamp: new Date().toISOString(),
level,
message,
...this.context,
...metadata,
userAgent: navigator.userAgent,
url: window.location.href
};
// Send to log service
fetch('/logs', {
method: 'POST',
body: JSON.stringify(logEntry),
headers: { 'Content-Type': 'application/json' }
}).catch(() => {
// Fallback to console if network fails
console[level](logEntry);
});
}
generateSessionId() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
}
// Usage
const logger = new FrontendLogger();
logger.log('error', 'Cart validation failed', { cartId: '123' });
Monitoring Strategy Checklist
- Error Tracking
- [ ] Implement error boundaries
- [ ] Track unhandled exceptions
- [ ] Monitor API failures
- Performance Monitoring
- [ ] Track Core Web Vitals
- [ ] Measure route change times
- [ ] Monitor resource loading
- User Experience
- [ ] Track key user journeys
- [ ] Measure interaction delays
- [ ] Monitor abandoned flows
- Business Metrics
- [ ] Track conversions
- [ ] Monitor engagement metrics
- [ ] Measure feature adoption
- Infrastructure
- [ ] Monitor CDN performance
- [ ] Track asset caching
- [ ] Measure third-party script impact
- Alerting
- [ ] Set up error rate alerts
- [ ] Configure performance degradation alerts
- [ ] Implement business metric thresholds
- Synthetic Monitoring
- [ ] Set up smoke tests
- [ ] Monitor critical user journeys
- [ ] Test from multiple locations
- Log Management
- [ ] Implement structured logging
- [ ] Centralize frontend logs
- [ ] Correlate with backend logs
Tooling Recommendations
- Error Tracking
- Sentry
- Rollbar
- Bugsnag
- Performance Monitoring
- New Relic Browser
- Datadog RUM
- Google Analytics 4
- Synthetic Monitoring
- Checkly
- Pingdom
- UptimeRobot
- Log Management
- ELK Stack
- Splunk
- Grafana Loki
- Dashboarding
- Grafana
- Datadog
- Kibana
