At a glance
Interaction to Next Paint at the 75th percentile. Measures the time from a user’s interaction (click, tap, keypress) to the next visible screen update, in milliseconds. INP replaced First Input Delay (FID) as a Core Web Vital in March 2024 because FID only measured the first interaction; INP measures all interactions during the page lifecycle and reports the longest (or near-longest) delay. Google’s “good” threshold is 200ms, sites at p75 INP under 200ms pass this CWV; over 500ms is “poor” and indicates the site feels unresponsive. INP is the most-failed CWV for sites with heavy JavaScript-driven interactivity (filter widgets, sort controls, currency switchers, A/B testing scripts).
| What it counts | The 75th-percentile of interaction_to_next_paint measurements across all real-user page-loads in the 28-day CrUX window. INP is calculated per-interaction as the time from input event to the next paint after all event handlers complete. The page-level INP is reported as the longest (or near-longest, depending on interaction count) per user session. |
| Sample type | Field data sourced from Chrome User Experience Report (CrUX). Lab equivalent does not exist directly; lab Lighthouse approximates via Total Blocking Time (psi_lab_tbt). |
| What replaced FID | INP measures all interactions during the page lifecycle; FID measured only the first. The change matters because: a site with a clean first-click and slow subsequent clicks (filter widgets, sort dropdowns, modal opens) passed FID but felt slow. INP catches this. Google switched the CWV definition in March 2024. |
| Google thresholds | Good: ≤ 200ms (passes CWV). Needs improvement: 200-500ms. Poor: > 500ms. |
| What drives INP slowness | (a) Heavy JavaScript main-thread work during interaction: filter widgets, sort handlers, currency conversions, A/B test variation switches, popup triggers. (b) Third-party scripts blocking the main thread: chat widgets, analytics tags, tag managers. (c) Long tasks unrelated to the interaction: a long-running task elsewhere on the page delays the response to a click. (d) Heavy DOM updates: re-rendering a large product list after a filter change. |
| Common ecommerce INP patterns | Filter widgets on collection pages: clicking a filter checkbox triggers JS that re-fetches and re-renders products; total time often exceeds 500ms on mid-tier mobile. Sort dropdowns: similar pattern. Currency switchers: page-level recalculation of all visible prices. Modal opens (cart drawer, search overlay): JS cost of mounting the modal component. |
| Optimisation playbook | (1) Yield to the main thread between heavy JS work using requestIdleCallback or setTimeout(fn, 0). (2) Debounce filter inputs so rapid clicks don’t queue up. (3) Virtualise long product lists so re-render cost is proportional to viewport, not catalogue size. (4) Defer non-critical third-party scripts: chat widgets, analytics tags load after first interaction. (5) Use CSS for state changes where possible instead of JS-driven re-renders. |
| Sample size threshold | CrUX p75 calculation requires sufficient real-user volume (~1,000+ page-loads per 28-day window per device). |
| Currency | n/a, this is a duration in milliseconds. |
| Time window | 28D (CrUX-fixed). |
| Alert trigger | > 200ms (Google’s good threshold). Sub-thresholds: amber 200-500ms, red > 500ms. |
| Sentiment key | psi_inp |
| Roles | owner, marketing, operations |
Calculation
Calculated automatically from your Website Performance (PageSpeed + CrUX) data. See the At a glance summary above for what the metric tracks and the worked example below for a typical reading.Worked example
A US-based BigCommerce home goods store with 320,000 mobile page-views over 28 days, Stencil theme with custom faceted-search filter widget on collection pages plus a Klaviyo popup and Tidio chat. Snapshot Wednesday 15 May 26.| Interaction type | p75 INP | Google band | Driver |
|---|---|---|---|
| Homepage hero CTA tap | 142ms | Good | Light page, minimal JS in handler |
| PDP “Add to cart” click | 218ms | Needs improvement | Cart-drawer mount + analytics fire |
| Collection filter checkbox | 612ms | Poor | Faceted-search re-fetch + full grid re-render |
| Collection sort dropdown | 484ms | Needs improvement | Sort handler + grid re-render |
| Currency switcher | 720ms | Poor | Page-level price recalculation |
| Mobile menu open | 168ms | Good | CSS-driven, minimal JS |
| Search overlay open | 312ms | Needs improvement | Modal mount + product-search fetch |
| Origin p75 (mobile) | 520ms | Poor | Dragged by collection filter + currency switcher |
- The 520ms origin p75 INP is in the “poor” band (> 500ms threshold), failing CWV. The collection-filter checkbox at 612ms and currency switcher at 720ms are the load-bearing failures; both are JavaScript-heavy interactions on the most-visited interactive surface (collection pages).
-
The faceted-search filter widget is the single biggest fix. Currently each filter checkbox click triggers: (a) a JS event handler that builds a new query string, (b) a fetch to the BC catalog API for the filtered product list, (c) a full re-render of the 24-item grid, (d) a Klaviyo “filter applied” custom event tracking call. Total main-thread cost: 600+ms on mid-tier mobile. Optimisation path: (a) debounce rapid clicks (saves 100-200ms when users select multiple filters quickly), (b) virtualise the product grid so re-render cost is proportional to viewport (saves 200-300ms), (c) defer the Klaviyo tracking to
requestIdleCallback(saves 50-100ms), (d) use CSS transitions for the filter-pill UI rather than JS class toggles (saves 30-60ms). - The currency switcher at 720ms is the second priority. The current implementation fetches a fresh exchange rate, then re-renders every visible price element on the page. Better implementation: pre-compute all currency variants at page-load time, switch by toggling visibility CSS rather than re-rendering. Estimated post-fix: 80-150ms.
- PDP “Add to cart” at 218ms is borderline-failing but high-frequency. Each interaction here directly affects conversion rate. The cart-drawer mount is the cost driver; switching from a JS-driven drawer to a CSS-only slide-out (with progressive enhancement for advanced features) typically halves the INP cost. Estimated post-fix: 110-150ms.
- The healthy interactions (homepage CTA, mobile menu) confirm the site’s baseline JS performance is OK; the problem is concentrated in specific JS-heavy widgets. Don’t refactor the whole frontend; concentrate work on the 3 worst-offending widgets.
- Commercial impact estimation. Collection pages drive roughly 35 percent of mobile traffic for the brand (typical for category-discovery-heavy ecommerce). The filter-checkbox interaction is on the critical path: users filter then click into PDPs to convert. Slow filter response (612ms perceived as “broken”) drives users to abandon the filtering session. Industry data suggests: every 100ms of INP delay above 200ms reduces filter-engagement-to-PDP-click rate by 2-4 percent. At 612ms current vs 200ms target = 4.12 × 100ms over threshold = roughly 8-16 percent fewer filter-driven PDP visits. For a brand with 200k filter sessions/month, that’s 16k-32k missed PDP visits / month.
- Identify the worst-INP interactions. Use the Web Vitals Chrome extension or Chrome DevTools Performance panel to capture real interactions and identify the worst.
- Profile the JS handler. Chrome DevTools’ Performance tab records the main-thread work during the interaction; long tasks (over 50ms) are obvious culprits.
- Check third-party script execution during interaction.
psi_third_party_costsurfaces third-party JS cost. Klaviyo, chat widgets, analytics tags often add 100-300ms of main-thread work during interactions. - Cross-reference with
psi_lab_tbt. Total Blocking Time is the lab approximation of INP. Lab TBT improvement typically translates to field INP improvement at 1:1.5 ratio (lab measurements are stricter). - Pair with
psi_unused_js. Unused JavaScript bloats main-thread parse + execute time even if not directly involved in the interaction. Removing unused JS reduces baseline interaction cost.
| Time horizon | Action |
|---|---|
| First 1 hour after alert | Identify worst-INP interaction. Capture in DevTools Performance. |
| First 4 hours | Profile JS handler; identify long tasks; plan refactor. |
| First 24 hours | Implement fix on the worst-offending interaction; deploy. |
| First 7 days | Field INP partial movement. Confirm direction. |
| Day 28 | Field INP fully reflects fix. Move to next-priority interaction. |
Sibling cards merchants should reference together
| Card | Why merchants reach for it |
|---|---|
crux_inp_distribution | INP good/needs-improvement/poor distribution. |
crux_inp_trend | INP over time; drift detection. |
psi_lab_tbt | Total Blocking Time, the lab approximation of INP. The single biggest contributor to lab Performance Score. |
psi_third_party_cost | Third-party script cost. Often the dominant contributor to interaction-time slowness. |
psi_unused_js | Unused JavaScript. Bloats main-thread cost even when not directly involved in interactions. |
psi_js_execution | JS execution time. The main-thread budget that interactions compete with. |
crux_lcp_p75 | Sister CWV; pair for the full load + interaction picture. |
crux_cls_p75 | Sister CWV. |
psi_cwv_pass_rate | All-three CWV gate. INP failing alone fails the gate. |
psi_perf_score_summary | Composite score. TBT (lab INP proxy) is 30 percent of the weight. |
GA4 ga_engaged_sessions | Engagement metric correlating with site responsiveness; slow interactions reduce engagement. |
Reconciling against the vendor’s own dashboard
Where to look in PageSpeed Insights / GSC / CrUX’s own dashboards:- PageSpeed Insights, field-data section shows origin-level p75 INP under “Interaction to Next Paint”.
- Google Search Console → Core Web Vitals, surfaces URL groups failing INP threshold.
- Web Vitals Chrome extension, measures INP per-interaction live as you browse a page. Most useful diagnostic tool for INP work.
- Chrome DevTools → Performance Insights tab, captures INP for specific interactions during recording.
| Reason | Direction | What to do |
|---|---|---|
| Window timing. Vortex IQ refreshes daily; CrUX dataset has 1-2 day lag. | Vortex IQ lags for 1-2 days | Wait for next refresh. |
| Origin vs URL. Vortex IQ headline shows origin-level; PSI defaults to URL when querying a specific URL. | Different aggregation | Use per-URL breakdown for direct comparison. |
| Form factor. Vortex IQ defaults to mobile; PSI shows mobile/desktop tabs. | n/a if both mobile | Confirm form factor. |
| CrUX dataset version. Monthly publication; transitions can produce step changes. | Either direction | Acknowledge the monthly boundary. |
| INP definition update March 2024. Sites comparing year-over-year see a methodology break: pre-March-2024 used FID, post-March-2024 uses INP. The two metrics aren’t directly comparable. | Either direction | Anchor year-over-year comparisons on FID-to-March-2024 and INP-from-March-2024 separately. |
| Comparison | Expected relationship | When divergence is legitimate |
|---|---|---|
crux_inp_p75 ↔ psi_lab_tbt | Field INP and lab TBT directionally agree | Lab TBT measures total time main-thread is blocked during page-load; field INP measures interaction-specific delays. Persistent gaps suggest interactions occur in conditions different from page-load (e.g. cold-cache vs warm-cache, different time-of-day patterns). |
crux_inp_p75 ↔ Internal RUM tools | Should align within 50-150ms p75 | Internal RUM samples your traffic directly; CrUX samples opted-in Chrome users. Cohort differences explain modest divergence. |
Known limitations / merchant FAQs
My INP was passing under FID. What changed in March 2024? Google replaced FID with INP as the official Core Web Vital. FID measured only the first interaction: a site with a clean first-click and slow subsequent interactions could pass FID despite feeling unresponsive. INP measures all interactions: the longest (or near-longest) reported per session. Sites that previously passed FID but had slow filter widgets, sort dropdowns, or modal opens started failing INP after the switch. Most ecommerce sites saw INP fail after the change because filter and sort widgets are JS-heavy. Why is INP harder to fix than LCP? LCP is dominated by network and image issues; the fixes are mechanical (image format, preload, CDN). INP is dominated by JavaScript main-thread work; the fixes require code changes, often architectural. Common LCP fixes take 2-5 days; common INP fixes take 1-3 weeks because they typically require refactoring widget components or removing third-party scripts. My INP is fine on my own device but the CrUX number is poor. Why? Your device is faster than mid-tier mobile. INP scales with CPU power: a flagship phone takes 80ms for a heavy filter operation; a mid-tier Android takes 300-500ms for the same operation. CrUX represents the real-user mix, not your device. Use Chrome DevTools’ CPU throttling (set to 4x slowdown) to approximate the mid-tier mobile experience. Do third-party scripts affect INP? Yes, often dominantly. Klaviyo popups, Tidio chat widgets, A/B testing scripts (Optimizely, VWO, Convert), tag managers (GTM, Tealium), and analytics tags (Hotjar, FullStory) all run on the main thread and steal time from interaction handlers. The Vortex IQ pre-launch audit flags third-party cost specifically because it’s the most-fixable INP cost driver: deferring non-critical scripts to post-load typically improves INP by 100-300ms. Can I optimise INP without removing features? Usually yes. Optimisation patterns: (1) move work off the main thread using Web Workers (heavy computations like search-filtering large catalogs); (2) yield to the main thread between heavy tasks usingscheduler.postTask or requestIdleCallback; (3) virtualise long lists so re-render cost is bounded by viewport; (4) use CSS for state changes when possible (hover effects, simple toggles); (5) defer non-critical functionality to post-interaction. Removing features is a last resort, not the first move.
What’s the difference between INP and TBT?
TBT (Total Blocking Time) is a lab metric; INP is a field metric. TBT measures total main-thread blocked time during page-load; INP measures specific interaction delays. They correlate but aren’t identical. Use TBT in lab/CI testing (deterministic, runnable on every deploy); use INP in production monitoring (truth source for ranking and user experience).
Why does INP fluctuate so much between days?
INP is interaction-driven; if users do different interactions on different days (more filtering on weekdays vs more browsing on weekends), the per-day INP shifts. CrUX’s 28-day rolling window smooths this; daily measurements you might collect via internal RUM will be noisier.
Should I optimise for INP or for the user-facing perception of speed?
Both are aligned. INP is a real-user metric; optimising INP improves perceived responsiveness. The misalignment risk is “gaming” INP without improving experience: e.g. instant skeleton loaders that “complete” the interaction visually before real work finishes. The right test: ask a user to use the site on a mid-tier phone over coffee-shop wifi; if they complain about laginess, INP is failing regardless of the metric value.
My BC site uses Stencil. Is INP harder to fix here?
Stencil sites typically have higher INP than Catalyst sites due to differences in how each framework handles state changes. Stencil patterns: heavy use of jQuery in legacy themes, heavy DOM manipulation, less code-splitting. Catalyst patterns: React-based with built-in code-splitting, better state management primitives. Migration is a structural improvement for INP; a default Catalyst site often achieves 200-300ms p75 INP without active optimisation, where a default Stencil site sits at 400-600ms.
Can Vortex IQ identify which specific widget is the worst?
Yes, via the per-interaction-type breakdown in the worked example above. The audit module flags the top 3 worst-INP interactions and traces them to specific JS bundles via the Lighthouse audit JSON. Concentrate fix work on those three; don’t try to fix everything at once.
Does CSS-only animation affect INP?
Generally no. CSS transforms and opacity transitions run on the compositor thread, off the main thread, so they don’t compete with interaction handlers. CSS-only state changes (hover effects, simple toggles) are INP-friendly. Avoid CSS that triggers layout (changes to width, top, left, etc.) inside interaction handlers; those force main-thread layout work.