How are you building a "pick your pack" quantity selector (1/2/3 packs) with a subscription option?

Hey everyone!

I’m trying to build a product page setup like a lot of the supplement/DTC stores have, and I want to figure out the cleanest way to do it before I commit to a method.

Here’s what I’m after (picture a typical fat burner / supplement page):

  • A pack selector — “1 Package / 2 Package / 3 Package” as clickable options, with a “Best Deal” badge on one of them.
  • Choosing 2 Package should actually put 2 of the product in the cart, 3 Package puts 3, etc. — not just change a label, the real quantity needs to carry through to checkout.
  • Tiered pricing so bigger packs are cheaper per unit (e.g. 2-pack saves 30%).
  • On top of that, a one-time vs subscription toggle — “One Time Purchase” at full price, or “Flexible Subscription” at a discount with a “Deliver every month” dropdown.

Where I’m stuck is the how. A few questions for anyone who’s built this:

  • Do you do the pack selector as variants (a “Pack Size” option with 1/2/3), or as line-item quantity driven by JS on add-to-cart? What holds up better at checkout?
  • For the subscription part — is that basically a subscription app (Appstle, Recharge, etc.) doing the selling plan, and you just style the widget to match? Can the pack tiers and the subscription live together cleanly, or do they fight each other?
  • Is this realistically doable in the theme with some custom Liquid + JS, or is it really an app job once subscriptions enter the picture?
  • Any gotchas with the cart showing the right quantity/price, or the subscription discount stacking with the pack discount?

Basically — theme code, an app, or a combo of both? And if it’s a combo, how do you split the work between them?

Would love to hear how people have actually shipped this,

This is very doable, and for the pack selector I’d steer away from doing it as variants. A “Pack Size” variant with 1/2/3 gets messy fast because each pack is really just a different quantity of the same SKU, so you end up duplicating inventory and fighting the cart. The cleaner pattern is a quantity-break/bundle setup that drives the real line-item quantity on add-to-cart, so 2-Pack genuinely adds 2 units and the price/quantity carry through checkout correctly.

On the subscription side, yes - you’ll want a selling plan for the actual subscription mechanics, and the usual gotcha is exactly what you flagged: pack-tier discounts and subscription discounts stacking or fighting each other in the cart.

One option that handles all of this in a single app is Sleek Bundles Upsell. It offers every bundle type you’d need here - Quantity Breaks (your 1/2/3 packs with tiered per-unit pricing and a “Best Deal”-style highlight), plus Frequently Bought Together, Mix & Match, BOGO, Bundle Kits, and Cart Upsell. Discounts apply automatically at checkout via Shopify Functions rather than discount codes, which avoids a lot of the stacking headaches, and there’s a built-in Subscribe & Save toggle so the one-time vs subscription choice lives in the same widget instead of bolting two systems together. There’s a free plan to prototype with, and the team also offers free developer setup, so you don’t have to hand-build the Liquid/JS yourself.

If you do go the fully custom route, the key thing is making the pack selector write the real quantity (and selling plan, if subscribed) into the add-to-cart request - not just swap a label - so checkout stays accurate.

Happy to go deeper on whichever direction you lean. If this helps, feel free to mark it as a solution.

this is a solved pattern, and the cleanest approach splits neatly between variant selection and app-driven subscriptions.

  • Pack as variant, not dual-quantity.** Add a “Pack Size” option (1, 2, 3) as a true variant, each with its own SKU, cost, and tiered price. When a customer clicks “2 Package,” they add one unit of the 2-pack variant to the cart, not “add 2 of the 1-pack.” This survives checkout perfectly and avoids quantity math in Liquid or JavaScript
  • Subscription layer lives in the app, not the theme. A subscription app (Recharge, Appstle, or similar) handles selling plans, the one-time vs subscription toggle, and delivery frequency. The app reads your variant structure and layers subscription options on top without fighting it. Theme does the variant UI; app does the subscription logic.
  • They pair cleanly because they operate at different levels. The pack variant sets the base price and quantity; the subscription app then applies its own discount on top. You get both the pack discount (cheaper per unit on the 2-pack variant) and the subscription discount stacking correctly. The cart and checkout show one line item per variant, so no confusion.
  • Theme customization is minima Use Shopify’s native product options to display the pack selector as clickable buttons (CSS styling over radio buttons), and let the app handle its own toggle UI for the subscription choice. You don’t need custom add-to-cart logic.

Full disclosure: I work with the team behind Subscribfy, which handles product subscriptions this way, it documents flexible subscriptions, delivery frequency, and subscription discounts, so this is a practical pattern I’ve seen work. Start by mapping your packs to variants and pricing, then layer your subscription app on top. The separation keeps both working smoothly.

Hey @Rasel ,

This is definitely achievable, and in my experience the cleanest implementation is a combination of theme customization and a subscription app.

Here’s how I’d typically split the work:

Subscription: Let a subscription app (such as Recharge, Appstle, or Shopify Subscriptions) handle the selling plans, recurring billing, and delivery frequency. That’s what these apps are built for.

Pack selector: If the packs simply represent buying multiple units of the same product (1, 2, or 3), a small amount of JavaScript can update the quantity that’s added to the cart. However, if each pack has its own SKU, barcode, inventory, or merchandising requirements, I’d model them as separate variants or products instead.

Tiered pricing: If the discount is based on the pack itself, variants (or a bundle app) tend to be more reliable than calculating prices purely with JavaScript. That keeps pricing, checkout, reporting, and inventory consistent.

The main thing to watch out for is discount stacking. Some subscription apps apply the subscription discount to the already discounted pack price, while others don’t, so it’s worth confirming how your chosen app handles selling plans alongside volume or bundle pricing.

Overall, I’d avoid building the subscription logic yourself. Let the subscription app manage recurring purchases, and use the theme for the pack selector and UI. That approach is usually the easiest to maintain and provides the most reliable checkout experience.

If you found my reply helpful, feel free to mark it as the accepted solution so it can help other merchants following this discussion.

Thank You !

The subscription requirement decides the variant question for you, and it decides it earlier than the checkout argument does.

Bundles are the usual native answer for a multipack, since a fixed bundle with a component quantity of 3 decrements the shared stock properly. That route is closed here. The eligibility page states that bundles aren’t compatible with purchase options, which includes subscriptions, pre-orders and try-before-you-buy, so a bundle can’t carry a selling plan at all.

That matters for the pack-as-variant approach. Give the 2 pack and 3 pack their own SKUs and they each get their own inventory pool. Selling three of the 3 pack doesn’t move the single unit number at all, so one physical SKU sitting on one shelf is now counted in three places that never talk to each other. Bundles were the thing that would have tied them back together. With subscriptions in scope, driving line item quantity on one variant keeps one pool, and SubscriptionLine stores quantity alongside variantId, so a 3 pack subscriber rebills 3 units on every cycle.

On the stacking worry there is a concrete answer rather than an it depends. Discounts carry a Purchase type setting for one-time purchase, subscription, or both. Leave a volume tier on one-time and the pack saving disappears the moment someone flips to Flexible Subscription, and the 3 pack price moves under them mid page. Discounts also don’t combine unless you allow it, so the tier and the subscribe and save each need their Combinations set to accept the other.

One more that bites later. A discount applied to a subscription gets snapshotted onto the contract, so if you change pack pricing in six months your existing subscribers keep the old numbers and keep them forever. Better to decide now whether that’s what you want or whether you need a migration path.

Which subscription app are you leaning towards? Whether the pack tier comes from the app or from a separate automatic discount changes which of these you actually have to deal with.

Hey again @Rasel!

All I have to add here is a merchandising warning. Sometimes a pack selector and a subscription toggle on the same page can cause confusion.

Even phrasing like a “monthly three-pack” can cause certain customers to think they bought a three-month supply. Then they either email you after the first month thinking they got shorted, or they email you after the second month asking why they got billed again.

Whatever you end up going with, I’d put a plain sentence under the selector, possibly in the cart and definitely in the confirmation email, spelling out exactly what ships and how often. Something unmistakably simple like “You will receive 3 bottles at a time, every 30 days for 3 months.” should help cut down on confusion, tickets, and chargebacks.

The setup I’ve seen hold up best is:

  • If all packs use the same bottle SKU and inventory pool, keep one variant and send quantity 1, 2, or 3 in the cart request. Only use pack variants when each pack has its own SKU and inventory.
  • Let the subscription app create the selling plan. Your add-to-cart request needs both the selected quantity and selling_plan ID, so a 3-pack subscription renews as 3 units.
  • Do not calculate tier pricing only in JavaScript. Use an automatic discount or Shopify Function that applies at checkout, and confirm whether it applies to subscriptions and combines with the subscription discount.
  • Test all 6 combinations, 1/2/3 pack times one-time/subscription, through cart and checkout. Also state clearly: 3 bottles shipped every 30 days.

Hi @Rasel :raising_hands:

This is definitely doable, and in my experience it’s usually a combination of native Shopify, a subscription app, and (optionally) a product options/bundle app, rather than trying to solve everything with custom Liquid.

For the pack selector, I generally wouldn’t rely on JavaScript alone to change quantities at add-to-cart. It can work, but it tends to be more fragile, especially when you introduce subscriptions, cart drawers, or third-party apps. I prefer using a structure where the pack selection is treated as a distinct purchasing option, so the quantity and pricing remain consistent all the way through checkout.

For the subscription side, you’re right—this is typically handled by a subscription app such as Appstle or Recharge via Shopify Selling Plans. Those apps are built specifically for recurring purchases, and you can usually style the widget to match your theme.

The main challenge is making sure the pack selection and subscription logic work together cleanly. If you’re offering both a pack discount and a subscription discount, you’ll want to decide the pricing logic up front so customers always see the correct price in the product page, cart, and checkout.

For stores I’ve worked on, a split like this has worked well:

  • Theme: Layout, badges (“Best Deal”), styling, and overall UX.
  • Subscription app: Recurring billing and delivery frequency.
  • Bundle/Product Options app: Pack selection, quantity logic, and any optional add-ons if needed.

For example, I’ve used Easify Box Bundle Builder BYOB for quantity-based bundle offers and Easify Custom Product Options when stores also wanted optional add-ons or extra product selections on the same page. That approach avoids having to maintain a lot of custom JavaScript while keeping the buying experience clean.

One question though—when a customer selects the 2-pack, do you want the cart to show:

  • Quantity: 2 of the same product, or
  • One bundle item that internally represents a 2-pack?

That detail usually determines the cleanest implementation.:heart:

I’d also think about future flexibility. A setup that works well for 1, 2, and 3 packs today should ideally make it easy to introduce a 6-pack or limited-time bundle later without rebuilding the entire product page. That’s one reason I’d lean toward a structure that’s easy to extend rather than one that’s only optimized for the current offer.

This is super helpful, thanks :raising_hands: The point about not doing packs as variants really lands — I could see the duplicate-inventory-and-fight-the-cart mess coming, so hearing “drive the real line-item quantity on add-to-cart” confirms the direction.

And yeah, the discount stacking is exactly what I was worried about — good to know Shopify Functions handle it automatically instead of relying on codes. The single-widget Subscribe & Save toggle sounds like it avoids bolting two systems together too.

I’ll take a look at Sleek Bundles :+1: And totally agree on the custom-route key: write the real quantity + selling plan into the add-to-cart request, not just swap a label. Appreciate the detailed breakdown

This is a really clear breakdown, thanks John I like how cleanly you split it — theme handles the variant UI, app handles the subscription layer, and they operate at different levels so the discounts stack instead of fighting. The “one line item per variant, no quantity math” point is what sold me; that’s exactly the kind of checkout-safe simplicity I was after.

Good callout that theme customization stays minimal too — styling radio buttons into clickable pack buttons and letting the app render its own toggle. Appreciate the transparency on Subscribfy as well Marking this as the solution since it maps out the whole pattern so cleanly

Really solid breakdown Steve, thanks I like that you framed it as “it depends” rather than one-size-fits-all — JS-driven quantity if the packs are just multiples of the same unit, but separate variants/products once each pack has its own SKU, barcode, or inventory. That’s the nuance I was trying to figure out.

And the discount stacking warning is well noted — confirming whether the subscription app discounts off the already-discounted pack price vs full price is exactly the kind of thing that’d quietly break the math. “Let the app own the subscription logic, theme handles the UI” seems to be the consensus here Appreciate the thorough reply

This is an outstanding reply — probably the most technically precise one in the thread The point that the subscription requirement decides the variant question earlier than the checkout argument does is a genuine lightbulb moment. I hadn’t clocked that native bundles are incompatible with purchase options, which kills the clean multipack route entirely and reframes the whole thing.

The inventory pool explanation nails exactly why pack-as-variant gets messy here — one physical SKU counted in three pools that never talk. And driving line-item quantity keeping one pool while SubscriptionLine stores quantity alongside variantId is the detail that makes it click.

The discount notes are gold too: the Purchase type setting, Combinations needing to accept each other, and especially the snapshot-onto-contract gotcha — subscribers keeping old pricing forever is the kind of thing that bites six months later exactly like you said.

To your question — I’m leaning toward Appstle or Recharge, still weighing them. Curious whether you’d source the pack tier from the app itself or a separate automatic discount, since you mentioned that changes what I actually have to deal with

Really good shout Daniel This is the kind of thing that’s easy to overlook when you’re deep in the technical setup — the “monthly three-pack” ambiguity is such a real trap. I can totally picture the “did I get shorted?” and “why was I billed again?” emails.

Spelling it out in plain language right under the selector, in the cart, and in the confirmation email is a simple fix that saves a ton of support headaches (and chargebacks). Stealing that exact phrasing — “You will receive 3 bottles at a time, every 30 days” leaves no room to misread it. Appreciate you flagging the merchandising side, not just the build

This is a great summary of everything the thread landed on The “same SKU + inventory pool → one variant with quantity, separate SKU → pack variants” rule is the clean decision tree I needed. And sending both quantity and selling_plan ID in the add-to-cart request so a 3-pack renews as 3 units is the exact mechanic that makes it work.

Fully agree on not doing tier pricing in JS alone — automatic discount or Function at checkout, and verify it plays nice with the subscription discount. The “test all 6 combinations through cart and checkout” reminder is one people skip and regret. And that clear shipping sentence keeps coming up, which tells me it really matters Appreciate you tying it all together