Interaction to Next Paint (INP) is a Google Core Web Vital that measures the responsiveness of a web page. It records the longest delay between a user interaction (click, tap, key press) and the next visual update on the screen during the entire page visit, then reports the 75th percentile across all real user sessions. INP became an official Core Web Vital and ranking signal on 12 March 2024, replacing First Input Delay (FID), which was the original responsiveness metric since 2020. A good INP value is 200 milliseconds or less. Above 500 ms the experience feels noticeably laggy. INP is measured from real Chrome users (Chrome User Experience Report, CrUX dataset) and reported in Google Search Console under Core Web Vitals, in PageSpeed Insights, in the Chrome DevTools Performance panel and via the web-vitals JavaScript library. INP rewards pages with light JavaScript, small event handlers, server side rendering and careful task scheduling. It punishes heavy React rerenders, blocking analytics on click, synchronous third party scripts and unbroken long tasks above 50 ms.
How is INP measured?
For every interaction on a page (click, tap, key press, drag in some forms), the browser measures three phases:
- Input delay: time from when the user interacts until the corresponding event handler starts running. Long input delay means the main thread was busy with another task.
- Processing time: how long the event handler (and any other listener registered for that event) takes to run.
- Presentation delay: time from the end of processing until the browser paints the next frame on screen.
The sum is one interaction latency. INP reports the longest latency observed during the visit (with a small allowance: one outlier per 50 interactions is ignored for pages with very high interaction counts). The metric is finalized when the page is unloaded and reported back via the Performance Observer API.
What are the INP thresholds?
| Category | Threshold | What it feels like |
|---|---|---|
| Good | 200 ms or less | Instant. Buttons highlight immediately, lists update without perceptible lag. |
| Needs improvement | 200 to 500 ms | Slight but noticeable lag. Users may tap twice or assume the click was lost. |
| Poor | Above 500 ms | Visibly slow. Frequent double clicks, dropped interactions, frustration. |
Google passes the Core Web Vitals threshold when the 75th percentile of mobile sessions and the 75th percentile of desktop sessions both stay below 200 ms. As of February 2025, about 65 percent of mobile URLs in the CrUX dataset pass the INP threshold globally, up from 55 percent at launch in March 2024.
Why did INP replace FID?
First Input Delay only measured the delay before the very first interaction was processed. It missed two important problems:
- FID ignored every interaction after the first. A page could feel instant on first click but lag on every subsequent action.
- FID did not include processing or rendering time. A handler that ran for 800 ms after a fast input delay still got a great FID score.
INP fixes both: it watches every interaction and includes the entire path until the next frame is painted. The result correlates much better with user reported responsiveness in Google internal studies.
What causes a bad INP?
- Long tasks on the main thread: any JavaScript that runs for more than 50 ms without yielding blocks the next interaction. Common offenders are large React/Vue rerenders, framework hydration, analytics initialization (Google Tag Manager with many tags, Hotjar, Segment), advertising libraries.
- Synchronous third party scripts: a chat widget, cookie consent script, or A/B test that blocks the main thread on click.
- Heavy event handlers: a click handler that filters a 10000 row table client side, sorts an array of objects, or calls
JSON.parseon a large payload. - Layout thrashing: reading and writing layout values in alternation forces synchronous reflow.
- Slow framework rerenders: typing in an input that triggers a full app rerender (React with no memoization, Angular zone churn).
- Animations on the main thread: JS based animations that should be CSS animations on the compositor.
- Slow CSS recalcs: pages with hundreds of thousands of DOM nodes recalculating styles on every interaction.
How do I measure INP?
- PageSpeed Insights at
pagespeed.web.dev: shows lab INP from Lighthouse and field INP from CrUX (real users in the last 28 days). - Search Console » Core Web Vitals report: shows INP grouped by URL pattern for the verified property.
- Chrome DevTools Performance panel: in Chrome 121 and later, the Performance panel highlights long interactions and shows their three phases.
- web-vitals library by Google (
npm install web-vitals): sends real INP from your users to your own analytics. Minimum recommended setup:import { onINP } from 'web-vitals'; onINP(metric => { fetch('/api/vitals', { method: 'POST', body: JSON.stringify(metric), keepalive: true, }); }); - RUM providers: Cloudflare Web Analytics, Vercel Speed Insights, SpeedCurve, Calibre, DebugBear, Sentry Performance.
- CrUX dashboard on BigQuery: for site wide trend analysis across months.
How do I optimize INP?
- Break long tasks into chunks. Use
scheduler.yield()(Chrome 129, October 2024) or fall back tosetTimeout(fn, 0)orrequestIdleCallbackto give the browser room to handle the next interaction. - Defer non critical JavaScript. Add
deferorasyncto script tags, lazy load analytics and chat widgets withrequestIdleCallbackor after first input. - Avoid hydration over the whole page. Use partial hydration (Astro Islands, React Server Components, Qwik) so only interactive parts of the page boot up.
- Memoize React components with
React.memo,useMemo,useCallbackto avoid rerenders on every keystroke. - Use CSS animations for transitions instead of JS animations. CSS transform and opacity run on the compositor thread.
- Debounce expensive handlers. Search as you type should debounce by 200 to 300 ms or use a Web Worker.
- Move heavy work off the main thread. Web Workers for JSON parsing, image processing, search indexing.
- Reduce DOM size. A page with 5000 nodes recalculates styles faster than one with 50000.
- Use
content-visibility: autoon off screen sections to skip their layout work. - Audit third party scripts. Replace heavy widgets with lightweight alternatives (replace heavy chat with a button that loads chat on demand).
How do I improve INP in WordPress?
- Disable jQuery on the frontend if no theme or plugin requires it. WordPress core moves slowly away from jQuery (Twenty Twenty Four does not need it).
- Use a fast theme: GeneratePress, Astra, Kadence, Blocksy. Avoid bloated multi purpose themes like Avada or Bridge with all demos imported.
- Avoid heavy page builders: Elementor and Divi often produce 200 KB+ of CSS and JS plus complex DOM structures. Block Editor (Gutenberg) with native blocks scores better.
- Lazy load Google Tag Manager and analytics. WP Rocket has a delay JavaScript option, FlyingPress and Perfmatters offer the same.
- Cache pages so the server response is fast and the client has more time budget.
- Optimize WooCommerce: the cart and checkout pages run a lot of jQuery on click. Use plugins like CartFlows or Cart Pro for streamlined checkouts, or move to a headless setup.
- Limit chat widgets: Crisp, Intercom, Drift, LiveChat add 100 to 400 KB of JavaScript. Load them after first interaction or only on contact pages.
- Measure with the Site Kit by Google plugin which surfaces INP from CrUX directly in the WordPress dashboard.
Common INP myths
- "My Lighthouse score is 100, so INP is fine." Lighthouse runs lab tests in a controlled environment. Real user INP from CrUX is what counts for ranking and can be very different.
- "Less JavaScript always means better INP." True only if you remove blocking JavaScript. Lazy loaded JavaScript that runs later does not hurt INP at all.
- "INP only matters on mobile." INP is measured separately on mobile and desktop. Both need to pass for the Core Web Vitals threshold.
- "INP is the same as TBT (Total Blocking Time)." TBT is a lab metric measuring blocked time during load. INP is a field metric measuring actual interactions. They correlate but are not identical.
How does InspectWP help with INP?
InspectWP analyzes the loaded JavaScript size, the number of synchronous third party scripts and the use of common performance plugins (WP Rocket, LiteSpeed Cache, Perfmatters). The report flags pages that load jQuery on the frontend, large blocking analytics scripts and known slow page builders.