Exploring options for bundling products in Shopify with Sanity discounts

16 replies
Last updated: Oct 13, 2021
Hi all, has anyone worked on a bundle/packs type feature in headless sanity/shopify?
We’re basically looking for:

1. Take existing product skus
2. Bundle them into a 1 price product
3. Discount the bundle to price set in sanity (aka would need a discount applied on shopify)
4. Automatic suggesting add products to cart based on having 1 in cart, aka add a tshirt, suggest hoodie for a 5 euro discount already applied
We thought of using shopfy automatic discounts but you can only have 1 apply per product.


Here’s how it would work for clothing :
AI Update

I've worked on similar Shopify + Sanity bundle implementations! This is definitely achievable, though there are some important considerations about how Shopify handles bundles and discounts in headless contexts.

The Bundle Challenge with Headless Shopify

The tricky part is that Shopify's native Bundles app and discount stacking work differently in headless storefronts compared to their hosted checkout. The Shopify Bundles app is primarily designed for Shopify's hosted storefront, and when using the Storefront API in a headless setup, you'll need to build much of the bundle logic yourself.

Here's how I'd approach your requirements:

1. Model Bundles in Sanity

Create a bundle document type in Sanity that references your Shopify products:

{
  name: 'productBundle',
  type: 'document',
  fields: [
    {
      name: 'title',
      type: 'string'
    },
    {
      name: 'bundleProducts',
      type: 'array',
      of: [{
        type: 'object',
        fields: [
          {name: 'sku', type: 'string'},
          {name: 'quantity', type: 'number'}
        ]
      }]
    },
    {
      name: 'bundlePrice',
      type: 'number'
    },
    {
      name: 'discountAmount',
      type: 'number'
    }
  ]
}

2. Sync to Shopify with Functions or Webhooks

When you create or update bundles in Sanity, you'll need to sync this information to Shopify. You have a few options:

Option A: Sanity Functions (Recommended)

Sanity Functions are serverless compute functions that run on Sanity's infrastructure in response to document events. This is the modern approach for handling content changes without needing your own hosting infrastructure.

With Functions, you can:

  • Trigger automatically when bundle documents are published/updated
  • Call Shopify's Admin API to create discount codes or update product metadata
  • Run on Sanity's infrastructure (no external hosting needed)
  • Use environment variables for secure API key management

Functions are defined in Blueprints and can be deployed using the Sanity CLI. They run on Node.js v22 and support TypeScript. While they're powerful for this use case, be aware they're still being actively developed with APIs that may evolve.

Option B: Webhooks

Sanity webhooks can trigger your own hosted endpoint when bundle documents change. Webhooks use GROQ filters and projections, allowing you to customize exactly which changes trigger notifications and what data gets sent in the payload.

Your endpoint would then call Shopify's Admin API. This requires hosting your own endpoint but gives you complete control over the integration logic.

Option C: Scheduled Sync

Run a scheduled job (via cron or similar) that queries Sanity for bundle changes and syncs to Shopify. Less real-time but more predictable for production environments.

3. Bundle Discount Strategy

Since Shopify's automatic discounts have limitations (especially the "one per product" issue you mentioned), here are two approaches:

Option A: Dynamic Discount Codes

  • When a bundle is added to cart, your storefront generates a unique discount code via Shopify Admin API
  • Apply it automatically in the cart using the Storefront API's discountCodesUpdate mutation
  • This gives you more flexibility than automatic discounts
  • You can create codes programmatically with specific product combinations

Option B: Cart-level Price Adjustments

  • Handle bundle pricing entirely in your headless storefront UI
  • Send individual line items to Shopify but display the bundle price to customers
  • Use Shopify's Draft Orders API if you need server-side price control before checkout
  • This approach gives you complete control but requires careful implementation to avoid price mismatches

4. Smart Product Suggestions

For your "add t-shirt, suggest hoodie" feature, model these relationships in Sanity:

{
  name: 'productSuggestion',
  type: 'document',
  fields: [
    {
      name: 'triggerProduct',
      type: 'reference',
      to: [{type: 'product'}]
    },
    {
      name: 'suggestedProducts',
      type: 'array',
      of: [{
        type: 'object',
        fields: [
          {name: 'product', type: 'reference', to: [{type: 'product'}]},
          {name: 'discountAmount', type: 'number'},
          {name: 'discountType', type: 'string', options: {list: ['percentage', 'fixed']}}
        ]
      }]
    }
  ]
}

In your storefront:

  1. Query Sanity for suggestion rules based on cart contents using GROQ
  2. Display suggested products with "Add for €5 off" messaging
  3. Apply the discount when they add the suggested item (using one of the discount methods above)

Implementation Flow

  1. Content team creates bundles in Sanity - defines which SKUs, pricing, and discounts
  2. Sync mechanism triggers - Functions (recommended) or webhooks update Shopify
  3. Storefront queries Sanity - gets bundle definitions and suggestion rules via GROQ
  4. Cart logic - your frontend applies bundle pricing and shows suggestions
  5. Checkout - pass properly discounted line items to Shopify Checkout

Why This Approach Works

By managing bundle logic and product relationships in Sanity, you get:

  • Flexibility: Content editors can create bundles without developer involvement
  • Rich content: Add marketing copy, images, SEO metadata to bundles
  • Multi-market support: Different bundle rules for different regions
  • Unified content: Manage products, bundles, and marketing content in one place

Sanity's composable architecture is built for exactly this kind of headless e-commerce scenario where you need content flexibility beyond what Shopify's CMS provides.

Technical Note on Shopify Limitations

The challenge with headless Shopify is that many of their newer features (like the Bundles app) are tightly coupled to their hosted checkout experience. The Shopify Storefront API provides access to products and cart functionality, but bundle-specific features aren't fully exposed for headless implementations.

For headless, you're essentially building a custom cart experience anyway, so treating bundles as a content/pricing concern (managed in Sanity) rather than a pure Shopify product concern often gives you more control.

The discount stacking limitation you mentioned is real - Shopify's automatic discounts have complex rules about combining. Using programmatically generated discount codes gives you more flexibility than relying solely on Shopify's automatic discount system, though you'll need to implement the logic for which discounts can stack.

Hope this helps! Let me know if you need clarification on any part of the implementation.

user G
user J
you guys ever done something like this
bundling in shopify is an absolute nightmare
hahah so basically its tough
theres 3… ways you can do this1. bundle products together as a similar sku, usually limits the possibilities for bundles
2. Use shopify plus to apply discounts to the line items based on the products in the cart (should get around the single discount code)
3. without shopify plus, use variants on products, this one is a lot more complicated and won’t apply to all situations, but i basically create a variant of a product with a lower price, the variant is the bundled* price so when you add a product that is in a bundle you add the variant version, you have to of course ensure customers can’t remove individual variant versions of products, it also means in the shopify checkout itself you don’t have a
bundle
it’s the individual items at a bundled price*
and maybe 4th, use the order api itself and i believe you can apply a discount to products before applying the discount codes*
user G
thank you 🙂 I’ve been pitching the third solution since it makes the most sense. Our situation is complicated by the fact that we want to offer a bundled and a non-bundled version of the product, and we were hoping we could do this by not creating multiple SKUs and instead use the built-in Shopify discount system. I believe your first option wouldn’t make it possible (I wish it did) since each item in the bundle has different variants the customer would have to choose, not sure what other limitations would be though
the 3rd option gets dicy if the products need native variants like, size/color + the bundled variant discount
Yup, dicy indeed, but it’s the only possible way as far as I know 🤷‍♂️ the thought is to not let them enter the checkout page alternatively remove the bundled items, unless all items in a bundle is actually there. This is because they can just apply it on the checkout page due to how Shopify’s discount system works. As in, if they remove one product from the bundle, Shopify would have no way to enforce anything on the checkout page, since the discounts work on one item each
yeah
https://www.prima.co/products/skincare-power-trio number 3 is how this works, ignore all the other stuff that’s thrown at you when you add to cart 🙃
you can also create multiple levels of discount for a product, i stitch these variants together inside of sanity
how does 2 work exactly, as we’re shopify plus
thanks so much for the help!!
user U
knows more than I do here, and will correct me if I spoke inaccurately 🙂
thanks
user G
, appreciate it 🙂 that’s basically how I’ve done it too on the frontned, but with the addition of allowing variant selection for each item
user N
if this is helpful here is what we do with Shopify Plus and discounting…
1. Select which products are apart of the bundle in the Sanity Admin (or shopify admin, wherever
2. When user adds to cart we add a hidden line item props
a. Bundle Name
b. grouped uid
c. Discounted Price
d. Ghost product its being pulled from.
e. If user removes, all items are removed from cart.
3. Display products in the mini cart via the ghost product so it shows the discounted price, items included in the bundle.
4. Shopify Plus Script which sorted out cart items and applies the applicable discount to the bundle products based on shared uid

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?