Documentation Index
Fetch the complete documentation index at: https://docs.uselayers.com/llms.txt
Use this file to discover all available pages before exploring further.
Installation
npm install @commerce-blocks/sdk
Configuration
Required configuration
| Option | Type | Required | Description |
|---|
token | string | Yes | Layers API public token |
sorts | Sort[] | Yes | Sort options (see below) |
facets | Facet[] | Yes | Facet fields (see below) |
Sort:
| Property | Type | Required | Description |
|---|
name | string | Yes | Display name shown to users |
code | string | Yes | Sort order code configured in Layers |
scope | ('search' | 'collection')[] | No | Restrict to specific controllers. Omit to allow everywhere. |
order | number | No | Display order (lower numbers appear first) |
Facet:
| Property | Type | Required | Description |
|---|
name | string | Yes | Display name shown to users |
code | string | Yes | Attribute code in Layers (e.g. options.color, vendor, variants.price) |
Optional configuration
| Option | Type | Description |
|---|
attributes | string[] | Product attributes to fetch |
baseUrl | string | Custom API URL |
fetch | CustomFetch | Custom fetch implementation (SSR, testing) |
context | Context | Default market and shopper context applied to every controller (see Context) |
Context
Pass market and shopper context to personalize results across all controllers. Set it globally on the client config, per-query on execute(), or both — per-query context shallow-merges with and overrides the global context.
import { createClient } from '@commerce-blocks/sdk'
const { data: client } = createClient({
token: 'your-token',
sorts: [{ name: 'Featured', code: 'featured' }],
facets: [{ name: 'Color', code: 'options.color' }],
context: {
market: 'US',
geo: { country: 'US' },
shoppingChannel: 'web',
},
})
// Per-query override — merges with global context
const collection = client.collection({ handle: 'shirts' })
await collection.execute({
context: { geo: { country: 'CA', province: 'ON' } },
})
// Effective context: { market: 'US', geo: { country: 'CA', province: 'ON' }, shoppingChannel: 'web' }
Context fields:
| Field | Type | Description |
|---|
geo | GeoLocation | Geographic location: { country, province, city } |
market | string | Market identifier |
productsInCart | CartProduct[] | Products currently in the shopper’s cart |
productsPurchased | CartProduct[] | Previously purchased products |
priorSearches | PriorSearch[] | Recent searches: { searchQuery, hadClick, hasResults } |
marketing | Marketing | UTM-style attribution: { source, medium, campaign, term } |
customer | CustomerContext | Customer profile: { signedIn, returning, numberOfOrders, ... } |
shoppingChannel | 'web' | 'app' | Shopping channel the request originates from |
custom | Record<string, unknown> | Custom key-value pairs forwarded to merchandising strategies |
CartProduct:
| Property | Type | Required | Description |
|---|
title | string | Yes | Product title |
price | number | No | Unit price |
type | string | No | Product type |
productId | string | No | Product ID |
variantId | string | No | Variant ID |
quantity | number | No | Quantity in cart |
options | Record<string, string> | No | Selected options (e.g. { Size: 'L' }) |
CustomerContext:
| Property | Type | Description |
|---|
signedIn | boolean | Whether the shopper is signed in |
returning | boolean | Whether the shopper has visited before |
numberOfOrders | number | Lifetime order count |
averageOrderValue | number | Average order value |
daysBetweenOrders | number | Average days between orders |
daysSinceLastOrder | number | Days since the most recent order |
daysSinceOldestOrder | number | Days since the first order |
totalSpent | number | Lifetime spend |
Use the global context for values that rarely change within a session (market, channel, customer profile). Use per-query context for values that vary by page or interaction (current cart, geo override).
Product configuration
| Option | Type | Description |
|---|
currency | string | Currency for price formatting |
formatPrice | (amount, currency) => string | Custom price formatter |
swatches | Swatch[] | Color swatch definitions (see below) |
includeMeta | boolean | Include _meta in results (applied rules, variant breakouts) |
Swatch:
| Property | Type | Required | Description |
|---|
name | string | Yes | Option name this swatch belongs to (e.g. Color) |
value | string | Yes | Option value to match (e.g. Red) |
color | string | null | Yes | CSS color value (e.g. #ff0000) |
imageUrl | string | null | Yes | URL to a swatch image. Use when a color alone is not sufficient. |
Transforms post-process results before caching. Filter aliases map URL-friendly keys to API property names.
| Option | Type | Description |
|---|
transforms.product | ({ base, raw }) => object | Extend products with custom fields |
transforms.collection | (result, raw) => result | Transform collection results |
transforms.search | (result, raw) => result | Transform search results |
transforms.block | (result, raw) => result | Transform block results |
transforms.searchContent | (result, raw) => result | Transform content search results |
transforms.filters | (filters) => FilterGroup | Custom filter transformation |
filterAliases | FilterAliases | URL-friendly filter key mapping |
Once configured, transforms and aliases are applied automatically:
import { createClient } from '@commerce-blocks/sdk'
const { data: client } = createClient({
token: 'your-token',
sorts: [{ name: 'Featured', code: 'featured' }],
facets: [{ name: 'Color', code: 'options.color' }],
attributes: ['body_html'],
transforms: {
product: ({ raw }) => ({
description: raw.body_html ?? '',
rating: raw.calculated?.average_rating ?? 0,
}),
},
filterAliases: {
color: 'options.color',
size: 'options.size',
brand: { property: 'vendor', values: { nike: 'Nike', adidas: 'Adidas' } },
},
})
// Aliases resolve automatically
const collection = client.collection({ handle: 'shirts' })
await collection.execute({ filters: { color: 'Red', brand: 'nike' } })
// Products now include description and rating from the product transform
Cache configuration
| Option | Type | Description |
|---|
cacheLimit | number | Max entries in cache |
cacheLifetime | number | TTL in milliseconds |
storage | StorageAdapter | Custom storage adapter for cache persistence (defaults to localStorage in browser) |
initialData | CacheData | Pre-populate cache at initialization |
restoreCache | boolean | Auto-restore from storage on init (default: true) |
Singleton access
After initialization, access the client anywhere:
import { getClient, isInitialized } from '@commerce-blocks/sdk'
if (isInitialized()) {
const { data: client } = getClient()
if (client) {
// Use client
}
}
Important notes
All SDK methods return a Result type instead of throwing exceptions. Always check for result.error before accessing result.data.