Skip to main content
A combo bundle sells a fixed set of products together at a discount. The merchant picks the products whose pages show the offer and defines one or more combos for them, such as “Coffee duo: this coffee plus the decaf, 20% off both”. Each combo is a set of products, and each product in the set has its own discount. This guide shows how to run a combo bundle from your own storefront UI: your product page and your cart drawer, without the Appstle widget. You use the same rule data, cart-line attributes and Shopify Function as the built-in widget, so only the UI is yours. If you haven’t read the headless overview, start there: it explains the automatic-discount model these steps rely on.

How pricing works

Unlike a fixed pricing bundle, a combo has no single bundle price. Every product in the set (a slot) carries its own discountType and discount: The discount applies automatically, in the cart and at checkout, when the cart holds every product of the set with the combo’s attributes on each line. You don’t compute or submit it.
A combo can also give a free gift (freeProducts on the combo). This guide doesn’t cover gifts.

Step 1 — Read the rule from the metafield

Read the active rules from the appstle_bundles.bundle_rules shop metafield, as the other bundle guides do (see Reading bundle configuration), and keep the combo rules whose product list contains the product on the page. This guide covers combos shown on the products listed in the rule’s variants. A combo that takes its products from collections (productSelectionType is COLLECTION) isn’t covered.
combos and variants are JSON strings inside the rule, so parse them before you use them. The fields you need: Each item of combos: Each item of a combo’s products: Here is the Coffee duo combo of a demo rule, trimmed:
Hydrate titles, images and prices from Shopify’s own Storefront API or Liquid product objects, as the other guides do. The selectedVariants[].price in the rule is the price when the merchant saved it, not a live price.

Step 2 — Render your selector

Build the UI that fits your theme, and drive it from the rule:
  • Show each combo of the rule for the product on the page. When a rule offers several combos, let the shopper pick one (the widget shows them as options).
  • Show the products of the set: the product on the page (the "default" slot) and the other slots.
  • Show the discount from each slot’s discountType and discount, and optionally the savings (see Previewing savings).

Step 3 — Add the set to the cart

Add every product of the set as its own cart line, each carrying the same four attributes. On a Shopify theme they are line-item properties; through Shopify’s Storefront API they are line attributes.
Every line of the set must carry the same _appstle-bb-id and _appstle_bundle_combo_id. The Function groups lines by rule and combo, and discounts a combo only when the cart holds every one of its slots, or as many as minRequiredProducts or productChoiceCount allow. Lines without the attributes are treated as normal products.

Step 4 — Add subscription lines

A combo’s appliesOn decides how it can be bought: To sell a combo as a subscription, add each line with a selling_plan (sellingPlanId on the line in Shopify’s Storefront API). A selling plan belongs to the products it’s attached to, so choose each product’s own plan with the delivery interval the shopper picked: take it from the product’s selling_plan_allocations, or from selling_plan_groups in /products/<handle>.js. If a line’s plan isn’t attached to its variant, /cart/add.js returns 422:
A failed request can still leave part of the set in the cart: in a live test with two lines, one of them was added anyway. After a 422, read /cart.js and remove the set’s lines before you retry.
The combo discount applies on top of the plan’s own subscription price. For example, a 22.00 coffee on a plan that takes 10% off costs 19.80, and the combo’s 20% takes it to 15.84.

Step 5 — Discount applies automatically

Once the lines are in the cart, the Function discounts every line of the set. There is nothing else to call. Confirm it on the cart: each line carries a discount allocation titled with the rule’s discountName, or with its name when discountName is empty. This is the real /cart.js result for the Coffee duo combo (a 22.00 coffee and an 18.00 decaf, 20% off each), trimmed to the decaf line:
When a percentage doesn’t come to whole cents, the Function sends that slot’s discount as a fixed amount, so value_type can be fixed_amount on a PERCENTAGE slot. Match allocations by title, not by type. Add a set more than once, or add several units of each product, and every complete set is discounted: two units of each product in the same combo cost 64.00 instead of 80.00.

What does not get a discount

Each of these carts was tested live. None of them gets the combo discount:
A set also stays undiscounted when:
  • The rule isn’t ACTIVE.
  • A line carrying the same _appstle-bb-id and _appstle_bundle_combo_id doesn’t match appliesOn. The check covers every set of that combo in the cart, so one one-time set of a SUBSCRIPTION combo removes the discount from all of them.
  • The rule is limited by customer tags (allowedTags, restrictTags) or by uses per customer (limitToUsePerCustomer), and the cart’s buyer isn’t identified or doesn’t qualify.
  • The buyer is purchasing for a Shopify B2B company and the rule’s settings has excludeB2BCustomers: true.

Previewing savings

To show the shopper what they save on one set before checkout, compute it from the slots you add. Cart prices are in cents:
This is a display-only preview. The Shopify Function applies the authoritative discount at checkout.

Checklist

1

The offer is live in the Appstle admin

Only live offers (status is ACTIVE) have an automatic discount.
2

The product on the page is in the rule's variants

Offer the combos only on products the rule lists.
3

Every product of the set is in the cart

One line per slot, with the slot’s quantity.
4

Every line carries the three required attributes

The same _appstle-bb-id (the rule’s uniqueRef), _appstle_bundles_type (COMBO_BUNDLE) and _appstle_bundle_combo_id (the combo’s id).
5

Subscription lines match appliesOn

Put every line on a selling plan for a SUBSCRIPTION rule, and none for ONE_TIME.
6

Verify the discount in the cart

Check /cart.js for the discount allocation on each line.

Next steps

Fixed pricing bundle

Sell a curated set for one fixed price.

Build your own frontend

How the metafield, attributes and discount Function fit together.