Subscription Commerce

Shopify subscription box
structured data and schema markup

How to implement schema.org Product markup for Shopify subscription boxes — recurring price signaling, contents description, cancellation policy, and AI shopping agent visibility for box subscription products.

TL;DR Subscription apps don't auto-generate structured data. Manually add Product JSON-LD with UnitPriceSpecification (billing period + amount), a description covering box contents and retail value, and AggregateRating from subscriber reviews. Make the subscription price visible in plain text on the page — AI agents cross-check JSON-LD against page copy and suppress products where they disagree.

The structured data challenge unique to subscription boxes

Subscription boxes present three structured data challenges that standard Shopify product pages don't have:

  1. Recurring price vs. one-time price — The "price" shown ($39/month, $129/quarter) is fundamentally different from a product price. Schema.org's standard Offer.price is designed for one-time purchases. Subscription pricing requires UnitPriceSpecification with billing period context.
  2. Variable contents — A mystery box that ships different items each month can't have a stable product description. AI agents may classify the product inconsistently across months if description changes aren't managed carefully.
  3. Subscription apps own the checkout — Recharge, Bold Subscriptions, and Skio handle billing logic but leave structured data entirely to the store theme. The result: most subscription box Shopify stores have either no Product JSON-LD or standard one-time-purchase markup that misrepresents the actual pricing model.

Implementing subscription pricing in schema.org

Schema.org's UnitPriceSpecification is the correct type for recurring prices. It supports billing period, billing increment, and price per unit:

Monthly subscription box markup

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Monthly Artisan Snack Box",
  "description": "Monthly curated box of 5–7 artisan snacks from small-batch US producers. Retail value $60+. Allergen info included. Cancel anytime.",
  "image": "https://yourstore.com/products/snack-box.jpg",
  "brand": { "@type": "Brand", "name": "Snack Collective" },
  "offers": {
    "@type": "Offer",
    "url": "https://yourstore.com/products/monthly-snack-box",
    "availability": "https://schema.org/InStock",
    "priceSpecification": {
      "@type": "UnitPriceSpecification",
      "price": "39.00",
      "priceCurrency": "USD",
      "referenceQuantity": {
        "@type": "QuantitativeValue",
        "value": "1",
        "unitCode": "MON"
      },
      "billingIncrement": 1
    }
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.7",
    "reviewCount": "312",
    "bestRating": "5",
    "worstRating": "1"
  }
}

The unitCode: "MON" signals a monthly billing period. Use "ANN" for annual subscriptions. billingIncrement: 1 means one billing period per cycle — use 3 for quarterly (every 3 months).

Multi-tier subscription box markup (monthly / quarterly / annual)

If you offer multiple subscription tiers, use AggregateOffer to expose the price range, and list individual offers for each tier:

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Artisan Snack Box",
  "description": "Curated artisan snack subscription. Choose monthly, quarterly, or annual. 5–7 items per box, retail value $60+.",
  "offers": {
    "@type": "AggregateOffer",
    "lowPrice": "34.00",
    "highPrice": "39.00",
    "priceCurrency": "USD",
    "offerCount": "3",
    "offers": [
      {
        "@type": "Offer",
        "name": "Monthly",
        "priceSpecification": {
          "@type": "UnitPriceSpecification",
          "price": "39.00",
          "priceCurrency": "USD",
          "referenceQuantity": { "@type": "QuantitativeValue", "value": "1", "unitCode": "MON" },
          "billingIncrement": 1
        },
        "availability": "https://schema.org/InStock"
      },
      {
        "@type": "Offer",
        "name": "Quarterly (save 10%)",
        "priceSpecification": {
          "@type": "UnitPriceSpecification",
          "price": "105.00",
          "priceCurrency": "USD",
          "referenceQuantity": { "@type": "QuantitativeValue", "value": "3", "unitCode": "MON" },
          "billingIncrement": 3
        },
        "availability": "https://schema.org/InStock"
      },
      {
        "@type": "Offer",
        "name": "Annual (save 13%)",
        "priceSpecification": {
          "@type": "UnitPriceSpecification",
          "price": "408.00",
          "priceCurrency": "USD",
          "referenceQuantity": { "@type": "QuantitativeValue", "value": "1", "unitCode": "ANN" },
          "billingIncrement": 1
        },
        "availability": "https://schema.org/InStock"
      }
    ]
  }
}

Implementing in Shopify Liquid with subscription app metafields

Since subscription apps manage pricing logic separately from Shopify's native product price, the cleanest approach is to store subscription pricing data in metafields and output it in Liquid:

{% comment %}
  Requires metafields:
  - subscription.monthly_price (number)
  - subscription.quarterly_price (number)
  - subscription.annual_price (number)
  - subscription.billing_currency (single_line_text, default: store currency)
  Set these in Shopify admin → Products → Metafields
{% endcomment %}
{% if product.metafields.subscription.monthly_price %}
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "{{ product.title | escape }}",
  "description": "{{ product.description | strip_html | truncate: 500 | escape }}",
  "image": "{{ product.featured_image | img_url: 'master' | prepend: 'https:' }}",
  "brand": { "@type": "Brand", "name": "{{ product.vendor | escape }}" },
  "offers": {
    "@type": "Offer",
    "availability": "https://schema.org/InStock",
    "priceSpecification": {
      "@type": "UnitPriceSpecification",
      "price": "{{ product.metafields.subscription.monthly_price }}",
      "priceCurrency": "{{ cart.currency.iso_code }}",
      "referenceQuantity": {
        "@type": "QuantitativeValue",
        "value": "1",
        "unitCode": "MON"
      },
      "billingIncrement": 1
    }
  }
  {% if product.metafields.reviews.rating_count > 0 %}
  ,"aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "{{ product.metafields.reviews.rating | round: 1 }}",
    "reviewCount": "{{ product.metafields.reviews.rating_count }}"
  }
  {% endif %}
}
</script>
{% endif %}

What to put in subscription box descriptions for AI agents

AI shopping agents match subscription boxes to queries like "best snack subscription box", "coffee subscription gift", "monthly book box under $30". Your Product.description is the primary relevance signal. Include all of these elements:

Description elementWhy it matters for AI agentsExample
Contents categoryMatches category-intent queries"artisan snacks", "specialty coffee", "beauty samples"
Item count per boxAnswers "how many items" queries; differentiates from competitors"5–7 full-size items"
Retail value of contentsAI agents use value vs. price differential to rank value"retail value $60+"
Curation methodQuality signal for premium queries"curated by certified sommeliers", "selected by our editorial team"
Audience / occasion fitGift query matching ("subscription box for coffee lover")"perfect gift for coffee enthusiasts", "ideal for home bakers"
Cancellation policyTrust signal; appears in "no commitment" queries"cancel anytime, no commitment"
Shipping frequency + timingMatches "monthly delivery" queries"ships on the 15th of each month"

Google Merchant Center for subscription boxes

Google AI Mode reads from GMC for product surfacing. Subscription boxes in GMC require specific handling:

Subscription box structured data checklist

CheckPriority
Product JSON-LD present on subscription product page (server-rendered)Critical
UnitPriceSpecification with unitCode MON or ANN instead of bare Offer.priceCritical
Monthly/recurring price matches visible page price (no discrepancy)Critical
Description covers contents, item count, retail value, curation methodHigh
AggregateRating present if subscriber reviews collectedHigh
Cancellation policy visible in page textHigh
GMC feed includes subscription_cost attributeMedium
Gift-giving keywords in description for holiday query coverageMedium

Run a CatalogScan check on your subscription product pages to see exactly which structured data signals are present and how your store compares to the 100-store benchmark. Subscription boxes are an underserved category for AI agent optimization — the bar is low and the upside is real.

Related: Shopify subscription products and AI agents · Product bundles structured data · AI shopping agent ranking factors

Frequently asked questions

Does schema.org support recurring billing markup?

Not natively, but you can express recurring pricing with UnitPriceSpecification and referenceQuantity.unitCode: "MON" for monthly billing. Google's documentation recommends this pattern for subscription products. No Shopify subscription app generates this automatically — manual theme implementation is required.

How should I describe a mystery box with variable monthly contents?

Describe the value proposition, not the specific items: category of contents, item count range, retail value vs. subscription price, curation method, and audience fit. AI agents use this to match "subscription box for [category]" queries. Don't list specific monthly items in JSON-LD since they change — add a "past boxes" page for content depth instead.

Will subscription boxes appear in AI shopping agent results?

Yes, with proper setup. Requirements: accessible product page (no login required to view), complete Product JSON-LD with recurring price, description covering box contents and value, and AggregateRating. Boxes with external editorial reviews (Wirecutter, gift guides) rank significantly higher in Perplexity recommendations.

What Shopify apps handle subscription box structured data?

No major subscription app (Recharge, Bold, Skio, Stay AI, Loop) automatically generates complete structured data as of 2026. They handle billing mechanics but leave JSON-LD to your theme. Use metafields to store subscription pricing data and output it in your product template's JSON-LD block.