Skip to main content

Installation

This page documents @commerce-blocks/sdk v3 (3.x). For v2 integrations, see Upgrade to v3.

Loading from a CDN

The SDK ships as a pure ES module with no Node-only dependencies, so it works in the browser with no build step. Use this when you’re integrating directly into a Shopify theme, a static HTML page, or any environment where you don’t run npm install. unpkg serves the published npm package directly. Add the ?module query string and unpkg rewrites the SDK’s imports into sibling unpkg URLs, so the browser resolves the entire module graph without a bundler.
Pin the version explicitly in production so a new release never silently changes behavior on your storefront. unpkg accepts a major (@3), minor (@3.0), or exact (@3.0.0) tag. For example, https://unpkg.com/@commerce-blocks/sdk@3?module. See the SDK changelog for the latest version.

esm.sh

esm.sh is an alternative ESM CDN that pre-bundles the SDK and its dependencies into a single file.

jsDelivr

jsDelivr mirrors npm with its own ESM transform. Use the +esm suffix to get a browser-compatible bundle.

Import maps

If you load multiple modules from a CDN and want to keep imports short, declare an import map once and use bare specifiers everywhere else:

Reusing the SDK across modules

createSDK registers the SDK in a singleton, so any later <script type="module"> block can pull it back with getSDK. Use this pattern for theme integrations where one snippet boots the SDK and many other sections consume it.
The token sources map to createSDK() options as follows:
When pulling the SDK from a CDN, also add <link rel="modulepreload" href="https://unpkg.com/@commerce-blocks/sdk@3?module" /> to your <head>. The browser then starts fetching the module during HTML parse instead of waiting for the first <script type="module"> to execute.

Configuration

Required configuration

Optional configuration

Identity

Using the Layers app embed? Leave identity unset. On a Shopify theme with the app embed enabled, the Storefront Pixel adds the device, session, and customer identifiers to every Layers request the page makes, including the SDK’s. It only fills identity when the request doesn’t already carry one, so an identity you pass replaces the pixel’s values instead of adding to them. Don’t read the pixel’s cookies and pass them back in. The example below is for headless and custom storefronts that don’t load the app embed.
identity carries the device, session, and customer identifiers attached to every request and tracking event. Pass a static Identity object or a () => Identity resolver. A resolver is read live per call, so a login or session rotation is picked up automatically. Per-call identity overrides the config fields.

Context

Using the Layers app embed? Don’t hand-build context. With the app embed enabled, the Storefront Pixel wraps fetch and fills context on every Layers request: market, locale, and currency from Shopify, productsInCart and productsPurchased, the customer profile, B2B company location, and marketing (UTM parameters and click IDs). Layers fills geo from the shopper’s location on the server. The request’s own context wins field by field, so a hand-built market, geo, or productsInCart replaces the embed’s value and can disagree with it (for example, a cart snapshot that goes stale after an add to cart).Fields a theme still sends itself, because the embed doesn’t:
  • freeShippingThreshold, in store currency (not cents), for free-shipping blocks.
  • custom keys your merchandising rules target. The pixel merges your custom keys with the ones it captures instead of replacing them.
  • priorSearches, only if you use search-anchored blocks.
  • shoppingChannel: 'app' from a mobile app webview that Layers doesn’t detect on its own. Requests default to web.
The full example below is for headless and custom storefronts that don’t load the app embed.
Pass market and shopper context on each request to personalize results. Context is a per-request parameter: set it when you create the controller, pass it to get(), or both. get() options merge with the controller’s initial params at the top level, so a context passed to get() replaces the controller’s context value entirely.
Context fields: CartProduct: CustomerContext:
Set context on the controller for values that rarely change within a session (market, channel, customer profile). Use per-query context in get() for values that vary by page or interaction (current cart, geo override).

Swatch configuration

Use swatches to map option values to colors or images. Swatches are matched by option name and value. Swatch:

Transforms

Transforms post-process response data before it is cached and returned. Once configured, transforms are applied automatically:

Cache configuration

The SDK keeps controller responses in an in-memory LRU cache with TTL eviction for the life of the page. storage is optional and persists prepared search IDs for reuse across pages. Pass localStorage, sessionStorage, or a custom storage backend when you need cross-page prepare reuse.

Singleton access

After initialization, access the SDK anywhere:

Important notes

All SDK methods return an ApiResult type ({ data, error }) instead of throwing exceptions. Always check for error before accessing data.

Troubleshooting

401 Unauthorized on the first request

If the first get() returns an ApiError with status 401 (for example, POST /api/storefront/v1/browse/frontpage 401), the storefrontAccessToken passed to createSDK() is missing, invalid, or expired. On Shopify, the storefront token is delivered by the app embed as a <script id="layers-config" type="application/json"> tag in the theme <head> (backed by the embed_settings metafield). If the tag is missing or its storefrontApiToken is empty:
  1. Confirm the Layers app is installed and the theme app extension is enabled in Online Store → Themes → Customize → App embeds.
  2. Trigger a resync from Settings → Integrations in the Layers dashboard so the metafield is written. See Collection & app metafields.
  3. View the page source and confirm #layers-config now contains a non-empty storefrontApiToken.
If the tag is still not populated after a resync, contact Layers support.

"The selected sort order code is invalid."

The sort you passed to get() does not match a sort order configured in Layers for the current collection, or the sort order no longer exists in the Layers dashboard.
  • Fetch available sort orders at runtime with sdk.sortOrders({ collectionHandle: 'shirts' }).
  • Use a code from the returned sort orders when calling collection.get() or creating a collection controller with sort.
  • Omit sort from get() to fall back to the collection’s default sort order.

"The selected facet is invalid."

A filterGroup you passed references an attribute that is not configured as a facet in Layers.
  • Fetch available facets at runtime with sdk.facets({ collectionHandle: 'shirts' }).
  • Attribute codes are case-sensitive and must exactly match the attribute code shown in the Layers dashboard (for example, your-attribute, not Your-Attribute).
  • Remove filters that reference attributes no longer configured as facets.