Real User Monitoring (RUM)
RUM (Real User Monitoring) — сбор и анализ метрик производительности от реальных пользователей в реальных условиях (разные устройства, браузеры, сети), в отличие от синтетических тестов в лабораторных условиях.
Зачем нужно
Lighthouse показывает производительность на одном устройстве в контролируемой среде. RUM отражает реальный опыт: пользователи из разных регионов, на медленных устройствах, с мобильным интернетом. CrUX данные Google основаны на RUM Chrome-браузера.
Где используется
- Мониторинг Core Web Vitals на production для реальных пользователей
- Сравнение производительности до и после деплоя оптимизаций
- Обнаружение деградации в конкретных регионах или на конкретных устройствах
- Data-driven принятие решений о приоритетах оптимизации
Основной контент
Самостоятельный сбор (web-vitals + endpoint)
// public/rum.js
import { onLCP, onINP, onCLS, onFCP, onTTFB } from 'web-vitals/attribution';
const sessionId = crypto.randomUUID;
function sendMetric(metric) {
const body = JSON.stringify({
name: metric.name,
value: metric.value,
rating: metric.rating, // 'good' | 'needs-improvement' | 'poor'
delta: metric.delta,
id: metric.id,
attribution: metric.attribution,
// Контекст
sessionId,
url: location.href,
userAgent: navigator.userAgent,
connectionType: navigator.connection?.effectiveType,
deviceMemory: navigator.deviceMemory,
timestamp: Date.now(),
});
// sendBeacon не блокирует unload и гарантирует отправку
navigator.sendBeacon('/api/metrics', body);
}
// Регистрируем все метрики
[onLCP, onINP, onCLS, onFCP, onTTFB].forEach(fn => fn(sendMetric));
Endpoint для сбора метрик (Express)
app.post('/api/metrics', express.json({ limit: '10kb' }), async (req, res) => {
const metric = req.body;
// Валидация
if (!['LCP', 'INP', 'CLS', 'FCP', 'TTFB'].includes(metric.name)) {
return res.status(400).end();
}
// Сохранение в ClickHouse/InfluxDB/BigQuery
await metricsDb.insert('web_vitals', {
name: metric.name,
value: metric.value,
rating: metric.rating,
url: new URL(metric.url).pathname,
connection: metric.connectionType,
timestamp: new Date,
});
res.status(204).end();
});
Готовые RUM-решения
Коммерческие:
DataDog RUM — полный observability + session replay
New Relic Browser — трассировка + метрики
Sentry Performance — интеграция с error tracking
Open Source / Бесплатные:
Grafana Faro — self-hosted RUM
web-vitals.js — сбор, Beacon API, обработка на вашем бэкенде
Google Analytics 4 — Core Web Vitals в отчёте
Анализ данных — SQL запрос к RUM-данным
-- p75 LCP по устройству за последние 7 дней
SELECT
DATE(timestamp) as date,
connection_type,
PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY value) as p75_lcp,
COUNT(*) as sessions,
COUNT(CASE WHEN rating = 'good' THEN 1 END) * 100.0 / COUNT(*) as good_pct
FROM web_vitals
WHERE name = 'LCP'
AND timestamp > NOW - INTERVAL '7 days'
GROUP BY date, connection_type
ORDER BY date DESC;
Частые ошибки
- Сэмплинг 100% пользователей с тяжёлым RUM-скриптом — влияние на производительность
- Не фильтровать боты и crawlers — искажают метрики
- Только средние значения вместо перцентилей (p75, p95) — выбросы скрываются
- Хранение полных URL с query string — утечка PII (email в URL)
Связанные темы
- _MOC Производительность
- Core Web Vitals -- LCP, FID, CLS
- Chrome User Experience Report (CrUX)
- Synthetic Monitoring
- Alerting -- когда бить тревогу