NEWSLayers closes first external funding round led by LOI VentureRead more
‹ All Articles

B2B Search on Shopify Plus: Why the Same Query Should Return Different Results Per Buyer

Deb Mukherjee14 min read

Key Takeaways

  • B2B search is identity-scoped. The same query from two companies should return different products, prices, and collections, because each buyer is scoped to their company location's catalog.
  • On Shopify Plus, passing identity.companyLocationId on the request scopes search, browse, and recommendation results to that company's catalog products, hides out-of-catalog collections, and returns the catalog's price-list pricing.
  • Company buyers should never see retail prices in search. The catalog price list resolves first, then market pricing, then the default variant price.
  • Part numbers and SKUs are an intent-recognition and attribute-indexing job, not a synonym list. A raw SKU is recognized as its own lookup type.
  • Layer segment-specific merchandising on top of catalog scoping using customer tags, account status, geo, and channel, so a tagged company's buyers get their own promotions, pins, and filters.

In early April 2026, Shopify made B2B native for every merchant. The Spring '26 Edition turned company-scoped catalogs, volume pricing, and net terms on for a wave of Plus brands this quarter.

Most of them assumed search came along for free. It didn't.

On the onboarding calls we run with brands flipping B2B on, the pattern repeats: the companies and price lists synced fine, but search still hands wholesale buyers the retail store.

The fix comes down to a single field on the request.

Why is a B2B catalog not a search box on a bigger catalog?

B2B search on Shopify Plus is identity-scoped, not global.

A B2B catalog is not a retail catalog with a wholesale price column; each company location has its own assigned products, collections, and price list.

Until search knows which company is asking, it returns retail results, which is why B2B buyers see wrong products and wrong prices.

You imported your companies and your price lists, you flipped B2B on, and you assumed discovery understood the difference.

A wholesale buyer opens search, types a part number, and gets hundreds of near-matches.

Or worse, they see a retail price, decide the store was never set up for them, and close the tab.

The cause is structural. Retail search treats your catalog as one global index. B2B is not one catalog; it is one per company.

A company that buys 40 SKUs at negotiated prices and a company that buys 4,000 at list prices are two different stores wearing the same domain.

"Doesn't enabling Shopify B2B handle all of this?" It gives you the company, the catalog, and the price-list data.

Whether search uses that data to scope what a buyer sees is a separate decision, and that decision is the whole subject of this post. The mechanism is one field.

What does companyLocationId actually scope?

Passing identity.companyLocationId on a storefront request scopes discovery to that company's catalog.

Search, browse, and recommendation results restrict to the catalog's products, out-of-catalog collections are hidden, and pricing comes from the catalog's price list.

The field is not auto-resolved from the customer ID, so the storefront passes it, and an unknown company returns zero results.

That field is a Shopify CompanyLocation GID, for example gid://shopify/CompanyLocation/123456789. When the request carries it, three things scope at once.

  1. Products. Search, browse, and recommendation block results restrict to the products in that company's catalog. Catalog scoping applies across the surfaces buyers rely on to find products: full search, browse, recommendation blocks, and similar-products.
  2. Collections. Collections excluded from the catalog are hidden, and a request for an out-of-catalog collection returns a 404 for that buyer.
  3. Pricing. Prices come from the catalog's assigned price list. When the field is absent, B2B-only products, variants, and inventory locations drop out of retail traffic.

Two integration facts carry weight for the technical reader. The storefront passes the field itself, because it is not auto-resolved from the signed-in customer ID.

And an unknown or unsynced company location fails closed: zero results, rather than the retail catalog leaking to a B2B buyer.

The sync behind this pulls catalogs, catalog products and variants, the catalog price list with per-variant overrides, catalog collections, and companies and company locations.

It runs on three Shopify scopes: read_customers, read_publications, and read_price_lists.

One precedence rule connects to multi-market work.

For a signed-in company-location buyer, B2B catalog rules take precedence, while Shopify Markets pricing applies to all other traffic, resolved from the same context.geo.country signal our multi-market pricing post walks through.

The scope map splits into two columns: what the field handles automatically, and what you configure on top.

Scoped automatically by companyLocationIdConfigurable via rules and tags
Products returned in search, browse, recommendationsPromotions, pins, and demotions by customer tag
Collections (out-of-catalog hidden, returns 404)Account-status and purchase-history targeting
Pricing (catalog price list resolves)Geo, channel, device, and UTM conditions
B2B-only products and inventory filtered from retailInjected filter groups via request transforms
Fail-closed behavior on unknown companyKeyword weights on SKU and spec attributes

The left column is automatic once the field is passed. The right column is where you do the merchandising work. The rest of this post walks both.

How do you keep B2B buyers from seeing retail prices?

When identity.companyLocationId is present, pricing in search resolves in order: the catalog price-list override first, then market pricing if Shopify Markets sync is on, then the default variant price.

So a company buyer sees their negotiated price-list price in search, not retail, which closes the most common B2B abandonment loop.

The most expensive B2B search failure is a buyer seeing the wrong number.

A wholesale buyer who sees retail pricing assumes the store is misconfigured for them and leaves, and you never learn the order was lost, the line item that never posts, the reorder that quietly routes to whichever supplier showed the right price first.

Shopify already holds the negotiated price; it lives on the price list assigned to that company's catalog. Search just has to read it.

With the company in context, the resolution is fixed:

  1. Catalog price-list override. The price set on the company's catalog wins first. This is where negotiated B2B pricing lives.
  2. Market pricing. If Markets sync is on and a market is in context, market-adjusted pricing applies next.
  3. Default variant price. The standard Shopify variant price is the fallback when neither of the above sets a value.

So company A sees its negotiated price, company B sees its own, and retail traffic sees retail. Each buyer sees one number: theirs.

Confirm it on three best-sellers per company, and you will know your pricing is honest before a buyer reaches checkout.

How do you make part numbers and SKUs findable?

A B2B buyer who types a part number should get the part, not a wall of near-matches.

The engine recognizes a raw code like WKR04 as a SKU lookup and routes it as its own query type, while keyword-weighted attributes give SKU, part-number, and spec fields findability.

You configure which attributes carry keyword weight to match your catalog.

B2B catalogs run dense with part numbers, SKUs, spec fields, and trade abbreviations, and plain keyword search drowns the buyer in fuzzy matches.

Baymard's research on how people search backs the behavior here: when shoppers know the exact item, they type the model number or product title verbatim, often pasted straight from a spec sheet.

The engine has to treat that input as what it is, an exact lookup, not a phrase to fuzzy-match.

Two documented levers do the work together.

  1. SKU-lookup recognition. User-intent processing recognizes a raw code like WKR04 as a distinct query type and routes it separately from general text search, so the part number returns the part. Trade abbreviations normalize before expansion, and query expansion stays catalog-aware, expanding within what you actually sell rather than the open web.
  2. Keyword-weighted attributes. Attribute roles let you mark which fields carry keyword search weight, sourced from product options and metafields through dot notation. Give SKU, manufacturer part number, material, and dimension real weight, and the fields a B2B buyer actually searches on become findable.

This keeps us consistent with the position in our synonym-list post: manual term dictionaries are a merchandising decision, never a language workaround.

You steer findability with attribute weights, not a hand-maintained list of every code in the warehouse, and tiered recall keeps a large technical catalog fast while it resolves.

Can you merchandise differently for each company?

Company A and company B already see different products and prices through catalog scoping.

To differentiate merchandising on top, scope rules and request transforms by customer tags, account status, geo, and channel.

The repeatable pattern for company-specific curation is to tag a company's buyers, then attach promotions, pins, and filters to that tag.

Two layers do the work, and they stack cleanly.

The first layer is automatic. Through companyLocationId, company A and company B already get different products, collections, and prices, with no rule to write.

That is the catalog scoping from earlier, working on its own.

The second layer is where you curate. Contextual conditions target by customer tags, account status, purchase history, geo, market, channel, device, and UTM, with case-insensitive operators evaluated before defaults.

Request transforms inject filter groups and modify queries, scoped by signals like context.customer.signedIn and context.customer.numberOfOrders.

A signed-in B2B buyer carrying customer tags can receive tag-scoped promotions, pins, and injected filters.

The pattern that scales is one tag per account. Tag a company's buyers, then point every promotion, pin, and filter that segment should see at that one tag.

You reuse the same tag for the next company without rebuilding anything, which is how you run merchandising per segment instead of a separate configuration per buyer.

Is your catalog legible to a procurement agent?

A catalog is legible to a procurement agent when the agent's request carries identity.companyLocationId.

With it, the agent gets that company's scoped products, collections, and price-list pricing, and raw SKUs resolve as lookups.

Without it, the agent gets retail or, for an unknown company, zero results, because scoping fails closed. Agent-readiness is the same identity discipline as buyer-readiness.

The operator question is shifting from "can my buyer find this" to "can an automated buyer find this." Procurement is starting to run through agents that query catalogs programmatically.

B2B buyers already expect self-serve channels to carry their full weight: McKinsey's B2B Pulse work shows a third of buyers prefer fully digital, rep-free purchasing across the whole buying process.

An agent is the next turn of that same wheel.

The mechanism does not change for a machine. The same identity scoping that serves a human serves an agent, on one condition: the caller passes identity.companyLocationId.

Pass it, and the agent receives the scoped products, the scoped collections, and the price-list pricing, with a raw SKU resolving as the exact lookup an agent sends.

Skip it, and the agent gets retail, or zero for an unknown company, because the system fails closed.

Get the identity right for humans, and you have already gotten it right for the agents arriving behind them.

How does one identity-scoped configuration come together?

The efficient B2B pattern is one configuration that scopes per company, not a separate build per buyer.

Pass companyLocationId on every request, confirm the catalog and price-list sync, verify pricing precedence, give part-number attributes keyword weight, and merchandise with customer tags and contextual conditions.

Identity does the scoping; you configure the rest.

Six steps turn the scope map into an operating model your team can run.

  1. Pass the identity. Make every B2B storefront or headless request carry identity.companyLocationId. The storefront owns this, since the field is not auto-resolved from the customer ID.
  2. Confirm the sync. Catalogs, products, price lists, and collections synced with the read_customers, read_publications, and read_price_lists scopes, so scoping has data to act on.
  3. Verify pricing precedence. Catalog price list first, then market, then default. Spot-check that a company buyer sees the negotiated price.
  4. Make part numbers findable. Confirm SKU lookups resolve, and give SKU, part-number, and spec attributes keyword weight.
  5. Merchandise by segment. Scope promotions and pins with customer tags and contextual conditions, driving company-specific curation by tagging a company's buyers and pointing rules at that tag.
  6. Treat fail-closed as a feature. An unknown company returning zero results is correct behavior. Build the storefront to handle that empty state rather than fall back to retail.

Identity scopes; you curate on top. That division of labor is what lets one configuration serve the tenth company as cheaply as the first.

How do you run a B2B search readiness check this week?

To audit B2B search readiness, run five checks per company against your live storefront and record pass or fail: scoped catalog, scoped collections, scoped price list, part-number findability, and agent-readability.

Every fail is a buyer who is mis-scoped to the wrong catalog. Run a representative sample of company contexts and the pattern shows fast.

For each company you sell into, or a representative sample, run the same five checks:

  1. Scoped catalog. Sign in as the company buyer or pass its companyLocationId, then confirm search returns only that catalog's products, no retail-only items.
  2. Scoped collections. Request an out-of-catalog collection directly and confirm it 404s or hides for that company, not the retail version.
  3. Scoped price list. Pull three best-sellers and confirm the buyer sees the negotiated price-list price, not retail.
  4. Part-number findability. Run five real part numbers from your catalog and confirm the exact item ranks first.
  5. Agent-readability. Fire a programmatic request carrying the company's companyLocationId and confirm it gets the scoped catalog, then fire one with a bogus company and confirm it returns zero results.

Any "fail" cell is a buyer mis-scoped to the wrong catalog, and the grid you produce maps exactly which buyers to fix first.

Run the checks, then book a demo and we'll run them live against your catalog, company by company, and show you exactly which buyers are mis-scoped right now.

Where to start

Shopify hands you the companies, the catalogs, and the price lists.

Identity-scoped search is what turns them into the right results for the buyer in front of you, whether that buyer is a person or an agent.

Run the readiness checks. The fails are the buyers still searching the retail store under a B2B login.

Book a demo →

FAQs

1. How does B2B search work on Shopify Plus? B2B search on Shopify Plus is identity-scoped.

When a storefront request carries identity.companyLocationId, search, browse, and recommendation results scope to that company's catalog: only the catalog's products appear, out-of-catalog collections are hidden, and pricing comes from the catalog's assigned price list.

A B2B catalog is not a retail catalog with a wholesale flag; it is effectively one catalog per company.

2. Can I scope search results to a company's B2B catalog and price list? Yes.

Passing identity.companyLocationId, a Shopify CompanyLocation GID, on the request restricts search and browse to that catalog's products, hides out-of-catalog collections, and returns the catalog's price-list pricing.

The field is not auto-resolved from the customer ID, so the storefront must pass it, and an unknown company location returns zero results because scoping fails closed.

3. How do I keep B2B buyers from seeing retail prices in search? Scope the request with companyLocationId so pricing resolves from the company's catalog.

Pricing resolves in order: the catalog price-list override first, then market pricing if Shopify Markets sync is on, then the default variant price.

A company buyer then sees their negotiated price-list price in search, not retail, which closes the most common B2B abandonment loop.

4. How do I make part numbers and SKUs findable in a large B2B catalog? Part numbers and SKUs are an intent-recognition and attribute-indexing job, not a synonym list.

A raw code like WKR04 is recognized as a SKU lookup and routed as its own query type.

Give SKU, manufacturer part number, and key spec attributes keyword weight so they carry findability. You configure which attributes carry keyword weight to match your catalog.

5. Can I merchandise differently for each company on Shopify B2B? Catalog scoping already gives each company different products, collections, and prices through companyLocationId, with no rule needed.

To differentiate merchandising on top, scope rules by customer tags, account status, purchase history, geo, and channel.

The repeatable pattern for company-specific curation is to tag a company's buyers, then attach promotions, pins, and filters to that tag.

6. Is my Shopify catalog legible to AI procurement agents? A catalog is legible to a procurement agent when the agent's request carries identity.companyLocationId.

With it, the agent receives that company's scoped products, collections, and price-list pricing, and raw SKUs resolve as lookups.

Without it, the agent gets retail results or, for an unknown company, zero results, because scoping fails closed.

Agent-readiness is the same identity discipline as buyer-readiness, driven by the same field.

7. What happens if a B2B buyer's company is unknown to search? Scoping fails closed. An unknown or unsynced companyLocationId returns zero results rather than leaking the retail catalog to the buyer.

This is correct, safe behavior, so the storefront should handle the empty state deliberately instead of falling back to retail results.

Deb Mukherjee · Ecom Growth Advisor

Deb Mukherjee is an Ecom Growth Advisor who writes about ecommerce search and merchandising for Layers, the enterprise search and merchandising platform built for Shopify Plus. He works with Plus brands on search relevance, merchandising, and the catalog-data work behind product discovery at scale.

Connect on LinkedIn