Interaction to Next Paint (INP)
Responsiveness as a metric: input delay, processing, presentation — and how a busy main thread wrecks it.
Interaction to Next Paint measures the thing that makes a site feel alive: when you tap, type, or click, how long until the screen actually updates? It watches every interaction for the whole visit and reports the worst. Good is ≤ 200 ms; cross ~500 ms and the page feels broken.
Feel a slow interaction
Turn up the background work — simulating JavaScript hogging the main thread — then tap the button. The “Done” state only appears after the interaction completes, so you literally feel the lag. Then flip the optimize switch and watch INP fall back into the green:
An interaction is a group of events
From the user's view, they “clicked a button.” Under the hood, that fires a group of events — and INP measures the whole group plus the paint after it. INP only counts clicks, taps, and keystrokes; hover and scroll don't count:
The three phases
Every interaction breaks into three phases — and the live demo above maps directly onto them:
- Input delay — from your tap until the browser is free to run the handler. Big when the main thread is busy.
- Processing time — running all the event handlers for the interaction.
- Presentation delay — recalculating layout and painting the next frame.
INP vs the old FID
| FID (old) | INP (now) | |
|---|---|---|
| What it measures | Input delay of the first interaction only | Full duration of (nearly) every interaction |
| Covers | Just the first tap | The whole visit |
| Catches late slowdowns | No | Yes (e.g. memory leaks) |
| Includes processing + paint | No, delay only | Yes |
FID could call a site “responsive” off one fast first tap, even if it bogged down later. INP watches the whole session, so it reflects how the app actually feels over time.
Optimizing each phase
Input delay — yield the main thread
The thread is often busy with script evaluation (downloading, parsing, compiling, running JS) right when the user first interacts. Ship less JS, defer non-critical work, and break long tasks so the thread is free to respond.
Processing time — do less, and break it up
In the handler, do only the critical work (show the visual feedback the user expects) and push the rest — analytics, syncing, spell-check — into a later task so the paint isn't blocked:
input.addEventListener("input", (e) => {
updateTextbox(e); // critical: user must SEE their text now
setTimeout(() => { // hand the rest to a later task
updateWordCount();
runSpellCheck();
syncToServer();
}, 0);
});Presentation delay — paint less
A huge DOM makes every frame expensive. Keep the DOM lean, render only what's above the fold, and use content-visibility: auto to let the browser skip off-screen work.
- →INP measures responsiveness across the whole visit. Good ≤ 200 ms, poor > 500 ms.
- →It counts clicks, taps, keystrokes — not hover or scroll — and measures the whole event group + paint.
- →Three phases: input delay, processing, presentation.
- →It replaced FID, which only saw the first interaction's delay.
- →Fixes: yield the main thread, do less in handlers + break up tasks, keep the DOM lean.