Exploring options for bundling products in Shopify with Sanity discounts
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.
Recommended Architecture
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
discountCodesUpdatemutation - 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:
- Query Sanity for suggestion rules based on cart contents using GROQ
- Display suggested products with "Add for €5 off" messaging
- Apply the discount when they add the suggested item (using one of the discount methods above)
Implementation Flow
- Content team creates bundles in Sanity - defines which SKUs, pricing, and discounts
- Sync mechanism triggers - Functions (recommended) or webhooks update Shopify
- Storefront queries Sanity - gets bundle definitions and suggestion rules via GROQ
- Cart logic - your frontend applies bundle pricing and shows suggestions
- 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.
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.