Fix INP on WooCommerce: Find and Speed Up Slow Interactions

Fix INP on WooCommerce using real-user data: trace slow variation selectors, AJAX add-to-cart, filters and cookie banners from Search Console to DevTools.

Fix INP on WooCommerce: Find and Speed Up Slow Interactions
Fix INP on WooCommerce: Find and Speed Up Slow Interactions

Your product pages load quickly, yet Search Console says INP is failing. If you need to fix INP on WooCommerce, the problem is usually not load speed. It is one slow tap, click or key press that shoppers keep hitting.

It might be a variation swatch, a filter checkbox, the mini-cart toggle or the cookie banner. Each one runs JavaScript from your theme, WooCommerce and every plugin listening for the same event.

This guide shows you how to find the slow interaction and identify which phase is slow, then fix it.

You will use Search Console and CrUX field data to confirm the problem. You will use Chrome DevTools to reproduce it.

It is written for WooCommerce store owners, developers and in-house SEOs. It assumes you can open DevTools, but you don’t need to be a JavaScript expert.

The goal is simple: an INP of 200 ms or less at the 75th percentile, on both mobile and desktop.

Key Takeaways

  • INP measures the slowest visible response to clicks, taps and key presses.
  • Good INP is 200 ms or less at the 75th percentile.
  • One slow swatch, filter or cart drawer can fail a fast-loading page.
  • PageSpeed Insights scores can't confirm INP fixes; check field data instead.
  • Use Search Console URL groups to find which templates fail.
  • Reproduce slow interactions in DevTools and find the slow phase.
  • Field data takes weeks to reflect fixes, so start before sales.

What INP measures on a WooCommerce store (and what it doesn’t)

Interaction to Next Paint (INP) measures how long your store takes to visibly respond after a shopper clicks, taps or presses a key. The clock starts at the input and stops when the browser paints the next frame that shows a response.

INP is not about the first interaction only. It observes every qualifying interaction during the visit. The reported value is the longest one, with some outliers ignored on pages that get many interactions (web.dev).

INP replaced First Input Delay (FID) as a Core Web Vital in March 2024 (web.dev). FID only measured the delay before the first interaction started. INP measures the full response for every interaction, which is why many stores that passed FID now fail INP.

The thresholds that matter

INP at the 75th percentile Status
200 ms or less Good
Over 200 ms up to 500 ms Needs improvement
Over 500 ms Poor

These thresholds come from web.dev. Google Search Central puts it simply: strive to have an INP of less than 200 milliseconds (Google Search Central).

The pass mark is the 75th percentile of real visits, judged separately for mobile and desktop. If a quarter of your mobile visitors get a slow response, the page fails on mobile, even if your own laptop feels instant.

What counts as an interaction, and what doesn’t

Only discrete inputs count: clicks, taps and key presses. Scrolling and hovering are not measured by INP. A janky scroll on a category page is a real problem, but it won’t show up in this metric.

On a typical WooCommerce store, these interactions do count:

  • Variation swatches and dropdowns for size, colour or material on variable products.
  • Quantity steppers (the + and − buttons) on product and cart pages.
  • Filter checkboxes and price sliders on shop and category pages.
  • Add to cart buttons, especially AJAX add to cart on archives.
  • The mini-cart toggle in the header or a slide-out cart drawer.
  • Cookie consent buttons, which are often the very first tap of the visit.
  • Typing in search boxes and checkout fields, because each key press is an interaction.
  • Opening menus, tabs, accordions, image galleries and size-guide pop-ups.

The three parts of an interaction

Every interaction breaks down into three phases. You need to know which one is slow, because each has a different fix.

  1. Input delay: the time between the tap and the moment your event handlers start running. It grows when the main thread is busy with something else.
  2. Processing time: the time your event handlers take to run, including every plugin listening for the same event.
  3. Presentation delay: the time from handlers finishing to the browser painting the next frame. This covers style recalculation, layout and paint.

Take a shopper tapping the “Large” size swatch on a variable product:

  • Input delay: the page loaded two seconds ago, and the theme bundle, a reviews widget and a chat script are still executing. The tap waits in the queue.
  • Processing time: the variation form works out the matching variation, then updates price, stock text, SKU and the add-to-cart button. A swatches plugin and a tracking script also react to the same change.
  • Presentation delay: the main product image swaps, the gallery rebuilds its thumbnails and the layout shifts around the new price. The browser has a lot to recalculate before it can paint.

The shopper only sees the total. If it adds up to 450 ms, the swatch feels sticky, and the page sits in “needs improvement”.

Phase Typical WooCommerce causes What to look for later
Input delay Theme and plugin JavaScript still parsing or running; analytics, chat and review widgets starting up; cookie banner scripts loading Long tasks overlapping the moment of the tap
Processing time Heavy change and click handlers; several plugins bound to the same event; synchronous tracking calls inside handlers Long event handler entries in the trace
Presentation delay Large DOM re-renders; gallery or slider rebuilds; replacing big HTML fragments; a very large page DOM Long style, layout and paint work after the handler

Why one slow click can fail a fast page

Because INP reports the longest interaction in a visit, one slow interaction can define the whole visit. Twenty quick taps don’t average out one slow one.

This catches store owners out. A product page can load quickly and have a good LCP, yet fail INP because the swatch or the cart drawer is slow. Load speed and responsiveness are separate problems.

It also means the slow interaction may not be on the obvious path. A cookie “Accept” button tapped while scripts are still loading, or a filter checkbox on a large category page, can be the interaction that sets the score.

Decision rule: when INP fails, don’t ask “is the page slow?” Ask “which interaction is slow, and in which phase?” The rest of this guide is built around answering that question.

Why a PageSpeed Insights score can’t tell you if INP is fixed

“My PageSpeed Insights score jumped to 90, so INP is fixed.”

The performance score and INP are not the same thing. The score comes from a Lighthouse lab test. INP is measured from real visitors. A higher score can be a useful sign, but it can’t confirm that shoppers’ taps are faster.

Worse, the score can move without you changing anything at all.

What the Lighthouse 13.6 update changed

PageSpeed Insights now runs Lighthouse 13.6.0, which includes changes to the Lantern simulation used to estimate performance (Search Engine Journal). The report highlights a few points that matter for store owners:

  • Scores can change even when the page has not.
  • Scores usually come out better after the update.
  • JavaScript-heavy sites are more likely to be affected, which describes most WooCommerce stores with page builders, swatches, sliders and tracking.
  • Scores from before and after the update are not comparable.

So if you deferred some scripts last week and your score jumped this week, you can’t tell how much of the jump came from your work and how much from the new Lighthouse version. If you report PSI scores to clients or managers, note the Lighthouse version in each report. I explain this in more detail in PageSpeed Insights Score Changed? Lab vs Field Data Explained.

Why Lighthouse can’t measure INP on a normal run

A standard Lighthouse run is a navigation test. It loads the page and measures loading. Nobody taps a swatch, opens the mini-cart or ticks a filter.

No interactions means no INP. Instead, the lab report shows Total Blocking Time (TBT), which adds up how long the main thread was blocked during load.

TBT is a proxy, and a limited one:

  • It captures load-time blocking, which relates to input delay for early taps such as the cookie button.
  • It doesn’t measure processing time in your swatch, filter or cart handlers, because those handlers never run in the test.
  • It doesn’t measure presentation delay from re-rendering the gallery or cart drawer.
  • It doesn’t see interactions that happen well after load, such as a shopper adjusting quantities on the cart page.

A page can have low TBT and still fail INP because one handler is slow.

Field data versus lab data

PageSpeed Insights actually shows two different datasets on the same page. Read them separately.

Field data (top of PSI) Lab data (Lighthouse section)
Source Chrome UX Report (CrUX): real Chrome users One simulated load on Google’s test setup
Includes INP? Yes, at the 75th percentile No. Shows TBT as a proxy
Time window A rolling 28-day period The moment you ran the test
Reacts to your fix Gradually, as new visits replace old ones Immediately, but also to Lighthouse updates
Best used for Deciding if there is a real problem, and confirming it’s gone Diagnosing why, and checking a change in isolation

Two practical notes. First, a low-traffic product URL may have no URL-level field data, so PSI shows origin-level data instead. Second, Search Console keeps URL parameters while PSI strips them, so a single PSI URL can show different numbers from the Search Console group it belongs to (Search Console Help). That matters for stores with filter and variation parameters, which I cover in Faceted Navigation SEO for WooCommerce.

If you add your own real-user monitoring to collect INP, treat that script like any other third-party code: check what it loads, who controls it and how you’d remove it quickly. My third-party script audit guide walks through that process.

The decision rule

Use field data to decide whether you have an INP problem. Use lab traces to find out why.

  1. Problem or not? Check Search Console and CrUX field data. If INP at the 75th percentile is 200 ms or less on mobile and desktop, move on to other work.
  2. Where? Use Search Console URL groups to find which templates fail: product, category, cart or checkout.
  3. Why? Reproduce the slow interaction in Chrome DevTools and see which phase is slow.
  4. Fixed? Confirm in field data over the following weeks, not in the PSI score.

If you’re heading into a big sale period, start now. Field data needs time to reflect a fix, so changes made the week of a sale won’t show as passing until well after it. My Black Friday SEO for WooCommerce guide covers the rest of the pre-sale preparation.

The next three steps follow this order: find failing groups in Search Console, confirm with CrUX, then reproduce the interaction in DevTools.

Step 1: Find failing INP groups in Search Console

Search Console is the best place to start because it shows which kinds of pages fail INP for real visitors, not which pages fail in a lab test. It uses Chrome UX Report (CrUX) data from real Chrome users.

Open the report like this:

  1. In Search Console, go to Experience > Core Web Vitals.
  2. Next to the Mobile chart, click Open report. Start with mobile because shoppers on mid-range phones usually have the slowest interactions.
  3. In the issues table, find the rows that start with INP issue. One row covers “Poor” (longer than 500 ms) and one covers “Needs improvement” (longer than 200 ms).
  4. Click a row to see the URL groups affected by that issue.
  5. Click a group to see its Group INP and a sample of member URLs.
  6. Repeat the steps for Desktop. The two device types are assessed separately.

Reading URL groups and Group INP

Search Console does not report INP for every URL one by one. It groups URLs that look similar and gives each group one status (Search Console Help).

  • Group INP is a 75th percentile value. If a group shows 340 ms, 75% of visits to URLs in that group had an INP of 340 ms or better. The other 25% were slower.
  • A group takes the status of its worst metric. A group can pass LCP and CLS and still be marked “Poor” because of INP alone. Check which metric is the reason before you start work.
  • Origin fallback: if a group lacks enough data, Search Console can use data from the whole origin instead. On small stores this is common, so the number may describe your whole site rather than that template.
  • Members are listed by impressions. The URLs at the top of the group get the most search exposure. They are good candidates for testing.
  • The data covers a rolling 28-day window. A fix you deploy today takes weeks to show fully. Read the current wording on data windows and the Validate fix flow in the Help article before you report timelines to a client.

“Group INP is 340 ms, so every product page takes 340 ms to respond.”

That is not what the number means. It is the 75th percentile across the whole group. Some URLs in the group may be fine while a few heavy pages pull the value up. You still need Step 2 and Step 3 to find the actual cause.

Which WooCommerce templates usually cluster together

Search Console groups URLs by similarity, not by WooCommerce template. In practice, though, groups usually line up with templates because those pages share the same HTML structure and scripts. Map each group to a template before you look for causes. A slow variable product page and a slow filtered archive need different fixes.

  • Single product, simple: add-to-cart button, gallery, tabs, reviews.
  • Single product, variable: the same as simple, plus attribute dropdowns or swatches. Variation selection runs JavaScript that updates price, stock, image and button state.
  • Shop and product category archives: product grids, AJAX add-to-cart buttons, quick view, sorting.
  • Filtered archive URLs: the same template with query parameters for filters, sorting or pagination.
  • Cart and checkout: quantity changes, coupon fields, shipping recalculation, payment fields. These pages are often noindexed and get few search impressions, so they may appear weakly in the report or fall back to origin data. Do not take low visibility as proof that they are fast.

Search Console keeps URL parameters, while PageSpeed Insights strips them (Search Console Help). A filtered URL in a failing group can therefore look different when you paste it into PSI. Note the full parameter URL so you can test that exact state later in DevTools. If filter URLs are multiplying in your reports, also read faceted navigation SEO for WooCommerce.

Write down each failing group in a table like the one below. The INP values are illustrative. Use your own numbers.

Group Example URL Template Group INP (mobile) Priority
A /product/linen-shirt/ Single product (variable) Poor, e.g. 520 ms High: revenue template, high impressions
B /product-category/shirts/ Category archive Needs improvement, e.g. 290 ms High: entry page from search
C /product-category/shirts/?filter_colour=blue&orderby=price Filtered archive Needs improvement, e.g. 310 ms Medium: check whether these URLs should be indexed at all
D /product/gift-card/ Single product (simple) Good, e.g. 180 ms Low: monitor only
Origin /cart/, /checkout/ Cart and checkout Origin fallback High for revenue: confirm with RUM

Prioritise by impressions first, then by revenue. A product group with heavy search exposure and a checkout that loses sales both come before a blog archive. Pages that earn neither impressions nor revenue can wait.

Step 2: Confirm with CrUX field data per URL and origin

Search Console tells you which group is failing. The next step is to check individual URLs and the whole origin with CrUX data, so you know whether a problem belongs to one page, one template or the whole store.

PSI’s field section

Paste a URL from a failing group into PageSpeed Insights. Read only the top section, which shows what real users are experiencing. Ignore the performance score below it for INP purposes. The reason is explained in PageSpeed Insights lab vs field data.

In the field section, check four things:

  1. Mobile or Desktop tab. Match the device type to the Search Console report you came from.
  2. This URL or Origin toggle. URL data covers that page only. Origin data covers every page on the domain.
  3. The INP value. This is the 75th percentile over the collection period. Good is 200 ms or less, poor is over 500 ms, and anything between needs improvement (web.dev).
  4. The collection period. It is a rolling 28-day window, so a fix deployed last week is only partly reflected.

Use this decision rule to read what you see:

What PSI shows What it means Next action
URL poor, origin good The problem is specific to this page or template Reproduce on this URL in Step 3
URL and origin both poor The cause is probably sitewide: theme, header scripts, cart fragments or tag manager Test several templates and look for shared scripts
No URL data, origin poor The page has too few visits for URL-level data Use origin and Search Console group data, then test the template
No URL or origin data There is not enough Chrome traffic Collect your own field data with RUM (below)

“PSI has no field data for this product, so I’ll use the lab score instead.”

A standard Lighthouse run does not measure INP at all. Total Blocking Time is only a lab proxy. When URL data is missing, fall back to the origin or the Search Console group. Do not chase lab numbers. Lab scores can also shift between Lighthouse versions even when your page has not changed (Search Engine Journal).

CrUX History and BigQuery for trends

A single 28-day value does not show whether INP is getting worse. Before Black Friday and Cyber Monday you want to know whether a new plugin, theme update or tag has pushed INP up over recent weeks.

  • CrUX visualisation tools: Google provides a web tool for CrUX trends by origin and URL. The older Looker Studio dashboard has been replaced, so check the current tool name and link on developer.chrome.com/docs/crux.
  • CrUX History API: returns weekly snapshots of the 28-day p75 for a URL or origin. It is useful for spotting the week a regression started.
  • CrUX on BigQuery: monthly, origin-level data. Use it to compare your store with competitors or to keep a long history.

A simple History API request body looks like this:

{
  "origin": "https://www.example-store.com",
  "formFactor": "PHONE",
  "metrics": ["interaction_to_next_paint"]
}

Before you build reports on these tools, verify the current endpoints, quotas and number of weekly periods in the CrUX documentation. These details change.

Match any spike to your change log, such as plugin updates, new tracking tags or a PHP upgrade. If you changed hosting or PHP recently, see updating PHP in WooCommerce without SEO loss.

Optional: your own RUM with the web-vitals library

CrUX tells you how slow INP is. It does not tell you which element was clicked or which phase was slow. The attribution build of Google’s web-vitals library adds that information. It reports the interaction target, the interaction type, and the time spent in input delay, processing and presentation delay.

This example sends INP to GA4 as an event. It assumes GA4 is already loaded with gtag.js and that you bundle or self-host the library:

<script type="module">
  import { onINP } from '/wp-content/themes/your-child-theme/js/web-vitals.attribution.js';

  onINP(function (metric) {
    var a = metric.attribution;
    gtag('event', 'inp', {
      value: Math.round(metric.value),
      metric_id: metric.id,
      metric_rating: metric.rating,
      inp_target: (a.interactionTarget || '(none)').slice(0, 100),
      inp_type: a.interactionType,
      inp_input_delay: Math.round(a.inputDelay),
      inp_processing: Math.round(a.processingDuration),
      inp_presentation: Math.round(a.presentationDelay),
      page_template: document.body.className.match(/single-product|tax-product_cat|woocommerce-cart|woocommerce-checkout/)?.[0] || 'other'
    });
  });
</script>

To make this data usable in GA4:

  • Register inp_target, inp_type and page_template as event-scoped custom dimensions in Admin > Custom definitions. Register the timing fields as custom metrics.
  • Check the property names against the version of web-vitals you install. Attribution fields have been renamed between major versions.
  • In an exploration, filter to metric_rating = poor and break down by inp_target. Selectors such as a variation select or .single_add_to_cart_button point you straight to the interaction to reproduce in Step 3.

Security note: self-host or vet any RUM script

A RUM script runs on every page, including checkout. If its source is compromised, so is your store. On 31 October 2026, DebugBear’s DNS was hijacked to serve malicious JavaScript, and customers were told to remove its RUM script (Search Engine Journal).

This incident is not a reason to stop collecting field data. It is a reason to control how you collect it:

  • Self-host the web-vitals library from your own domain, pinned to a specific version, rather than loading it from a third-party CDN.
  • If you use a commercial RUM vendor, check how it serves its script, whether it supports Subresource Integrity, and whether a Content Security Policy can restrict it.
  • Keep an inventory of every external script and who owns it. The third-party script audit for WordPress walks through this process.

By the end of Step 2 you should know which templates fail, whether the problem is page-level or sitewide, whether it is getting worse, and ideally which element shoppers were interacting with. If you would like a second pair of eyes on that data before peak season, you can book a free consultation.

Step 3: Reproduce the slow interaction in Chrome DevTools

Search Console and CrUX tell you which page types fail INP. They don’t tell you which click is slow or which script causes it. To find that, you need to reproduce the interaction on your own machine and record it.

Your local numbers won’t match the field data exactly. That’s fine. The goal here is to find the cause, not to recreate the 75th percentile.

Set up a realistic test

A fast laptop with ten extensions installed hides real problems and adds fake ones. Set up a clean, slowed-down environment first:

  1. Open an Incognito window. Extensions are off by default unless you have allowed them in Incognito. Check chrome://extensions if you’re not sure.
  2. Stay logged out of WordPress. The admin bar, editor scripts and caching rules for logged-in users all change what loads. Shoppers are logged out, so test that way.
  3. Turn on a mobile viewport. Open DevTools, press Ctrl+Shift+M (Cmd+Shift+M on Mac) and choose a mid-range phone size. Many themes load different menus, sliders and drawers on mobile.
  4. Throttle the CPU. In the Performance panel, set CPU throttling to 4x or 6x slowdown. Recent Chrome versions may also offer calibrated low-tier and mid-tier mobile presets. Use those if they are available in your version.
  5. Set the cart state the test needs. For variation swatches, an empty cart is fine. For mini-cart drawers, cart pages and “add another item” tests, add two or three products first. A full cart is a different DOM from an empty one.

Network throttling matters less for INP than CPU throttling. INP measures main-thread work and rendering, not download time. You can leave the network unthrottled unless an interaction waits for an AJAX response before it shows anything.

Use live metrics before you record

Open the Performance panel and load the product page. Current Chrome versions show a live metrics view with local LCP, CLS and INP that update as you use the page.

Now click through the interactions that matter on that template: a variation swatch, the quantity stepper, Add to cart, the mini-cart icon, the cookie banner’s accept button. The Interactions log lists each one with its duration. Expand an entry to see the input delay, processing and presentation delay split.

The live view can also show field data from CrUX for the URL and origin next to your local numbers, once you enable it in the panel’s field data setup. The labels and location of this option have changed between Chrome releases, so check your version. If it’s available, use it to sense-check your throttling. If your local INP is far better than the field value, increase CPU throttling.

Write down the slowest interaction and the element you clicked. That’s the one to record.

Record a Performance trace

  1. Reload the page and let it finish loading. Wait a few seconds so late-loading tags, chat widgets and pixels have run.
  2. Click Record (Ctrl+E / Cmd+E).
  3. Do the single slow interaction, for example click the “Blue” swatch on a variable product.
  4. Wait until the UI has visibly updated, which here means the price, image and stock status have changed.
  5. Click Stop.

Record one interaction per trace. If you click five things, it becomes hard to tell which work belongs to which click.

Read the interaction track

Find the Interactions track near the top of the trace. Each interaction is drawn as a bar with whiskers:

  • Left whisker: input delay. The browser was busy with something else when you clicked, so your handler had to wait.
  • Solid bar: processing time. Your event handlers ran, both pointerdown/click handlers and anything else attached to the same events.
  • Right whisker: presentation delay. The handlers finished, but style recalculation, layout and paint took time before the next frame appeared.

Hover over the bar to see the exact milliseconds for each phase. Interactions over 200 ms are usually flagged, and the Insights sidebar may show an INP breakdown for the same interaction.

Then look directly underneath in the Main track. Long tasks have a red corner marker. Zoom into the tasks that line up with the interaction bar and note what’s at the top of each flame stack: Event: click, Function call, Recalculate style, Layout.

Attribute time to scripts with Bottom-up and Call tree

Select the time range of the interaction (drag across it on the timeline). Then use the tabs at the bottom:

  • Bottom-up: shows which functions used the most self time. Change the grouping to Group by domain or Group by URL to see whether the time belongs to your site, Google Tag Manager, Meta or a chat vendor.
  • Call tree: shows the chain from the event down. This is where you see that a click handler in your swatch plugin triggered a jQuery event that WooCommerce, the gallery and three other plugins all listen to.
  • Event log: handy for spotting repeated forced layouts or a handler that runs dozens of times.

Typical file names to look for on a WooCommerce store:

/wp-content/plugins/woocommerce/assets/js/frontend/add-to-cart-variation.min.js   (handle: wc-add-to-cart-variation)
/wp-content/plugins/woocommerce/assets/js/frontend/add-to-cart.min.js             (handle: wc-add-to-cart)
/wp-content/plugins/woocommerce/assets/js/frontend/cart-fragments.min.js          (handle: wc-cart-fragments)
/wp-content/themes/your-theme/assets/js/...                                         (theme)
/wp-content/plugins/some-swatches-plugin/...                                        (swatches, gallery, filters)
googletagmanager.com/gtm.js, /gtag/js                                               (tag manager, GA4, Ads)
connect.facebook.net/.../fbevents.js                                                (Meta pixel)

If third-party domains take most of the time, run a full third-party script audit before you touch your theme code.

For real-user attribution later, the web-vitals library has an attribution build that reports the interaction target and the three phases for INP. Check the README for the current field names in the version you install. If you load any RUM vendor’s script from their domain, treat it like any other third-party code. The DebugBear DNS hijack on 31 October 2026 is a recent reminder. Field data is still essential. Just know what you’re loading and from where.

Trace checklist: what you saw and where to look next

What you saw What it means Where to look next
Long input delay, short processing Something else was hogging the main thread when the user clicked Tasks just before the click: late tags, chat widgets, sliders autoplaying, timers
Long processing, one big task Your click handlers do too much work in one go Call tree under Event: click or change, then the plugin or theme file at the top
Long processing, many listeners Several plugins react to the same WooCommerce or jQuery event Call tree for found_variation, added_to_cart or change handlers
Long presentation delay Big style/layout/paint cost after handlers finish Purple Recalculate style and Layout blocks, DOM size, animated width/height
Repeated purple Layout blocks inside JS Forced synchronous layout (read, write, read) Code reading offsetHeight or getBoundingClientRect() after changing the DOM
Most self time on gtm.js, fbevents.js, etc. Tracking runs inside the interaction Triggers firing on click, added_to_cart or consent update
Short trace locally, poor in field Your test is too fast or misses the slow path Higher CPU throttling, populated cart, different variation or filter combinations

WooCommerce interactions that are usually slow, and why

On most stores, poor INP comes from a small number of repeat offenders. Test these interactions first, because they appear on the templates that carry your revenue: product pages, category pages and the cart.

Variation selectors and swatches

Choosing a size or colour looks simple. Behind it, wc-add-to-cart-variation matches the selected attributes against the variation data, then fires events such as found_variation and show_variation. Everything listening to those events runs in the same interaction.

Common causes of slow variation changes:

  • Large variation JSON. For products under the AJAX threshold, all variation data is printed into the data-product_variations attribute on the form. Products with many variations and long descriptions make this payload heavy to parse and search.
  • Image gallery swaps. Changing the main image can re-initialise a slider, zoom or lightbox, which triggers image decoding and layout.
  • Price and stock HTML re-render. Replacing the price, availability and description blocks forces style and layout work, especially when the theme animates them.
  • Swatch plugins doubling up. A swatch plugin, a gallery plugin and the theme may all listen to change or found_variation and each do their own DOM updates.

WooCommerce switches behaviour above a variation count. Below the threshold, data is inline. Above it, the form loads the matching variation by AJAX after each selection. The threshold is controlled by the woocommerce_ajax_variation_threshold filter, and the long-standing default is 30. Confirm the current default in the WooCommerce developer docs or source for your version before you change it.

// Raise or lower the inline variation threshold (test both directions).
add_filter( 'woocommerce_ajax_variation_threshold', function ( $threshold, $product ) {
    return 50;
}, 10, 2 );

This is a trade-off, not a fix. A higher threshold means more inline data but no network wait. A lower threshold means lighter HTML, but each selection waits on a request. That wait only hurts INP if nothing visible changes until the response arrives.

AJAX add to cart and cart fragments

On archive pages, WooCommerce’s AJAX add to cart sends a request and then triggers the added_to_cart event with updated fragments. Themes open drawers on that event. Tracking setups fire pixels on it.

Slow add-to-cart interactions usually come from:

  • Synchronous work in the click handler before any feedback appears, such as building tracking payloads or reading the DOM.
  • Fragment refreshes that replace large blocks of mini-cart HTML in one go. Since WooCommerce 7.8, wc-cart-fragments is no longer loaded on every page by default. It loads where the cart widget or mini-cart needs it. Many themes and plugins re-enqueue it everywhere, so check what your site actually loads and confirm the current behaviour in the WooCommerce developer documentation.
  • Pixels on added_to_cart: GA4, Meta, TikTok and Pinterest all reacting to the same event.

“Add to cart is slow because the server is slow.”

Server time affects how long the cart takes to update, but INP measures time to the next paint after the click. If the button changes to a loading state immediately, the network wait isn’t counted. Show feedback before network work, then let the request and tracking follow.

Product filters on archive pages

Filter plugins often replace the entire product grid on every checkbox change, then re-initialise lazy loading, quick-view buttons and swatches for every card. Price sliders and search boxes make it worse when they react to every input event with no debounce, so dragging a slider fires dozens of updates.

Filters also create crawlable URL combinations. If you’re changing how they work, review faceted navigation SEO for WooCommerce at the same time.

Mini-cart drawers

Opening a side cart looks light, but it can trigger layout across a large DOM. This happens when the drawer is animated with width, height, left or right, when the body is locked by reading and writing scroll positions, or when the drawer fetches fragments before it opens.

/* Slow: animates layout properties */
.mini-cart { right: -400px; transition: right .3s; }
.mini-cart.is-open { right: 0; }

/* Better: compositor-friendly transform */
.mini-cart { transform: translateX(100%); transition: transform .3s; }
.mini-cart.is-open { transform: translateX(0); }

Cookie banners and consent tools

This is a classic INP spike. When a shopper clicks “Accept all”, the consent tool updates consent and fires every tag that was waiting, often in the same task as the click. GA4, Ads, Meta, heatmaps and chat can all initialise before the banner even disappears.

The fix is to hide the banner first, then update consent and release tags in a later task. You still honour the user’s choice. You just don’t make them wait for 20 scripts to boot before the screen responds.

Quick reference: slow interactions and first fixes

Interaction Typical cause What the trace shows First fix
Variation swatch / select Large inline variation data, gallery re-init, several listeners Long processing under change and found_variation, plus image decode and layout Update the selected state first, defer gallery work, remove duplicate swatch or gallery plugins
AJAX add to cart Sync work before feedback, fragment replace, pixels on added_to_cart Long click task, then big tasks on gtm.js / fbevents.js Show the button loading state immediately, then yield before tracking
Filter checkbox / price slider Whole grid re-render, no debounce Repeated tasks per input event, heavy layout after HTML swap Debounce inputs, update only the changed parts of the grid
Mini-cart open Animating layout properties, large DOM, fetch before open Long presentation delay, purple Layout blocks Animate transform, open the drawer before refreshing contents
Cookie banner accept All consented tags fire synchronously One very long task across many third-party domains Hide the banner first, release tags after yielding

Fix these before the sale season. Retesting under load matters, and changes made in the week of a sale are risky. The Black Friday SEO for WooCommerce guide covers the page side of that preparation. If you’d like a second pair of eyes on your traces, you can book a free consultation.

Fix pattern 1: Give feedback first, then yield

Most slow WooCommerce interactions have the same shape. A shopper clicks a swatch, a filter or a button, and one long JavaScript task runs before the browser can paint anything.

INP measures the time from the input to the next frame the browser paints. If your handler does everything in one task, the paint has to wait for the slowest part of the work. The fix is to change the order: paint a cheap visual change first, then hand control back to the browser, then do the heavy work.

Google’s guidance calls this yielding to the main thread. A long task is split into smaller ones so the browser can render and respond to input between them (web.dev). MDN’s example for scheduler.yield() follows the same order: show feedback, then yield (MDN).

scheduler.yield() with a fallback

scheduler.yield() pauses your task and lets the browser do pending work, such as painting a frame. Your code then resumes ahead of other queued tasks instead of joining the back of the queue (Chrome for Developers).

It isn’t supported in every browser, so feature-detect it. The fallback is setTimeout. It still yields, but its continuation runs after tasks that are already queued, which can include third-party scripts.

// Yield to the main thread: prioritised where supported, setTimeout elsewhere
function yieldToMain() {
  if (globalThis.scheduler && typeof globalThis.scheduler.yield === 'function') {
    return globalThis.scheduler.yield();
  }
  return new Promise(function (resolve) {
    setTimeout(resolve, 0);
  });
}

Here is a swatch handler built on that helper. It suits the common setup where custom swatches sit on top of WooCommerce’s hidden variation <select>, and wc-add-to-cart-variation reacts to its change event. Check how your theme or swatch plugin connects to the form before you copy this. Script behaviour can change between WooCommerce versions.

let swatchToken = 0;

document.addEventListener('click', async function (event) {
  const swatch = event.target.closest('.store-swatch');
  if (!swatch) return;

  const token = ++swatchToken; // used to drop stale work after rapid clicks
  const group = swatch.closest('.store-swatch-group');

  // 1. Cheap visual feedback only
  group.querySelectorAll('.store-swatch.is-selected').forEach(function (el) {
    el.classList.remove('is-selected');
    el.setAttribute('aria-pressed', 'false');
  });
  swatch.classList.add('is-selected');
  swatch.setAttribute('aria-pressed', 'true');

  // 2. Let the browser paint the selected state
  await yieldToMain();
  if (token !== swatchToken) return;

  // 3. Heavy work: WooCommerce updates price, image and stock from here
  const select = document.querySelector(
    'select[name="' + group.dataset.attribute + '"]'
  );
  select.value = swatch.dataset.value;
  jQuery(select).trigger('change');
});

Two details matter here:

  • The token check. If a shopper taps three colours quickly, only the last tap should trigger the expensive update.
  • Only cheap work goes before the yield. Toggling a class and an ARIA attribute is cheap. Reading layout (offsetHeight, getBoundingClientRect) or rebuilding a gallery is not.

If you control the update functions yourself, yield between them as well. For example, update the price, yield, swap the gallery, yield, then update the stock message. Each step becomes its own task.

Breaking up long loops with a 50 ms budget

Some work is one big loop. Typical examples are building an availability map for a product with hundreds of variations, recalculating which swatches to disable, or re-rendering a long product grid after a filter changes.

Yielding after every item adds overhead. Never yielding creates one long task. A practical middle ground is a time budget of about 50 ms per chunk:

async function processInChunks(items, processItem) {
  let deadline = performance.now() + 50;

  for (const item of items) {
    if (performance.now() >= deadline) {
      await yieldToMain();
      deadline = performance.now() + 50;
    }
    processItem(item);
  }
}

// Example: mark unavailable swatch combinations without blocking input
processInChunks(variations, function (variation) {
  if (!variation.is_in_stock) {
    markCombinationUnavailable(variation.attributes);
  }
});

On variable products, also check how the variation data reaches the browser. WooCommerce embeds the data in the form below a variation threshold and fetches it by AJAX above it. You can change that threshold with the woocommerce_ajax_variation_threshold filter. Test both modes on your largest products, because they spread the work differently.

“If we add yields everywhere, the store will be faster.”

It won’t. Yielding doesn’t reduce total work. It changes when the work runs so the browser can paint and respond in between. If a swatch click runs 400 ms of unnecessary code, remove that code first. Typical culprits are duplicate listeners, a slider library re-initialising on every change, and a tracking call inside the handler. Use yielding for the work that is left.

Interaction Paint first Do after the yield
Variation swatch Selected border, aria-pressed Price, gallery, stock, SKU
Add to cart (AJAX) Button loading state Request, mini-cart refresh, tracking
Filter checkbox Checked state, “Updating…” label Fetch results, re-render grid
Quantity stepper New number in the field Subtotal recalculation, cart update

Fix pattern 2: Debounce inputs and defer third-party work

Pattern 1 handles one expensive interaction. This pattern handles two other sources of poor INP: inputs that fire many events in a row, and third-party code that runs inside your click handlers.

Debouncing filters, sliders and search

A price slider can fire dozens of input events during a single drag. Live search fires one on every keystroke. If each event starts an AJAX request and a grid re-render, the main thread stays busy and the next interaction waits.

Debouncing means waiting until the shopper pauses before doing the expensive work. A delay of about 250–300 ms is a sensible starting point. The visible state, such as the slider label or typed text, must still update immediately on every event.

function debounce(fn, wait) {
  let timer;
  return function () {
    const args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function () { fn.apply(null, args); }, wait);
  };
}

let controller;

const fetchFiltered = debounce(function (min, max) {
  if (controller) controller.abort(); // cancel the stale request
  controller = new AbortController();

  fetch('/wp-json/store-filter/v1/products?min=' + min + '&max=' + max, {
    signal: controller.signal
  })
    .then(function (res) { return res.json(); })
    .then(renderGrid)
    .catch(function (err) {
      if (err.name !== 'AbortError') showFilterError();
    });
}, 300);

priceSlider.addEventListener('input', function () {
  // Immediate, cheap feedback
  priceLabel.textContent = '£' + priceSlider.valueLow + ' – £' + priceSlider.valueHigh;
  resultsArea.setAttribute('aria-busy', 'true');

  // Expensive work only after the shopper pauses
  fetchFiltered(priceSlider.valueLow, priceSlider.valueHigh);
});

The endpoint and slider properties above are placeholders. Your filter plugin will have its own. The structure is what matters: immediate label, debounced fetch, aborted stale requests.

If your filter plugin doesn’t expose a setting or hook for this, look at its documentation for an “apply” button mode. A button adds a click, but it removes a lot of background work on mobile. Filters also create crawlable URLs, so check them for SEO too (see faceted navigation SEO for WooCommerce).

Moving analytics and pixels out of the click path

A common pattern on WooCommerce stores is an add-to-cart click that also runs a dataLayer.push(), a Meta pixel call, a TikTok event and sometimes a heatmap tag. All of them run before the browser can paint the button’s loading state.

The tracking still needs to happen. It just doesn’t need to happen before the shopper sees a response.

function runAfterPaint(fn) {
  // Prefer a prioritised yield, then idle time with a timeout, then setTimeout
  if (globalThis.scheduler && typeof globalThis.scheduler.yield === 'function') {
    globalThis.scheduler.yield().then(fn);
  } else if ('requestIdleCallback' in window) {
    requestIdleCallback(fn, { timeout: 1000 });
  } else {
    setTimeout(fn, 0);
  }
}

jQuery(document.body).on('added_to_cart', function (e, fragments, hash, button) {
  const data = {
    event: 'add_to_cart',
    ecommerce: {
      currency: 'GBP',
      items: [{ item_id: button.data('product_sku'), quantity: 1 }]
    }
  };

  // Capture the data now, send it after the paint
  runAfterPaint(function () {
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({ ecommerce: null });
    window.dataLayer.push(data);
  });
});

Note that the event data is captured synchronously, and only the push is deferred. This way, nothing about the event is lost if the DOM changes before the callback runs. The timeout on requestIdleCallback makes sure the callback still runs on a busy page.

Pushing to dataLayer is cheap in itself. The cost comes from the GTM tags that fire on that event. That’s why deferring the push helps.

The trade-off: navigation can drop deferred events

Deferred work only runs if the page is still open. If a click leads straight to a new page, such as a non-AJAX add-to-cart on a single product page or a “Proceed to checkout” link, a deferred callback may never fire.

Use this decision rule:

Interaction Page stays open? Approach
AJAX add to cart, swatch, filter Yes Defer with runAfterPaint()
Form submit or link that navigates No Send immediately with a beacon-style request, keep it small
Queued events not yet sent Unknown Flush on pagehide or visibilitychange with navigator.sendBeacon()

navigator.sendBeacon() is designed to send small payloads that survive page unload. For GA4, check that your tag’s requests actually complete. In DevTools, open the Network panel, tick Preserve log, click the button and look for the collect request. Then compare the event counts in GA4 before and after the change. Missing events often show up as session and attribution oddities (see GA4 unassigned traffic).

Splitting consent-triggered tags

The “Accept all” click on a cookie banner is often one of the slowest interactions on a store. In a single task, the CMP saves the choice, updates consent, and GTM fires every tag that was waiting for consent.

Use this order instead:

  1. Hide the banner first. This is the visual response the shopper is waiting for.
  2. Yield so the browser paints the page without the banner.
  3. Send the consent update (gtag('consent', 'update', …) or your CMP’s equivalent).
  4. Stagger the heavy tags. Fire essential analytics first. Load advertising pixels, heatmaps and chat widgets on later triggers, such as a custom event fired after another yield, or Window Loaded.
acceptButton.addEventListener('click', async function () {
  banner.hidden = true;           // 1. visual response
  await yieldToMain();            // 2. let it paint
  saveConsentChoice('granted');   // 3. CMP / consent mode update
  await yieldToMain();
  window.dataLayer.push({ event: 'consent_ready_deferred' }); // 4. trigger for non-essential tags
});

Most stores use a commercial CMP, so you often can’t edit its click handler. In that case, record the “Accept” click in the DevTools Performance panel and see which scripts run. Then check your CMP’s documentation for asynchronous or deferred consent options, and check how its Google Tag Manager consent mode template fires updates. In GTM, move non-essential tags off the consent update trigger where your legal setup allows it. Don’t break consent rules to improve a metric.

Each third-party script is also a security dependency. On 31 October 2026, DebugBear’s DNS was hijacked to serve malicious JavaScript, and customers were told to remove its RUM script (Search Engine Journal). Field data is still essential for INP work. Just treat every external script, including monitoring tools, as something to inventory and review. Our third-party script audit for WordPress walks through that process.

If you’d like a second pair of eyes on which scripts sit in your click path before the sales season, you can book a free consultation.

Fix pattern 3: Reduce the work WordPress loads on interactive templates

Yielding and debouncing fix how your code runs. This pattern removes code that should not run at all.

On a typical WooCommerce site, every plugin enqueues its scripts and styles on every page by default. Each extra script competes for the main thread when a shopper taps something, even if that page never uses it.

Unload scripts where they aren’t needed

Start by listing what actually loads on your slow template. The free Query Monitor plugin shows every enqueued script and style with its handle, under Scripts and Styles in its panel.

Then decide, template by template, what each script is for:

  • Swatch scripts are needed on product pages. They are also needed on shop and category pages if you show swatches in the product grid.
  • Homepage sliders and hero carousels are rarely needed on product or category pages.
  • Form, booking and review-widget scripts often load sitewide but are used on one or two pages.
  • WooCommerce’s own wc-add-to-cart-variation loads on variable product pages. Leave it alone there, because it controls variation selection and price updates.

Here is a pattern for conditional unloading. Replace the example handles with the real ones from Query Monitor, and put it in a child theme or a small site-specific plugin.

add_action( 'wp_enqueue_scripts', 'mhr_trim_store_scripts', 100 );

function mhr_trim_store_scripts() {
    // Stop if WooCommerce is not active.
    if ( ! function_exists( 'is_product' ) ) {
        return;
    }

    $is_store_template = is_product() || is_shop() || is_product_category() || is_product_tag();

    // Swatches: only product pages and product archives.
    if ( ! $is_store_template ) {
        wp_dequeue_script( 'example-swatches' );
        wp_dequeue_style( 'example-swatches' );
    }

    // Homepage slider: never needed on store templates.
    if ( $is_store_template ) {
        wp_dequeue_script( 'example-home-slider' );
        wp_dequeue_style( 'example-home-slider' );
    }
}

Two things to note about this snippet:

  • Priority 100 makes it run after most plugins have enqueued their files. If a plugin enqueues late, raise the number.
  • Handles can change between plugin and WooCommerce versions. After every update, re-check the handles in Query Monitor rather than assuming they still match.

Check cart fragments before you touch them

The wc-cart-fragments script keeps the header cart count and mini-cart up to date. It does this with a request to ?wc-ajax=get_refreshed_fragments, then replaces parts of the page HTML.

Older advice says to dequeue it sitewide. That advice predates a behaviour change: from WooCommerce 7.8, cart fragments are no longer enqueued on every page by default. They load when something on the page needs them, such as a cart widget. Confirm the current behaviour on WooCommerce Developer for your version before you change anything.

Then check what your site actually does:

  1. Open a product page in a private window and open DevTools.
  2. In the Network panel, filter for cart-fragments and for get_refreshed_fragments.
  3. Note which templates load the script and whether those templates show a mini-cart or cart count.
  4. If the script loads on a page with no mini-cart, find out what is enqueueing it. Common culprits are the theme or a header builder.

Do not remove fragments from pages that show a cart count. With full-page caching, shoppers would see a stale or empty cart. That costs more sales than a slightly slower tap.

DOM size and CSS that make every paint expensive

Even a fast click handler still has to wait for the browser to recalculate styles, lay out the page and paint. That cost sits in presentation delay, the third part of every interaction.

Google explains that large DOMs make style and layout work more expensive, so even small visual updates take longer to render (web.dev).

On WooCommerce stores, the bloat usually comes from markup the shopper never sees:

  • Mega menus with hundreds of category links, rendered in full on every page.
  • Hidden off-canvas markup: a mobile menu, a cart drawer, a filter drawer and a search overlay all sitting in the DOM at once.
  • Long related-product and upsell carousels with 20 or more product cards, each holding images, prices, badges and buttons.
  • Page-builder wrappers that nest a single heading inside six or seven divs.

Practical ways to cut it down:

  • Limit related and upsell products to what fits on one or two screens.
  • Render drawers and overlays on first open, not on page load. Combine this with Pattern 1: open an empty shell first, then fill it.
  • Trim mega menus to top-level categories and link to category pages for the rest.
  • Consider content-visibility: auto for long below-the-fold sections, such as reviews and related products, so the browser skips rendering work for them until they are needed. Test it, because it can affect scroll position and in-page anchors.
  • Remove unused CSS from heavy themes. Broad selectors and large stylesheets increase the cost of style recalculation after every class change.

Be careful with “delay all JavaScript” settings

Many optimisation plugins offer a setting that delays all scripts until the first user interaction. It improves lab scores because nothing runs during the test.

“Delaying all JavaScript fixes INP because the page has nothing to run.”

It often does the opposite. The first tap triggers downloading, parsing and running every delayed script at once, and that tap becomes your slowest interaction. On a variable product, the swatch the shopper tapped may not even respond until wc-add-to-cart-variation has loaded.

Test the first interaction specifically:

  1. Load the page fresh, with cache cleared, and with 4x CPU throttling in the DevTools Performance panel.
  2. Don’t scroll or move the mouse. Tap a swatch or the add-to-cart button straight away.
  3. Check the INP value and the long task that follows the tap.
  4. If it is poor, exclude interaction-critical scripts (jQuery, WooCommerce variation and cart scripts, your swatch plugin) from the delay list and test again.

For a structured way to decide which third-party scripts stay, delay or go, see the third-party script audit for WordPress.

Common mistakes, validation and a pre-BFCM checklist

INP fixes fail more often because of process mistakes than code mistakes. A fix works in a test, but nobody checks it against the visits that Google actually measures.

Mistakes that waste time

  • Testing only on a fast desktop. Most failing WooCommerce groups are on mobile. Use CPU throttling in DevTools and test on a real mid-range Android phone if you can.
  • Judging by the PageSpeed Insights score. A standard Lighthouse run does not measure INP, and Total Blocking Time is only a lab proxy. Scores also shift when Lighthouse itself changes, as explained in PageSpeed Insights score changed? Lab vs field data explained.
  • Fixing a template with no traffic. Search Console lists group URLs by impressions. Start with the template behind the top URLs, not with the page that is easiest to edit.
  • Adding a RUM script without vetting it. Real-user monitoring is valuable, but it is also third-party JavaScript running on your checkout. On 31 October 2026, DebugBear’s DNS was hijacked to serve malicious JavaScript, and customers were told to remove its RUM script (Search Engine Journal). Keep field data, but treat every monitoring script as a security dependency: know who controls it, where it loads from and how to remove it fast.
  • Stacking swatch or filter plugins. Two swatch plugins, or a theme filter plus a filter plugin, can both attach handlers to the same click. Each handler adds processing time. Keep one, and remove the other completely.

Validating the fix in Search Console

Field data moves slowly, so follow a fixed order and record dates as you go:

  1. Deploy the change to production and clear page and CDN caches.
  2. Confirm in a local trace. Repeat the exact interaction from Step 3 with the same throttling and compare the INP and the long-task breakdown.
  3. Monitor field data. Watch your vetted RUM data, or CrUX for URLs and origins with enough traffic, for the template you changed.
  4. Click Validate fix in the Core Web Vitals report on the failing issue, separately for mobile and desktop where both fail.
  5. Wait for the data window to roll over. The report uses a 28-day collection period, so old slow visits stay in the numbers for a while (Search Console Help). Check the current Help Center wording for how validation is monitored.

Don’t promise a client or manager a date. Low-traffic groups may fall back to origin data, and a group only passes when 75% of visits reach 200 ms or less. If validation fails, the report shows which URLs are still poor. Go back to Step 3 with one of those URLs.

Troubleshooting by symptom

Symptom Likely causes What to check first
INP poor only on mobile Slower CPUs, touch-only handlers, off-canvas menus and drawers, heavy mobile header scripts Trace with 4x or 6x CPU throttling; tap the menu, filter drawer and swatches
INP poor only on category pages AJAX filter plugins, large product grids, archive swatches, faceted navigation re-rendering the whole grid Filter clicks and sort changes; DOM size of the grid. See faceted navigation SEO for WooCommerce
INP poor only for new visitors Consent banner click loading tag managers, pixels and chat widgets in one task; “delay JS” firing on the first tap Trace the banner’s accept click in a private window
INP poor only after the cart has items Cart fragments refreshing and replacing header HTML, large mini-cart or cart-drawer markup, cross-sell widgets in the drawer Add an item, reload, then trace opening the cart drawer and changing quantity

Checklist before peak traffic

Use this in the week before Black Friday and Cyber Monday. Freeze plugin and theme updates after it is done, unless an update is a security fix.

Task Owner Done when
Check the CWV report for mobile and desktop INP groups Store owner Failing groups and their top URLs are listed
Trace swatch, add-to-cart, filter and cart-drawer interactions with CPU throttling Developer Each interaction is recorded with its INP value
Test the first interaction with “delay JS” settings on Developer Interaction-critical scripts are excluded from delay
Confirm conditional script unloading still matches current handles Developer Query Monitor shows only the expected scripts per template
Check cart fragments on templates with and without a mini-cart Developer Cart count is correct and fragments load only where needed
Review sale banners, countdown timers and popups added for the campaign Store owner Each new widget is tested on mobile before going live
Review every third-party and RUM script Developer and store owner Owner, source and removal steps are documented
Remove duplicate swatch, filter or slider plugins Store owner One plugin per job
Start Validate fix for groups you have fixed Store owner Validation started and the date recorded

Speed is one part of peak-season readiness. For the pages that need to rank before the traffic arrives, see Black Friday SEO for WooCommerce.

If your INP groups are still failing and you can’t find the long task, book a free consultation and we can go through the traces together.

Fix INP on WooCommerce: Find and Speed Up Slow Interactions — key takeaways
Key takeaways at a glance

Frequently Asked Questions

What is a good INP score for a WooCommerce store?

Aim for 200 ms or less at the 75th percentile of real visits. Between 200 and 500 ms needs improvement, and over 500 ms is poor. Mobile and desktop are assessed separately, so check both.

Why does my product page pass LCP but fail INP?

LCP measures how fast the main content loads. INP measures how fast the page responds after the shopper interacts with it. A page can render quickly and still respond slowly when someone picks a size or opens the cart, because those actions run heavy JavaScript after load.

Will a caching or optimisation plugin fix INP?

Page caching mainly speeds up server response and loading. It does little for slow event handlers in the browser. Deferring or delaying scripts can reduce input delay for early taps. However, settings that load scripts on the first interaction can make that first tap slower. Test the actual interaction after changing these settings.

How long does it take for INP fixes to show in Search Console?

CrUX data covers a rolling 28-day window, so improvements appear gradually as new visits replace old ones. Expect roughly four weeks before a group reflects the change. The Validate Fix process in Search Console also runs over a similar monitoring period.

Why does PageSpeed Insights show no INP data for my product URL?

The URL probably doesn't have enough real Chrome traffic for URL-level field data. In that case, PSI may show origin-level data for the whole site instead. Search Console URL groups are often more useful for low-traffic product pages, because similar URLs are assessed together.

Does INP affect Google rankings?

INP is one of the Core Web Vitals, which Google's ranking systems use as part of page experience. Relevance and helpful content still matter far more. Fixing INP is mainly about shoppers who abandon sticky swatches, filters and carts, so treat any ranking benefit as a bonus.

Does scrolling or hovering affect INP?

No. INP only counts discrete inputs: clicks, taps and key presses. Janky scrolling is still worth fixing for shoppers, but it won't change your INP value.

Final Thoughts

Start with Search Console. Open the mobile Core Web Vitals report, find the INP issue rows and note which templates fail: product, category, cart or checkout.

Next, reproduce the most likely slow interaction on that template in Chrome DevTools. Work out whether input delay, processing time or presentation delay is the problem, and fix that phase first.

Judge success by field data, not by the PSI score. Give the fix around four weeks to show in CrUX and Search Console. If a busy sales period is coming up, make the changes well before it.

Want help applying this to your site? Run the free SEO check or book a free consultation with MD Harunur Rashid. Free SEO check · Book a free consultation

Written by

MD Harunur Rashid

MD Harunur Rashid — Digital Growth & Web Solutions Expert, a passionate SEO and Digital Marketing Consultant based in Dhaka, Bangladesh. With years of hands-on experience in Local SEO, WordPress web design, affiliate marketing, and digital strategy, I have dedicated my career to helping businesses build a strong, sustainable online presence. SEO is not just my profession — it is my passion. I love diving deep into search algorithms, uncovering growth opportunities, and turning underperforming websites into top-ranking, high-converting digital assets. Whether it is a local business trying to dominate its neighborhood market or a brand looking to scale globally, I bring the strategy, skills, and dedication to make it happen. On the web development side, I specialize in WordPress — designing clean, fast, and functional websites that not only look great but perform even better in search engines. From custom themes to plugin development, I bring both the technical and creative sides together seamlessly. Beyond my consulting work, I am the founder of Sofhor Tourism, born from my personal love of travel and nature. It is my way of helping fellow explorers discover the beauty of Bangladesh and beyond. I also proudly stand behind Tinnis Bakeshop — my wife's baking passion project that I am helping grow into a recognized brand in Bangladesh. I am hardworking, endlessly curious, and fiercely honest. I do not believe in shortcuts — only in real strategies that deliver real results. Every project I take on gets my full commitment, from start to finish. If you are looking for a digital partner who genuinely cares about your growth, let's connect.