Core Web Vitals мало просто измерить — важно понимать, где смотреть эти данные, чем лабораторные результаты отличаются от полевых и как искать причину плохой метрики, а не только видеть, что она плохая. Разберём инструменты, подход к диагностике и типичные ошибки при работе с LCP, INP и CLS.
Лабораторные данные !== реальные
СкопированоЭто самая частая причина непонимания: «Почему метрика в Lighthouse зелёная, а в Search Console красная?» Есть два принципиально разных источника данных:
- лабораторные (lab) — синтетический прогон в контролируемых условиях: фиксированное устройство, заданная сеть, без реального пользователя. Это Lighthouse и симуляция в PageSpeed Insights;
- реальные или полевые (field) — данные реальных пользователей (RUM, Real User Monitoring). Это CrUX (Chrome User Experience Report), который Google учитывает в ранжировании, и своя аналитика на библиотеке
web— она в ранжировании не участвует, но даёт более детальную картину по вашей аудитории. Оба источника показывают 75-й перцентиль распределения (значение, хуже которого метрика бывает только у четверти загрузок).- vitals
Данные собираются скользящим окном в 28 дней. Поэтому после релиза с оптимизациями не ждите, что зелёная зона в Search Console наступит завтра: эффект проявляется постепенно и полностью виден только примерно через 28 дней.
Почему лабораторные и полевые данные расходятся:
- INP в лабораторных условиях не измеряется вообще — он зависит от взаимодействий пользователя на протяжении всей жизни страницы в реальный момент, а синтетика не знает, когда и куда нажмёт человек. Lighthouse вместо INP показывает приближение, TBT (Total Blocking Time), и это лишь приблизительный ориентир;
- CLS различается — в лаборатории фиксируется в основном сдвиг при загрузке (верх страницы), а в поле — за весь жизненный цикл: пользователь скроллит, догружаются ленивые картинки без размеров, срабатывают A/B-тесты, и все эти сдвиги лабораторные измерители не видят;
- LCP различается — разным людям на разных экранах виден разный LCP-элемент; у реальных пользователей часть ресурсов уже находится в кеше браузера, а в синтетике кеш холодный.
Вывод: для отладки удобны лабораторные инструменты (они воспроизводимы и подсказывают, что чинить), а для приоритизации и оценки результата доверяйте полевым данным.
Инструменты
СкопированоЛабораторные инструменты (Lab Data)
СкопированоИнструменты, которые запускают контролируемые тесты и помогают найти конкретные проблемы в коде, загрузке и рендеринге страницы:
- Lighthouse (в DevTools, CLI или CI) — лабораторный аудит с конкретными рекомендациями. Помните про оговорку с INP: в лабораторных тестах Lighthouse использует TBT (Total Blocking Time) как приближение, а реальный INP измеряется только на реальных пользователях. Lighthouse CI удобно ставить в пайплайн, чтобы ловить регрессии до релиза;
- Chrome DevTools — основной инструмент глубокой диагностики. На вкладке Performance — профилирование главного потока, анализ долгих JavaScript-задач, Layout Shifts для CLS и причин медленных взаимодействий. Для INP включите Screenshots, запишите трейс во время взаимодействия и смотрите дорожку Interactions: наведение на конкретное взаимодействие покажет три отрезка — input delay, processing, presentation delay — с подписью длительности каждого, а красные треугольники в стеке вызовов подсветят виновные обработчики. Если проблема не воспроизводится локально, включите CPU throttling (4× или 6×) или, как вариант, подключите реальный Android-телефон через remote debugging. На самой панели Performance есть боковая вкладка Insights с упрощённым разбором ключевых проблем, а в разделе Application → Back/forward cache можно проверить, может ли страница использовать bfcache (back/forward cache, кеш, из которого браузер мгновенно восстанавливает страницу целиком при переходе «назад»/«вперёд», без новой загрузки);
- PageSpeed Insights — удобная отправная точка для диагностики: показывает лабораторный прогон Lighthouse и рекомендации по оптимизации.
Полевые инструменты (Field Data / Real User Monitoring)
СкопированоИнструменты, которые показывают реальный пользовательский опыт на основе фактических загрузок и взаимодействий:
- PageSpeed Insights кроме Lighthouse на сервере показывает данные CrUX за последние 28 дней, если по сайту достаточно трафика;
- Search Console → Core Web Vitals — полевые данные по группам URL, которые показывают реальное качество страниц с точки зрения пользователей, и на них Google смотрит, когда оценивает опыт взаимодействия;
- CrUX Vis и CrUX Dashboard / BigQuery — публичные исторические данные CrUX по домену, по ним видно тренды Core Web Vitals;
- сторонние RUM-сервисы — DebugBear, SpeedCurve, Vercel Speed Insights, RUMVision. В отличие от CrUX, они обновляются быстрее, работают не только с Chrome и дают более детальную атрибуцию проблем: какой ресурс, скрипт или компонент повлиял на метрику;
- библиотека
webсобирает Core Web Vitals у реальных пользователей и отправляет данные в вашу аналитику.- vitals
Своя аналитика на web-vitals
СкопированоНа практике полезно отправлять не только саму метрику, но и дополнительный контекст: URL страницы, тип устройства, размер экрана, версию приложения или номер релиза. Тогда после выкладки новой версии будет гораздо проще понять, какой именно релиз ухудшил Core Web Vitals и для каких пользователей.
import { onCLS, onINP, onLCP } from "web-vitals";function sendToAnalytics(metric) { const body = JSON.stringify({ name: metric.name, value: metric.value, id: metric.id, url: location.href, release: window.APP_RELEASE, }); navigator.sendBeacon("/analytics", body);}onCLS(sendToAnalytics);onINP(sendToAnalytics);onLCP(sendToAnalytics);
import { onCLS, onINP, onLCP } from "web-vitals";
function sendToAnalytics(metric) {
const body = JSON.stringify({
name: metric.name,
value: metric.value,
id: metric.id,
url: location.href,
release: window.APP_RELEASE,
});
navigator.sendBeacon("/analytics", body);
}
onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);
В Next.js те же метрики у реальных пользователей собирает use. Вынесите хук в отдельный клиентский компонент, чтобы не добавлять 'use client' всему layout:
"use client";import { useReportWebVitals } from "next/web-vitals";const report = (metric) => navigator.sendBeacon("/analytics", JSON.stringify(metric));export function WebVitals() { useReportWebVitals(report); return null;}
"use client";
import { useReportWebVitals } from "next/web-vitals";
const report = (metric) =>
navigator.sendBeacon("/analytics", JSON.stringify(metric));
export function WebVitals() {
useReportWebVitals(report);
return null;
}
У библиотеки есть attribution-сборка, которая показывает, что именно виновато: для CLS — селектор самого двигающегося элемента, для INP — тип взаимодействия и разбивка по фазам, для LCP — какой элемент и из чего сложилось его время.
import { onLCP } from "web-vitals/attribution";onLCP((metric) => { // metric.attribution.element, .url, .timeToFirstByte, // .resourceLoadDelay, .resourceLoadDuration, .elementRenderDelay console.log(metric.attribution);});
import { onLCP } from "web-vitals/attribution";
onLCP((metric) => {
// metric.attribution.element, .url, .timeToFirstByte,
// .resourceLoadDelay, .resourceLoadDuration, .elementRenderDelay
console.log(metric.attribution);
});
Для INP attribution-сборка идёт дальше и отдаёт interaction (какой элемент), interaction (клик/тап/клавиша) и, самое ценное, массив long из LoAF API (Long Animation Frames): там для каждого «тяжёлого» кадра расписано, какой именно скрипт его вызвал — source, source, даже позиция символа в файле. Это разница между «у нас плохой INP» и «вот эта функция в vendor-bundle.js виновата».
Если строите свою аналитику на web, учтите две детали.
Во-первых, отправляйте метрики при событии visibilitychange (когда document становится hidden), а не по beforeunload/unload. visibilitychange — последний надёжный момент, когда ещё можно отправить данные через navigator или fetch, особенно на мобильных устройствах. Кроме того, устаревшие события beforeunload и unload могут помешать работе bfcache.
Во-вторых, считайте перцентили, а не среднее: одно экстремальное значение на медленном устройстве может сильно исказить среднее, но почти не повлияет на 75-й перцентиль.
Подход к работе с метриками
Скопировано- сначала измерьте на реальных пользователях (CrUX /
web): поймите, какая из трёх Core-метрик в красной или жёлтой зоне для десктопа и мобильных устройств;- vitals - воспроизведите в лаборатории (Lighthouse, DevTools) и найдите конкретного виновника через DevTools или attribution;
- чините по разбивке метрики: не «улучшаем LCP вообще», а «у нас увеличен отрезок render delay из-за блокирующего CSS»;
- проверьте, что не сломали соседнюю метрику: например, агрессивный
preloadвсего подряд может ухудшить LCP, потому что слишком большое количество предзагруженных ресурсов начинает конкурировать с действительно критичными ресурсами за пропускную способность сети и приоритеты загрузки браузера; - мониторьте постоянно. Производительность деградирует незаметно: добавили виджет, обновили зависимость — и метрика испортилась. Держите
webв продакшене и следите за трендом.- vitals
Оптимизацию почти никогда не делают за один проход. После каждого изменения перепроверяйте все Core Web Vitals — улучшение одной метрики может случайно ухудшить другую.
Как связать метрику с пользовательским сценарием
СкопированоУдобно начинать не с технического термина, а с того, что замечает человек:
- долго не появляется главное содержимое — проверяем LCP;
- интерфейс медленно отвечает на нажатия — проверяем INP;
- элементы меняют положение во время загрузки — проверяем CLS;
- страница долго остаётся полностью пустой — проверяем FCP и TTFB.
После этого проблему можно связать с конкретной страницей, типом устройства, источником трафика и целевым действием.
На практике почти всегда начинайте с мобильных устройств. Именно мобильные данные чаще всего оказываются в жёлтой или красной зоне из-за менее производительных процессоров и более медленных сетей.
Шаблон постановки задачи
СкопированоХорошая постановка задачи может выглядеть так:
На мобильных устройствах у карточек товаров LCP 4,6 с на 75-м перцентиле. Проблема затрагивает 38% органического трафика. Цель — довести LCP до 2,5 с или ниже и проследить изменение доли отказов.
В такой формулировке есть проблемная страница, тип устройства, текущее и целевое значения метрики, затронутая аудитория и бизнес-показатель, который нужно наблюдать после изменений.
Короткие варианты для других метрик:
- INP: на мобильной странице оформления заказа кнопка «Продолжить» отвечает до 700 мс; цель — не более 200 мс;
- CLS: блок рекомендаций сдвигает текст, CLS составляет 0,31; цель — зарезервировать место и снизить показатель до 0,1.
Частые ошибки, на которых легко обжечься
СкопированоКроме уже разобранных выше ловушек — лабораторные баллы вместо полевых значений, ожидание мгновенного эффекта, оптимизация «среднего» вместо перцентиля и порча соседней метрики агрессивным preload, — есть ещё одна: оптимизировать страницы с минимальным трафиком. Начинайте с тех, что получают основную долю посещений или напрямую влияют на бизнес — именно они дадут наибольший эффект для пользователей и отчётов Core Web Vitals.