Skip to content
BolderBolder Developers
Esc
↑↓navigate↵open⌘Jpreview
On this page

Cart

Adding and updating line items, and how cart identity survives cross-origin, cookie-blocked headless integrations.

storefront.cart is an event emitter (see Emitter) wrapping the shop’s cart session.

storefront.cart.on('updated', function() {
  document.querySelector('#cart-count').textContent = storefront.cart.units
})

// Add by numeric product/variant id — see addItem below for the full signature
storefront.cart.addItem(productId, variantId, 1)

// Add by a product's URL slug instead — no need to look up its numeric id yourself,
// the server resolves it (product must have exactly one variant, or you'll need
// to resolve the variant id yourself and use addItem)
storefront.cart.quickAdd('aurora-runner', function(item) {
  if (item) console.log('added', item)
})
  • quickAdd(productIdOrSlug, fn?) — Add a product by numeric ID or by URL slug. A numeric-looking string/number is sent as product_id; anything else is sent as product_slug and resolved server-side. Respects onBeforeAdd (see Config Reference) the same way addItem does.
  • addItem(productId, variantId, quantity, formData?, fn?) — Add or increase quantity of a line item. Pass variantId: -1 to let the server pick the product’s default/only variant. formData.product_slug resolves a slug the same way quickAdd does internally.

Cross-origin cart identity

The cart session is identified server-side by an id (_btc_oid) that hosted themes carry in a same-site cookie automatically. A headless page served from a different origin than apiBase — true for almost any headless integration that isn’t proxied under the shop’s own domain — can’t rely on that cookie the normal way: SameSite/Secure cross-site cookie rules would require the API to be served over HTTPS just for the cookie to be honored.

To sidestep that entirely, the SDK’s cart client doesn’t depend on the cookie:

  • Every cart response includes the cart’s id (cart.id), which the SDK caches in localStorage and sends back as an X-Cart-Token header on subsequent cart requests — a plain custom header, not a cookie, so none of the SameSite/HTTPS requirements apply. Server-side, cart_cookie (the single method every cart-resolving code path in app.rb goes through) accepts either the cookie or this header, in that order.
  • The one exception is the checkout button itself: it’s a real <form method="post"> full-page navigation (via cart-table-v3), which can’t carry a custom header. It carries the same id as a hidden cart_token field instead, which cart_cookie also accepts as a final fallback.
  • The cookie is still set and read too (unchanged for hosted themes, and same-origin headless integrations get it for free) — the token/field are purely an additional path, not a replacement.

This means cart identity survives even with cookies fully blocked (verified by wiping all cookies mid-session and continuing to add items / checking out — same cart throughout).

Was this page helpful?