Reviewed November 1, 2026
INP on Collection Pages: The Filter Click That Feels Broken
On collection pages, INP fails at the filter interaction. The click handler often tears down and rebuilds the entire product grid, re runs every card's scripts and badges, and only then paints, stretching the interaction well past the 200 millisecond good threshold. Cut the work, not the feedback: render only the changed grid region, avoid rebuilding unchanged cards, keep handlers off the main thread's long tasks, and show the pending state instantly so the paint the metric waits for is not held hostage by the full re render.
Ask a store owner where their site feels slow and they will describe the homepage. Measure where shoppers feel it and a different screen wins: the collection page, mid filter, on a mid range Android, where tapping a size filter produces a pause long enough to tap it again. That pause is INP, interaction to next paint, and filtering is the heaviest interaction most stores own, because it recomputes and repaints the largest DOM on the site in response to a single tap.
INP replaced first input delay as a Core Web Vital, and it is stricter company: it considers nearly every interaction across the visit and grades roughly the worst. A store can pass LCP on the strength of a good hero image and fail INP on the strength of one ambitious filter script. The shoppers experiencing it rarely complain in words. They filter once instead of three times, browse less deeply, and buy less, quietly.
What the filter click actually triggers
Trace one filter tap with performance tooling and watch the main thread. A typical app driven filter serializes the state, fetches or computes the matching set, destroys the existing grid nodes, constructs dozens of new product cards with images, badges, price formatting, review stars, and quick view bindings, then lays out and paints the page, sometimes shifting the filter panel itself in the process. Each stage is defensible in isolation. Stacked inside one interaction, they produce a long task the shopper experiences as a dead button.
Two amplifiers show up repeatedly. The first is rebuilding unchanged work: cards for products that were already visible are demolished and recreated identically, because the render path has no concept of a diff. The second is synchronous extras hitched to the render: analytics events, personalization rechecks, and currency formatting all queuing on the same main thread before paint. The browser cannot show the shopper anything until that queue clears. The spinner, if one exists, is often rendered by the same blocked thread, which is why it appears late, after the pause it was meant to explain.
Cutting the work in the order the thread feels it
Start with the render scope. Update the grid region only, leave the filter panel, header, and everything static untouched, and where the tooling allows it, reuse or patch existing cards instead of recreating the set. Next, move the pending feedback out of the blocked path: a lightweight CSS driven indicator toggled by a class at the very start of the handler paints early and tells the shopper the tap registered, which also kills the double tap that restarts the whole computation.
Then shed the hitchhikers. Defer analytics and personalization calls until after the grid paints, using idle callbacks or a simple post render queue. Virtualize or paginate very large result sets rather than painting three hundred cards because a broad filter matched them. And measure with INP breakdown in the trace: input delay, processing time, and presentation delay point at different fixes, and treating a presentation problem with handler optimizations wastes the sprint.
Setting a budget the team can keep
Adopt an interaction budget the way serious stores adopt a page weight budget: filter interactions respond with a visual change inside 200 milliseconds at the p75 on a mid range device profile, tested on the largest collection, not the smallest. Add the check to the release routine for theme and filter app updates, because filter apps update silently and an INP regression arrives the same way, silently, discovered by nobody until the quarterly vitals report.
Report INP by template in the monthly review alongside LCP. Collection pages carry the filtering load, product pages carry quick view and variant selection, and each has its own worst interaction. A site level average launders them into a pass while shoppers are living the failures individually. The metric was designed, deliberately, to surface the worst experiences. Report it the way it was designed.
Related reading: Pixels and Tag Managers: The Request Weight Nobody Budgets, AVIF and WebP on Shopify: What the CDN Serves and What It Skips, and TTFB on Shopify: What Actually Moves the First Byte, and What Does Not.
Frequently asked questions
What INP score should a collection page aim for?
200 milliseconds or under at the 75th percentile counts as good. Filtering interactions are usually a store's worst, so measure them specifically, on real devices where possible, rather than relying on the site level average that blends in easy interactions like menu taps.
Why does the filter spinner appear after the delay instead of during it?
If the spinner is rendered by the same JavaScript that performs the filtering, the main thread is blocked doing the work before it can paint the spinner. Toggle a lightweight visual state first, before the heavy computation, so feedback paints immediately.
Is it better to filter without reloading the page?
For responsiveness, yes, client side or AJAX filtering avoids a full page load. But it concentrates the work in the interaction, which is why its INP needs active management. A fast server rendered filter page can beat a sluggish client side one; measure the interaction, not the architecture label.
Which part of INP is usually biggest on filter clicks?
Processing time, the handler doing fetch, DOM teardown, and card rebuild, is typically the largest slice, followed by presentation delay when the new grid is large. The INP breakdown in a performance trace separates the three parts so you fix the right one.