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.

TL;DR Set 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.keyTypeExample valuePurpose
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:

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

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.

Related Resources