Свіжа інсталяція Sentry на Next.js-застосунку генерує близько 400 подій на день на сайті з 2K щоденних відвідувачів. 390 з них — шум: гідраційні невідповідності, помилки браузерних розширень, ResizeObserver-цикли та 404 від prefetch. 10 корисних тонуть у потоці.
Я налаштовував конфіги Sentry на 6 клієнтських проєктах. Ось сетап, який я копіюю в кожен новий білд.
Крок 1: Фільтруємо шум на вході
Sentry бере гроші за об'єм подій. Важливіше: шум привчає мозок ігнорувати алерти. Вбиваємо сміття до того, як воно потрапить на дашборд.
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 0.1, // 10% транзакцій — достатньо для перф-даних
replaysSessionSampleRate: 0,
replaysOnErrorSampleRate: 0.5, // реплей 50% помилок
beforeSend(event) {
const message = event.exception?.values?.[0]?.value ?? ''
// Гідраційні невідповідності — проблема React, не твоя
if (message.includes('Hydration failed')) return null
if (message.includes('Text content does not match')) return null
// Браузерні розширення інжектять помилки
if (message.includes('chrome-extension://')) return null
if (message.includes('moz-extension://')) return null
// ResizeObserver — безшкідний, стріляє в кожному браузері
if (message.includes('ResizeObserver loop')) return null
// Мережеві помилки від prefetch/preload — користувач пішов зі сторінки
if (
message.includes('Failed to fetch') &&
event.request?.url?.includes('_next/data')
) {
return null
}
return event
},
ignoreErrors: [
// Типовий браузерний шум
'AbortError',
'Network request failed',
'Load failed',
'cancelled',
// Боти та краулери
'Non-Error promise rejection captured',
],
denyUrls: [
// Браузерні розширення
/extensions\//i,
/^chrome:\/\//i,
/^moz-extension:\/\//i,
// Google Translate інжектить зламані скрипти
/translate\.googleapis\.com/,
],
})
Одне це знижує об'єм подій на ~85% на типовому Next.js-сайті.
Крок 2: Серверна фільтрація
Серверний конфіг чистіший — немає шуму від розширень. Але сміття все одно є:
// sentry.server.config.ts
import * as Sentry from '@sentry/nextjs'
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 0.2,
beforeSend(event) {
const message = event.exception?.values?.[0]?.value ?? ''
// Next.js кидає NOT_FOUND як помилку — це не помилка
if (message.includes('NEXT_NOT_FOUND')) return null
// Next.js redirect() кидає — by design
if (message.includes('NEXT_REDIRECT')) return null
return event
},
})
NEXT_NOT_FOUND та NEXT_REDIRECT — це Next.js, що використовує виключення для керування потоком. Це не баги в твоєму коді. Фільтрація прибирає ~30% серверних подій.
Крок 3: Кастомні fingerprint-и для корисного групування
За замовчуванням Sentry групує помилки за стектрейсом. Один і той самий баг створює різні issues, якщо трапляється в різних користувацьких флоу. Виправляємо кастомними fingerprint-ами:
// sentry.client.config.ts — додаємо в beforeSend
beforeSend(event) {
// ... фільтри шуму вище ...
// Групуємо API-помилки за ендпоінтом, не за стектрейсом
const frames = event.exception?.values?.[0]?.stacktrace?.frames;
if (frames?.some(f => f.filename?.includes('/api/'))) {
const url = event.request?.url ?? 'unknown';
const path = new URL(url).pathname;
event.fingerprint = ['api-error', path];
}
// Групуємо помилки валідації форми разом
if (event.tags?.component === 'ContactForm') {
event.fingerprint = ['form-error', 'contact'];
}
return event;
}
Кастомні fingerprint-и скоротили кількість issues на ~40% — один і той самий баг групується коректно, а не розщеплюється на 12 issues.
Крок 4: Осмислений контекст на кожній помилці
Різниця між корисною помилкою та марною — контекст. Додаємо глобально:
// В кореневому layout або обгортці застосунку
Sentry.setContext('app', {
locale: currentLocale,
route: pathname,
deployment: process.env.VERCEL_GIT_COMMIT_SHA?.slice(0, 7),
})
// Для авторизованих зон
Sentry.setUser({
id: user.id,
// Ніколи не відправляй PII — ні email, ні ім'я
})
Коли помилка спрацьовує, я одразу бачу: яка локаль, який роут, який деплой і який користувач (за ID, не за іменем). Цього зазвичай достатньо, щоб відтворити за 2 хвилини замість 20.
Крок 5: Алерти, що будять по справі
Дефолтні алерти Sentry стріляють на кожен новий issue. Після деплою отримуєш 15 алертів на дрібні регресії. Співвідношення сигнал/шум обвалюється.
Мої правила алертів:
Алерт 1: Виявлення сплесків — спрацьовує, коли кількість помилок перевищує 5× ковзне середнє за будь-яке 15-хвилинне вікно. Це ловить реальні аутейджі, а не поодинокі помилки.
Алерт 2: Новий issue в платежах — будь-яка нова помилка у файлах, що збігаються з */api/payment* або */stripe*. Платежі — єдина область, де одна помилка має значення.
Алерт 3: Відсоток необроблених rejection — спрацьовує, коли unhandled rejection перевищують 1% сесій у годинному вікні. Це ловить каскадні збої.
Все інше йде в щотижневий дайджест. Переглядаю в понеділок вранці — 5 хвилин на перегляд, тріаж всього, що варто чинити.
Крок 6: Source maps (те, що всі забувають)
Без source maps стектрейси Sentry показують мініфіковані імена змінних. Марно. Next.js + Vercel спрощують це, але не автоматично:
// next.config.js
const { withSentryConfig } = require('@sentry/nextjs')
module.exports = withSentryConfig(nextConfig, {
org: 'your-org',
project: 'your-project',
silent: true,
hideSourceMaps: true, // Не експозимо в браузерних devtools
widenClientFileUpload: true, // Завантажуємо всі клієнтські чанки
})
hideSourceMaps: true критичний — завантажує source maps у Sentry під час білду, але не роздає їх публічно. Користувачі не можуть реверс-інжинірити твій код, але Sentry показує чисті стектрейси.
Результат
До налаштування: ~400 подій/день, 3 алерти/день, 95% шуму. Я перестав перевіряти Sentry.
Після налаштування: ~40 подій/день, ~2 алерти/тиждень, кожен actionable. Я знову перевіряю Sentry.
Конфіг зайняв 2 години на налаштування — клієнт + сервер + алерти. Копіюю в кожен проєкт відтоді. ROI не в тому, щоб ловити більше помилок — а в тому, щоб ловити менше, але потрібних.
Хочеш, щоб твій Sentry повідомляв про те, що варто знати, а не кричав даремно? Напиши — я налаштовую це для кожного клієнтського проєкту і можу проаудити твій поточний конфіг за одну сесію.