Cart And Checkout
The Shoppex SDK manages the entire purchase flow: cart state, coupon validation, price formatting, and checkout handoff. All cart data lives in the browser (localStorage) and is scoped per store.The SDK handles cart persistence automatically. You never need to read or write localStorage directly.
Quick Example
Cart API
addToCart
Adds an item to the cart, or increments its quantity if it already exists.| Parameter | Type | Default | Description |
|---|---|---|---|
productId | string | required | Product ID |
variantId | string | required | Variant ID |
quantity | number | 1 | Units to add |
options | CartAddOptions | undefined | Addons, custom fields, price overrides |
getCart
Returns the current cart contents as an array.getCartItemCount
Returns the total quantity across all cart items (sum of allquantity values). For the number of distinct line items, use getCartStats().item_count.
updateCartItem
Updates an existing cart item. You can change quantity, addons, custom fields, or price data.| Parameter | Type | Description |
|---|---|---|
productId | string | Product ID of the item to update |
variantId | string | Variant ID of the item to update |
updates | Partial<Omit<CartItem, 'product_id' | 'variant_id'>> | Fields to merge into the item |
removeFromCart
Removes an item from the cart entirely.clearCart
Empties the entire cart.Types
CartItem
Each entry in the cart array is aCartItem:
| Field | Type | Required | Description |
|---|---|---|---|
product_id | string | yes | Product ID |
variant_id | string | yes | Variant ID |
quantity | number | yes | Units of this line item |
addons | CartAddon[] | no | Attached addons |
custom_fields | Record<string, string> | no | Key-value custom data (e.g. engraving text) |
price_variant_id | string | no | Override pricing variant (sent to the API during checkout) |
price_data | { unit_price: number } | no | UI-only unit price override for theme-side calculations (not sent during checkout) |
CartAddon
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Addon ID |
quantity | number | no | Addon quantity |
CartAddOptions
Passed as the fourth argument toaddToCart:
| Field | Type | Description |
|---|---|---|
addons | CartAddon[] | Addons to attach |
custom_fields | Record<string, string> | Custom key-value data |
price_variant_id | string | Override pricing variant |
price_data | { unit_price: number } | UI-only unit price override (does not affect invoice/checkout pricing) |
During checkout, the SDK currently sends
price_variant_id to the backend, but ignores price_data. So price_data can change what your cart UI displays, but it will not change the final invoice total.Cart Storage
The SDK persists the cart inlocalStorage, scoped per store slug.
| Key | Purpose |
|---|---|
shoppex_cart_{storeSlug} | Cart items array |
shoppex_cart_meta_{storeSlug} | Cart metadata (version, timestamps) |
shoppex_cart_backup_{storeSlug} | Backup of cart items (created before checkout) |
shoppex_cart_backup_meta_{storeSlug} | Backup metadata |
You should never read or write these keys directly. Use the SDK methods. The key format is documented here for debugging purposes only.
Cart UI Updates
When the cart changes, your UI needs to re-render. The SDK does not emit events automatically. The recommended pattern is a thin event wrapper in your theme.Recommended Pattern: shoppex:cart-changed
Dispatch a CustomEvent after every cart mutation, then listen for it wherever your UI shows cart state.
- Emit Helper
- Usage (Vanilla)
- Usage (React Hook)
shoppex:cart-changed is a theme-level pattern, not a built-in SDK feature. You own the dispatch and the listener.Coupon Validation
Validate a coupon code before checkout. Optionally scope validation to a specific product. UsevalidateCoupon(code, productId) on a product page, and validateCoupon(code) when validating against the current cart.
| Parameter | Type | Required | Description |
|---|---|---|---|
code | string | yes | Coupon code to validate |
productId | string | no | Scope validation to a single product |
SDKResponse<CouponValidation> shape: check res.success and res.data?.valid together.
If you call
validateCoupon(code) without productId, the SDK validates against the current cart. If the cart is empty it returns { success: false, message: 'Cart is empty' }.Price Formatting
The SDK providesformatPrice to format currency values using Intl.NumberFormat.
| Parameter | Type | Default | Description |
|---|---|---|---|
amount | number | string | required | Price value in major units (e.g. 19.99, not 1999) |
currency | string | store default | ISO 4217 currency code |
locale | string | browser default | BCP 47 locale tag |
formatPrice passes the value directly to Intl.NumberFormat.format(). Use major units (e.g. 19.99 for $19.99), not minor units / cents.Checkout
checkout()
Initiates the checkout flow. By default, the customer is automatically redirected to the hosted checkout page.CheckoutOptions
| Field | Type | Default | Description |
|---|---|---|---|
autoRedirect | boolean | true | Redirect the browser to the checkout URL automatically |
email | string | undefined | Pre-fill the customer email on checkout |
coupon | string | undefined | Apply a coupon code |
locale | string | undefined | Reserved for future use — not currently processed by the backend |
CheckoutResult
checkout() returns a CheckoutResult:
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the checkout was created successfully |
redirectUrl | string | undefined | The hosted checkout URL |
invoiceId | string | undefined | The created invoice ID |
message | string | undefined | Error or status message |
Checkout Flow
Custom Checkout Flow (No Auto-Redirect)
If you need to display a confirmation screen or track analytics before redirecting, disable auto-redirect:buildCheckoutUrl
Builds the checkout URL without triggering redirect or clearing the cart. Useful for preview links or “open in new tab” flows.checkout() — accepts a coupon string or a CheckoutOptions object.
Cart Utilities (Advanced)
These methods are available for advanced use cases like cart recovery, migration, and diagnostics.getCartStats()
getCartStats()
Returns a snapshot of current cart state and metadata.CartStats:
| Field | Type | Description |
|---|---|---|
item_count | number | Distinct line items |
total_quantity | number | Sum of all item quantities |
last_modified | number | Timestamp of last cart change |
version | number | Cart version counter |
has_backup | boolean | Whether a backup exists |
integrity_valid | boolean | Whether the cart passes integrity checks |
total_price | number | Computed total price |
total_price_is_estimate | boolean | Whether the price is an estimate (e.g. missing price data) |
createCartBackup() / restoreCartFromBackup()
createCartBackup() / restoreCartFromBackup()
Manually create or restore a cart backup. The SDK automatically creates a backup before checkout, but you can also trigger this manually.
validateCartIntegrity()
validateCartIntegrity()
Checks that the cart data structure is consistent and valid.
mergeBaskets(items)
mergeBaskets(items)
Merges an external array of cart items with the current cart. Useful for syncing carts across devices or migrating from another system.
moveBasketItem(fromProductId, fromVariantId, toProductId, toVariantId)
moveBasketItem(fromProductId, fromVariantId, toProductId, toVariantId)
Moves a cart item from one product/variant combination to another. Useful for variant swaps.
Common Mistakes
Forgetting to call init() before cart methods
Forgetting to call init() before cart methods
All SDK methods require
shoppex.init(slug) to have been called first. Without it, the SDK does not know which store’s cart to operate on.Not checking res.success AND res.data?.valid for coupons
Not checking res.success AND res.data?.valid for coupons
The coupon validation response has two levels of success. Both must be checked.
Reading localStorage directly instead of using SDK methods
Reading localStorage directly instead of using SDK methods
The internal storage format may change between SDK versions. Always use
getCart(), getCartItemCount(), and other SDK methods.Expecting the SDK to emit cart-changed events automatically
Expecting the SDK to emit cart-changed events automatically
The SDK does not dispatch DOM events. The
shoppex:cart-changed pattern is a theme-level convention that you implement yourself. See Cart UI Updates above.Not clearing the cart after manual redirect
Not clearing the cart after manual redirect
When using
autoRedirect: false, the SDK does not clear the cart for you. Call clearCart() after redirecting.