Что такое Interaction to Next Paint?

Полное руководство по метрике Interaction to Next Paint (INP) в 2025: что это, как замерить и быстро оптимизировать для SEO. Примеры, кейсы, инструкции.

Какое определение Interaction to Next Paint в SEO?

SEO-определение: Полное руководство по метрике Interaction to Next Paint (INP) в 2025: что это, как замерить и быстро оптимизировать для SEO. Примеры, кейсы, инструкции.

Как Interaction to Next Paint влияет на ранжирование?

Влияет на релевантность страницы поисковым запросам.
Полное руководство по метрике Interaction to Next Paint (INP) в 2025: что это, как замерить и быстро оптимизировать для SEO. Примеры, кейсы, инструкции.
SEO Лаборатория

Interaction to Next Paint

Interaction to Next Paint (INP) — это метрика скорости реакции сайта, которая измеряет, сколько времени проходит от вашего клика, нажатия клавиши или касания до момента, когда браузер показывает визуальный отклик на это действие.

Представьте, что вы нажимаете кнопку «Добавить в корзину» в интернет-магазине. INP — это та миллисекундная пауза между вашим щелчком и появлением зелёной галочки или увеличением счётчика в корзине. Если эта пауза слишком велика, сайт кажется «задумчивым» и неотзывчивым.

С марта 2024 года Google официально заменил ей старую метрику First Input Delay (FID) в составе Core Web Vitals. Теперь INP напрямую влияет на ранжирование в поиске, потому что точно отражает, насколько комфортно пользователю взаимодействовать с вашей страницей.

Interaction to Next Paint: как замерять и интерпретировать метрику отзывчивости на практике

Знакомо ощущение, когда нажимаешь на кнопку «Купить», а она будто задумалась на полминуты? Пользователь уходит, а вы теряете деньги. В 2025 году Google строго судит сайты за такую «задумчивость» через метрику Interaction to Next Paint (INP), которая сменила старый добрый FID. Если коротко, INP — это хронометраж вашей реакции на действия человека: от клика до видимого отклика браузера. И это теперь прямой фактор ранжирования. Но как его замерять, чтобы не гадать, а точно знать, где болит? Давайте разбираться на живом примере.

Не просто цифра: почему ваш средний INP может лгать

Большинство смотрит на одну цифру — 75-й процентиль в отчёте PageSpeed Insights или CrUX. «У меня 280 мс, почти вписались в хорошие значения (до 200 мс)!» — думает оптимизатор. А пользователи уже бегут. Потому что 75-й процентиль скрывает правду. Представьте:

  • 99 раз вы нажимаете на кнопку, и она реагирует за 50 мс — супер быстро.
  • Но 1 раз из 100 тот же клик блокирует интерфейс на целых 1500 мс.

75-й процентиль этого «кошмара» может быть отличным, но тот единственный, но долгий отклик — это гарантированная потеря доверия и, скорее всего, конверсии. Ваша главная задача — бороться не со средним, а с худшим опытом. Это первый неочевидный нюанс.

Лаборатория и поле: два крыла одной диагностики

Чтобы найти эти болезненные «одиночные» клики, нужен двойной подход. Нельзя полагаться только на симуляции.

  1. Полевые данные (Real User Monitoring, RUM): это факты из жизни. Google CrUX, данные от сервисов вроде New Relic или самонаписанный сбор через Performance Observer API. Они показывают, как реальные люди с разными устройствами и сетями чувствуют ваш сайт.
  2. Лабораторные инструменты: это микроскоп хирурга. Chrome DevTools (вкладка Performance), Lighthouse, WebPageTest. Они воспроизводят проблему в контролируемых условиях и позволяют увидеть причину задержки в деталях.

Полевые данные говорят «здесь болит», лабораторные — «почему болит». Игнорируя первые, вы оптимизируете вслепую. Игнорируя вторые, вы не поймёте, что лечить.

Кейс: разбираем «тормозящий» фильтр интернет-магазина

Давайте пройдём весь путь анализа на примере, знакомом каждому. У нас есть сайт эко-товаров. Страница категории с фильтром по цене, бренду и составу. Полевые данные (CrUX) показывают INP = 320 мс (плохо). Пора надеть перчатки и заглянуть под капот.

Мы открываем DevTools (F12), вкладка Performance. Ставим запись, нажимаем на чекбокс «Без глютена» в фильтре и останавливаем запись. Вот что мы видим на временной шкале (flame chart):

Что ищем Как выглядит в DevTools Что это значит для INP
Длинная задача (Long Task) Сплошной жёлтый блок длительностью >50 мс Браузер заблокирован и не может обработать ввод или перерисовать экран. Главный убийца отзывчивости.
Всплеск активности Main Thread Густой «лес» из мелких фиолетовых (Layout) и зелёных (Paint) блоков после события Клик вызвал каскад перерасчётов стилей и отрисовок. Слишком дорогое взаимодействие.
Задержка перед обработкой события (Input Delay) Разрыв между серой полосой «клика» и началом выполнения скрипта Основной поток был занят другим JS. Пользователь чувствует lag.

В нашем случае обнаруживается длинная задача на 180 мс, вызванная скриптом фильтра. Он не просто применяет фильтр, а делает следующее:

  • Сортирует ВСЕ товары на странице (а их 500) в основном потоке.
  • Пересоздаёт DOM-дерево для всего списка заново.
  • Запускает несколько синхронных вызовов `offsetHeight` для расчёта новой раскладки, вызывая форсированный синхронный layout — это тихий убийца производительности.

И вот мы нашли точку роста. Но как это измерить количественно, чтобы доказать коллегам необходимость изменений?

Формула понимания: разбираем INP на части

Метрика INP сама состоит из трёх ключевых периодов. Представьте её как уравнение:

INP = Input Delay + Processing Time + Presentation Delay

Давайте расшифруем каждый компонент для нашего кейса с фильтром:

  1. Input Delay (Задержка ввода): Время от клика до начала выполнения нашего обработчика события. Если в этот момент Main Thread забит загрузкой скрипта или парсингом JSON, обработчик будет ждать в очереди. В нашем случае: ~15 мс. Не критично, но есть.
  2. Processing Time (Время обработки): Это и есть выполнение нашего «тяжёлого» JavaScript — те самые 180 мс сортировки и манипуляций с DOM. Основной виновник. Здесь живет та самая длинная задача.
  3. Presentation Delay (Задержка отображения): Браузеру нужно пересчитать стили, layout и нарисовать изменения. Если наш код вызвал каскад пересчётов, это время взлетает. У нас: ещё ~40 мс.

Итого: 15 + 180 + 40 = 235 мс только для этого одного взаимодействия. А если пользователь в это время на слабом ноутбуке? Цифра легко перепрыгнет за 500 мс. И это лишь один из десятков элементов на странице.

Скрытые риски: что упускают даже опытные разработчики

Казалось бы, нашли длинную задачу — оптимизируй код. Но не всё так просто. Вот подводные камни:

  • «Ленивые» риски: Вы решили вынести сортировку в Web Worker (отдельный поток). Это правильно! Но передача огромного массива данных между потоками (postMessage) тоже занимает время. Если массив очень велик, выигрыш может быть меньше ожидаемого.
  • Риск третьих сторон: На вашу страницу может «приземлиться» виджет обратного звонка с собственным тяжёлым JS. Его длинная задача будет увеличивать задержку ввода (Input Delay) для ВАШИХ же обработчиков. Мониторинг должен быть тотальным.
  • Альтернатива тотальному мониторингу: Не всегда есть ресурс внедрять сложные системы RUM. Начните с прицельного замера через Performance Event Timing API. Вот кусочек кода, который можно вставить в консоль для нашего кейса с фильтром:
// Слушаем события performance типа 'event'
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
// Нас интересуют события клика
if (entry.name === 'click') {
console.log('INP-компоненты для клика:');
console.log(`  - Задержка ввода: ${entry.processingStart - entry.startTime} мс`);
console.log(`  - Время обработки: ${entry.processingEnd - entry.processingStart} мс`);
console.log(`  - Задержка отрисовки: ${entry.duration - (entry.processingEnd - entry.startTime)} мс`);
console.log(`  - ПОЛНЫЙ INP: ${entry.duration} мс`);
}
}
});

// Начинаем наблюдать за событиями
observer.observe({ type: 'event', buffered: true });

Запустите этот код, нажмите на фильтр — и вы получите детальную разбивку INP прямо в консоли. Это мощный и быстрый способ валидации проблемы без сложных инструментов.

Итог этапа анализа: что у нас в руках

Мы начали с общей цифры «INP 320 мс — плохо». Прошли путь через двойную диагностику, разобрали живой пример и выяснили, что:

  1. Главная боль — длинная задача (180 мс) в обработчике фильтра.
  2. Есть побочные эффекты — форсированные лейауты, добавляющие ещё 40 мс.
  3. Мы понимаем формулу метрики и можем замерять её компоненты даже простым скриптом.

Это состояние нашей «пациентки» — страницы категории. Мы нанесли на карту координаты самой большой проблемы. Но одной констатации недостаточно. Знание — это только полдела. Теперь перед нами встаёт вопрос: а что, собственно, делать с этим монстром в 180 мс? Как превратить его в плавный отклик меньше 200? И какие ещё «виновники» могут прятаться в тени, готовые испортить отзывчивость даже после этой правки?

Это уже переход к следующей, самой интересной части — выявлению всех точек роста и генерации гипотез для оптимизации. Мы переходим от диагноза к лечению. И здесь на сцену выходят не только ручные методы, но и хитрости, которые помогут нам предупредить проблемы ещё на этапе разработки.

От анализа к гипотезам: разбираем главных «виновников» плохого Interaction to Next Paint в 2025 году

Итак, диагноз поставлен. В нашем интернет-магазине эко-товаров фильтр создаёт длинную задачу в 180 мс. Казалось бы, вот он — корень зла! Бери и оптимизируй. Но если вы сейчас кинетесь переписывать только этот скрипт, рискуете потратить кучу времени, а общий INP страницы улучшится всего на 10-15%. Разочарование, потеря бюджета, зря выпитый кофе.

Почему? Потому что плохой INP — это редко одна проблема. Это системный сбой, где несколько «виновников» играют в пинг-понг, перекидываясь блокировками основного потока. Наша задача — не срубить одно самое высокое дерево, а проредить весь лес. Давайте картографируем эту территорию, используя данные нашего кейса и лучшие мировые практики 2025 года.

Виновник №1: Длинные задачи (Long Tasks) — не только ваш код

Мы уже нашли одну такую задачу. Но откуда они вообще берутся? Представьте Main Thread браузера как однополосную дорогу. Длинная задача — это фура, которая перегородила всё движение. Машины (другие клики, скроллы, анимации) встали в пробку. Наш INP взлетает.

Неочевидные источники длинных задач:

  • «Мёртвый» код сторонних виджетов: Вы поставили красивый чат для поддержки или виджет отзывов. Он загрузился, пользователь им не пользуется, но его JavaScript-бундл периодически «просыпается», чтобы проверить обновления, и грузит поток. Как найти? В DevTools во вкладке Performance ищите задачи с названиями, отличными от ваших доменных. Часто это домены вроде *widget.com*, *chatprovider.com*.
  • Агрессивные полифиллы и трансляторы кода (Babel): Стремясь поддержать старые браузеры, вы можете загружать тонны полифиллов для функций, которые уже встроены в 95% браузеров вашей аудитории. Они парсятся и компилируются, создавая задачи на этапе загрузки и выполнения.
  • Накопительный эффект микрозадач (Microtasks): Обещания (Promises), обработчики .then() или queueMicrotask() выполняются в конце текущей задачи. Если их много, они могут незаметно растянуть её за 50 мс.

Вернёмся к нашему магазину. Мы копнули глубже и, просматривая отчёт Lighthouse, обнаружили, что на странице пять сторонних виджетов: чат, кнопка «Поделиться в соцсетях», виджет обратного звонка, система рекомендаций и метрика. Каждый при старте создаёт свою длинную задачу. Пока пользователь думает, что нажать, фоном идёт настоящая битва за ресурсы.

Анализ «виновников» INP на странице категории (лабораторные данные Lighthouse)
Источник проблемы Тип Оценочное влияние на INP Приоритет исправления Комментарий и риск
Скрипт фильтра товаров (сортировка) Длинная задача, Форсированный лейаут Высокое (180-235 мс) Критический (P0) Блокирует UI при каждом использовании. Явная боль пользователя. Риск: Сложная логика, требует аккуратного рефакторинга.
Виджет обратного звонка (третий) Длинная задача при загрузке Среднее (80-120 мс) Высокий (P1) Влияет на INP первых кликов после загрузки страницы. Альтернатива: Отложить загрузку до первого ховера на кнопке «Позвоните мне».
Библиотека анимаций (вся) Большой JS-бундл, парсинг Низкое/Среднее (30-50 мс TBT) Средний (P2) Увеличивает общую загрузку потока, повышает Input Delay для всех событий. Лучшая практика: Заменить на нативные CSS-анимации где возможно.
Каскад пересчётов от динамического контента Накопительные лейауты Переменное (10-40 мс за раз) Высокий (P1) Самый коварный враг. Каждое обновление цены или статуса «в корзине» может запускать цепочку лейаутов. Суммарный эффект хуже одной длинной задачи.

Смотрите, картина меняется! Наш фильтр — главный, но не единственный виновник. И если мы не придумаем, как укротить «каскад пересчётов», даже после оптимизации фильтра пользователь будет чувствовать дёргания при добавлении товара в корзину.

Виновник №2: Каскадные лейауты (Layout Thrashing) — тихий убийца плавности

Этот парень работает не в лоб, а по касательной. Вы меняете стили в JavaScript (например, обновляете высоту блока), а потом сразу же хотите прочитать геометрические свойства (ширину, позицию) этого же или соседнего элемента. Браузер, чтобы дать вам актуальные данные, вынужден срочно, синхронно выполнить полный перерасчёт макета (layout) всей страницы или её части. Это форсированный синхронный лейаут. Сделайте это в цикле — и INP взлетит до небес.

Плохой код: element.style.width = '200px'; -> let w = element.offsetWidth; -> БЛОКИРОВКА
Хороший код: Прочитать всё -> Записать всё -> Перечитать (если нужно)

В нашем кейсе фильтр не просто сортировал массив, он делал это с нарушением паттерна. В цикле для каждого товара он:
1. Создавал новый DOM-элемент (изменение).
2. Сразу вставлял его в список (изменение).
3. Вызывал `container.offsetHeight`, чтобы рассчитать что-то для следующей итерации (чтение!).
Это и есть layout thrashing. Браузер пересчитывал layout на каждой итерации цикла из 500 товаров.

От инвентаризации к гипотезам: как AI может ускорить поиск решений

Составили таблицу, нашли виновников. Что дальше? Обычно начинается долгий мозговой штурм. «Давайте вынесем сортировку в воркер!», «А может, сделать виртуализацию списка?», «Давайте вообще уберём этот виджет!». Споры, недели на прототипы.

Современный подход — использовать AI как генератор и валидатор гипотез. Не для написания кода, а для анализа и приоритизации.

  1. Генерация идей: Вы загружаете в ChatGPT или Claude фрагмент проблемного кода (без критических данных) и таблицу с метриками. Запрос: «На основе этого кода и метрик, предложи 3 технические гипотезы для оптимизации INP, ранжируй их по предполагаемой эффективности и сложности внедрения». ИИ часто выдаёт неочевидные комбинации: «использовать алгоритм быстрой сортировки + DocumentFragment для batch-вставки + CSS containment для изоляции лейаута».
  2. Приоритизация через симуляцию: Некоторые инструменты (например, часть функций в WebPageTest или SpeedCurve) позволяют смоделировать эффект от изменений. «Что будет с INP, если мы уменьшим размер бундла виджета на 30%?» Прогноз строится на исторических данных о корреляции.
  3. Альтернативный путь — точечный мониторинг: Не хотите грузить AI? Сфокусируйтесь на критичных для конверсии точках. Вам не нужно мониторить INP для каждого клика по футеру. Нужно — для кнопок «В корзину», «Оформить заказ», полей формы. Используйте Performance Event Timing API для выборочного сбора данных только по этим элементам. Это резко снизит шум и выделит сигнал.

Для нашего магазина мы сформировали такие гипотезы:

  • Гипотеза A (Высокий приоритет): Рефакторинг скрипта фильтра с устранением layout thrashing и выносом сортировки в Web Worker даст снижение INP для этого взаимодействия на ~70% (с 235 мс до ~70 мс).
  • Гипотеза B (Средний приоритет): Отложенная загрузка виджета обратного звонка (по событию hover или через 5 секунд после load) снизит INP для первых кликов на 15% в 75-м процентиле.
  • Гипотеза C (Низкий приоритет): Добавление CSS-правила `contain: content` для карточек товаров изолирует их лейауты и снизит совокупное влияние микровзаимодействий (добавление в корзину) на 5-10%.

Теперь у нас есть не просто список багов, а план атаки с измеримыми целями. Мы перешли от состояния «всё плохо» к чёткому набору проверяемых действий. Каждая гипотеза — это мини-эксперимент, который приведёт нас либо к победе, либо к новому, более точному пониманию.

Но как провести эти эксперименты правильно? Как превратить гипотезу A в работающий код, который не сломает фильтр, а сделает его молниеносным? И как убедиться, что наша оптимизация не стала «игрой в whack-a-mole», где исправление одного INP порождает три новых?

Это точка перехода к финальному, самому практическому акту — разработке и внедрению стратегии оптимизации. От слов и планов мы движемся к коду, таблицам результатов и автоматизации, которая не даст проблеме вернуться.

Стратегия оптимизации Interaction to Next Paint: от планирования до автоматизации

Гипотезы готовы. Энтузиазм зашкаливает. Самое время нажать на курок и начать оптимизировать! Стоп. Именно здесь команды совершают роковую ошибку: они хватаются за первую гипотезу и начинают бессистемно пилить код. Результат? Потратили неделю, INP упал на 10%, но через две недели новая фича снова всё испортила. Вечный бой с симптомами, а не болезнью.

Нам нужна не разовая акция, а стратегия. Такой план, который превратит нашу таблицу гипотез в конкретные действия, даст измеримый результат и — что самое важное — не позволит проблеме вернуться. Давайте построим эту стратегию вместе, шаг за шагом, на примере нашего магазина эко-товаров. Мы пойдём от быстрых побед к глубокой архитектуре, завершив всё петлёй автоматического контроля.

Этап 1: Тактический рефакторинг — быстрые победы (INP < 200 мс)

Цель этого этапа — получить первый ощутимый результат и поддержку команды. Работаем с гипотезой A: рефакторинг фильтра. Помните, его INP был 235 мс. Наша тактика — разделить длинную задачу и убить layout thrashing.

Шаг 1. Устранение Layout Thrashing

Вместо того чтобы в цикле читать `offsetHeight`, мы применим паттерн «Прочитать всё → Записать всё». Используем `DocumentFragment` как временный контейнер в памяти.

// БЫЛО (плохо)
function renderProducts(products) {
container.innerHTML = '';
for (const product of products) {
const item = createProductElement(product); // Создаём элемент
container.appendChild(item); // Вставляем (запись)
// Layout Thrashing! Чтение после записи в цикле:
const height = container.offsetHeight;
// ... какая-то логика с height ...
}
}

// СТАЛО (хорошо)
function renderProductsOptimized(products) {
// 1. ВСЁ ЧИТАЕМ заранее, если нужно
const initialHeight = container.offsetHeight;

// 2. ВСЁ ЗАПИСЫВАЕМ в буфер (DocumentFragment)
const fragment = document.createDocumentFragment();
for (const product of products) {
fragment.appendChild(createProductElement(product));
}

// 3. ОДНА операция вставки в DOM
container.innerHTML = '';
container.appendChild(fragment);

// 4. Последующее чтение, если необходимо
const newHeight = container.offsetHeight;
}

Уже это простое изменение сокращает количество форсированных лейаутов с 500 до 2! Это даёт мгновенный выигрыш в 30-40 мс.

Шаг 2. Разделение длинной задачи с помощью yield

Сортировка 500 товаров — тяжёлая операция. Мы не можем просто выкинуть её, но можем разбить на части, чтобы браузер «дышал». Используем `setTimeout` или, что современнее, `scheduler.yield()` (экспериментальный API).

async function sortAndRenderInChunks(products) {
// 1. Быстрая сортировка в фоне (не блокируем поток надолго)
const sorted = await quickSortInChunks(products);

// 2. Рендеринг через yield
const BATCH_SIZE = 50;
for (let i = 0; i < sorted.length; i += BATCH_SIZE) {
const batch = sorted.slice(i, i + BATCH_SIZE);
renderBatch(batch); // Функция, которая рендерит пачку в DocumentFragment
// Даём браузеру шанс обработать другие события
if (typeof scheduler !== 'undefined' && scheduler.yield) {
await scheduler.yield();
} else {
// fallback
await new Promise(resolve => setTimeout(resolve, 0));
}
}
}

Скрытый риск: Слишком мелкое разбиение (пачки по 1 элементу) или слишком частая отдача управления (`yield`) могут, наоборот, увеличить общее время выполнения. Нужен баланс. Эмпирическое правило: делите задачу так, чтобы кусок выполнялся не более 10-15 мс.

Результат этапа: После внедрения этих двух тактик, лабораторные замеры показали, что INP фильтра упал с 235 мс до 110 мс. Мы уже в зелёной зоне (< 200 мс)! Но это только одна точка. Пора масштабировать успех.

План оптимизации INP: от тактики к стратегии
Целевой INP Основные тактики Инструменты для контроля и проверки Ключевые метрики (KPI) для этапа
< 200 мс 1. Разделение длинных задач (yield).
2. Устранение layout thrashing.
3. Отложенная загрузка неиспользуемого JS (виджеты).
Chrome DevTools (Long Tasks panel), Performance Insights, Lighthouse Audit for "Avoid long main-thread tasks". 1. Процент длинных задач (>50мс) снижен на 70%.
2. Total Blocking Time (TBT) < 200мс.
3. INP 75-го процентиля в поле < 200 мс (CrUX).
< 150 мс 1. Приоритизация критического ресурса.
2. Оптимизация обработчиков событий (дебаунсинг, throttling).
3. Использование CSS `contain` для изоляции.
Webpack Bundle Analyzer (размер бандлов), Chrome DevTools (Coverage tab), Scheduling API для приоритизации. 1. Размер основного JS-бандла < 100 КБ после gzip.
2. Время парсинга и компиляции JS снижено на 40%.
3. INP 75-го процентиля < 150 мс.
< 100 мс 1. Изоляция тяжёлой логики в Web Workers.
2. Полное предотвращение синхронных лейаутов.
3. Оптимизация анимаций исключительно на compositor thread.
Lighthouse CI, автоматические тесты на Web Vitals в CI/CD (например, с помощью `lighthouse-ci`), RUM-дашборды. 1. 95-й процентиль INP < 200 мс (стабильность).
2. 0 синхронных пересчётов layout в ключевых сценариях.
3. INP 75-го процентиля < 100 мс (элитный уровень).

Этап 2: Архитектурные изменения — движение к INP < 150 мс

Теперь, когда мы убрали явные косяки, нужно копать глубже. Основной враг на этом этапе — тяжёлая загрузка и парсинг JavaScript, который увеличивает Input Delay для всех последующих взаимодействий. Гипотеза B (виджет) и C (CSS containment) вступают в игру.

  1. Приоритизация ресурсов: Мы используем `` для критического CSS и шрифтов, но деприоритизируем сторонние виджеты с помощью `` или атрибута `fetchpriority="low"` для тега скрипта. Виджет обратного звонка теперь грузится в последнюю очередь.
  2. Оптимизация обработчиков: Добавляем на поля ввода (поиск, форма) не просто дебаунсинг, а дебаунсинг с приоритетом. Первый ввод обрабатывается быстро (для мгновенной обратной связи), последующие — с задержкой.
  3. CSS Containment: Внедряем для карточек товаров правило `contain: layout style paint`. Это создаёт изолированный подграф лейаута. Теперь изменение состояния одной карточки (например, «в корзине») не заставляет браузер пересчитывать layout всего списка. Это прямое воздействие на «каскадные лейауты».

Лучшая мировая практика 2025: Использование `@scope` в CSS для более жёсткой изоляции стилей и предотвращения непреднамеренных перерасчётов. Пока экспериментально, но за этим будущее.

Этап 3: Автоматизация и культура производительности

Вы внедрили всё. INP на странице категории стал стабильно 130 мс. Можно выдохнуть? Нет. Без автоматизации любой новый разработчик, добавляя «крутую анимацию» или подключая новый маркетинговый скрипт, откатит все ваши труды за один коммит. Ключ — встроить проверку INP в процесс разработки.

Шаг 1. Lighthouse CI в пайплайне

Настройте запуск Lighthouse в режиме CI (например, через GitHub Actions) на каждый Pull Request. Бот будет проверять ключевые страницы и блокировать мерж, если INP деградировал ниже установленного порога (например, выше 200 мс).

# Упрощённый пример конфига .github/workflows/lighthouse-ci.yml
name: Lighthouse CI
on: [pull_request]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v9
with:
configPath: './lighthouserc.json'
uploadArtifacts: true
temporaryPublicStorage: true

А в `lighthouserc.json` вы задаёте пороговые значения:

{
"ci": {
"collect": {
"url": ["http://localhost:3000/category/eco"]
},
"assert": {
"assertions": {
"interaction-to-next-paint": ["error", {"maxNumericValue": 200}],
"long-tasks": ["error", {"maxLength": 0}]
}
}
}
}

Теперь плохой код не попадёт в продакшн. Это не бюрократия, это страховка ваших KPI.

Шаг 2. Мониторинг RUM в реальном времени

Lighthouse — это лаборатория. Но вам нужны и полевые данные. Настройте дашборд в Data Studio или аналогичном инструменте, который показывает тренд INP по ключевым страницам из данных CrUX или вашего RUM-провайдера. Падение графика — сигнал для внепланового расследования.

Формула успеха: Лабораторный контроль (CI) + Полевой мониторинг (RUM) = Стабильно низкий INP

Итог: что у нас получилось в кейсе магазина?

Вернёмся к нашему магазину. Мы прошли все три этапа стратегии:

  • Старт: INP страницы категории = 320 мс (CrUX, 75p). Пользователи уходили из-за тормозов.
  • После тактического рефакторинга (Этап 1): INP упал до ~180 мс. Фильтр перестал «лагать».
  • После архитектурных изменений (Этап 2): INP стабилизировался на уровне ~130 мс за счёт оптимизации загрузки и CSS containment. Улучшились и другие метрики (LCP, CLS).
  • После автоматизации (Этап 3): Команда внедрила Lighthouse CI. Через месяц разработчик случайно добавил синхронную библиотеку для красоты — сборка упала, мерж заблокирован. Проблема была устранена до релиза. INP в поле остался стабильным на 130 мс.

Мы превратили метрику из страшного абстрактного числа в понятный, управляемый процесс. От анализа и гипотез — к коду, от кода — к автоматизированной защите. Это и есть современный подход к работе с Core Web Vitals. Не героический разовый подвиг, а рутина, которая гарантирует, что ваш сайт всегда будет быстрым и отзывчивым. А значит — будет нравиться и пользователям, и поисковым системам.

Как использовать Interaction to Next Paint в SEO-оптимизации

Шаг 1: Анализ текущего состояния

Определите текущие показатели Interaction to Next Paint с помощью инструментов аудита.

Шаг 2: Оптимизация параметров

Внесите изменения на основе рекомендаций по Interaction to Next Paint.

Шаг 3: Мониторинг результатов

Отслеживайте изменения в метриках после оптимизации Interaction to Next Paint.
Время выполнения: 30 минут