Monitoring Next.js : Sentry, Vercel Analytics & Error Tracking 2026
Production without monitoring = flying blind. 78% bugs discovered by users, not teams.
Ce guide couvre monitoring complet Next.js : Sentry error tracking, Vercel Analytics, OpenTelemetry, performance monitoring, alerting et debugging production.
Résultat client : Mean Time To Resolution (MTTR) -73% (12h → 3h)
TL;DR : Stack Monitoring Next.js 2026
| Tool | Purpose | Prix | Setup Time | Best For |
|---|---|---|---|---|
| Sentry | Error tracking | 0-26€/mois | 15min | 🏆 Errors & exceptions |
| Vercel Analytics | Performance (Web Vitals) | 10-150€/mois | 5min | Performance metrics |
| PostHog | Product analytics | 0-450€/mois | 30min | User behavior |
| LogRocket | Session replay | 99€+/mois | 20min | User sessions |
| Datadog | Full observability | 15€+/mois | 2h | Enterprise monitoring |
| OpenTelemetry | Custom traces | Gratuit | 3-4h | Advanced tracing |
Recommendation Stack :
- Sentry : Error tracking (must-have)
- Vercel Analytics : Core Web Vitals (si Vercel hosting)
- PostHog : Product analytics (optional)
1. Sentry — Error Tracking & Performance
Présentation
Prix 2026 :
- Developer : Gratuit (5k errors/mois, 1 user)
- Team : 26€/mois (50k errors/mois, 5 seats)
- Business : 80€/mois (100k errors/mois, unlimited seats)
Features :
- ✅ Error tracking (JavaScript, Server)
- ✅ Performance monitoring (transactions, spans)
- ✅ Source maps (production debugging)
- ✅ Release tracking
- ✅ User feedback
- ✅ Alerting (Slack, Email, PagerDuty)
Setup Sentry Next.js 15
# Install Sentry SDK
pnpm add @sentry/nextjs
# Initialize (interactive wizard)
npx @sentry/wizard@latest -i nextjs
Configuration générée :
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
// Tracing
tracesSampleRate: 1.0, // 100% production (adjust based on traffic)
// Session Replay
replaysOnErrorSampleRate: 1.0, // Capture 100% sessions with errors
replaysSessionSampleRate: 0.1, // Capture 10% normal sessions
integrations: [
Sentry.replayIntegration({
maskAllText: true, // Privacy: mask sensitive text
blockAllMedia: true, // Don't capture images/videos
}),
],
// Environment
environment: process.env.NODE_ENV,
// Release tracking
release: process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA,
})
// sentry.server.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
environment: process.env.NODE_ENV,
})
// sentry.edge.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
})
Instrumentation :
// instrumentation.ts (Next.js 15 required)
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
await import('./sentry.server.config')
}
if (process.env.NEXT_RUNTIME === 'edge') {
await import('./sentry.edge.config')
}
}
Build configuration :
// next.config.ts
import { withSentryConfig } from '@sentry/nextjs'
const nextConfig = {
// Your Next.js config
}
export default withSentryConfig(nextConfig, {
org: 'your-org',
project: 'your-project',
// Upload source maps
silent: !process.env.CI,
widenClientFileUpload: true,
// Route browser requests to Sentry through a Next.js rewrite
tunnelRoute: '/monitoring',
// Don't delete source maps (for debugging)
hideSourceMaps: false,
// Disable telemetry
disableLogger: true,
})
Error Tracking Usage
Automatic error capture :
// app/page.tsx
export default function HomePage() {
// Sentry automatically captures unhandled errors
throw new Error('Test error') // ✅ Auto-captured
}
Manual error tracking :
import * as Sentry from '@sentry/nextjs'
try {
await riskyOperation()
} catch (error) {
Sentry.captureException(error, {
level: 'error',
tags: {
section: 'checkout',
user_action: 'payment',
},
extra: {
paymentAmount: 99.99,
currency: 'EUR',
},
})
}
Custom context :
// Set user context
Sentry.setUser({
id: user.id,
email: user.email,
username: user.name,
})
// Set custom tags
Sentry.setTag('payment_provider', 'stripe')
Sentry.setTag('subscription_plan', 'pro')
// Add breadcrumbs (user actions)
Sentry.addBreadcrumb({
category: 'navigation',
message: 'User navigated to checkout',
level: 'info',
})
Server Actions error tracking :
// app/actions/create-post.ts
'use server'
import * as Sentry from '@sentry/nextjs'
import { revalidatePath } from 'next/cache'
export async function createPost(formData: FormData) {
try {
const title = formData.get('title') as string
await db.insert(posts).values({ title })
revalidatePath('/blog')
return { success: true }
} catch (error) {
Sentry.captureException(error, {
tags: { action: 'create_post' },
extra: { formData: Object.fromEntries(formData) },
})
return { error: 'Failed to create post' }
}
}
Performance Monitoring
// Custom transaction
import * as Sentry from '@sentry/nextjs'
const transaction = Sentry.startTransaction({
name: 'checkout-flow',
op: 'checkout',
})
// Start span
const span = transaction.startChild({
op: 'stripe-payment',
description: 'Create Stripe payment intent',
})
try {
await stripe.paymentIntents.create({ ... })
span.setStatus('ok')
} catch (error) {
span.setStatus('internal_error')
throw error
} finally {
span.finish()
transaction.finish()
}
Automatic performance tracking :
// sentry.client.config.ts
Sentry.init({
// ...
integrations: [
Sentry.browserTracingIntegration({
tracePropagationTargets: ['localhost', /^https:\/\/yoursite\.com/],
}),
],
})
Alerting (Slack Integration)
Sentry Dashboard :
- Settings > Integrations > Slack
- Connect workspace
- Configure alert rules
Alert rules example :
IF errors > 10 in 5 minutes
THEN notify #engineering-alerts channel
PagerDuty integration : For on-call critical alerts
2. Vercel Analytics — Web Vitals & Traffic
Présentation
Prix 2026 :
- Hobby : Gratuit (2,500 events/mois)
- Pro : Inclus Vercel Pro (100k events/mois)
- Enterprise : Unlimited
Features :
- ✅ Core Web Vitals (LCP, FID, CLS)
- ✅ Real User Monitoring (RUM)
- ✅ Traffic analytics
- ✅ Audience insights (country, device)
- ✅ Top pages
Setup Vercel Analytics
# Install
pnpm add @vercel/analytics
// app/layout.tsx
import { Analytics } from '@vercel/analytics/react'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="fr">
<body>
{children}
<Analytics /> {/* ✅ Add analytics */}
</body>
</html>
)
}
Web Vitals tracking :
// app/layout.tsx
import { SpeedInsights } from '@vercel/speed-insights/next'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
{children}
<SpeedInsights /> {/* ✅ Core Web Vitals */}
</body>
</html>
)
}
Custom events :
// components/buy-button.tsx
'use client'
import { track } from '@vercel/analytics'
export function BuyButton() {
function handleClick() {
track('purchase_initiated', {
product: 'Pro Plan',
price: 99,
})
}
return <button onClick={handleClick}>Buy Now</button>
}
Vercel Web Analytics Dashboard
Metrics tracked :
- LCP (Largest Contentful Paint)
- FID (First Input Delay)
- CLS (Cumulative Layout Shift)
- TTFB (Time To First Byte)
- FCP (First Contentful Paint)
Visualization :
- Performance score (0-100)
- Page-by-page breakdown
- Device type comparison (desktop vs mobile)
- Country breakdown
3. PostHog — Product Analytics
Présentation
Prix 2026 :
- Gratuit : 1M events/mois
- Paid : $0.00045/event (après free tier)
Features :
- ✅ Product analytics (funnels, retention)
- ✅ Session recordings
- ✅ Feature flags
- ✅ A/B testing
- ✅ Heatmaps
Setup PostHog
pnpm add posthog-js
// app/providers.tsx
'use client'
import posthog from 'posthog-js'
import { PostHogProvider as PHProvider } from 'posthog-js/react'
import { useEffect } from 'react'
export function PostHogProvider({ children }: { children: React.ReactNode }) {
useEffect(() => {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
api_host: 'https://app.posthog.com',
capture_pageview: false, // Disable auto pageview (we'll track manually)
})
}, [])
return <PHProvider client={posthog}>{children}</PHProvider>
}
Track events :
// components/signup-form.tsx
'use client'
import { usePostHog } from 'posthog-js/react'
export function SignupForm() {
const posthog = usePostHog()
function handleSignup() {
posthog.capture('user_signed_up', {
plan: 'pro',
source: 'landing_page',
})
}
return <form onSubmit={handleSignup}>...</form>
}
4. Source Maps (Production Debugging)
Problem
Production :
Error at build/chunks/app.js:1:45821
Can't debug! Code minified/obfuscated.
Solution : Source Maps
Sentry automatic source maps upload :
// next.config.ts
export default withSentryConfig(nextConfig, {
widenClientFileUpload: true, // ✅ Upload source maps
hideSourceMaps: false, // Keep source maps in build
})
Manual upload (if needed) :
# Sentry CLI
sentry-cli sourcemaps upload \
--org your-org \
--project your-project \
--release $RELEASE \
.next/static/chunks
Result : Stack traces show original source code in Sentry
5. Logging (Structured Logs)
Pino Logger (Fast & Structured)
pnpm add pino pino-pretty
// lib/logger.ts
import pino from 'pino'
export const logger = pino({
level: process.env.LOG_LEVEL || 'info',
...(process.env.NODE_ENV === 'development' && {
transport: {
target: 'pino-pretty',
options: {
colorize: true,
},
},
}),
})
Usage :
// app/api/users/route.ts
import { logger } from '@/lib/logger'
export async function GET(req: Request) {
logger.info({ path: req.url }, 'Fetching users')
try {
const users = await db.query.users.findMany()
logger.info({ count: users.length }, 'Users fetched')
return Response.json(users)
} catch (error) {
logger.error({ error }, 'Failed to fetch users')
throw error
}
}
Ship logs to external service :
// lib/logger.ts (production)
import pino from 'pino'
export const logger = pino({
level: 'info',
...(process.env.NODE_ENV === 'production' && {
transport: {
target: 'pino-logflare', // LogFlare sink
options: {
apiKey: process.env.LOGFLARE_API_KEY,
sourceToken: process.env.LOGFLARE_SOURCE_TOKEN,
},
},
}),
})
Alternatives :
- Axiom (Vercel integration)
- Datadog Logs
- CloudWatch (AWS)
6. Uptime Monitoring
BetterStack (formerly Better Uptime)
Prix : 25€/mois (10 monitors)
Features :
- ✅ HTTP/HTTPS monitoring
- ✅ SSL certificate expiry alerts
- ✅ Multi-region checks (15 locations)
- ✅ Incident management
- ✅ Status page
Setup :
- Add monitor URL (https://yoursite.com)
- Configure check interval (30s-5min)
- Set alert channels (Slack, SMS, Call)
Alternative : UptimeRobot (gratuit, 50 monitors)
7. Real User Monitoring (RUM)
Performance Observer API
// lib/rum.ts
'use client'
import { useEffect } from 'react'
export function useRUM() {
useEffect(() => {
// Core Web Vitals
if (typeof window !== 'undefined' && 'PerformanceObserver' in window) {
const observer = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
if (entry.entryType === 'largest-contentful-paint') {
console.log('LCP:', entry.startTime)
// Send to analytics
fetch('/api/analytics', {
method: 'POST',
body: JSON.stringify({
metric: 'LCP',
value: entry.startTime,
}),
})
}
})
})
observer.observe({ entryTypes: ['largest-contentful-paint'] })
return () => observer.disconnect()
}
}, [])
}
8. Error Boundaries (React)
// app/error.tsx
'use client'
import * as Sentry from '@sentry/nextjs'
import { useEffect } from 'react'
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
useEffect(() => {
Sentry.captureException(error)
}, [error])
return (
<div className="flex min-h-screen items-center justify-center">
<div className="text-center">
<h2 className="text-2xl font-bold">Something went wrong!</h2>
<button onClick={reset} className="mt-4 rounded bg-blue-600 px-4 py-2 text-white">
Try again
</button>
</div>
</div>
)
}
Global error (app-level) :
// app/global-error.tsx
'use client'
import * as Sentry from '@sentry/nextjs'
import { useEffect } from 'react'
export default function GlobalError({ error }: { error: Error & { digest?: string } }) {
useEffect(() => {
Sentry.captureException(error)
}, [error])
return (
<html>
<body>
<h2>Application Error</h2>
</body>
</html>
)
}
9. Monitoring Checklist Production
Pre-Launch
- Sentry configured (client + server + edge)
- Source maps uploaded
- Vercel Analytics enabled
- Error boundaries implemented
- Alerting configured (Slack/Email)
- Uptime monitor setup (BetterStack/UptimeRobot)
- Logging structured (Pino)
- Performance budget defined (Core Web Vitals thresholds)
Post-Launch
- Monitor error rate daily (Sentry dashboard)
- Track Core Web Vitals weekly (Vercel Analytics)
- Review logs for anomalies (Axiom/Datadog)
- Check uptime SLA (99.9%+ target)
- Analyze user journeys (PostHog funnels)
- Review slow API routes (Sentry performance)
10. Cost Comparison
Monitoring Stack Costs (50k users/mois)
| Tool | Plan | Prix/mois |
|---|---|---|
| Sentry | Team | 26€ |
| Vercel Analytics | Pro (included) | 0€ |
| PostHog | Cloud | 50€ |
| BetterStack | Starter | 25€ |
| Axiom Logs | Pro | 25€ |
| Total | 126€/mois |
ROI :
- MTTR -73% (12h → 3h)
- Prevented downtime : ~4h/mois saved
- Downtime cost (SaaS) : ~3,000€/h
- Savings : 12,000€/mois (vs 126€ cost)
ROI ratio : 95× return
Conclusion
Monitoring Next.js = non-négociable production.
Stack recommandé 2026 :
- Sentry : Error tracking (26€/mois)
- Vercel Analytics : Core Web Vitals (gratuit Vercel Pro)
- BetterStack : Uptime (25€/mois)
Total : 51€/mois pour monitoring complet
Alternative budget serré :
- Sentry Developer (gratuit)
- UptimeRobot (gratuit)
- Vercel Analytics (gratuit Hobby)
Total : 0€/mois (limites strictes)
FAQ
Sentry gratuit production-ready ?
⚠️ Non. Developer plan = 5k errors/mois. Production business dépasse rapidement. Team minimum (26€) recommandé.
Vercel Analytics vs Google Analytics ?
Vercel : Performance (Core Web Vitals). Google : Marketing (acquisition, conversions). Complémentaires, pas alternatives.
Sentry impact performance ?
✅ Négligeable si configured correctement. tracesSampleRate: 0.1 (sample 10% traffic) recommandé high-traffic apps.
Articles connexes :