Ecommerce SEO + AI Visibility

Out-of-stock SEO and structured data
for ecommerce

OutOfStock, BackOrder, PreOrder, Discontinued — the four availability values that control how AI shopping agents handle your unavailable products.

TL;DR Most Shopify stores output OutOfStock for every unavailable product, even back-orderable items. Using BackOrder + OrderDeliveryTime unlocks "ships by [date]" signals in ChatGPT Shopping and Google AI Mode. Use PreOrder for future launches, Discontinued for permanent removals. Never use InStock for an unavailable product.

The four schema.org availability values you actually need

Schema.org's ItemAvailability enumeration has 14 values, but only four matter for AI shopping agents in 2026. Using the wrong one costs you either in AI agent visibility (unavailable products surfaced as buyable) or in conversion quality (back-orderable products hidden entirely).

ValueMeaningWhen to usePair with
InStock Available now, will ship immediately Inventory > 0, ready to ship Standard Offer
OutOfStock Unavailable, no restock commitment Inventory = 0, no continue-selling flag Optional availabilityEnds for seasonal items
BackOrder Unavailable now, accepting orders for future fulfillment Inventory = 0, continue-selling enabled, restock date known/estimated OrderDeliveryTime with handlingTime + transitTime
PreOrder Product not yet released, accepting early orders Product launch > today, accepting orders before availability availabilityStarts with the release date
Discontinued Permanently unavailable, will not return Product EOL, never restocking Consider 301 redirect after 90 days

The most expensive mistake: using OutOfStock for back-orderable items

Shopify's default theme outputs OutOfStock for any product where product.available == false. But a product with inventory_policy: continue (the "Continue selling when out of stock" setting) is actually back-orderable — the merchant intends to accept orders and fulfill them when stock arrives. Using OutOfStock here causes:

AI agent behavior by availability value

AvailabilityChatGPT ShoppingGoogle AI ModePerplexityBing AI
InStock Shows, buy CTA Shows, buy CTA Shows, in-stock label Shows, buy CTA
BackOrder Shows + ship date Shows "ships by [date]" Shows, back-order label Shows in comparison
PreOrder Shows, pre-order CTA Shows + release date Shows, pre-order label Shows in research mode
OutOfStock Hidden (transactional) Hidden from shopping Shows, unavailable label Hidden from shopping
Discontinued Hidden Hidden Hidden Hidden

Correct Liquid JSON-LD for all availability states

Complete availability detection snippet (Shopify Liquid)

{% assign variant = product.selected_or_first_available_variant %}
{% assign avail_url = "https://schema.org/" %}

{% if variant.available %}
  {% assign availability = "InStock" %}
{% elsif variant.inventory_policy == "continue" %}
  {% comment %} Continue selling = back-orderable {% endcomment %}
  {% assign availability = "BackOrder" %}
{% elsif product.tags contains "pre-order" or product.tags contains "preorder" %}
  {% assign availability = "PreOrder" %}
{% elsif product.tags contains "discontinued" %}
  {% assign availability = "Discontinued" %}
{% else %}
  {% assign availability = "OutOfStock" %}
{% endif %}

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": {{ product.title | json }},
  "offers": {
    "@type": "Offer",
    "availability": {{ avail_url | append: availability | json }},
    "price": {{ variant.price | divided_by: 100.0 | json }},
    "priceCurrency": {{ shop.currency | json }},
    "url": "{{ shop.url }}{{ product.url }}"
    {% if availability == "BackOrder" and product.metafields.custom.restock_date != blank %}
    ,"orderDeliveryTime": {
      "@type": "ShippingDeliveryTime",
      "handlingTime": {
        "@type": "QuantitativeValue",
        "minValue": 0,
        "maxValue": {{ product.metafields.custom.restock_days_min | default: 7 }},
        "unitCode": "DAY"
      },
      "transitTime": {
        "@type": "QuantitativeValue",
        "minValue": 2,
        "maxValue": 5,
        "unitCode": "DAY"
      }
    }
    {% endif %}
    {% if availability == "PreOrder" and product.metafields.custom.release_date != blank %}
    ,"availabilityStarts": {{ product.metafields.custom.release_date | json }}
    {% endif %}
  }
}
</script>

BackOrder with explicit delivery window

For back-orderable items, Google AI Mode and ChatGPT Shopping both surface the expected delivery date when you pair BackOrder with a proper OrderDeliveryTime block. This drives measurably higher click-through than a bare "back order" label.

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Titanium Water Bottle 32oz",
  "offers": {
    "@type": "Offer",
    "availability": "https://schema.org/BackOrder",
    "price": 49.00,
    "priceCurrency": "USD",
    "availabilityEnds": "2026-07-15T00:00:00-05:00",
    "orderDeliveryTime": {
      "@type": "ShippingDeliveryTime",
      "handlingTime": {
        "@type": "QuantitativeValue",
        "minValue": 14,
        "maxValue": 21,
        "unitCode": "DAY"
      },
      "transitTime": {
        "@type": "QuantitativeValue",
        "minValue": 2,
        "maxValue": 5,
        "unitCode": "DAY"
      },
      "businessDays": {
        "@type": "OpeningHoursSpecification",
        "dayOfWeek": [
          "https://schema.org/Monday",
          "https://schema.org/Tuesday",
          "https://schema.org/Wednesday",
          "https://schema.org/Thursday",
          "https://schema.org/Friday"
        ]
      }
    }
  }
}

PreOrder with launch date

{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Model X Pro Headphones — 2026 Edition",
  "offers": {
    "@type": "Offer",
    "availability": "https://schema.org/PreOrder",
    "availabilityStarts": "2026-09-01T09:00:00-07:00",
    "price": 299.00,
    "priceCurrency": "USD",
    "priceValidUntil": "2026-12-31"
  }
}

Shopify inventory_policy: the hidden back-order signal

The most overlooked Shopify availability signal is variant.inventory_policy. When a merchant enables "Continue selling when out of stock" in the product variant inventory settings, Shopify sets this field to "continue". The default Dawn theme completely ignores this and outputs OutOfStock regardless.

Shopify settinginventory_policy valueCorrect schema.org valueDefault Dawn theme output
Stop selling when out of stock deny OutOfStock (when qty = 0) OutOfStock ✓
Continue selling when out of stock continue BackOrder (when qty = 0) OutOfStock ✗
Track quantity (positive stock) deny InStock InStock ✓
Don't track quantity deny InStock (assumed) InStock ✓

In CatalogScan's scan data, 34% of stores that accept back-orders output OutOfStock in their JSON-LD, causing AI agents to suppress products the merchant is ready and willing to sell.

Keeping availability in sync via webhooks

Availability values in JSON-LD must match actual inventory state. AI agents do not appreciate discovering a product marked InStock in structured data that is actually sold out on the product page — it erodes trust scores and can trigger content quality penalties in Google Search. The cleanest approach for high-volume stores is a webhook that updates the product page's availability metafield in near real-time.

// Shopify webhook: inventory_levels/update
// Node.js handler
app.post('/webhooks/inventory', shopifyWebhookMiddleware, async (req, res) => {
  const { inventory_item_id, available } = req.body;

  // Look up which product variant owns this inventory item
  const variant = await shopify.rest.Variant.all({
    session,
    inventory_item_ids: inventory_item_id
  });

  if (!variant?.data?.length) return res.sendStatus(200);

  const v = variant.data[0];
  const policy = v.inventory_policy; // 'deny' or 'continue'

  let availability;
  if (available > 0) {
    availability = 'InStock';
  } else if (policy === 'continue') {
    availability = 'BackOrder';
  } else {
    availability = 'OutOfStock';
  }

  // Store in metafield so Liquid template can read it
  await shopify.rest.Metafield.save({
    session,
    body: {
      metafield: {
        owner_resource: 'product_variant',
        owner_id: v.id,
        namespace: 'catalog_scan',
        key: 'availability',
        value: availability,
        type: 'single_line_text_field'
      }
    }
  });

  res.sendStatus(200);
});

SEO strategy for permanently out-of-stock pages

When a product is discontinued or permanently removed, you have three options:

  1. Keep the page live with Discontinued availability — maintains any accumulated backlinks and lets AI agents understand the product exists but is gone. Add internal links to the closest in-stock alternatives. Best for high-traffic product pages.
  2. 301 redirect to the closest in-stock alternative — transfers link equity and prevents AI agents from surfacing the dead product. Best for products with a clear direct replacement.
  3. 301 redirect to the parent collection — least disruptive for generic products with no clear replacement. Ensures users land on relevant inventory rather than a dead end.

Never serve a 410 Gone for a product page that has existing inbound links from editorial coverage or AI citation lists. The 410 immediately signals "this no longer exists" and purges the page from AI agent knowledge bases, destroying any earned AI-citation authority permanently.

FAQ

Do AI shopping agents show out-of-stock products to users?

It depends on the agent and the query. ChatGPT Shopping and Google AI Mode generally filter out products with OutOfStock availability for transactional queries but may still show them for research queries. Perplexity Shopping tends to show availability status explicitly and does not filter OOS from discovery results. Bing Shopping AI hides OutOfStock from transactional but shows them in comparison mode. The most important thing is to use the correct availability value — using InStock when unavailable causes AI agents to recommend products users cannot buy, damaging trust.

What is the difference between BackOrder and OutOfStock in schema.org?

OutOfStock means the product is currently unavailable with no commitment to restocking. BackOrder means the product is unavailable but can be ordered now and will ship when stock is replenished. BackOrder is always preferable when you accept back-orders because AI agents pair it with your OrderDeliveryTime to display "ships by [date]" in shopping results — a signal that increases click-through rate vs. a blank availability field.

Should I keep out-of-stock Shopify product pages indexed?

Generally yes, if the product will return to stock. Removing a URL forces re-crawling and re-indexing when it comes back, costing 2–6 weeks of visibility. Keep the page indexed with OutOfStock or BackOrder availability, add an email capture, and use availabilityEnds or availabilityStarts to give crawlers date context.

Does Shopify set the correct availability in JSON-LD automatically?

Shopify's default Dawn theme outputs InStock when product.available is true and OutOfStock when false — but it does not distinguish between BackOrder, PreOrder, or Discontinued. If you use Shopify's "Continue selling when out of stock" option, the default theme still outputs OutOfStock instead of BackOrder. You need a custom Liquid snippet that reads variant.inventory_policy to output the correct value.

What happens if my JSON-LD says InStock but my page shows out of stock?

Google's systems detect conflicts between structured data and visible page content. When the schema signals InStock but the page clearly states "sold out" or disables the add-to-cart button, it triggers a data quality issue that can reduce your Rich Results eligibility and your Google Merchant Center product listing quality score. Always keep your JSON-LD availability in sync with actual inventory — use the webhook pattern above for high-volume stores.

Scan for availability mismatches

CatalogScan's free scan checks whether your product JSON-LD availability values match your actual Shopify inventory state, flags back-orderable products incorrectly marked OutOfStock, and identifies products using InStock while the add-to-cart button is disabled.

Scan your store free

Related: Subscription product availability · Schema markup guide · Metafields and AI agents