Collection Page Filtering at Scale: Why Your Shopify Facets Are Killing Conversion
Faceted filtering on large Shopify collections quietly destroys mobile conversion. Here's how the requests stack up, why theme defaults fall over past 500 SKUs, and what actually holds up in production.

Every catalog over a few hundred SKUs eventually hits the same wall: the collection page starts feeling sluggish, filters take a beat to respond, and mobile bounce creeps up on the exact URLs that were supposed to convert best. It's rarely one big bug. It's the compounding cost of Shopify's default faceting, a theme that re-renders too much, and a client that fetches too often.
This is a breakdown of where the time actually goes on a filtered collection page, what your options are once the built-in Search & Discovery app stops being enough, and how to decide between staying on-theme, going headless, or splitting the difference.
Where the time actually goes
Open DevTools on a mid-sized Shopify store — say 800 SKUs in one collection, with filters for size, color, price, and two custom metafields — and watch a filter click. On a decent theme running Dawn or a Dawn fork, you'll usually see:
- A full-section render request to
/collections/{handle}?filter.v.option.size=M§ion_id=main-collection-product-grid - Between 40 KB and 200 KB of HTML back, depending on how many products render
- A re-parse of the product grid, re-hydration of any JS behavior, and a fresh batch of image requests
On a fast connection that's 300–600 ms and feels fine. On a 3G-ish mobile connection in a secondary market, it's routinely 1.5–3 seconds per filter click. Users click two or three filters. Do the math.
The theme isn't doing anything wrong exactly — Shopify's section rendering API is the correct primitive here. The problem is that Liquid re-renders the entire grid server-side on every facet change, and if your product card template is heavy (metafield lookups, badge logic, swatches, review snippets), that cost is paid every single click.
The metafield tax nobody budgets for
If your product cards read four or five metafields per product to render swatches, badges, or shipping copy, you're doing four or five extra lookups per card, per render. Twenty-four cards on the page, three filter clicks per session — that's ~300 metafield resolutions for one user browsing one collection. It's fine at 100 SKUs. It's not fine at 2,000.
What Search & Discovery actually gives you
Shopify's Search & Discovery app is the default answer and it's genuinely improved. You get:
- Metafield-based filters without custom Liquid
- Boosting rules and synonyms
- Basic analytics on what users search and filter for
What it doesn't give you:
- Sub-100 ms filter response on large collections
- Filter counts that update without a full section fetch
- Multi-select behavior that feels instant
- Any real control over the ranking algorithm
In our experience, Search & Discovery is the right choice up to roughly 500–1,000 active SKUs per collection, provided your product card template is lean. Past that, or if your merchandising team wants real control, you're shopping for either a dedicated search app or a custom index.
Three architectures that hold up
Here are the three patterns we actually deploy, in rough order of complexity.
1. Keep the theme, offload filtering to a search app
Algolia, Searchanise, Boost, Klevu, Fast Simon — they all follow the same pattern. Products get indexed out-of-band into their infrastructure. On the storefront, filters query their API directly from the client, and results render into a container you control.
This is the highest ROI move for most stores in the 1k–20k SKU range. You keep the theme, keep the checkout, keep the CMS story, and you get filter response times in the 50–150 ms range because you're hitting a purpose-built search index instead of re-rendering Liquid.
The tradeoffs:
- You pay monthly, and pricing scales with search volume or SKU count
- Your product card gets rendered twice — once by Liquid for SEO/initial load, once by JS after filter interaction — so keep the two templates in sync
- Indexing lag is real: a product edit in Shopify admin may take 1–5 minutes to reflect in the search index
2. Section rendering with smart client-side caching
If you're not ready to pay for a search app, you can squeeze surprising performance out of the section rendering API by being disciplined about two things: caching responses on the client, and shrinking the payload.
const sectionCache = new Map();
async function fetchFilteredSection(url) {
const key = url.toString();
if (sectionCache.has(key)) return sectionCache.get(key);
const res = await fetch(`${url}§ion_id=main-collection-product-grid`, {
headers: { 'Accept': 'text/html' }
});
const html = await res.text();
sectionCache.set(key, html);
return html;
}
function applyFilter(url) {
fetchFilteredSection(url).then(html => {
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
const newGrid = doc.querySelector('#product-grid');
document.querySelector('#product-grid').replaceWith(newGrid);
history.pushState({}, '', url);
});
}
A cache like this turns backtracking ("show me M again") into an instant swap. Combine it with:
- A stripped-down product card partial specifically for filtered renders (no reviews block, no swatches computed from metafields, just the essentials)
fetchpriorityand native lazy-loading tuned so above-the-fold cards load first- Debouncing rapid filter clicks so you don't fire three requests when the user is still deciding
This pattern gets you to something that feels close to instant on modern devices, without leaving the theme.
3. Headless collection pages, everything else stays
The pragmatic headless play in 2026 isn't a full storefront rebuild. It's carving out the collection page — the highest-traffic, highest-friction surface — into a separate app (Hydrogen, Next.js, Remix, whatever) served at /c/ or via a reverse proxy, while product pages, cart, and checkout stay on the theme.
You build against the Storefront API or a dedicated search backend, control every millisecond of the render, and get real streaming with instant filter feedback. The rest of the store keeps working.
When this makes sense:
- You have 10k+ SKUs and merchandising is a competitive advantage
- You're already running a headless PDP or marketing surface
- You have the engineering bandwidth to own a second deployment target
When it doesn't:
- You have one developer and a Shopify Plus contract
- Your collections all fit under 500 SKUs
- Nobody on the business side can articulate what "better filtering" would actually unlock
Measuring the right thing
Stop looking at Lighthouse for this problem. Lighthouse loads the page once and grades it. Filtering is an interaction cost.
Instrument three things:
- Time from filter click to visible grid update. Wrap the fetch and the DOM swap in
performance.mark()calls and send the delta to your analytics. - Filter-to-add-to-cart rate. Segment sessions that used filters versus sessions that didn't. If filter users convert worse, your filtering is friction, not a feature.
- Empty-result rate per filter combination. If 30% of users are hitting empty states, your merchandising or your filter logic is broken, and no amount of performance work fixes that.
We've seen stores where filter-users converted at half the rate of non-filter-users, purely because the interaction felt broken. Fixing the perceived latency — even with the same underlying data — moved the number more than any A/B test on button copy ever did.
The CRO angle nobody talks about
Fast filters change user behavior. When response is instant, users click more filters, explore more combinations, and — critically — recover from bad filter choices without leaving. When response is slow, they pick one filter, scroll, and bounce.
That means the ROI on filter performance isn't just "page feels faster." It's more products viewed per session, better data on what users actually want to narrow by, and a stronger signal for whatever recommendation or search ranking system you plug in next.
Where we'd start
If you're staring at a slow collection page tomorrow morning, do these in order:
- Profile one filter click on a real mid-range Android device on throttled 4G. Write down the number. That's your baseline.
- Audit your product card template. Every metafield lookup, every conditional, every included snippet has a cost multiplied by grid size.
- Add client-side caching to your existing section-render fetches. This is a half-day of work and buys you meaningful perceived speed.
- If you're past 1,000 SKUs and the numbers still aren't there, price out a search app before you price out a headless rebuild. The math almost always favors the app first.
Headless is the right answer for some stores. It's rarely the first answer. If you want a second set of eyes on which path fits your catalog, our team works on this daily — see our e-commerce engineering work for how we approach it.
Want a team like ours?
72Technologies builds production software for the kind of teams who actually read this blog.
Start a projectKeep reading

Shop Pay vs Custom Checkout: The Real Cost of Owning Your Funnel
Shop Pay converts. Custom checkouts flex. Here's how to decide which one to run in 2026 — and what the migration actually costs when you get it wrong.

Cart Abandonment Recovery: Why Your Email Flow Is Losing to SMS and What to Rebuild
Email-only abandoned cart flows are quietly bleeding revenue in 2026. Here's how we rebuild them around SMS, event timing, and identity — and what actually recovers carts.

Shopify Functions vs Scripts: What Actually Changes When You Migrate Discount Logic
Shopify Scripts are on borrowed time. Here's what breaks, what improves, and what you'll wish you knew before rewriting your discount logic as Shopify Functions.
