Optimization Guide
Ecommerce Pre-Order and Deposit Payment Structured Data for AI Shopping Agents
Pre-order products sitting at zero inventory look identical to permanently out-of-stock items in AI shopping indexes. Without Offer.availability = PreOrder and a releaseDate signal, your upcoming product launch is invisible to every "can I pre-order X?" and "when does Y ship?" query.
Offer.availability to https://schema.org/PreOrder for products accepting pre-orders. Add a releaseDate additionalProperty with the expected ship date. Use availabilityStarts if pre-orders open on a future date. For deposit-based pre-orders, declare the deposit amount in priceSpecification separately from the full price. Update availability to InStock on the actual ship date — not the announcement date.
The Pre-Order Visibility Problem
Shopify's inventory system treats products with zero stock and "continue selling" enabled as effectively out-of-stock in structured data terms — because that's what the inventory quantity signals. The product JSON-LD generated by Shopify defaults to OutOfStock when inventory is zero, regardless of whether you've configured a pre-order tag, a pre-order app, or a product description that explicitly says "Pre-order now — ships August 15."
The consequence for AI shopping agents is that your pre-order product competes in the same "unavailable" bucket as discontinued items and stock-outs. When a user asks "can I pre-order the new standing desk from X brand?", the AI agent has no machine-readable signal to distinguish your pre-order from a product that's simply sold out.
Availability states and AI agent behavior
| Availability value | AI agent interpretation | Shopping result behavior |
|---|---|---|
InStock |
Ships now; ready for immediate fulfillment | Standard listing; full filter eligibility |
PreOrder |
Accepts orders now; ships on release date | Pre-order badge; eligible for "pre-order" filter queries |
PreSale |
Order placed; payment processed at ship date | Similar to PreOrder; used for deferred payment pre-orders |
OutOfStock |
No units available; no order pathway | Suppressed from most shopping panels; back-in-stock filter only |
Discontinued |
Product retired; no future availability | Suppressed; should not appear in recommendations |
Pre-Order JSON-LD Patterns
Minimum viable pre-order markup
The single most impactful change is setting Offer.availability to PreOrder and adding a releaseDate property. AI agents can surface "pre-order available" and estimate delivery context from these two signals alone:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Adjustable Standing Desk Pro — Walnut",
"description": "Motorized standing desk with walnut desktop. Pre-order now for August 2026 delivery.",
"additionalProperty": [
{
"@type": "PropertyValue",
"propertyID": "releaseDate",
"name": "Expected ship date",
"value": "2026-08-15"
}
],
"offers": {
"@type": "Offer",
"price": "649.00",
"priceCurrency": "USD",
"availability": "https://schema.org/PreOrder",
"url": "https://example.com/products/standing-desk-walnut"
}
}
Pre-order with deposit payment structure
For products requiring a deposit at order time with the balance due at shipping, use priceSpecification to declare both the deposit and the full price. The Offer.price must always reflect the total product price — not just the deposit:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Limited Edition Handmade Sofa — Forest Green",
"description": "Hand-stitched linen sofa. 12-week production. $250 deposit reserves your order; balance charged at shipping.",
"additionalProperty": [
{
"@type": "PropertyValue",
"propertyID": "releaseDate",
"name": "Expected ship date",
"value": "2026-09-01"
},
{
"@type": "PropertyValue",
"propertyID": "depositAmount",
"name": "Pre-order deposit",
"value": "250.00",
"unitCode": "USD"
},
{
"@type": "PropertyValue",
"propertyID": "remainingBalanceDue",
"name": "Balance due at shipping",
"value": "1150.00",
"unitCode": "USD"
},
{
"@type": "PropertyValue",
"propertyID": "productionLeadTime",
"name": "Production lead time",
"value": "12 weeks"
}
],
"offers": {
"@type": "Offer",
"price": "1400.00",
"priceCurrency": "USD",
"availability": "https://schema.org/PreOrder",
"priceSpecification": [
{
"@type": "PriceSpecification",
"price": "250.00",
"priceCurrency": "USD",
"name": "Pre-order deposit (due now)"
},
{
"@type": "PriceSpecification",
"price": "1150.00",
"priceCurrency": "USD",
"name": "Balance due at shipping"
}
]
}
}
Pre-order with future open date
When pre-orders haven't opened yet (announcement phase), use availabilityStarts on the Offer to tell AI agents when ordering becomes possible:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Wireless Noise-Cancelling Headphones X2",
"additionalProperty": [
{
"@type": "PropertyValue",
"propertyID": "releaseDate",
"name": "Expected ship date",
"value": "2026-10-01"
}
],
"offers": {
"@type": "Offer",
"price": "299.00",
"priceCurrency": "USD",
"availability": "https://schema.org/PreOrder",
"availabilityStarts": "2026-07-15T00:00:00Z",
"availabilityEnds": "2026-09-30T23:59:59Z"
}
}
Shopify Liquid Implementation
Shopify's default JSON-LD uses inventory quantity to determine availability. For pre-orders, you need to override this logic using a metafield that explicitly flags the product as a pre-order. This prevents the zero-inventory fallback to OutOfStock.
Recommended metafield structure
| Namespace.key | Type | Example value | Purpose |
|---|---|---|---|
preorder.is_preorder |
Boolean | true |
Override availability to PreOrder in JSON-LD |
preorder.ship_date |
Date | 2026-08-15 |
Expected ship date for releaseDate property |
preorder.deposit_amount |
Number (decimal) | 250.00 |
Deposit due at order time (if applicable) |
preorder.availability_starts |
Date and time | 2026-07-15T00:00:00Z |
Pre-order open date (if future-gated) |
Liquid snippet for product JSON-LD
{% assign po = product.metafields.preorder %}
{% assign is_preorder = po.is_preorder %}
{% assign full_price = product.price | money_without_currency | remove: ',' %}
{
"@context": "https://schema.org",
"@type": "Product",
"name": {{ product.title | json }},
"description": {{ product.description | strip_html | truncate: 500 | json }},
{% if is_preorder and po.ship_date != blank %}
"additionalProperty": [
{
"@type": "PropertyValue",
"propertyID": "releaseDate",
"name": "Expected ship date",
"value": {{ po.ship_date | date: '%Y-%m-%d' | json }}
}
{% if po.deposit_amount != blank %}
,{
"@type": "PropertyValue",
"propertyID": "depositAmount",
"name": "Pre-order deposit",
"value": {{ po.deposit_amount | json }},
"unitCode": {{ cart.currency.iso_code | json }}
}
,{
"@type": "PropertyValue",
"propertyID": "remainingBalanceDue",
"name": "Balance due at shipping",
"value": {{ product.price | minus: po.deposit_amount | money_without_currency | remove: ',' | json }},
"unitCode": {{ cart.currency.iso_code | json }}
}
{% endif %}
],
{% endif %}
"offers": {
"@type": "Offer",
"price": {{ full_price | json }},
"priceCurrency": {{ cart.currency.iso_code | json }},
"availability": {% if is_preorder %}"https://schema.org/PreOrder"{% elsif product.available %}"https://schema.org/InStock"{% else %}"https://schema.org/OutOfStock"{% endif %}
{% if is_preorder and po.availability_starts != blank %}
,"availabilityStarts": {{ po.availability_starts | date: '%Y-%m-%dT%H:%M:%SZ' | json }}
{% endif %}
{% if is_preorder and po.deposit_amount != blank %}
,"priceSpecification": [
{
"@type": "PriceSpecification",
"price": {{ po.deposit_amount | json }},
"priceCurrency": {{ cart.currency.iso_code | json }},
"name": "Pre-order deposit (due now)"
},
{
"@type": "PriceSpecification",
"price": {{ product.price | minus: po.deposit_amount | money_without_currency | remove: ',' | json }},
"priceCurrency": {{ cart.currency.iso_code | json }},
"name": "Balance due at shipping"
}
]
{% endif %}
}
}
Automating the PreOrder → InStock transition
The most common pre-order structured data error is forgetting to flip availability from PreOrder to InStock when fulfillment begins. Options for automation:
- Shopify Flow: Trigger on inventory quantity threshold — when
inventory_quantity > 0andpreorder.is_preorder = true, setpreorder.is_preorder = false - Ship date check in Liquid: Compare
po.ship_dateto'now' | date: '%Y-%m-%d'; if ship date is past, fall back to inventory-based availability - Shopify Bulk Operations + metafield mutation: Run a nightly script that sets
preorder.is_preorder = falsefor all products whose ship date has passed
Pre-Order Availability Transition Timeline
| Phase | Offer.availability | availabilityStarts | releaseDate additionalProperty |
|---|---|---|---|
| Announcement (pre-orders not yet open) | PreOrder |
Future open date set | Expected ship date set |
| Pre-orders open | PreOrder |
Remove or set to past | Expected ship date maintained |
| Pre-orders closed / sold out | SoldOut |
— | Maintain for "coming soon" queries |
| Fulfillment begins | InStock |
— | Remove or set to launch date |
| Remaining stock depleted | OutOfStock |
— | Remove |
Common Mistakes and How to Avoid Them
| Mistake | AI agent consequence | Fix |
|---|---|---|
Using InStock for pre-order products to avoid suppression |
Policy violation; AI agents surface misleading delivery window | Use PreOrder; AI agents support pre-order queries natively |
| Offer.price set to deposit amount instead of full price | AI agent shows incorrect price; misleads comparison shoppers | Always use full product price in Offer.price; declare deposit in priceSpecification |
No releaseDate additionalProperty |
AI agent cannot answer "when does it ship?" queries | Add releaseDate PropertyValue with ISO 8601 date string |
Forgetting to flip to InStock when fulfillment starts |
Products remain in PreOrder state after shipping begins; misleads buyers | Automate transition via Shopify Flow or ship-date comparison in Liquid |
| No IndexNow ping when pre-order opens or closes | 48–72h delay before AI agents recrawl updated availability | Ping IndexNow when pre-order status changes |
Implementation Checklist
- Set
Offer.availability = https://schema.org/PreOrderfor all pre-order products - Add
releaseDateadditionalProperty with ISO 8601 date (YYYY-MM-DD) - Use full product price in
Offer.price— never the deposit amount alone - Declare deposit and balance in
priceSpecificationif deposit-based pre-order - Add
availabilityStartsif pre-orders open on a specific future date - Create
preorder.is_preorderboolean metafield to toggle JSON-LD availability - Automate PreOrder → InStock transition when fulfillment begins
- Ping IndexNow on status changes (pre-order opens, closes, ships)
- Test Rich Results Test after setting PreOrder to confirm structured data validates
- Run CatalogScan to verify pre-order availability appears in AI readiness score
Frequently Asked Questions
What schema.org availability value should I use for pre-order products?
Use https://schema.org/PreOrder as the Offer.availability value. This is a native schema.org type recognized by Google, Bing, and AI shopping agents. Pair it with a releaseDate additionalProperty for the expected ship date and availabilityStarts if pre-orders open on a specific future date.
How do I declare a deposit or partial payment requirement in structured data?
Keep Offer.price at the full product price. Declare the deposit in priceSpecification with a named PriceSpecification entry ("Pre-order deposit — due now") and a separate entry for the balance ("Balance due at shipping"). You can also add depositAmount and remainingBalanceDue as additionalProperty entries for parsers that prefer flat properties.
Can AI shopping agents surface pre-order products in search results?
Yes. ChatGPT Shopping, Perplexity Shopping, and Google AI Mode all process PreOrder availability and surface upcoming products for "can I pre-order X?" and "when does Y ship?" queries. Google Shopping shows a "Pre-order" badge. Without the PreOrder signal, your upcoming product is indistinguishable from an out-of-stock item.
When should I switch availability from PreOrder to InStock?
Switch Offer.availability to InStock on the day you begin shipping — not the announcement date. Switching before fulfillment begins is a Google Merchant Center policy violation. Use Shopify Flow or a Liquid ship-date comparison to automate the transition.
Does Shopify automatically set PreOrder availability in structured data?
No. Shopify's default JSON-LD uses inventory quantity — zero stock defaults to OutOfStock. You must override this with a preorder.is_preorder metafield and update your product.liquid JSON-LD template to inject PreOrder availability when the metafield is true.