Optimization Guide

Ecommerce Installment Payment and BNPL Structured Data for AI Shopping Agents

AI shopping agents answer "best sofas under $100 per month" and "furniture I can pay for in installments" by reading structured data — not your checkout UI. Shop Pay Installments, Afterpay, and Klarna are invisible to every AI shopping agent unless you declare them in product JSON-LD.

TL;DR Use additionalProperty on the Offer type to declare BNPL options (provider name, installment count, per-installment amount). Always keep Offer.price at the full product price. Add a priceSpecification entry naming the installment plan (e.g., "4 payments of $74.75 — interest free"). Only inject installment signals for products within your BNPL provider's eligible price range.

The BNPL Visibility Gap

Buy now pay later providers (Shop Pay Installments, Afterpay, Klarna, Sezzle) are checkout-layer integrations. They appear after the customer has already added to cart — in the payment method selection step, or as a widget injected into the product page by a third-party script. Neither the checkout flow nor the JavaScript widget is accessible to AI shopping agent crawlers.

The result: a $599 sofa with 12-month interest-free financing looks identical to a $599 sofa with no payment flexibility in every AI shopping index. When a user asks ChatGPT or Perplexity for "sofas I can pay off monthly", the financing option — potentially the strongest conversion signal for a high-AOV product — is completely absent from the AI's consideration set.

Affordability query types that require installment signals

Query type Example Required signal
Monthly budget filter "bedroom furniture under $80 per month" installmentAmount with per-month value
BNPL provider search "Klarna eligible mattresses" installmentProvider: "Klarna" additionalProperty
Interest-free filter "treadmill 0% financing options" installmentInterestRate: 0 additionalProperty
Split pay search "pay in 4 headphones" numberOfInstallments: 4 additionalProperty
Long-term financing "12-month financing sofa" numberOfInstallments: 12 + installmentPeriod: "monthly"

What Shopify's default JSON-LD shows vs. what's needed

Shopify default (no BNPL signal)
{
  "@type": "Offer",
  "price": "599.00",
  "priceCurrency": "USD",
  "availability":
    "InStock"
}
With installment structured data
{
  "@type": "Offer",
  "price": "599.00",
  "additionalProperty": [{
    "@type": "PropertyValue",
    "propertyID":
      "installmentOption",
    "name":
      "4 payments of $149.75",
    "value": "Shop Pay"
  }]
}

Installment Payment JSON-LD Patterns

Minimum viable installment markup — single BNPL provider

The most impactful addition is an installmentOption additionalProperty describing the payment plan in plain terms. AI agents parse the string value for "payments of", "per month", and provider names:

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Platform Bed Frame — Queen",
  "offers": {
    "@type": "Offer",
    "price": "599.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "additionalProperty": [
      {
        "@type": "PropertyValue",
        "propertyID": "installmentOption",
        "name": "Shop Pay Installments",
        "value": "4 interest-free payments of $149.75"
      }
    ]
  }
}

Full installment markup with structured payment plan data

For richer AI agent parsing, include the number of installments, per-installment amount, interest rate, and period as separate properties alongside a human-readable priceSpecification entry:

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Adjustable Dumbbells — 50 lb Set",
  "offers": {
    "@type": "Offer",
    "price": "349.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "priceSpecification": [
      {
        "@type": "PriceSpecification",
        "price": "349.00",
        "priceCurrency": "USD",
        "name": "Full price"
      },
      {
        "@type": "PriceSpecification",
        "price": "87.25",
        "priceCurrency": "USD",
        "name": "4 interest-free payments of $87.25 via Afterpay"
      }
    ],
    "additionalProperty": [
      {
        "@type": "PropertyValue",
        "propertyID": "installmentProvider",
        "name": "BNPL provider",
        "value": "Afterpay"
      },
      {
        "@type": "PropertyValue",
        "propertyID": "numberOfInstallments",
        "name": "Number of payments",
        "value": "4"
      },
      {
        "@type": "PropertyValue",
        "propertyID": "installmentAmount",
        "name": "Per-payment amount",
        "value": "87.25",
        "unitCode": "USD"
      },
      {
        "@type": "PropertyValue",
        "propertyID": "installmentInterestRate",
        "name": "Interest rate",
        "value": "0",
        "unitCode": "P1"
      },
      {
        "@type": "PropertyValue",
        "propertyID": "installmentPeriod",
        "name": "Payment frequency",
        "value": "biweekly"
      }
    ]
  }
}

Multiple BNPL providers on one product

If your store offers multiple BNPL options (Shop Pay + Afterpay), declare each as a separate installmentOption additionalProperty entry:

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Standing Desk Converter — Large",
  "offers": {
    "@type": "Offer",
    "price": "299.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "additionalProperty": [
      {
        "@type": "PropertyValue",
        "propertyID": "installmentOption",
        "name": "Shop Pay Installments",
        "value": "4 interest-free payments of $74.75"
      },
      {
        "@type": "PropertyValue",
        "propertyID": "installmentOption",
        "name": "Klarna",
        "value": "3 interest-free payments of $99.67"
      },
      {
        "@type": "PropertyValue",
        "propertyID": "installmentOption",
        "name": "Afterpay",
        "value": "4 interest-free payments of $74.75"
      }
    ]
  }
}

Shopify Liquid Implementation

The key constraint for Shopify installment structured data is the BNPL eligibility threshold. Only inject installment signals for products within the eligible price range. Use Liquid math to calculate the per-installment amount dynamically so it stays accurate as prices change.

BNPL provider eligibility thresholds (2026)

Provider Min order (USD) Max order (USD) Installment count Frequency
Shop Pay Installments $50 $17,500 4 (interest-free) or 12/24 (with APR) Biweekly (4) / Monthly (12, 24)
Afterpay $35 $2,000 4 Biweekly
Klarna $10 $10,000 4 (Pay in 4) or 6/12 (financing) Biweekly (4) / Monthly (6, 12)
Sezzle $10 $2,500 4 Biweekly
Zip (Quadpay) $35 $1,500 4 Biweekly

Liquid snippet for product JSON-LD

{% comment %}
  BNPL installment structured data.
  Shop Pay: eligible $50–$17,500. 4 biweekly payments (interest-free).
  Afterpay: eligible $35–$2,000. 4 biweekly payments (interest-free).
  Inject only for eligible products.
{% endcomment %}
{% assign price_dollars = product.price | divided_by: 100.0 %}
{% assign shop_pay_min = 50 %}
{% assign shop_pay_max = 17500 %}
{% assign afterpay_min = 35 %}
{% assign afterpay_max = 2000 %}
{% assign shop_pay_eligible = false %}
{% assign afterpay_eligible = false %}
{% if price_dollars >= shop_pay_min and price_dollars <= shop_pay_max %}
  {% assign shop_pay_eligible = true %}
{% endif %}
{% if price_dollars >= afterpay_min and price_dollars <= afterpay_max %}
  {% assign afterpay_eligible = true %}
{% endif %}

{% if shop_pay_eligible or afterpay_eligible %}
{% assign installment_4 = price_dollars | divided_by: 4.0 | round: 2 %}
"additionalProperty": [
  {% if shop_pay_eligible %}
  {
    "@type": "PropertyValue",
    "propertyID": "installmentOption",
    "name": "Shop Pay Installments",
    "value": {{ '4 interest-free payments of $' | append: installment_4 | json }}
  }
  {% endif %}
  {% if afterpay_eligible %}
  {% if shop_pay_eligible %},{% endif %}
  {
    "@type": "PropertyValue",
    "propertyID": "installmentOption",
    "name": "Afterpay",
    "value": {{ '4 interest-free payments of $' | append: installment_4 | json }}
  }
  {% endif %}
],
"priceSpecification": [
  {
    "@type": "PriceSpecification",
    "price": {{ price_dollars | json }},
    "priceCurrency": {{ cart.currency.iso_code | json }},
    "name": "Full price"
  }
  {% if shop_pay_eligible %}
  ,{
    "@type": "PriceSpecification",
    "price": {{ installment_4 | json }},
    "priceCurrency": {{ cart.currency.iso_code | json }},
    "name": {{ '4 interest-free payments via Shop Pay' | json }}
  }
  {% endif %}
],
{% endif %}

Common Mistakes to Avoid

Mistake AI agent consequence Fix
Setting Offer.price to installment amount instead of full price Misleads price comparison; product appears cheaper than it is Always use full price in Offer.price; installment amount goes in additionalProperty or priceSpecification
No eligibility threshold check in Liquid Installment signal declared for $20 product; creates false expectation at checkout Use Liquid conditional: only inject for products within provider's min/max price range
Hardcoding installment amounts instead of calculating from product price Stale installment value after price change; misleads AI agent recommendations Use Liquid math: product.price | divided_by: 400.0 | round: 2 for 4-payment amount
Declaring interest-bearing installments as "interest-free" Structured data policy violation; post-click trust damage Only use "interest-free" for 0% APR plans; declare APR for financing plans
BNPL signals on sitewide layout instead of product-level Offer AI agents associate financing with the store generally, not specific products Place installment additionalProperty inside Offer on product.liquid, not in theme.liquid

Implementation Checklist

Frequently Asked Questions

How do I declare BNPL installment options in schema.org structured data?

Use additionalProperty on the Offer type with propertyID: "installmentOption". Include the provider name in name and a plain-text description of the plan in value (e.g., "4 interest-free payments of $87.25"). For structured parsing, add separate installmentProvider, numberOfInstallments, and installmentAmount properties. Offer.price must always be the full price.

Can AI shopping agents surface BNPL options in budget queries?

Yes — when a user asks "sofas under $100 a month" or "best BNPL options for furniture", AI shopping agents look for installment payment signals in structured data. ChatGPT Shopping and Perplexity Shopping parse installmentOption additionalProperty values. Google AI Mode surfaces installment pricing when it appears in both structured data and visible page content.

What is the correct way to display installment price vs. full price in structured data?

Always use the full product price in Offer.price. Declare the installment price in priceSpecification with a named entry ("4 interest-free payments of $87.25 via Afterpay"). AI agents use Offer.price for price comparison; they surface the installment price as supplementary context. Never set Offer.price to the installment amount.

Does Shop Pay Installments integrate with Shopify structured data automatically?

No. Shop Pay Installments is a checkout-layer feature that appears in the cart and payment UI. Shopify's default product JSON-LD does not include any installment or BNPL signals. You must add installment plan information manually to your product.liquid JSON-LD using Liquid math to calculate per-installment amounts dynamically.

How do I handle products where BNPL is not available due to price thresholds?

Only add installment additionalProperty to products within your BNPL provider's eligible price range (e.g., Shop Pay: $50–$17,500; Afterpay: $35–$2,000). In Liquid, use a conditional based on product.price | divided_by: 100.0 and inject the installment block only when the price falls within the eligible range. Showing installment options outside the eligible range creates a false checkout expectation.

Related Resources