Skip to main content
Use the base @commercengine/storefront package for React SPAs. Keep the SDK factory in one module, use the public accessor for catalog reads, and initialize one live session for cart, authentication, account, and order flows.

Installation

For the recommended checkout experience:

Configure the storefront

src/lib/storefront.ts
The SDK instances are stable and can be imported directly. A React context is optional; do not add one merely to wrap an already shared singleton.

Root bootstrap

Establish the anonymous session once when the application starts. Public catalog rendering does not need to wait for this call.
src/providers.tsx
ensureAccessToken() is safe to centralize at startup. Do not repeat it before every session method.

Public catalog queries

src/hooks/use-products.ts
Use searchProducts() rather than listProducts() when the page needs facets, filtering, or search. The search response contains flattened sellable Items/SKUs. Hosted Checkout supplies cart, login, addresses, fulfilment, discounts, payment, and confirmation. When the React app also uses the Storefront SDK, the Storefront SDK must own the session. Update the storefront configuration to send SDK token changes to checkout:
src/lib/storefront.ts
Initialize checkout once after session bootstrap and clean it up when the root unmounts:
src/storefront-bootstrap.tsx
Mount it once inside the query provider:
Then use the checkout hook in any component:
src/components/cart-button.tsx
src/components/add-to-cart-button.tsx

Custom authentication UI

Build custom auth only when the storefront needs login state outside Hosted Checkout, such as account, order, loyalty, or saved-address pages. An OTP form has two explicit steps:
After login, invalidate account and cart queries. Commerce Engine merges the active anonymous cart automatically; do not create a new cart. Logout preserves the returned anonymous session:
Do not call sdk.clearTokens() after successful logout.

Custom cart: advanced

Use a custom cart only when the storefront needs a fully custom cart/checkout UI. Hosted Checkout already handles these concerns.

First add versus later mutations

Commerce Engine does not create an empty cart.
addDeleteCartItem() accepts the desired total quantity, not a delta. Call this helper inside the serialized mutation queue with the latest returned cart, so repeated Add to Cart actions increment the existing line rather than resetting it to 1.

Serialize cart mutations

Every mutation returns the full updated cart. Concurrent mutations can race and overwrite local state with an older response. Queue mutations with concurrency 1 or use an async mutex.

Query shape

Display cart.cart_items and use cart.to_be_paid as the final amount. Check expires_at when restoring a persisted cart ID.

Product detail state

For products with variants:
  • use option query parameters as canonical URL state
  • resolve a variant only when all option keys match its associated_options
  • disable impossible or unavailable combinations
  • keep Add to Cart disabled until the selected variant is purchasable
  • pass the selected variant.id
For simple products, pass variant_id: null. See Catalog and the production starters for the full model.

Error and loading states

A production React storefront should distinguish:
  • first load from background refresh
  • empty result from request failure
  • confirmed 404 from transient server failure
  • checkout not ready from checkout error
  • anonymous user from invalid session
Use query error boundaries or route-level error components, but continue checking the SDK’s { data, error, response } result inside each query function.

Production checklist

React production examples

Compare the Vite React storefronts with the Next.js and TanStack Start implementations to separate React component patterns from framework rendering patterns.