CatalogScan

SEO Guide · 2026

E-commerce checkout structured data: what AI agents see before and after purchase (2026)

The cart and checkout are the most misunderstood pages in e-commerce structured data. Merchants add Product schema to cart pages thinking it helps — it doesn't, it causes validation errors. The real post-purchase opportunity is Order schema on confirmation pages, where AI agents like ChatGPT can use it for order tracking answers. Here's the complete picture for Shopify merchants.

TL;DR Cart pages and checkout step pages should have no Product JSON-LD — these are transient session pages that cause duplicate structured data conflicts. The order confirmation page is the valuable structured data opportunity: Order schema with nested OrderItem objects lets AI agents (and Google's receipt-parsing system) read order details for tracking intents. Shopify Plus merchants can inject this into checkout.liquid or the thank-you page extension; non-Plus merchants must add it to the /orders/{token} customer account template instead.
0Valid rich result types for cart and checkout step pages
3AI agent touchpoints in the post-purchase journey
4Shopify page types with different structured data rules
PlusRequired for checkout.liquid structured data access

The structured data landscape around checkout

The checkout funnel for a Shopify store consists of four distinct page types, each with different structured data rules, different AI agent touchpoints, and different technical constraints for implementation. Understanding what's valid — and what's explicitly harmful — at each stage is essential before adding any JSON-LD.

Page typeShopify URL patternValid schema typesExplicitly excludedAI agent touches this?
Cart page /cart None — no structured data Product, ItemList, BreadcrumbList (technically valid HTML but provides no value; Google doesn't crawl session-specific carts) No — session-locked, no public crawl
Checkout steps /checkouts/{token} BreadcrumbList (Plus only via checkout.liquid) Product, Order, FAQPage — these pages are session-gated and not publicly crawlable No — requires authentication; not indexed
Order confirmation /thank-you (Plus) or thank-you step in checkout Order, OrderItem, BreadcrumbList Product standalone, ItemList, FAQPage Partial — Google reads receipts; ChatGPT with email access
Account order page /account/orders/{order_id} Order, OrderItem, BreadcrumbList Product standalone (wrong context) Yes — publicly crawlable if logged in with correct session; Google indexes order status pages

Why you should NOT add Product schema to cart pages

This is the most common checkout structured data mistake. Merchants add Product JSON-LD to the cart page (/cart) intending to reinforce product data for Google. The result is the opposite of helpful — it causes three specific problems:

Problem 1: Duplicate conflicting signals. Your product page at /products/cloudstrike-pro already outputs Product schema with canonical: https://yourstore.com/products/cloudstrike-pro. If the cart page also outputs Product schema for the same product, Google sees two different URLs claiming to be the authoritative source for the same product's structured data. This creates a duplicate signal conflict that can suppress both pages' rich result eligibility.

Problem 2: Session-specific content on a crawlable URL. /cart is a publicly accessible URL. Googlebot crawls it. What it finds there depends entirely on which session's cart is cached or what an empty cart shows. If Googlebot visits /cart and finds Product schema for items from a previous crawl session, then visits again and finds an empty cart with no schema, the structured data becomes inconsistent and unreliable — Google's quality systems treat inconsistent structured data as a spam signal.

Problem 3: Rich Results Test validation errors. Product schema requires Offer with a current price, availability, and URL. On a cart page, the product URL in the schema correctly points to /products/cloudstrike-pro, but the page URL is /cart. The Rich Results Test flags this as a mismatch — the schema URL doesn't match the page URL, which is a validation error for Product rich results.

Do not add this to your cart page: Any Product or ItemList JSON-LD block. The cart page's structured data should be empty. If your theme or an app is injecting Product schema on the cart page, remove it.

Pre/post-purchase AI agent touchpoints

Journey stageAI agentWhat it readsMerchant action
Pre-purchase research ChatGPT Shopping, Google AI Mode, Perplexity Product page JSON-LD (Product, Offer, AggregateRating, shippingDetails, returnPolicy) Ensure complete Product schema on all product pages
Cart / checkout None publicly Session-gated; no AI agent crawls these pages No action — leave without structured data
Order confirmation email ChatGPT (Gmail integration), Google Assistant Email body order details; Schema.org email markup (ConfirmationOrder); tracking links Structure confirmation email with clear order #, item list, estimated delivery, and tracking link
Order confirmation page Google (receipt page indexing) Order JSON-LD with OrderItem details, order number, total, merchant identity Add Order schema to confirmation page via checkout.liquid (Plus) or post-purchase extension
Order status / account page Google AI Mode (order tracking queries) Order JSON-LD with current orderStatus, tracking URL, estimated delivery Add Order schema with dynamic orderStatus to customer account order pages
Delivery / receipt ChatGPT (email access), Google (Gmail actions) Shipping confirmation email; tracking number; delivery confirmation Structure shipping emails with machine-readable tracking numbers and carrier names
The order confirmation page and the customer account order status page are where post-purchase structured data pays off. Google can use Order schema to answer "what's the status of my order from [store]?" queries in AI Mode.

Order schema JSON-LD for confirmation pages

The Order schema type represents a purchase order. For an e-commerce order confirmation page, include the order number, order date, order status, the merchant as seller, the customer as customer (with care about PII), and each ordered item as an OrderItem. The orderStatus field should reflect the current status using the https://schema.org/OrderStatus value set.

<!-- Order confirmation page: Order JSON-LD (Shopify Plus: checkout.liquid or post-purchase extension) -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Order",
  "orderNumber": "1058273",
  "orderDate": "2026-06-02T14:37:00Z",
  "orderStatus": "https://schema.org/OrderProcessing",
  "confirmationNumber": "1058273",
  "merchant": {
    "@type": "Organization",
    "name": "TrailForce Store",
    "url": "https://trailforce.com",
    "logo": "https://trailforce.com/assets/logo.svg"
  },
  "seller": {
    "@type": "Organization",
    "name": "TrailForce Store",
    "url": "https://trailforce.com"
  },
  "url": "https://trailforce.com/account/orders/1058273",
  "priceCurrency": "USD",
  "price": "167.98",
  "discount": "0.00",
  "acceptedOffer": [
    {
      "@type": "Offer",
      "itemOffered": {
        "@type": "Product",
        "name": "Cloudstrike Pro Women's Trail Running Shoe — Midnight Blue / US 8",
        "sku": "TF-CLOUDSTRIKE-W-US8-MIDBLUE",
        "url": "https://trailforce.com/products/cloudstrike-pro-women",
        "image": "https://trailforce.com/cdn/shop/products/cloudstrike-pro-w-midnight-blue-front.jpg"
      },
      "price": "139.99",
      "priceCurrency": "USD"
    },
    {
      "@type": "Offer",
      "itemOffered": {
        "@type": "Product",
        "name": "TrailForce Performance Running Socks — 3-Pack",
        "sku": "TF-SOCKS-3PK-M",
        "url": "https://trailforce.com/products/performance-socks-3pack",
        "image": "https://trailforce.com/cdn/shop/products/performance-socks-3pack.jpg"
      },
      "price": "27.99",
      "priceCurrency": "USD"
    }
  ],
  "orderedItem": [
    {
      "@type": "OrderItem",
      "orderItemNumber": "1",
      "orderQuantity": 1,
      "orderDelivery": {
        "@type": "ParcelDelivery",
        "expectedArrivalFrom": "2026-06-05",
        "expectedArrivalUntil": "2026-06-07",
        "hasDeliveryMethod": {
          "@type": "DeliveryMethod",
          "name": "Standard Shipping"
        }
      },
      "orderedItem": {
        "@type": "Product",
        "name": "Cloudstrike Pro Women's Trail Running Shoe — Midnight Blue / US 8",
        "sku": "TF-CLOUDSTRIKE-W-US8-MIDBLUE",
        "url": "https://trailforce.com/products/cloudstrike-pro-women"
      }
    },
    {
      "@type": "OrderItem",
      "orderItemNumber": "2",
      "orderQuantity": 1,
      "orderedItem": {
        "@type": "Product",
        "name": "TrailForce Performance Running Socks — 3-Pack",
        "sku": "TF-SOCKS-3PK-M",
        "url": "https://trailforce.com/products/performance-socks-3pack"
      }
    }
  ],
  "paymentMethod": "https://schema.org/CreditCard",
  "paymentMethodId": "Visa ending 4242",
  "billingAddress": {
    "@type": "PostalAddress",
    "addressCountry": "US"
  }
}
</script>
Privacy note: Do not include the customer's full name, email address, full shipping address, or payment card details in Order schema JSON-LD on any publicly accessible page. Schema.org Order supports customer and billingAddress fields, but these should contain only the minimum necessary for machine-readable context (e.g. addressCountry) — not full PII that would be visible in the page source. Order status pages protected by customer account authentication can include more detail; public confirmation pages cannot.

Shopify Plus vs. non-Plus structured data options

CapabilityShopify PlusShopify (non-Plus)
Customize checkout step pages Yes — via checkout.liquid (being deprecated) or checkout extensibility No — checkout is locked by Shopify
Add BreadcrumbList to checkout steps Yes — via checkout.liquid or checkout UI extension script tag No
Add Order schema to thank-you page Yes — via checkout.liquid additional_checkout_scripts or Post-Purchase extension Limited — via "Additional scripts" in Settings › Checkout (being removed)
Add Order schema to customer account order page Yes — edit customers/order.liquid Yes — edit customers/order.liquid
Checkout UI Extensions (post-purchase page) Yes No
Order status schema on account pages Yes Yes
Add script tags to checkout Yes No
Transactional email customization Full HTML email editor Full HTML email editor

Implementing Order schema on the Shopify customer account order page

The customer account order page (/account/orders/{order_id}) is available on all Shopify plans. Unlike the checkout confirmation page, the account order page remains accessible to the customer after their session ends — and importantly, it's where customers return to check order status. Adding Order schema to this template benefits both non-Plus merchants and Plus merchants as a stable, non-session-gated location for order structured data.

Edit customers/order.liquid in your Shopify theme and add this Liquid-generated JSON-LD block:

{% comment %}
  Order schema for customer account order page
  File: customers/order.liquid
  Works on: All Shopify plans
{% endcomment %}

{% assign order_url = shop.url | append: '/account/orders/' | append: order.id %}

{% comment %} Map Shopify order financial_status to schema.org OrderStatus {% endcomment %}
{% case order.financial_status %}
  {% when 'pending' %}
    {% assign schema_order_status = 'https://schema.org/OrderPaymentDue' %}
  {% when 'authorized', 'partially_paid' %}
    {% assign schema_order_status = 'https://schema.org/OrderProcessing' %}
  {% when 'paid' %}
    {% assign schema_order_status = 'https://schema.org/OrderProcessing' %}
  {% when 'refunded', 'voided' %}
    {% assign schema_order_status = 'https://schema.org/OrderCancelled' %}
  {% else %}
    {% assign schema_order_status = 'https://schema.org/OrderProcessing' %}
{% endcase %}

{% comment %} Override with fulfillment status if shipped {% endcomment %}
{% if order.fulfillment_status == 'fulfilled' %}
  {% assign schema_order_status = 'https://schema.org/OrderDelivered' %}
{% elsif order.fulfillment_status == 'partial' %}
  {% assign schema_order_status = 'https://schema.org/OrderInTransit' %}
{% endif %}

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Order",
  "orderNumber": {{ order.name | json }},
  "orderDate": {{ order.created_at | date: '%Y-%m-%dT%H:%M:%SZ' | json }},
  "orderStatus": {{ schema_order_status | json }},
  "confirmationNumber": {{ order.name | json }},
  "url": {{ order_url | json }},
  "priceCurrency": {{ order.currency | json }},
  "price": "{{ order.total_price | money_without_currency }}",
  "merchant": {
    "@type": "Organization",
    "name": {{ shop.name | json }},
    "url": {{ shop.url | json }}
  },
  "seller": {
    "@type": "Organization",
    "name": {{ shop.name | json }},
    "url": {{ shop.url | json }}
  },
  "orderedItem": [
    {% for line_item in order.line_items %}
    {
      "@type": "OrderItem",
      "orderItemNumber": "{{ forloop.index }}",
      "orderQuantity": {{ line_item.quantity }},
      "orderedItem": {
        "@type": "Product",
        "name": {{ line_item.title | json }},
        "sku": {{ line_item.sku | json }},
        "url": {{ shop.url | append: line_item.product.url | json }},
        "image": "https:{{ line_item.product.featured_image | img_url: '400x' }}"
      },
      "orderItemStatus": {% if order.fulfillment_status == 'fulfilled' %}"https://schema.org/OrderDelivered"{% else %}"https://schema.org/OrderInTransit"{% endif %}
    }{% unless forloop.last %},{% endunless %}
    {% endfor %}
  ]
  {% if order.fulfillments.size > 0 %}
  {% assign first_fulfillment = order.fulfillments | first %}
  {% if first_fulfillment.tracking_number != blank %}
  ,"trackingUrl": "{{ first_fulfillment.tracking_url }}"
  {% endif %}
  {% endif %}
}
</script>

OrderStatus values and their meanings

Schema.org OrderStatusShopify equivalentWhen to use
OrderPaymentDue financial_status: pending Order placed but payment not yet captured (e.g. bank transfer, net-30)
OrderProcessing financial_status: paid; fulfillment: unfulfilled Payment received; order being picked, packed, and prepared for shipment
OrderInTransit fulfillment_status: partial or in transit At least one shipment dispatched; tracking available
OrderDelivered fulfillment_status: fulfilled + delivery confirmed All items delivered to customer
OrderCancelled financial_status: refunded or voided; cancelled_at set Order cancelled before or after shipment
OrderProblem No direct Shopify equivalent; use for dispute/issue states Delivery exception, damaged goods, or fulfillment failure
OrderReturned financial_status: partially_refunded after fulfillment Items returned and refund issued

How AI agents use purchase confirmation data

ChatGPT with Gmail integration

ChatGPT Plus users can grant ChatGPT access to their Gmail inbox. When a customer asks "what did I order from TrailForce last week?", ChatGPT can search the Gmail inbox for order confirmation emails from TrailForce and parse the order details from the email body. Google's email platform also supports Schema.org markup in emails — if your transactional email includes OrderAction or ConfirmationOrder structured data, Gmail renders rich UI actions (view order, track shipment) directly in the email client. This is separate from web page structured data but uses the same schema.org vocabulary.

Google AI Mode for order tracking queries

Google's AI Mode can answer questions like "when will my order from [store] arrive?" by parsing order status pages indexed in Search Console or accessed via Google's receipt page indexing. When a user is signed into their Google account and performs this query, Google can match it to order confirmation emails in Gmail or to indexed order status pages on your website. Order schema on your customer account order page — with current orderStatus and trackingUrl — makes this matching more reliable and the AI Mode answer more accurate.

Post-purchase opportunity: OrderStatus on account pages

The customer account page is the highest-value post-purchase structured data location because it's persistent (unlike the one-time confirmation page) and publicly accessible to signed-in users (unlike the transient checkout). Updating the orderStatus field dynamically as the Shopify order fulfillment status changes means AI agents that index this page get current order status information — not just the initial "OrderProcessing" state from the confirmation email.

For Shopify stores, this dynamic update happens automatically if your customers/order.liquid template uses the Liquid order.fulfillment_status and order.financial_status variables to drive the schema orderStatus value, as shown in the Liquid snippet above. The page re-renders with the current status on every load — no additional webhook or job is needed.

BreadcrumbList on checkout pages (Shopify Plus)

Shopify Plus merchants can add BreadcrumbList to checkout step pages via checkout.liquid. While checkout pages are not indexed by Google (they require session cookies), BreadcrumbList on these pages benefits AI agents that access them via authenticated sessions — such as ChatGPT browsing a customer's checkout session with explicit permission, or automated order-tracking tools that use a customer's OAuth-connected Shopify account.

{% comment %}
  checkout.liquid: BreadcrumbList for checkout steps (Shopify Plus only)
  Output in the <head> of checkout.liquid
{% endcomment %}

{% assign step_position = 2 %}
{% case checkout.step %}
  {% when 'contact_information' %}
    {% assign step_name = 'Contact Information' %}
    {% assign step_position = 2 %}
  {% when 'shipping_method' %}
    {% assign step_name = 'Shipping Method' %}
    {% assign step_position = 3 %}
  {% when 'payment_method' %}
    {% assign step_name = 'Payment' %}
    {% assign step_position = 4 %}
{% endcase %}

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    { "@type": "ListItem", "position": 1, "name": {{ shop.name | json }}, "item": {{ shop.url | json }} },
    { "@type": "ListItem", "position": {{ step_position }}, "name": {{ step_name | json }} }
  ]
}
</script>

Frequently asked questions

Should I add Product schema to my Shopify cart page?

No. Product schema on cart pages causes duplicate structured data conflicts (the product page is the canonical source), generates validation errors (schema URL doesn't match page URL), and serves inconsistent content to Googlebot (which sees different products or an empty cart on different crawls). Cart pages should have no JSON-LD structured data.

What structured data is valid on an order confirmation page?

Order schema with nested OrderItem objects is the appropriate type for order confirmation pages. Include the order number, order date, orderStatus, merchant identity, and each ordered item. BreadcrumbList is also valid on confirmation pages. Do not add standalone Product, FAQPage, or ItemList schema to confirmation pages.

Can ChatGPT access customers' order confirmation emails?

Yes, with explicit user permission. ChatGPT Plus users with Gmail integration can allow ChatGPT to search their inbox for order confirmations. Merchants who structure confirmation emails with clear, machine-readable order details (order number, items, estimated delivery, tracking link) provide a better ChatGPT order-tracking experience for their customers.

What structured data can Shopify Plus merchants add to checkout that non-Plus merchants cannot?

Shopify Plus merchants can add BreadcrumbList to checkout step pages and Order schema to the thank-you page via checkout.liquid or checkout UI extensions. Non-Plus merchants cannot modify checkout pages — their best option is adding Order schema to the customer account order page (/account/orders/{id}), which is available on all Shopify plans via the customers/order.liquid template.

Audit your checkout structured data

CatalogScan detects Product schema incorrectly placed on cart pages, missing Order schema on confirmation pages, and other post-purchase structured data gaps that affect your AI agent order-tracking visibility.

Scan your store free Read the blog