Optimization Guide

Ecommerce Bundle Discount Schema for AI Shopping Agents

Bundle discounts, BOGO deals, and multi-buy pricing are invisible to AI shopping agents unless you encode them in JSON-LD structured data. Shopify automatic discounts apply at checkout — but AI agents never see checkout. Here's how to fix that.

TL;DR Use multiple Offer blocks with eligibleQuantity to expose bundle pricing to AI agents. One base Offer at full unit price (minValue: 1) and one bundle Offer at the effective discounted price (minValue: 2 or your threshold). Add an additionalProperty block with propertyID: "promotionType" for explicit promotion classification. Shopify automatic discounts never surface in structured data — you must encode the discounted price directly in your template.

Why Bundle Discounts Are Invisible to AI Agents

Shopify's discount system works entirely at checkout time. When a customer qualifies for "Buy 2 Get 10% Off", the discount applies in the cart on a checkout.shopify.com URL that AI agents cannot crawl. From an AI agent's perspective, your product has exactly one price: whatever appears in your product page JSON-LD.

Discount typeShopify mechanismAI agent visibility
Automatic discount (buy X, save Y%) Shopify Scripts / Discount Functions Invisible — checkout only
Discount code (BUNDLE20) Checkout coupon field Invisible — requires code entry
Compare-at price on individual variant Shopify Admin compare-at field Visible if reflected in JSON-LD
Bundle price in product JSON-LD Custom Liquid / theme edit Visible — fully machine-readable
Bundle price in product description Product admin description Partial — NLP fallback only

The implication: if you run any bundle deals that aren't reflected in JSON-LD, competing stores with cleaner markup will appear to offer better per-unit pricing — even if your effective price is lower. AI agents recommend based on what they can confirm, not what they have to guess.

Core Pattern: Dual Offer Blocks with eligibleQuantity

The schema.org standard for quantity-conditional pricing is the eligibleQuantity property on an Offer. Publish one Offer per pricing tier, each with its own quantity constraint using QuantitativeValue.

Buy 2, save 10% — full example

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Daily Vitamin C Serum 30ml",
  "offers": [
    {
      "@type": "Offer",
      "name": "Single bottle",
      "price": "38.00",
      "priceCurrency": "USD",
      "availability": "https://schema.org/InStock",
      "eligibleQuantity": {
        "@type": "QuantitativeValue",
        "minValue": 1,
        "maxValue": 1,
        "unitCode": "C62"
      }
    },
    {
      "@type": "Offer",
      "name": "2-pack — save 10%",
      "price": "34.20",
      "highPrice": "38.00",
      "priceCurrency": "USD",
      "availability": "https://schema.org/InStock",
      "eligibleQuantity": {
        "@type": "QuantitativeValue",
        "minValue": 2,
        "unitCode": "C62"
      },
      "additionalProperty": [
        {
          "@type": "PropertyValue",
          "propertyID": "promotionType",
          "name": "Promotion Type",
          "value": "MultiBuyDiscount"
        },
        {
          "@type": "PropertyValue",
          "propertyID": "discountPercent",
          "name": "Discount",
          "value": "10%"
        }
      ]
    }
  ]
}

Three-tier bundle (1 / 3 / 6)

"offers": [
  {
    "@type": "Offer", "name": "Single unit",
    "price": "24.00", "priceCurrency": "USD",
    "eligibleQuantity": { "@type": "QuantitativeValue", "minValue": 1, "maxValue": 2, "unitCode": "C62" }
  },
  {
    "@type": "Offer", "name": "3-pack — save 15%",
    "price": "20.40", "highPrice": "24.00", "priceCurrency": "USD",
    "eligibleQuantity": { "@type": "QuantitativeValue", "minValue": 3, "maxValue": 5, "unitCode": "C62" },
    "additionalProperty": { "@type": "PropertyValue", "propertyID": "discountPercent", "value": "15%" }
  },
  {
    "@type": "Offer", "name": "6-pack — save 25%",
    "price": "18.00", "highPrice": "24.00", "priceCurrency": "USD",
    "eligibleQuantity": { "@type": "QuantitativeValue", "minValue": 6, "unitCode": "C62" },
    "additionalProperty": { "@type": "PropertyValue", "propertyID": "discountPercent", "value": "25%" }
  }
]

BOGO Schema Pattern

Buy One Get One deals have an effective per-unit price of half the single-unit price for BOGO Free, or proportionally less for BOGO discounts. Encode this with maxValue: 2 and the correct effective price:

{
  "@type": "Offer",
  "name": "BOGO Free — buy 2, pay for 1",
  "price": "22.50",
  "highPrice": "45.00",
  "priceCurrency": "USD",
  "eligibleQuantity": {
    "@type": "QuantitativeValue",
    "minValue": 2,
    "maxValue": 2,
    "unitCode": "C62"
  },
  "additionalProperty": [
    {
      "@type": "PropertyValue",
      "propertyID": "promotionType",
      "value": "BOGO"
    },
    {
      "@type": "PropertyValue",
      "propertyID": "promotionDescription",
      "value": "Buy one, get one free — add two to cart to apply"
    }
  ]
}

Shopify Liquid Implementation

Store bundle pricing in a product metafield namespace (bundle.discount_pct, bundle.min_qty) and read it in your Liquid template. This approach lets marketing update discounts through Shopify Admin without touching theme code:

{% comment %} In product.liquid, inside the offers array {% endcomment %}
{% if product.metafields.bundle.discount_pct %}
  {% assign bundle_qty = product.metafields.bundle.min_qty | default: 2 %}
  {% assign discount = product.metafields.bundle.discount_pct | times: 1.0 %}
  {% assign bundle_price = product.price | times: 1.0 | divided_by: 100 %}
  {% assign bundle_price = bundle_price | times: 100 | minus: discount | divided_by: 100 %}
  ,{
    "@type": "Offer",
    "name": {{ bundle_qty | append: "-pack bundle — save " | append: product.metafields.bundle.discount_pct | append: "%" | json }},
    "price": {{ bundle_price | money_without_currency | json }},
    "highPrice": {{ product.price | money_without_currency | json }},
    "priceCurrency": {{ cart.currency.iso_code | json }},
    "availability": "https://schema.org/InStock",
    "eligibleQuantity": {
      "@type": "QuantitativeValue",
      "minValue": {{ bundle_qty }},
      "unitCode": "C62"
    },
    "additionalProperty": {
      "@type": "PropertyValue",
      "propertyID": "discountPercent",
      "value": {{ product.metafields.bundle.discount_pct | append: "%" | json }}
    }
  }
{% endif %}

Setting bundle metafields in Shopify Admin

Define two metafields in your Shopify Admin → Settings → Custom data → Products:

Namespace.keyTypeExample value
bundle.discount_pctInteger (number)10, 15, 25
bundle.min_qtyInteger (number)2, 3, 6

Bundle Discount Description Supplement

Add bundle pricing explicitly to your product description for NLP fallback coverage. AI agents parse description text when structured data is missing or ambiguous:

PatternExample phrase
Quantity + savings statement "Buy 2 and save 10% — automatically applied at checkout."
Per-unit effective price "As low as $20.40 per bottle when you buy 2 or more."
BOGO explicit statement "Buy one, get one free — add any two to your cart."
Tiered savings table in description "Buy 3: save 15% | Buy 6: save 25% | Buy 12: save 30%"

promotionType Values for AI Agent Classification

Using consistent promotionType values in your additionalProperty helps AI agents classify and filter promotions accurately:

promotionType valueUse caseExample
MultiBuyDiscountBuy N, save X%Buy 2 get 10% off
BOGOBuy one get one free / half priceBOGO free, BOGO 50% off
BundleSavingsFixed amount off a bundle$10 off when you buy 3
VolumeDiscountTiered pricing by volume3-pack: 15%, 6-pack: 25%
FreeShippingBundleFree shipping triggered by quantityFree shipping when you buy 2+

Bundle Discount Schema Checklist

  1. Store bundle discount parameters in product metafields (bundle.discount_pct, bundle.min_qty) rather than hard-coding values
  2. Add a second Offer block to your product JSON-LD with eligibleQuantity.minValue equal to the bundle threshold
  3. Set price in the bundle Offer to the effective per-unit discounted price (not the total bundle price)
  4. Set highPrice to the full unit price so AI agents can calculate the savings percentage
  5. Add additionalProperty with promotionType and discountPercent for explicit classification
  6. Add bundle pricing language to your product description for NLP fallback coverage
  7. For time-limited bundle deals, add priceValidUntil with an ISO 8601 date string
  8. Validate the updated JSON-LD using Google's Rich Results Test to catch syntax errors
  9. Ping IndexNow with updated product URLs after publishing bundle markup

Related Resources

Frequently Asked Questions

How do I mark up a buy-two-get-one-free deal in JSON-LD?

Use Offer.eligibleQuantity with QuantitativeValue (minValue 2, maxValue 2) and set price to the effective per-unit cost (half of the single unit price for BOGO free). Add an additionalProperty with promotionType: "BOGO" and a promotionDescription explaining the mechanic. Include priceValidUntil if time-limited.

Can AI shopping agents read Shopify automatic discount codes?

No. Shopify automatic discounts and codes apply at checkout on checkout.shopify.com — a URL AI agents cannot crawl. To expose bundle pricing, you must encode it in product-page JSON-LD. Use Liquid metafields to keep the values manageable without hard-coding per product.

What is the difference between a bundle discount and a sale price in schema.org?

A sale price (Offer.price lower than highPrice) applies to every unit regardless of quantity. A bundle discount applies only at a minimum quantity threshold — encoded via eligibleQuantity. Use separate Offer blocks: one at full price with minValue: 1, and one at the bundle price with minValue equal to your bundle threshold.

How should I encode a percentage-off bundle vs. a fixed savings amount?

For percentage-off, set Offer.price to the discounted price and highPrice to the original. Add additionalProperty with propertyID: "discountPercent". For fixed savings ($10 off when you buy 3), set the effective per-unit price and add additionalProperty with propertyID: "bundleSavings" and value "$10.00".

Check Your Bundle Pricing Visibility

CatalogScan scans your product catalog for missing bundle pricing signals, malformed eligibleQuantity blocks, and promotion markup gaps — then ranks them by impact on AI agent citation rates for deal-intent queries.

Scan your store free