What is INP
INP (Interaction to Next Paint) is a Core Web Vitals metric that measures the time from a user interaction (click, key press, or screen tap) until the browser renders the next frame in response to that interaction.
INP replaced FID (First Input Delay) in March 2024. The key difference:
- FID measured only the processing time for the first interaction
- INP measures all interactions on the page and takes the 98th percentile (the slowest of 50 interactions)
This makes INP a stricter metric that better reflects the real user experience.
INP thresholds
| Value | Rating |
|---|---|
| up to 200 ms | Good |
| 200 — 500 ms | Needs improvement |
| more than 500 ms | Poor |
How INP works
Each interaction consists of three phases:
- Input delay — the delay before processing begins (the main thread is busy)
- Processing time — execution of event handlers
- Presentation delay — waiting for the next frame to render
INP = max(input delay + processing time + presentation delay)
The browser calculates INP as the 98th percentile value of all interactions during a session.
Common causes of poor INP
- Long JavaScript tasks — tasks longer than 50 ms block the main thread
- Heavy event handlers — onclick/oninput perform too much work
- Excessive rendering — unnecessary component re-renders
- Synchronous operations — blocking calls in event handlers
- Large DOM — more than 1500 nodes slows rendering
How to improve INP
1. Break up long tasks
// Плохо: одна большая задача блокирует поток
function processData(items) {
items.forEach(item => heavyCompute(item));
}
// Хорошо: разбиваем с yield
async function processData(items) {
for (const item of items) {
heavyCompute(item);
// Передаём управление браузеру между итерациями
await scheduler.yield();
}
}2. Optimize event handlers
// Плохо: вся логика в click обработчике
button.addEventListener('click', () => {
const data = fetchSyncData(); // синхронный запрос
renderHeavyUI(data); // тяжёлый рендеринг
analytics.track('click'); // аналитика
});
// Хорошо: только критическое, остальное отложено
button.addEventListener('click', () => {
updateUI(); // только обновление UI
// Остальное через setTimeout или requestIdleCallback
setTimeout(() => analytics.track('click'), 0);
requestIdleCallback(() => syncData());
});3. Use Web Workers for heavy computations
// Перенести тяжёлую обработку в фоновый поток
const worker = new Worker('/data-processor.js');
worker.postMessage(largeDataset);
worker.onmessage = (e) => updateUI(e.data);4. Debounce frequent events
// input/scroll события срабатывают очень часто
const handleInput = debounce((e) => {
// Обработка только после паузы ввода
searchAPI(e.target.value);
}, 300);
input.addEventListener('input', handleInput);5. Virtualize long lists
// Рендерить только видимые элементы
// Используйте react-virtual, @tanstack/virtual
import { useVirtualizer } from '@tanstack/react-virtual';Measuring INP
import {onINP} from 'web-vitals';
onINP(metric => {
console.log('INP:', metric.value, 'мс');
console.log('Худшее взаимодействие:', metric.attribution);
});In Chrome DevTools → Performance, inspect the Interaction Timeline to analyze specific interactions.
Check INP with reChecker
Use Web Vitals to analyze page responsiveness. The tool will show:
- The current INP value
- The responsiveness rating (good/needs improvement/poor)
- All Core Web Vitals metrics
FAQ
Can INP be measured in a lab? Partially. Lighthouse and PageSpeed Insights show TBT (Total Blocking Time) as a lab proxy for INP. INP itself is measured only using real user data (CrUX), since it requires real interactions.
Why is INP poor on SPAs (React/Vue)? Single Page Applications perform heavy JavaScript work during navigation: unmounting components, fetching data, and mounting new components — all of this blocks the main thread. Solutions: React Concurrent Features, Suspense, code splitting.
How can I find the cause of poor INP? Chrome DevTools → Performance → record a session with an interaction → find long tasks (longer than 50 ms) in the Timeline. The Interactions section shows which interactions were slow.