Web Vitals: что это и как мы их собираем?

Рома Ахмадуллин

Дром

Web Vitals

Что это и как мы их собираем?

Рома Ахмадуллин

Performance

Как оценить объективно?

Этап
Not loaded

TTFB

Time To First Byte

Дока про TTFB
Этап
TTFB

FCP

First Contentful Paint

Дока про FCP
Этап
FCP

LCP

Largest Contentful Paint

Дока про LCP
Этап
LCP

А где же CLS и INP?

CLS

Cumulative Layout Shift

Дока про CLS

INP

Interaction to Next Paint

Дока про INP

Браузерная поддержка

Метрика Chrome Firefox Safari
TTFB
FCP
LCP
CLS
INP

Interop 2025

Interop 2025
Interop 2025: Core Web Vitals
Метрика Chrome Firefox Safari
TTFB
FCP
LCP ( ✅ )
CLS
INP ( ✅ ) ( ✅ )

Как считать?

Lab Data

Lighthouse
PageSpeed Insights
WebPageTest

npm пакеты

Lighthouse

PageSpeed Insights

WebPageTest

Field Data

Chrome UX Report
CrUX Vis
Sentry: Web Vitals
            
                Sentry.init({
                    // ...
                    integrations: [
                      Sentry.browserTracingIntegration({
                        enableInp: true,
                      }),
                    ],
                });
            
        
Sentry: tracing

Общий флоу

Сбор метрик

Performance APIs

Performance APIs
            
            const [navigationEntry] = performance.getEntriesByType('navigation');

            if (navigationEntry) {
                const { responseStart, activationStart } = navigationEntry;
                const ttfb = responseStart - activationStart;
                sendToBackend(ttfb);
            }
            
        
            
            const [navigationEntry] = performance.getEntriesByType('navigation');

            if (navigationEntry) {
                const { responseStart, activationStart } = navigationEntry;
                const ttfb = responseStart - activationStart;
                sendToBackend(ttfb);
            }
            
        
            
            const [navigationEntry] = performance.getEntriesByType('navigation');

            if (navigationEntry) {
                const { responseStart, activationStart } = navigationEntry;
                const ttfb = responseStart - activationStart;
                sendToBackend(ttfb);
            }
            
        
            
            const [navigationEntry] = performance.getEntriesByType('navigation');

            if (navigationEntry) {
                const { responseStart, activationStart } = navigationEntry;
                const ttfb = responseStart - activationStart;
                sendToBackend(ttfb);
            }
            
        
            
            const observer = new PerformanceObserver((list) => {
                const entries = list.getEntries();
                const lcp = entries[entries.length - 1].startTime;
                sendToBackend(lcp);
            });

            observer.observe({
                type: "largest-contentful-paint",
                buffered: true,
            });
            
        
            
            const observer = new PerformanceObserver((list) => {
                const entries = list.getEntries();
                const lcp = entries[entries.length - 1].startTime;
                sendToBackend(lcp);
            });

            observer.observe({
                type: "largest-contentful-paint",
                buffered: true,
            });
            
        
            
            const observer = new PerformanceObserver((list) => {
                const entries = list.getEntries();
                const lcp = entries[entries.length - 1].startTime;
                sendToBackend(lcp);
            });

            observer.observe({
                type: "largest-contentful-paint",
                buffered: true,
            });
            
        
            
            const observer = new PerformanceObserver((list) => {
                const entries = list.getEntries();
                const lcp = entries[entries.length - 1].startTime;
                sendToBackend(lcp);
            });

            observer.observe({
                type: "largest-contentful-paint",
                buffered: true,
            });
            
        

npm install web-vitals

npm: web-vitals
            
            import { onLCP, onINP, onCLS } from 'web-vitals';

            onCLS(sendToBackend);
            onINP(sendToBackend);
            onLCP(sendToBackend);
            
        

Агрегация и визуализация

Агрегация и визуализация

Агрегация и визуализация

Агрегация и визуализация

Как собираем на Дроме?

PSI

Page Speed Insights

            
                // config.js
                const config = {
                    ...,
                    pages: [
                        { 
                            id: 'home',
                            url: 'https://www.drom.ru/',
                        },
                        { 
                            id: 'auto', 
                            url: 'https://auto.drom.ru/',
                        },
                        { 
                            id: 'auto_brand',
                            url: 'https://auto.drom.ru/toyota/',
                        },
                        { 
                            id: 'auto_model',
                            url: 'https://auto.drom.ru/toyota/corolla/',
                        },
                        ...,
                    ],
                };
            
        
            
                // config.js
                const config = {
                    ...,
                    pages: [
                        { 
                            id: 'home',
                            url: 'https://www.drom.ru/',
                        },
                        { 
                            id: 'auto', 
                            url: 'https://auto.drom.ru/',
                        },
                        { 
                            id: 'auto_brand',
                            url: 'https://auto.drom.ru/toyota/',
                        },
                        { 
                            id: 'auto_model',
                            url: 'https://auto.drom.ru/toyota/corolla/',
                        },
                        ...,
                    ],
                };
            
        
            
                // experiments.js
                const experimentsConfig = {
                    no_gtm: {
                        params: { disablegtm: 1 },
                    },
                    no_ads: {
                        params: { disablead: 1 },
                    },
                    no_js: {
                        params: { disablejsinjector: 1, disableloadablescripts: 1 },
                    },
                };
            
        
            
                // config.js
                const config = {
                    ...,
                    pages: [
                        { 
                            id: 'auto', 
                            url: 'https://auto.drom.ru/',
                        },
                        ...,
                    ],
                };

                // experiments.js
                const experimentsConfig = {
                    no_gtm: {
                        params: { disablegtm: 1 },
                    },
                    no_ads: {
                        params: { disablead: 1 },
                    },
                    no_js: {
                        params: { disablejsinjector: 1, disableloadablescripts: 1 },
                    },
                };
            
        
            
                // config.js
                const config = {
                    ...,
                    pages: [
                        { 
                            id: 'auto', 
                            url: 'https://auto.drom.ru/',
                        },
                        ...,
                    ],
                };

                // experiments.js
                const experimentsConfig = {
                    no_gtm: {
                        params: { disablegtm: 1 },
                    },
                    no_ads: {
                        params: { disablead: 1 },
                    },
                    no_js: {
                        params: { disablejsinjector: 1, disableloadablescripts: 1 },
                    },
                };
            
        
            
                // config.js
                const config = {
                    ...,
                    pages: [
                        { 
                            id: 'auto', 
                            url: 'https://auto.drom.ru/',
                        },
                        ...,
                    ],
                };

                // experiments.js
                const experimentsConfig = {
                    no_gtm: {
                        params: { disablegtm: 1 },
                    },
                    no_ads: {
                        params: { disablead: 1 },
                    },
                    no_js: {
                        params: { disablejsinjector: 1, disableloadablescripts: 1 },
                    },
                };
            
        
            
                // auto
                'https://auto.drom.ru/',

                // auto no_gtm
                'https://auto.drom.ru/?disablegtm=1',

                // auto no_ads
                'https://auto.drom.ru/?disablead=1,

                // auto no_js
                'https://auto.drom.ru/?disablejsinjector=1&disableloadablescripts=1',
            
        
            
        // Controller на стороне Дрома
        if (queryParams['disablegtm']) {
            makeA();
        } else {
            makeB();
        }
            
        

Page Speed Insights

Page Speed Insights

Плюсы

Page Speed Insights

Плюсы

Page Speed Insights

Плюсы

Page Speed Insights

Плюсы

Минусы

Page Speed Insights

Плюсы

Минусы

Page Speed Insights

Плюсы

Минусы

Page Speed Insights

Плюсы

Минусы

🤖 Эмуляторы – OK

А что у пользователей?

RUM

Real User Monitoring

Vector

Real User Monitoring

Real User Monitoring

Плюсы

Real User Monitoring

Плюсы

Real User Monitoring

Плюсы

Real User Monitoring

Плюсы

Минусы

Real User Monitoring

Плюсы

Минусы

Real User Monitoring

Плюсы

Минусы

Самый главный вопрос

При чем тут попугаи?

Итоги

Web Vitals

Web Vitals

Web Vitals

Web Vitals

Web Vitals

Web Vitals

Web Vitals

Core Web Vitals

Lab data и Field data

Характеристика Lab data Field data
Web Vitals
Характеристика Lab data Field data
Web Vitals
Другие метрики
Характеристика Lab data Field data
Web Vitals
Другие метрики
Интеграция в код сайта
Характеристика Lab data Field data
Web Vitals
Другие метрики
Интеграция в код сайта
Разные устройства и сети
Характеристика Lab data Field data
Web Vitals
Другие метрики
Интеграция в код сайта
Разные устройства и сети
Разные сценарии и страницы
Характеристика Lab data Field data
Web Vitals
Другие метрики
Интеграция в код сайта
Разные устройства и сети
Разные сценарии и страницы
Вариативность перцентилей
Характеристика Lab data Field data
Web Vitals
Другие метрики
Интеграция в код сайта
Разные устройства и сети
Разные сценарии и страницы
Вариативность перцентилей
Реальный пользовательский опыт
Характеристика Lab data Field data
Web Vitals
Другие метрики
Интеграция в код сайта
Разные устройства и сети
Разные сценарии и страницы
Вариативность перцентилей
Реальный пользовательский опыт
CI/CD, процесс разработки
Характеристика Lab data Field data
Web Vitals
Другие метрики
Интеграция в код сайта
Разные устройства и сети
Разные сценарии и страницы
Вариативность перцентилей
Реальный пользовательский опыт
CI/CD, процесс разработки
Мониторинг перформанса в проде
Характеристика Lab data Field data
Web Vitals
Другие метрики
Интеграция в код сайта
Разные устройства и сети
Разные сценарии и страницы
Вариативность перцентилей
Реальный пользовательский опыт
CI/CD, процесс разработки
Мониторинг перформанса в проде

Приготовьте телефоны 🤳🏼

Подписаться

Рома вещает

Всем соточку в лайтхаусе!

Рома Ахмадуллин

Дром

Оценить доклад