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.
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
{
"@type": "Offer",
"price": "599.00",
"priceCurrency": "USD",
"availability":
"InStock"
}
{
"@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
- Add
installmentOptionadditionalProperty to productOfferfor each eligible BNPL provider - Use Liquid conditional to inject installment data only for products within BNPL eligibility price range
- Calculate per-installment amount dynamically from product price (never hardcode)
- Keep
Offer.priceat full product price — installment amounts go inadditionalProperty - Add
priceSpecificationentry with named installment plan for richer AI agent parsing - Include
installmentProvider,numberOfInstallments, andinstallmentInterestRatefor structured parsing - Only label plans as "interest-free" if the APR is 0% — declare APR for financing plans
- For multiple BNPL providers, add a separate
installmentOptionPropertyValue per provider - Test Rich Results Test after adding installment properties to confirm no validation errors
- Run CatalogScan to verify BNPL signals appear in AI readiness score
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.