All articles
E-commerceOctober 5, 2026 6 min read

Faceted Search on Shopify at 100k SKUs: Where the Native Filters Break

Shopify's built-in filtering is fine until your catalog crosses six figures. Here's where it falls apart, what Search & Discovery actually indexes, and how we rebuild filtered collection pages without wrecking SEO.

Shopify handles small and mid-size catalogs beautifully. Push past roughly 50k active variants with deep attribute filtering and the native experience starts to groan in ways that cost you both revenue and crawl budget. This is a breakdown of where it breaks, what we've seen work, and the architectural calls worth making before you reach for a third-party search engine.

Why faceted search gets harder past 50k SKUs

Filtering a collection sounds trivial — pick a color, pick a size, show matching products. The complexity isn't in the UI; it's in the combinatorics. A category with 8 filter dimensions and an average of 6 values each produces hundreds of thousands of possible filter states, most of which are reachable by a bot following links. Each of those states needs to resolve fast, return accurate counts, and either be indexable or firmly blocked.

Shopify's native Search & Discovery app covers the basics: product type, vendor, price, availability, and up to a configurable number of metafield- or option-backed filters per collection. For a storefront with a few thousand products and clean taxonomy, it's genuinely good. The friction shows up on three axes:

  • Catalog size. As variant counts grow, filter facet count queries get noticeably slower, especially on category pages that already carry heavy Liquid logic.
  • Attribute depth. Native filters work best on options and simple metafields. Nested metaobjects, computed attributes ("in stock within 30km"), or editorial groupings ("gift under $50") are awkward or impossible.
  • Multi-select and intersections. The UX is fine, but counts behind each facet require recomputation per request, which the storefront proxy will cache aggressively — meaning stale counts after inventory shifts.

In our experience, the breaking point isn't a hard number. It's the day a merchandiser asks for a filter the platform wasn't designed to express, and the "just add a metafield" answer stops being true.

What actually gets indexed, and where that bites you

Before touching architecture, audit what Google is doing with your filtered URLs. On a stock Shopify theme, filter selections typically produce URLs like:

/collections/outerwear?filter.v.option.color=black&filter.v.option.size=M&filter.v.price.gte=100

These are, by default, crawlable. Shopify emits a rel="canonical" back to the clean collection URL, which helps — but canonicals are a hint, not a directive. On large catalogs we routinely see:

  • Googlebot spending disproportionate crawl budget on filtered permutations instead of product pages.
  • Low-value filter combinations being indexed anyway when they accumulate internal links.
  • "Soft 404" warnings in Search Console for filter combos that return zero products.

A sane crawl policy for filtered pages

Pick a small set of filter combinations that have real search demand (think /collections/outerwear/black or /collections/running-shoes/mens) and treat those as first-class landing pages. Everything else should be discouraged from indexing. A practical pattern:

{%- if request.design_mode == false and current_tags.size > 0 or request.path contains '?filter.' -%}
  <meta name="robots" content="noindex, follow">
{%- endif -%}

Pair that with a robots.txt.liquid override that disallows the ?filter. query family for bots you don't want crawling it, while leaving your SEO-value tag URLs clean. The goal: a handful of indexable, keyword-targeted facets per collection; everything else closed off.

When to leave native search behind

We generally recommend sticking with Search & Discovery until you hit at least one of these:

  1. You need filter dimensions native options don't support — proximity, computed inventory, rule-based bundles, personalization.
  2. You need sub-200ms response times on filter interactions across large collections, measured at p75 on mobile.
  3. You're running merchandising experiments (reranking by margin, boosting slow movers, A/B pinned products) that need a real search engine's scoring model.
  4. Your catalog has multi-language or multi-currency complexity that your current filter counts can't keep accurate.

If none of those apply, don't introduce another system. The operational cost of a secondary index is real: reindex lag, schema drift, two sources of truth about what's "in stock."

The architecture that tends to work

For stores past the 50k–100k SKU mark that need serious faceting, the pattern we reach for most often is a hybrid: Shopify remains the system of record and checkout, but collection and search pages are powered by a dedicated engine — Algolia, Typesense, Meilisearch, or Elastic depending on budget and team.

The ingestion pipeline

The cleanest ingestion we've built uses Shopify's bulk operations API for the initial backfill, then webhooks plus a reconciliation job for ongoing sync.

// pseudo-code: webhook handler for products/update
export async function handleProductUpdate(payload: ShopifyProduct) {
  const doc = {
    objectID: payload.id.toString(),
    title: payload.title,
    handle: payload.handle,
    vendor: payload.vendor,
    product_type: payload.product_type,
    tags: payload.tags,
    price_min: minVariantPrice(payload.variants),
    inventory_total: sumInventory(payload.variants),
    options: flattenOptions(payload.variants),
    metafields: await fetchRelevantMetafields(payload.id),
    updated_at: payload.updated_at,
  };

  await searchIndex.saveObject(doc);
}

Two non-obvious lessons from running this in production:

  • Inventory webhooks fire a lot. Debounce by product ID with a short window (say 2–5 seconds) or you'll hammer your index during bulk stock updates from your ERP.
  • Reconcile nightly. Webhooks drop. Run a diff between Shopify's product list and your index at least once a day and reindex drift.

The storefront integration

For filter UIs, you have two choices on a non-headless Shopify store:

  1. Replace the collection template entirely with a client-rendered component that queries your search backend. Simplest to build, worst for SEO unless you also render server-side.
  2. Server-render the first page via an app proxy or edge function, then hydrate for subsequent interactions. More work, keeps the SEO value of your collection pages intact.

We default to option 2 for anything that matters commercially. Shopify's app proxy lets your backend render HTML that appears under your store domain, which keeps canonicals and crawling behavior sane. On headless stacks (Hydrogen, Next.js on Oxygen or Vercel), it's just a server component calling your search index — much tidier.

Measuring whether it was worth it

Before and after any search migration, track at least these:

  • Collection page LCP and INP, p75 mobile, from field data not lab.
  • Filter interaction time — how long between tap and visible result change.
  • Zero-result rate on filtered views (should drop; if it rises, your index is lying about inventory).
  • Add-to-cart rate from filtered collection pages vs unfiltered. This is the number that justifies the project.
  • Googlebot hits per day on ?filter. URLs. Should fall meaningfully once your noindex + robots policy is in place.

We've seen filter-interaction time drop from the 800ms–1.5s range on native Shopify filters at scale down to the 100–250ms range on a well-tuned Algolia or Typesense setup. Add-to-cart lift from filtered pages tends to be modest but real — in the single-digit percentage range — and it compounds with every merchandising experiment you can now actually run.

The traps worth naming

A few things we've watched teams get wrong:

  • Treating the search index as a product database. It's a derived view. If your frontend starts reading prices or inventory from it at checkout time, you will ship bugs. Keep Shopify authoritative for anything the customer transacts on.
  • Indexing every metafield "just in case." Index size and reindex time grow fast. Be deliberate about schema.
  • Forgetting about localized storefronts. If you run Shopify Markets, your index needs per-locale documents or per-locale indices, and your filter labels need translating too.
  • Skipping the SEO cleanup. A new search engine with the old crawl mess underneath just gives you faster indexed junk.

Where we'd start

If your catalog is approaching the point where native filters feel strained, don't start with the search engine. Start with a one-week audit: pull Search Console data for your top collections, log Googlebot's actual behavior on filter URLs, and measure p75 filter interaction time on mobile. Nine times out of ten, the first wins are tightening the crawl policy and promoting a handful of high-intent facet combinations to real landing pages. Only after that groundwork does adding Algolia or Typesense pay back cleanly. If you want a second pair of eyes on the architecture before you commit, our commerce engineering team does this kind of audit regularly.

#Shopify#Search#CRO#SEO#Headless Commerce

Want a team like ours?

72Technologies builds production software for the kind of teams who actually read this blog.

Start a project