Among the three Core Web Vitals, Interaction to Next Paint (INP) is the one that resists the most. Around 43% of sites still fail the 200-millisecond threshold, which makes it the most frequently missed signal. Unlike its predecessor, INP judges a page’s responsiveness across the whole visit, not just the first click — a change of method that explains why so many interfaces that feel “smooth” turn red.
What INP measures, and why it replaced FID
First Input Delay only measured the delay before the first interaction was acknowledged, and ignored all the work done afterwards. Most sites scored a “good” FID without it reflecting real experience. INP fixes that bias: it observes the latency of every interaction in a visit — clicks, taps, key presses — and keeps a value close to the worst one. An interface can therefore post a flawless LCP and CLS while still failing INP.
Each interaction breaks down into three phases, and INP adds them up: the input delay (the time the main thread stays busy before it can process the event), the processing time (running the event handlers), and the presentation delay (computing style and painting the next frame).
The thresholds to aim for
The thresholds are measured at the 75th percentile of real interactions, on the 75th-percentile device. A lab value is not enough to validate a site.
| Metric | Good | Needs improvement | Poor |
|---|---|---|---|
| INP (responsiveness) | ≤ 200 ms | 200 – 500 ms | > 500 ms |
| LCP (loading) | ≤ 2.5 s | 2.5 – 4 s | > 4 s |
| CLS (stability) | ≤ 0.1 | 0.1 – 0.25 | > 0.25 |
INP is not fixed in the lab: it is measured in the field, at the 75th percentile of real interactions.
Measuring INP in the field
The data that matters is field data, not a synthetic audit. The Chrome team’s web-vitals library exposes INP with attribution of the element and phase responsible, which turns an abstract number into an actionable lead. These values can be sent to the site’s analytics tool for continuous monitoring.
import { onINP } from 'web-vitals/attribution';
onINP((metric) => {
const a = metric.attribution;
// Élément et phase responsables de la pire interaction
console.log('INP', metric.value, a.interactionTarget, {
inputDelay: a.inputDelay,
processingDuration: a.processingDuration,
presentationDelay: a.presentationDelay,
});
navigator.sendBeacon('/rum', JSON.stringify({ inp: metric.value }));
}, { reportAllChanges: false });The phase at fault points to the fix: a high inputDelay flags a saturated main thread, a long processingDuration designates a too-heavy handler, and a large presentationDelay betrays an expensive render.
Break up long tasks
The most common cause of a poor INP is a long task that monopolises the main thread and delays the interaction’s processing. The remedy is to hand control back to the browser between chunks of work. The scheduler.yield() API allows this splitting while regaining control with priority, where a classic setTimeout sends the task to the back of the queue.
async function handleClick() {
updateUIImmediately(); // retour visuel instantané
for (const chunk of workChunks) {
processChunk(chunk);
// Rend la main au navigateur pour traiter d'autres interactions
if ('scheduler' in window && 'yield' in scheduler) {
await scheduler.yield();
} else {
await new Promise((r) => setTimeout(r, 0));
}
}
}Three further levers complete the splitting: defer non-essential work until after paint with requestIdleCallback, avoid layout thrashing by separating DOM reads and writes, and lower the render cost by limiting the scope of style recalculations. Reducing the amount of JavaScript executed at startup — code splitting, deferred hydration — remains the underlying lever.
Rule of thumb. A good Lighthouse score does not guarantee a good INP. Lighthouse produces a lab value on a single simulated interaction; the official INP comes from the field, aggregated over 28 days. A site can show 100 in Lighthouse performance and stay red on INP in Search Console.
The bottom line
INP measures the responsiveness of every interaction in a visit, with a target of 200 ms at the 75th percentile. It is diagnosed with field data and web-vitals attribution, never on a single lab audit. The gains come mostly from breaking up long tasks and reducing the JavaScript executed on the main thread. It is a deep piece of work, but it is also the Core Web Vital where the effort shows up fastest in real data.
On the sites I audit, the most common mistake is to validate INP in Lighthouse and consider the matter closed. The day you wire web-vitals attribution onto real traffic, the true cause jumps out — almost always a heavy event handler or a third-party script blocking the main thread. I always start by measuring before optimising anything: without field data, you are fixing blind. — Simon Janvier
Further reading: the reference documentation “Interaction to Next Paint (INP)” on web.dev details the phases of an interaction and the optimisation techniques.
