Even if your Magento store ranks well in Google, it may still not appear in AI-generated product results (ChatGPT, Gemini, Perplexity). A common reason is missing or incomplete Product schema. AI systems rely on structured data to extract pricing and availability. When that data is missing or inconsistent, products may not be eligible for inclusion. This guide covers what is typically missing, why, and how to fix it. TL;DR: Magento 2 outputs microdata by default; JSON-LD is generally more reliable and easier for parsers to consume Missing offers.availability is a common issue that breaks product eligibility for AI-powered shopping results Schema injected via GTM is often not visible to non-JavaScript crawlers Hyvä Theme does not include product schema out of the box What is AI Search? By "AI search" we refer to systems like ChatGPT browsing (via OAI-SearchBot), Google AI Overviews, Gemini, and Perplexity that extract structured data from pages to generate answers and product listings. Unlike traditional search engines that primarily rank links, these systems rely more heavily on structured data like JSON-LD to understand product details — price, availability, ratings — rather than inferring them from HTML layout. Before vs After: Schema and AI Eligibility Setup ChatGPT Shopping Gemini Perplexity No schema ❌ Not eligible / rarely shown ❌ Not eligible ❌ Rarely cited Microdata only (Luma default) ⚠️ Partially parsed ⚠️ Inconsistent ⚠️ Inconsistent JSON-LD, missing offers.availability ⚠️ Often fails eligibility check ⚠️ May appear ⚠️ May appear Full JSON-LD + availability + rating ✅ Eligible for Shopping results ✅ Product results ✅ Cited with price Why Magento 2 Falls Short for AI Schema Default Luma theme outputs microdata — the older itemscope / itemprop HTML format:

Product Name
49.99
Three issues worth addressing for AI search: 1. Microdata vs JSON-LD. JSON-LD is generally more reliable because it is self-contained and easier to parse compared to microdata embedded in HTML. Microdata is also more fragile when themes or extensions modify markup. 2. offers.availability is missing. This field tells AI systems whether a product can actually be purchased. Without a valid value, products may not pass eligibility checks for AI-powered shopping results. 3. JavaScript-rendered schema may not be indexed. While Google Search processes JS-rendered content reasonably well, many AI crawlers rely on the initial HTML response. Schema injected after page load (e.g. via GTM) is often not visible to these crawlers. On GTM specifically: While Google Search may process JavaScript-rendered schema, many AI crawlers rely on the initial HTML response. If all your structured data comes from GTM, there's a good chance AI systems aren't seeing it — even if Google Rich Results Test passes. Real Example A Magento store with correct pricing but missing offers.availability : Passed Google Rich Results Test ✅ Had valid microdata with price and name ✅ Did not appear consistently in AI-generated product listings ❌ After adding JSON-LD with "availability": "https://schema.org/InStock" and validating via curl (server-side output), the product became eligible for AI Shopping results. This is the most common schema issue across Magento stores — and it takes about five minutes to fix. The Copy-Paste Product JSON-LD A spec-compliant block that covers all the fields AI systems look for: " , "@type" : "Product" , "name" : "Alpine Hiking Jacket" , "description" : "Waterproof 3-layer shell for alpine conditions." , "sku" : "WB-004" , "image" : [ "https://yourstore.com/media/catalog/product/jacket.jpg" ], "brand" : { "@type" : "Brand" , "name" : "TrailMaster" }, "offers" : { "@type" : "Offer" , "priceCurrency" : "EUR" , "price" : "189.99" , "priceValidUntil" : "2026-12-31" , "availability" : "https://schema.org/InStock" , "itemCondition" : "https://schema.org/NewCondition" , "url" : "https://yourstore.com/alpine-hiking-jacket.html" , "seller" : { "@type" : "Organization" , "name" : "Your Store Name" } }, "aggregateRating" : { "@type" : "AggregateRating" , "ratingValue" : "4.6" , "reviewCount" : "38" , "bestRating" : "5" , "worstRating" : "1" } } Required and Recommended Fields Field Status Common mistake @type: Product ✅ Required — name ✅ Required HTML tags in name string offers.availability ✅ Required Text string instead of URI offers.price ✅ Required "€189" instead of "189.99" offers.priceCurrency ✅ Required Symbol € instead of code EUR image ⚠️ Recommended Relative URL instead of absolute sku ⚠️ Recommended Often missing entirely aggregateRating ⚠️ Recommended Including when reviewCount is 0 — causes validation error brand ⚠️ Recommended Plain string instead of {"@type":"Brand","name":"..."} offers.availability — full URI required Status ✅ Correct ❌ Often rejected In stock https://schema.org/InStock "In Stock" / "instock" Out of stock https://schema.org/OutOfStock "Out of Stock" Pre-order https://schema.org/PreOrder "preorder" Back order https://schema.org/BackOrder "backorder" The full schema.org URI is what the spec requires. Short strings are technically invalid — parsers may accept them or silently ignore them depending on the implementation. Configurable Products — Use AggregateOffer When individual variants have different availability states, it's cleaner to use AggregateOffer so AI systems can understand the full option matrix: { "@type" : "Product" , "name" : "Running Shoe" , "offers" : { "@type" : "AggregateOffer" , "offerCount" : 8 , "lowPrice" : "89.99" , "priceCurrency" : "EUR" , "availability" : "https://schema.org/InStock" , "offers" : [ { "@type" : "Offer" , "sku" : "RS-42-BLK" , "name" : "Size 42 / Black" , "availability" : "https://schema.org/InStock" , "price" : "89.99" , "priceCurrency" : "EUR" }, { "@type" : "Offer" , "sku" : "RS-43-BLK" , "name" : "Size 43 / Black" , "availability" : "https://schema.org/OutOfStock" , "price" : "89.99" , "priceCurrency" : "EUR" } ] } } Hyvä Theme — No Schema Out of the Box Hyvä Theme is built on Alpine.js and does not include Luma's product templates. This means Hyvä Theme does not include product schema out of the box in its default templates — neither microdata nor JSON-LD. Verify quickly: curl -s https://yourstore.com/sample-product.html | grep -c 'application/ld+json' # Returns 0 → no JSON-LD curl -s https://yourstore.com/sample-product.html | grep -c 'itemscope' # Returns 0 → no microdata either The fix is to inject JSON-LD via layout XML so it's server-side rendered. Create Vendor_Theme/layout/catalog_product_view.xml : Schema in via layout XML is part of the initial HTML response — visible to crawlers that don't execute JavaScript. Alternatively, you can use an open-source module like angeo/module-rich-data (MIT) to generate schema automatically for both Luma and Hyvä. Diagnosing Your Current Schema This one-liner checks what schema your product pages actually output: curl -s https://yourstore.com/sample-product.html | \ python3 -c " import sys, json, re body = sys.stdin.read() blocks = re.findall(r'<script[^>]+type= " application/ld + json " [^>]>(.?)', body, re.DOTALL) for b in blocks: try: d = json.loads(b) items = d if isinstance(d, list) else [d] for item in items: nodes = item.get('@graph', [item]) for n in nodes: if n.get('@type') in ('Product', 'IndividualProduct'): print('FOUND Product schema') offers = n.get('offers', {}) if isinstance(offers, list): offers = offers[0] if offers else {} print('availability:', offers.get('availability', 'MISSING')) print('price:', offers.get('price', 'MISSING')) print('aggregateRating:', 'present' if n.get('aggregateRating') else 'MISSING') except: pass " Output Meaning Next step No output No JSON-LD schema Add it or install a module availability: MISSING Offers block incomplete Fix the offers object availability: InStock Text string (non-spec) Change to full URI availability: https://schema.org/InStock ✅ Correct Validate at schema.org Implementation Options Option 1 — Module (5 min) composer require angeo/module-rich-data bin/magento setup:upgrade && bin/magento cache:flush MIT licensed, works on Luma and Hyvä. Adds Product, Organization, BreadcrumbList, WebSite, FAQPage schema — all server-side rendered. Option 2 — Manual phtml Create Magento_Catalog/templates/product/json-ld.phtml : getProduct (); $schema = [ '@context' => 'https://schema.org/' , '@type' => 'Product' , 'name' => $product -> getName (), 'sku' => $product -> getSku (), 'offers' => [ '@type' => 'Offer' , 'price' => ( string ) $product -> getFinalPrice (), 'priceCurrency' => $block -> getCurrencyCode (), 'availability' => $product -> isAvailable () ? 'https://schema.org/InStock' : 'https://schema.org/OutOfStock' , 'itemCondition' => 'https://schema.org/NewCondition' , ], ]; ?> Option 3 — GTM Worth mentioning because it comes up a lot: GTM-injected schema works for Google Search , which processes JavaScript. For AI crawlers that rely on the initial HTML response, GTM schema may not be seen. If you're specifically targeting AI search visibility, server-side rendering is safer. Validation Checklist [ ] JSON-LD format (not microdata) [ ] offers.availability — full schema.org URI [ ] offers.price — number string, no currency symbol [ ] offers.priceCurrency — ISO 4217 code (EUR, USD, GBP) [ ] image — at least one absolute URL [ ] aggregateRating omitted if reviewCount is 0 [ ] Schema present in raw curl output (server-side rendered) [ ] Hyvä: schema injected via layout XML [ ] Configurable products use AggregateOffer with per-variant Offer [ ] Zero errors at validator.schema.org Common Errors "The value of offers.availability is not valid" Using a text string. Change to "https://schema.org/InStock" . "Missing field: offers.priceCurrency" Add "priceCurrency": "EUR" to the offers object. "ratingValue out of range" Value must be between 1 and bestRating . A value of 0 is invalid — omit aggregateRating entirely if no reviews yet. Full AEO Check Product schema is one of 13 signals that affect AI search visibility in Magento. To check all of them at once: composer require angeo/module-aeo-audit bin/magento setup:upgrade && bin/magento cache:flush bin/magento angeo:aeo:audit Free CLI tool — weighted score across 13 signals, exact fix command for each failure. If you're debugging Magento schema issues, the CLI audit tool above can save a lot of manual checking. Originally published at angeo.dev