Настройка Time to Interactive (TTI) мониторинга для сайта
Time to Interactive — момент, когда страница не просто выглядит загруженной, а действительно готова реагировать на пользовательский ввод. Разница между «страница выглядит готовой» и «страница готова» может составлять 5–15 секунд на медленных устройствах. Именно эта разница объясняет высокий показатель отказов на мобильных при хороших показателях FCP.
Как вычисляется TTI
TTI — момент, после которого в течение 5 секунд нет Long Tasks (задач длиннее 50 мс в main thread) и сеть спокойна (не более 2 активных запросов). Lighthouse ищет последнюю Long Task в этом тихом окне и берёт её конец как TTI.
Практическое следствие: TTI напрямую определяется двумя вещами — количеством и размером JS, который парсируется и выполняется при загрузке, и тем, что этот JS делает в main thread.
Шкала Lighthouse:
- 0–3,8 с — хорошо
- 3,8–7,3 с — требует улучшения
-
7,3 с — плохо
Для мобильных устройств с CPU throttling 4x — умножайте свои десктопные результаты примерно на 3.
Инструменты мониторинга
Chrome User Experience Report (CrUX) — реальные данные от пользователей Chrome. TTI в CrUX не публикуется напрямую (из-за сложности измерения в полевых условиях), но коррелирует с TBT и INP, которые есть.
Lighthouse CI — лабораторные измерения при каждом деплое. Стабильны, воспроизводимы, позволяют ловить регрессии.
WebPageTest — детальный filmstrip + waterfall. Видно точно, какой скрипт держит main thread.
Treo / SpeedCurve — коммерческие платформы с историей и алертами.
Настройка Lighthouse CI с порогами TTI
npm install --save-dev @lhci/cli
.lighthouserc.json:
{
"ci": {
"collect": {
"url": [
"https://staging.example.com/",
"https://staging.example.com/product/example-product"
],
"numberOfRuns": 5,
"settings": {
"formFactor": "mobile",
"screenEmulation": {
"mobile": true,
"width": 390,
"height": 844,
"deviceScaleFactor": 3
},
"throttlingMethod": "simulate",
"throttling": {
"rttMs": 150,
"throughputKbps": 1638.4,
"cpuSlowdownMultiplier": 4
}
}
},
"assert": {
"preset": "lighthouse:recommended",
"assertions": {
"interactive": ["error", { "maxNumericValue": 7300 }],
"total-blocking-time": ["error", { "maxNumericValue": 300 }]
}
},
"upload": {
"target": "lhci",
"serverBaseUrl": "https://lhci.example.com",
"token": "$LHCI_TOKEN"
}
}
}
Параметры throttling имитируют Moto G4 на 3G — это стандартный Lighthouse mobile-профиль.
Сбор TTI через Performance Observer в браузере
TTI нельзя точно измерить через PerformanceObserver напрямую — API для этого нет. Но можно использовать полифил от Google:
npm install tti-polyfill
import ttiPolyfill from 'tti-polyfill';
ttiPolyfill.getFirstConsistentlyInteractive().then((tti) => {
// Отправляем в аналитику
if (typeof gtag !== 'undefined') {
gtag('event', 'performance', {
event_category: 'Web Vitals',
event_label: 'TTI',
value: Math.round(tti),
non_interaction: true,
});
}
// Или в свой бэкенд
fetch('/api/metrics', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
metric: 'tti',
value: tti,
url: window.location.href,
userAgent: navigator.userAgent,
timestamp: Date.now(),
}),
keepalive: true,
});
});
Полифил не идеален — он аппроксимирует TTI через Long Task API и Network Information API. Но для трендового мониторинга достаточно.
Хранение и визуализация метрик
Минимальная схема таблицы в PostgreSQL для хранения field data:
CREATE TABLE performance_metrics (
id BIGSERIAL PRIMARY KEY,
url TEXT NOT NULL,
metric VARCHAR(50) NOT NULL, -- 'tti', 'lcp', 'fid', 'cls'
value FLOAT NOT NULL, -- в миллисекундах
connection VARCHAR(20), -- '4g', '3g', 'wifi'
device VARCHAR(20), -- 'mobile', 'desktop'
country VARCHAR(2),
recorded_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX ON performance_metrics (metric, recorded_at);
CREATE INDEX ON performance_metrics (url, metric);
Запрос для перцентилей:
SELECT
url,
percentile_cont(0.75) WITHIN GROUP (ORDER BY value) AS p75,
percentile_cont(0.95) WITHIN GROUP (ORDER BY value) AS p95,
COUNT(*) AS sample_count
FROM performance_metrics
WHERE metric = 'tti'
AND recorded_at > NOW() - INTERVAL '7 days'
AND device = 'mobile'
GROUP BY url
ORDER BY p75 DESC;
Grafana-дашборд
Для визуализации подключаем PostgreSQL datasource в Grafana. Панель тренда TTI по времени:
SELECT
date_trunc('hour', recorded_at) AS time,
percentile_cont(0.75) WITHIN GROUP (ORDER BY value) AS p75_tti
FROM performance_metrics
WHERE metric = 'tti'
AND recorded_at BETWEEN $__timeFrom() AND $__timeTo()
GROUP BY 1
ORDER BY 1
Алерты при регрессии
Alertmanager или Grafana Alerting. Условие: p75 TTI за последние 24 часа превышает p75 TTI за предыдущие 7 дней более чем на 1 секунду.
Это отсекает ложные алерты от случайных выбросов и реагирует только на устойчивые регрессии.
Связь TTI с реальным бизнесом
Google опубликовал исследование: увеличение TTI на 1 секунду снижает конверсию мобильных посетителей на 7–12% в зависимости от тематики. Для e-commerce с 1 000 мобильных визитов в день и средним чеком $50 — это $350–600 в день потенциальных потерь при каждой лишней секунде TTI.
Именно поэтому мониторинг TTI нужно настраивать не только как технический, но и как бизнес-метрику — с привязкой к сегментам трафика и конверсионным воронкам.
Сроки
Настройка Lighthouse CI с TTI-порогами — 1 рабочий день. Сбор field data через Performance Observer + хранение в PostgreSQL + Grafana-дашборд — 3–5 рабочих дней. Полная система с алертами, сегментацией по устройствам и странам, интеграцией с аналитикой — 1–2 недели.







