For the complete documentation index, see llms.txt. This page is also available as Markdown.

Bundle SDK

Reference for the Elite Bundle Builder SDK: live bundle state, steps, cart, discount and actions for custom Shopify bundle storefronts.

Live bundle state and actions for custom storefront UIs. One SDK covers both bundle types: build-your-own bundles and multi-option bundles.

Available after the elite:byob:ready event fires. null when no bundle is on the current page, and the whole sdk object is absent unless SDK access is enabled in Settings → Developer SDK.

const sdk = window.eliteBundle.sdk?.byob;

Read the state fresh each time you use it. The object is replaced on every update, so a reference you stashed earlier will go stale.


Build-your-own and multi-option, one shape

A multi-option bundle is a bundle whose every step holds exactly one item. That is why there is no separate MOB SDK — the same steps, cart and checkout describe both:

Build your own
Multi-option

steps

the steps the shopper moves through

the options the bundle is built from

cart

everything the shopper picked

one line per option

pick an item

addToCart (adds / increments)

selectOne (replaces that option's pick)

add to cart

checkout()

the theme's own Add to cart button, which the app hooks

Read steps[i].optionMode to tell how an option is filled: "single_product_options" means the shopper builds a variant from one product's own options (Colour → Size); anything else means they pick from a list.


State

bundleId

string — Shopify product ID of the bundle.

steps

Step[] — the steps that show for the current picks (options, for a multi-option bundle), each with its fetched products. A step whose Show this step condition doesn't hold is left out, and changes as the shopper picks. A step set to Show it locked stays in, with locked: true and unlockRemaining (items, or money in the shopper's currency, still needed): show its products, but canAddToStep is false for it and its picks and minimum don't count.

The limits live under rules, not on the step itself. An "amount" limit is in the shop's currency, before discounts; compare it with cart prices times window.Shopify.currency.rate.

When showVariantAsIndividualCard is on, each variant is surfaced as its own entry with a synthetic id and a title suffixed by the variant name. Use sourceProductId whenever you need the real product.

cart

CartItem[] — the current selection.

cartTotal · cartTotalFormatted · cartCount

number · string · number — the sum of price × quantity, that sum run through the store's money format, and the total item count. Free gift items (isGift) are left out of all three: they cost nothing and count toward no tier or limit.

On a subscription, cartTotal and cartTotalFormatted are the bundle's total on the chosen plan, before the bundle discount. This applies while the shopper has a subscription selected in the bundle's purchase-options picker (see Subscriptions). Tier progress uses the same total. The cartTotal in the elite:byob:cart-change event follows the same rule.

addOnsTotal

number — the add-on fees of the cart's items, in the shopper's currency. It is not in cartTotal: add it for the amount the shopper pays. The bundle discount never applies to it.

canCheckout

boolean — every requirement is met: the bundle-wide minimum, plus the minimum of each step that is showing. Gate your add button on this.

bundleAddOns · details · detailsComplete

Array<{ id, title, type, required, choices, showIf? }> · Record<string, string> · boolean — the bundle add-ons, filled in once for the whole bundle (Offer → Add-ons: gift message, To & From, delivery date), titles and choices in the shopper's language; what the shopper has filled in so far (add-on id → text, a choice's id, or "1" for a ticked checkbox); and whether every required one is filled in. type is one of text, textarea, email, date (YYYY-MM-DD), checkbox, radio.

showIf ({ addOnId, choiceId? }) marks one that shows only while the add-on addOnId, earlier in the list and itself shown, is filled in (a ticked box, any text, an address that looks like an email, a date) or, with choiceId, set to that choice. Render it only then: while hidden it isn't required, so detailsComplete ignores it, and its answer isn't sent or charged even if setDetails passed one.

isTierMaxReached

boolean — the cart has reached the highest quantity tier, so there is no further discount to unlock. Only meaningful for quantity-based tiers.

isLoading · error

boolean · string | null — error is a single shopper-facing message; the diagnostic detail goes to the browser console.

isCheckingOut · checkoutError

boolean · string | null — in-flight and failure state for the add to cart.

discountConfig

DiscountSettings — the bundle's discount.

minValue is a count when tierBasedOn is "quantity" and a money amount when it is "order_total". A multi-option bundle's flat discount is expressed as a single tier with minValue: 0, so it always applies.

globalRules

GlobalRules — the bundle-wide rules from Config → Rules → Whole bundle.

An "amount" limit is in the shop's currency, before discounts. You rarely need to check it yourself: canCheckout and canAddToStep already do. Read it to show a message such as "Spend $20 more":


Actions

formatPrice(amount)

Formats an amount using the store's money format.

addToCart(product, variantId, stepId?, addons?, quantity?)

Adds one unit, or quantity. stepId defaults to product.stepId. With addons, the same variant answered differently is a separate cart item. A required add-on is not checked here: check it before calling, as quick view does.

It can silently do nothing — when the bundle-wide maximum is reached, when the step's own limit is reached, or when the step allows only one of each product and that product is already in. Check canAddToStep(stepId, price) first if you need to know.

selectOne(product, variantId, stepId?)

Multi-option bundles. Makes this the step's one and only pick, replacing whatever was selected before. Use this rather than addToCart for options — addToCart would leave two items in the same option.

removeFromCart(variantId, stepId?) · updateQuantity(variantId, delta, stepId?, itemId?)

Remove a line, or change its quantity by delta. A quantity of zero or less removes the line. updateQuantity is subject to the same limits as addToCart and will no-op rather than exceed them. One variant can be several items (each with its own add-on answers): pass the item's id as itemId to change that one; without it, the variant's latest item changes.

getItemQuantity(variantId, stepId?)

number — how many of this variant are in the cart.

isStepFull(stepId) · canAddToStep(stepId, price?)

boolean — whether the step has hit its own maximum, and whether one more item may be added. canAddToStep also accounts for the bundle-wide maximum, so it can be false even for a step with no limit of its own. Pass the variant's price for amount limits: a $30 item may not fit where a $10 one does. On a free gift step only the step's own limit applies, once the bundle has the paid items the gift needs.

setDetails(details)

Replaces what's filled in for bundleAddOns. It goes to the cart with the bundle, on its line, and is cleared once it's added.

checkout(redirectTarget?)

Adds the whole bundle to the Shopify cart. Only call it when canCheckout and detailsComplete are true: with a required bundle add-on empty it sets checkoutError and adds nothing.

redirectTarget

Behaviour

"stay_on_page" (default)

Stays put and asks the theme to open its cart drawer

"cart"

Redirects to /cart

"checkout"

Redirects to Shopify checkout

On success the bundle is emptied and a new bundle session begins, so a stay_on_page UI must be ready to re-render from an empty cart.

On a subscription, checkout() adds every item as its own cart line with its selling_plan and the bundle's Bundle_ID property, because Shopify does not merge lines that carry a selling plan. A one-time purchase is still one bundle line. The SDK has no method to pick a plan: checkout() uses the plan chosen in the built-in picker, or else the bundle's default from Config → Subscriptions.


Translated text

title and description are TranslatableString — either a plain string, or { default, translations } when the merchant has translated them. Rendering one directly can print [object Object]:


Full example

See the Events Reference for every event and its payload.

Last updated

Was this helpful?