Interaction to Next Paint (INP)
INP is Google's newest Core Web Vital, measuring responsiveness across all user interactions — not just the first click. Poor INP makes pages feel sluggish and directly suppresses conversion.
Google's Thresholds
Interaction to Next Paint replaced First Input Delay (FID) as a Core Web Vital in March 2024. Unlike FID which only measured the first interaction's input delay, INP captures all interactions throughout the page session and reports the worst-case delay.
An INP 'interaction' is a click, tap, or key press that causes a visible response. The measurement spans from when the user initiates the event to when the next frame is painted — including input delay, processing time, and presentation delay.
For React and JavaScript-heavy apps, INP is often the hardest Core Web Vital to optimise. Every state update, re-render, and DOM manipulation competes for main thread time. When a click handler triggers a large React reconciliation, users experience a visible freeze.
Common causes
Tasks over 50ms block the browser from responding to user input. React reconciliation, heavy computations, and third-party scripts are common sources.
Reading layout properties (offsetHeight, getBoundingClientRect) inside click handlers forces the browser to synchronously recalculate layout before proceeding — a 'forced reflow'.
State updates that trigger large component tree reconciliations can block the main thread for hundreds of milliseconds, causing high INP on interactive components.
Analytics, chat widgets, and A/B testing scripts often execute JavaScript at unpredictable times, including during user interactions.
Rendering thousands of DOM nodes when filtering or sorting a large list causes expensive layout recalculations that block interaction response.
How to fix it
Chrome's scheduler.yield() pauses long tasks to give the browser a chance to process user input. It's the most direct fix for high INP caused by long JavaScript tasks.
Mark state updates that don't need to be synchronous as transitions. React will defer and interrupt these updates in favour of urgent interaction responses.
Heavy calculations (data processing, parsing) should run in a Web Worker off the main thread, leaving the main thread free to respond to interactions instantly.
Use react-virtual or @tanstack/virtual to render only the visible portion of a long list, dramatically reducing DOM size and layout work during filtering.
Move getBoundingClientRect() and offsetHeight reads outside event handlers, or replace them with IntersectionObserver and ResizeObserver.
FAQ
What replaced FID in Core Web Vitals?
INP (Interaction to Next Paint) replaced FID as a Core Web Vital in March 2024. FID only measured the first interaction; INP measures all interactions throughout the session.
What is a good INP score?
Google considers 200ms or less as 'Good'. Between 200ms and 500ms is 'Needs Improvement'. Above 500ms is 'Poor'. Users can perceive latency above 100ms.
Does Lighthouse measure INP?
Not directly. Lighthouse reports Total Blocking Time (TBT) as a proxy. Real INP data comes from field measurements via the web-vitals library or RUM tools like AuditJet's RUM script.
How do I improve INP in a React app?
Use React 18's startTransition for non-urgent state updates, avoid forced reflows inside event handlers, move heavy computation to Web Workers, and virtualise long lists. Profile interactions in Chrome DevTools to find specific culprits.
Monitor Core Web Vitals continuously
AuditJet tracks every metric on a schedule and alerts you when scores regress — with revenue impact in dollars and AI fix suggestions.
Start Monitoring Free