The short answer
Interaction to Next Paint measures the delay between a user interaction and the visual response, across the whole page lifetime. A good score is 200ms or less at the 75th percentile. Most failures come from long JavaScript tasks blocking the main thread, and the highest-value fixes are breaking up long tasks, deferring non-critical scripts and reducing third-party load.
Key takeaways
- INP is measured across the whole session, not just the first interaction
- Any task over 50ms is a long task and a likely contributor
- Third-party scripts are the most common single cause
- Field data from CrUX is the metric that counts, not a lab score
Part of our guide to Generative engine optimisation: getting cited by AI answers.
Interaction to Next Paint replaced First Input Delay in March 2024, and a great many sites that comfortably passed FID do not pass INP. The reason is that FID measured only the delay before processing the first interaction, while INP measures the full interaction-to-paint duration for every interaction across the session.
What is being measured
For each interaction — click, tap, key press — INP measures from the input event to the next frame painted reflecting the result. The reported value is close to the worst interaction on the page. A good score is 200ms or less at the 75th percentile of real users; above 500ms is poor.
Note "real users". Lighthouse cannot measure INP meaningfully because it does not interact with your page. Use the Chrome User Experience Report or your own field data.
Where the time goes
An interaction has three phases: input delay while the main thread is busy with something else, processing time running your handlers, and presentation delay computing style and layout and painting. In our experience the first is usually the largest, and the cause is almost always JavaScript.
Break up long tasks
Any task occupying the main thread for more than 50ms blocks interaction for its full duration. Hydration, large data transforms, and analytics initialisation are common culprits. Yield to the main thread between chunks of work — scheduler.yield() where available, otherwise a setTimeout of zero — so pending interactions can be serviced between chunks.
Audit third-party scripts
This is the most common single cause we find. Tag managers loading a dozen tags, chat widgets, session recorders, A/B testing frameworks — each occupying the main thread at unpredictable moments. Load what you can with async or defer, delay non-essential tags until after first interaction, and remove the ones nobody has looked at in a year. There are usually several.
Paint feedback before doing the work
A click handler that runs 300ms of work before updating anything makes the interface feel broken. Update the visual state first — disable the button, show a spinner — let the frame paint, then do the work. The total duration is unchanged; the measured INP and the perceived responsiveness both improve substantially.
Watch for layout thrashing
Reading a layout property such as offsetHeight after writing a style forces a synchronous reflow. Do it in a loop and you have quietly built a performance problem. Batch reads and writes separately.
Reduce DOM size
Style and layout cost scales with node count. A page with 5,000 nodes recalculates far more slowly than one with 800. Virtualise long lists rather than rendering ten thousand rows and hiding most of them.
Measure the right thing
Lab tools identify candidates; field data tells you whether you fixed anything. Instrument INP with the web-vitals library, report it back, and segment by device and page template. Nearly every site we look at has a mobile problem masked by a desktop average.