Why INP Replaced FID
In March 2024, Google officially replaced First Input Delay (FID) with Interaction to Next Paint (INP) as a Core Web Vital. The change was significant.
FID measured only the delay before the browser starts processing the very first interaction on a page. It was relatively easy to pass — a quick mouse-down event handler could score well even if subsequent clicks took 2 seconds to respond.
INP measures the responsiveness of all interactions throughout the entire page lifetime — clicks, taps, and keyboard inputs — and reports the worst one (with a small allowance for outliers). This is a much harder standard because it catches slow interactions that happen after page load, during complex user workflows.
Thresholds to Know
- Good: INP ≤ 200ms
- Needs Improvement: 200ms < INP ≤ 500ms
- Poor: INP > 500ms
For context, a 200ms interaction feels near-instant. A 500ms interaction feels noticeably sluggish. Anything above 1 second breaks the user's perception of a responsive app.
What INP Actually Measures
When a user interacts with your page (clicks a button, taps a filter, presses a key), the browser must:
- Run event handlers triggered by the interaction
- Recalculate styles and layout
- Paint the updated pixels to screen
INP measures the time from the user's input to when the next frame is painted. If your button click triggers a heavy computation — sorting a 10,000-item list, making a synchronous API call, running a complex animation loop — all of that time counts against your INP score.
How to Measure INP
Chrome DevTools Performance panel: Record a user session, then look for long tasks (red bars in the main thread) that coincide with interaction events. The "Interactions" track shows the INP candidate interactions.
web-vitals.js library: Add to your site for real-user measurement:
import { onINP } from 'web-vitals';
onINP(({ value, rating, attribution }) => {
console.log('INP:', value, rating);
// Send to your analytics
});
GSC Core Web Vitals report: Shows aggregated field data from real Chrome users. Use this to identify which pages have poor INP in production — it often differs from local testing because real users interact differently.
PageSpeed Insights: Enter any URL at pagespeed.web.dev to see both lab and field INP data.
Common INP Causes and Fixes
Heavy event handlers: If a click handler runs 300ms of synchronous JavaScript, INP will fail. Fix: move work off the main thread using Web Workers, or break it into smaller chunks with setTimeout or the scheduler API.
Long tasks blocking the main thread: Tasks over 50ms are considered "long tasks" and block input responsiveness. Fix: use scheduler.postTask() (Chrome 94+) or requestIdleCallback to defer non-critical work.
Third-party scripts: Analytics, chat widgets, and ad scripts often inject long tasks. Use async and defer attributes, load them after interaction, or use a script loader with priority management.
React re-renders: Large React component trees re-rendering synchronously on every interaction. Fix: use React.memo, useMemo, and useCallback judiciously, or migrate to React concurrent features (useTransition, useDeferredValue) to keep the UI responsive during expensive updates.
Links: web.dev INP guide | GSC Core Web Vitals report | Chrome UX Report