Optimization Guide
Shopify Low Stock and Scarcity Signal Structured Data for AI Shopping Agents
AI shopping agents surface availability urgency when users ask "limited edition sneakers available now" or "exclusive drops I can still buy." Shopify's default JSON-LD shows InStock for everything — your low-stock urgency signals and true limited editions are invisible to every AI shopping index.
Offer.availability from InStock to LimitedAvailability when inventory drops below your threshold (typically 5–10 units). Drive this dynamically from variant.inventory_quantity in Liquid. For genuine limited editions, add additionalProperty: {propertyID: "limitedEdition", value: "true"} and optionally set inventoryLevel with the total production count. Use availabilityEnds for time-bounded drops. Never show LimitedAvailability permanently on always-restocked items — AI agents learn to ignore it.
The Scarcity Visibility Gap
Inventory urgency is one of the most powerful conversion levers in e-commerce. "Only 3 left" banners, low-stock warnings, and "limited edition" badges are standard on product pages — but they are JavaScript-rendered or text-based, neither of which is machine-readable by AI shopping agents crawling your structured data.
Shopify generates "availability": "https://schema.org/InStock" for any in-stock product, regardless of quantity. A product with 500 units and a product with 2 units left look identical to every AI shopping index. This means your genuine scarcity signals — the exact situations where urgency should drive recommendation priority — are completely absent from the AI shopping layer.
Scarcity query types that require LimitedAvailability signals
| Query type | Example | Required signal | AI behavior |
|---|---|---|---|
| Limited edition filter | "limited edition sneakers still available" | LimitedAvailability + limitedEdition: true |
Surfaces products flagged as limited runs with remaining stock |
| Exclusive drop discovery | "exclusive drops I can still buy" | LimitedAvailability + exclusiveDrop: true |
Surfaces drops that are live and not yet sold out |
| Low stock urgency | "last chance headphones before discontinue" | LimitedAvailability + lastChance: true |
Flags as urgency-priority in comparison recommendations |
| Time-limited availability | "holiday collection available this week only" | availabilityEnds (date) |
Surfaces in time-sensitive queries; deprioritizes after end date |
| Production count | "limited run of 500 — how many left?" | inventoryLevel with remaining count |
Surfaces products with known limited production runs |
InStock vs. LimitedAvailability — what AI agents see
{
"@type": "Offer",
"price": "149.00",
"availability":
"https://schema.org/
InStock"
// Same signal whether
// 500 units or 2 units
// No urgency for AI agent
}
{
"@type": "Offer",
"price": "149.00",
"availability":
"https://schema.org/
LimitedAvailability",
"additionalProperty": [{
"propertyID":
"limitedEdition",
"value": "true"
}],
"inventoryLevel": {
"value": 3
}
}
Scarcity JSON-LD Patterns
Dynamic low-stock — inventory-threshold based
The most important pattern: use LimitedAvailability when inventory is below threshold, driven dynamically by Liquid. This keeps your structured data synchronized with real stock levels:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Vintage Analog Watch — Navy Blue",
"offers": {
"@type": "Offer",
"price": "189.00",
"priceCurrency": "USD",
"availability": "https://schema.org/LimitedAvailability",
"inventoryLevel": {
"@type": "QuantitativeValue",
"value": 4
}
}
}
True limited edition — finite production run
For genuinely limited products (numbered prints, special colorways, one-time production batches), declare both the limited edition status and the total production count:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Artist Print — 'Morning Light' — Limited Edition",
"offers": {
"@type": "Offer",
"price": "450.00",
"priceCurrency": "USD",
"availability": "https://schema.org/LimitedAvailability",
"additionalProperty": [
{
"@type": "PropertyValue",
"propertyID": "limitedEdition",
"name": "Limited edition",
"value": "true"
},
{
"@type": "PropertyValue",
"propertyID": "productionRun",
"name": "Total production run",
"value": "250"
},
{
"@type": "PropertyValue",
"propertyID": "editionNumber",
"name": "This print",
"value": "Individually numbered 1–250"
}
],
"inventoryLevel": {
"@type": "QuantitativeValue",
"value": 47,
"description": "47 of 250 remaining"
}
}
}
Time-limited drop with availability end date
For flash drops or seasonal collections with a hard end date, use availabilityEnds to signal to AI agents that the product has a time deadline:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Holiday Gift Set — Collector's Edition",
"offers": {
"@type": "Offer",
"price": "89.00",
"priceCurrency": "USD",
"availability": "https://schema.org/LimitedAvailability",
"availabilityEnds": "2026-12-24T23:59:59-05:00",
"additionalProperty": [
{
"@type": "PropertyValue",
"propertyID": "limitedEdition",
"value": "true"
},
{
"@type": "PropertyValue",
"propertyID": "dropType",
"value": "Holiday seasonal — no restock after December 24"
}
]
}
}
Availability state progression
Manage the Offer.availability value as a lifecycle. The correct progression as inventory changes:
| Inventory state | availability value |
URI | AI agent interpretation |
|---|---|---|---|
| Well-stocked (10+ units) | InStock |
https://schema.org/InStock |
Available without urgency signal |
| Low stock (1–9 units) | LimitedAvailability |
https://schema.org/LimitedAvailability |
Available with urgency — surfaced in scarcity queries |
| Zero inventory, back-orderable | BackOrder |
https://schema.org/BackOrder |
Not immediately available; order fulfills when restocked |
| Discontinued, last stock | LimitedAvailability |
https://schema.org/LimitedAvailability |
Last chance — combine with lastChance: true additionalProperty |
| Sold out | OutOfStock |
https://schema.org/OutOfStock |
Excluded from in-stock queries; included in wishlist/alert queries |
Shopify Liquid Implementation
The key is driving availability dynamically from variant.inventory_quantity. This keeps structured data synchronized with actual stock levels without manual updates:
{% assign variant = product.selected_or_first_available_variant %}
{% assign qty = variant.inventory_quantity %}
{% assign is_limited_edition = product.metafields.scarcity.limited_edition %}
{% assign production_run = product.metafields.scarcity.production_run %}
{% assign availability_ends = product.metafields.scarcity.availability_ends %}
{% assign low_stock_threshold = 10 %}
{% if product.available %}
{% if qty <= low_stock_threshold %}
{% assign availability = 'LimitedAvailability' %}
{% else %}
{% assign availability = 'InStock' %}
{% endif %}
{% elsif variant.available == false and product.available %}
{% assign availability = 'BackOrder' %}
{% else %}
{% assign availability = 'OutOfStock' %}
{% endif %}
"offers": {
"@type": "Offer",
"price": {{ variant.price | money_without_currency | remove: ',' | json }},
"priceCurrency": {{ cart.currency.iso_code | json }},
"availability": "https://schema.org/{{ availability }}"
{% if availability_ends %}
,"availabilityEnds": {{ availability_ends | json }}
{% endif %}
{% if qty > 0 and qty <= 20 %}
,"inventoryLevel": {
"@type": "QuantitativeValue",
"value": {{ qty }}
}
{% endif %}
{% if is_limited_edition or production_run %}
,"additionalProperty": [
{% if is_limited_edition %}
{
"@type": "PropertyValue",
"propertyID": "limitedEdition",
"value": "true"
}
{% if production_run %},{% endif %}
{% endif %}
{% if production_run %}
{
"@type": "PropertyValue",
"propertyID": "productionRun",
"name": "Total production run",
"value": {{ production_run | json }}
}
{% endif %}
]
{% endif %}
}
Set up these metafields in Shopify Admin → Settings → Custom data → Products for the scarcity namespace:
| Metafield key | Type | Example | Purpose |
|---|---|---|---|
scarcity.limited_edition |
Boolean | true |
Flags product as a finite, non-repeating production run |
scarcity.production_run |
Integer | 250 |
Total units produced (for numbered editions) |
scarcity.availability_ends |
Date and time | 2026-12-24T23:59:59-05:00 |
Hard end date for time-limited drops |
scarcity.low_stock_threshold |
Integer | 5 |
Custom per-product threshold (override default 10) |
Common Mistakes
| Mistake | Impact | Fix |
|---|---|---|
Always using InStock regardless of quantity |
No urgency signal; limited editions and low-stock items treated identically to well-stocked items | Drive availability dynamically from variant.inventory_quantity in Liquid |
Permanently showing LimitedAvailability for restocked items |
AI agents learn to ignore LimitedAvailability from your store — signal loses credibility |
Only show LimitedAvailability when inventory is genuinely below threshold; revert to InStock after restock |
| Disclosing exact low inventory count (1 or 2 units) | Exact count enables competitor price-matching automation; creates customer hesitation if exact count seems artificially low | Consider only outputting inventoryLevel when qty is between 3 and 10; use "low stock" framing for smaller quantities |
Missing availabilityEnds for seasonal drops |
AI agents cannot surface products in "available this week" time-sensitive queries | Add availabilityEnds as an ISO 8601 datetime for all time-limited availability windows |
No limitedEdition additionalProperty for true limited runs |
AI cannot distinguish "low stock right now" from "genuinely never restocked" | Add limitedEdition: true and productionRun count for products that will never be restocked |
Implementation Checklist
- Update
product.liquidJSON-LD to driveOffer.availabilitydynamically fromvariant.inventory_quantity - Set
LimitedAvailabilitywheninventory_quantityis below your low-stock threshold (default: 10 units) - Create scarcity metafield namespace:
limited_edition,production_run,availability_ends - Add
limitedEdition: trueadditionalProperty for products that will never be restocked - Add
productionRunadditionalProperty for numbered or finite-edition products - Add
availabilityEndsfor all time-limited drops and seasonal collections - Only output
inventoryLevelwhen quantity is above 2 (to avoid exposing critically low counts to competitors) - Revert to
InStockautomatically when inventory exceeds threshold after restock - Validate with Rich Results Test after updating availability logic
- Run CatalogScan to verify scarcity signals appear correctly in your AI readiness score
Frequently Asked Questions
How do I declare low stock in Shopify structured data?
Use "availability": "https://schema.org/LimitedAvailability" as the Offer.availability value when inventory is below your threshold (typically 5–10 units). Drive this dynamically in Liquid using variant.inventory_quantity. Optionally add inventoryLevel as a QuantitativeValue with the remaining count. For genuine limited editions, add additionalProperty with propertyID: "limitedEdition" set to "true".
What is the difference between LimitedAvailability and InStock?
InStock signals the product is available without restriction. LimitedAvailability signals the product is available but with limited quantity — triggering urgency signals for AI agents and search engines. Use LimitedAvailability for low-stock situations, limited edition releases that won't be repeated, and flash sale inventory at limited quantities. Always switch back to InStock when inventory is replenished.
Can AI shopping agents surface scarcity signals?
Yes. ChatGPT Shopping and Perplexity Shopping increasingly include availability context in recommendations. Users asking "limited edition sneakers available now" or "exclusive drops I can still buy" see products with LimitedAvailability or limitedEdition signals prioritized. When comparing two similar products, AI agents may also note which is "limited availability" — influencing the recommendation even without explicit scarcity filtering.
How do I use Shopify inventory to dynamically set LimitedAvailability?
In Liquid, use product.selected_or_first_available_variant.inventory_quantity to get the current count. Add a conditional: if inventory_quantity > 0 and inventory_quantity <= 10, output LimitedAvailability; if inventory_quantity > 10, output InStock; if inventory_quantity == 0, output OutOfStock. This keeps structured data synchronized with real inventory without manual updates.
Should I always show LimitedAvailability to create urgency?
No. Perpetually showing LimitedAvailability on always-restocked products is deceptive. AI agents trained on cross-referencing availability claims with purchase patterns will learn to de-weight urgency signals from your store if they're consistently inaccurate. Reserve LimitedAvailability for genuine low-stock situations and true limited editions — accuracy preserves the signal's value.