What Layers syncs
When Markets sync is enabled, Layers ingests four kinds of data from your Shopify Markets configuration:
Sync is driven by
markets/create, markets/update, markets/delete, and product update webhooks — there’s no manual refresh required in normal operation. You can trigger a one-off refresh from the Catalog → Sync dashboard if you need to backfill historical data.
Currency rate refresh
Shopify recalculates the exchange rates behind market pricing on its own schedule and doesn’t emit a webhook when it does. To keep localized prices current, Layers polls each store’s Shopify currency settings every 15 minutes. When therateUpdatedAt timestamp on any enabled currency changes, Layers resyncs market pricing for the affected variants so shoppers see the new converted prices on the next request.
To keep large catalogs from re-pricing on every small FX tick, Layers refreshes market pricing at most once every six hours per store. Layers coalesces rate changes detected within that window and applies them on the next refresh. The poll itself only runs while the application mode is Adjust pricing only or Restrict to market catalog.
Markets sync is automatically disabled while the Global-E integration is active. Global-E manages its own localized pricing through a country rate table, so the two systems don’t run side-by-side. See Discount Entitlements for related Global-E details.
How Layers picks the market for a request
Every Search, Browse, and Blocks request can carry acontext.geo.country field. Layers resolves that country into a market using the synced region table:
- The storefront pixel and the JavaScript SDK populate
context.geo.countryautomatically from Cloudflare’s edge geolocation. Custom integrations should pass the shopper’s country explicitly (ISO 3166-1 alpha-2, e.g."US","GB","JP"). - Layers looks up which market that country belongs to.
- The resolved market ID is attached to the request and used downstream for filtering, pricing, and meta.
context.market. It accepts a two-letter country code, a numeric Shopify Market ID, or a Shopify Market GID (e.g. "gid://shopify/Market/12345"). Like every other market-related value, it must still be nested inside the request’s context object.
If context.geo.country is omitted, or if the country doesn’t map to any active market, Layers falls back to the primary market — the market marked as primary in Shopify.
Example request context
Application modes
Layers exposes three modes for how aggressively Markets data is applied to storefront responses. The mode is set in the Markets setting in search settings and defaults to Ignore markets for new stores.Ignore markets
Markets sync is paused and Markets data is not applied. Every shopper sees the full catalog and the variant’s default price, regardless of which market their country maps to. Layers stops polling Shopify for currency rate updates and stops running per-market pricing refreshes for the store while the mode is Ignore markets. Use this mode when you’ve enabled Markets in Shopify but don’t yet want the catalog to localize. When you switch back to Adjust pricing only or Restrict to market catalog, Layers automatically starts a catalog-wide market pricing refresh. Newly opted-in stores don’t have to wait for the next webhook to backfill.Adjust pricing only
Layers applies the resolved market’s price and currency to every variant in the response. The catalog itself is not filtered by market membership. Every shopper sees every product, priced in their market’s currency. This mode is the right choice when:- You want localized prices without hiding any products, even if some products aren’t published to every market in Shopify.
- You’re rolling out market-aware pricing and don’t want visibility changes to ship at the same time.
Restrict to market catalog
The full Markets experience. Layers applies the resolved market’s pricing and filters products to the ones published to that market. Products whoseavailable_market_ids array includes the resolved market are returned. Products published to other markets, but not the resolved one, are excluded from search, browse, and block results.
This is what most multi-region stores end up running. Combine it with the available_market_ids facet attribute if you also want merchandisers to filter or segment by market inside Lab.
A product whose
available_market_ids is empty or missing is treated as visible in every market, not “available nowhere”. Layers can’t distinguish a product Shopify reports as unpublished everywhere from one whose market sync hasn’t populated yet, so Restrict to market catalog mode errs on the side of showing it. Once Markets sync populates availability data, only products explicitly published to the resolved market are returned.
Only Restrict to market catalog filters search, browse, block, and facet responses (including facet-range counts on price) by
available_market_ids. Adjust pricing only localizes pricing without touching the catalog.
What shows up in API responses
When a market is resolved for a request, Layers enriches the response in two places:Variant pricing
In Restrict to market catalog and Adjust pricing only modes, theprice and compare_at_price on each variant (and the rolled-up price_range on the product) reflect the pricing Shopify returned for the shopper’s specific country within the resolved market — not a single collapsed currency for the whole market. A shopper in France browsing a USD-base International market sees the variant’s EUR price; a shopper in Japan on the same market sees the JPY price.
If Layers doesn’t have a price stored for the exact (market, country) pair — for example, the product was created before the market was published to, or context.geo.country was not supplied on the request — it falls back to the variant’s default price.
_meta.pricing
When market-aware pricing applies, the response includes a _meta.pricing object:
currency_code reflects the shopper country’s native currency inside the resolved market — the same currency the returned price and compare_at_price are expressed in. Use it on the storefront to format prices consistently — Intl.NumberFormat(locale, { style: "currency", currency: currency_code }) is the usual pattern.
The same
_meta.pricing shape is used by the Global-E integration when active. The shape of the object is stable across both integrations so your frontend doesn’t need to branch on which pricing provider is in play. When Shopify Markets is the active source, currency_decimal_places may be omitted (Shopify does not expose it) — derive decimals from the ISO currency_code if you need them.available_market_ids on products
Every product carries an available_market_ids array regardless of which mode you’re in (provided Markets sync is enabled). You can read it directly from any search, browse, or block result.
You can also expose available_market_ids as a filterable catalog attribute of type number to use it in merchandising rules, facets, and sort orders. See Filtering by Shopify Market for the setup steps.
Common patterns
Localize prices without hiding any products
Set the mode to Adjust pricing only. Shoppers see the full catalog, priced in their market’s currency, whether or not every product is published to every market in Shopify.Region-specific soft launches
Run in Restrict to market catalog mode. Publish a new product to a single market in Shopify, and that product will only appear in search and browse responses wherecontext.geo.country resolves to that market.
Per-market merchandising rules
Onceavailable_market_ids is exposed as a catalog attribute, you can write merchandising rules whose conditions or actions reference it — for example, pin a hero product in the EU market but not in the US. Combine with contextual conditions on geo.country for finer geo targeting than market-level rules.
Auditing what a shopper in country X sees
Passcontext.geo.country explicitly in a request from your own machine. The response will reflect whatever a real shopper in that country would see — same market, same pricing, same filtered catalog.
Limitations
- One market per request. Layers resolves exactly one market per request from
context.geo.country. There’s no notion of “multi-market” results in a single response. - Currency conversion is read from Shopify. Layers does not do its own FX — the price served is exactly what Shopify’s contextual pricing returned for the shopper’s country. If Shopify hasn’t computed a price for a given variant in a given
(market, country)pair, Layers falls back to the default variant price — even though that price is in the store’s primary currency. - A shopper country is required for market pricing. Requests that omit
context.geo.countryfall back to the variant’s default price and skip market pricing, even when a market is otherwise resolvable. See the warning under How Layers picks the market for a request. - Restrict to market catalog can hide products from anonymous shoppers. Anonymous traffic from a country with no resolvable market lands on the primary market. Make sure your primary market’s product publishing covers the products you want anonymous visitors to see.
FAQ
Q: Can I use Shopify Markets alongside B2B catalogs?A: Yes. B2B catalog rules win for buyers signed in to a company location. Markets apply to everyone else. See B2B Catalogs for the precedence rules. Q: Do I need to call a different endpoint for each market?
A: No. Every storefront endpoint accepts
context.geo.country and resolves the market automatically.
Q: What happens if Shopify Markets is disabled mid-traffic? A: Layers continues serving cached data until the next webhook arrives, then disables sync. The application mode reverts to Ignore markets so shoppers immediately see the unfiltered catalog and default pricing. Q: How do I test a specific market locally?
A: Pass the country code explicitly in
context.geo.country — for example, "DE" to simulate Germany. Cloudflare won’t override the value if it’s already set.