Your Merchant Center feed tells Google what products you sell, but your product pages are where customers see them. When Google crawls those pages, it looks for structured data markup to verify that the prices, availability, and product details in your feed match what is actually on your site. Missing or incorrect markup causes price mismatches, availability errors, and product disapprovals.
This guide covers everything you need to know about implementing structured data markup for Google Merchant Center, including JSON-LD templates, validation, synchronization with your feed, and how to fix common markup errors.
Scan Your Site for Structured Data IssuesStructured data is a standardized way of describing content in HTML so that machines (search engines, assistants, etc.) can understand it. For e-commerce, product schema markup tells Google the exact product name, price, currency, brand, availability, and unique identifier (GTIN).
Without markup, Google relies on heuristics: it guesses the price by scanning the page for dollar signs, it guesses availability by looking for "in stock" text. Guessing is unreliable, especially when multiple prices appear on the page (original price, sale price, variants). With JSON-LD structured data, you eliminate the guesswork.
Google uses this markup for two things:
Three formats exist for structured data: JSON-LD, microdata, and RDFa. For Google Merchant Center, JSON-LD is the clear winner.
| Format | Ease of Use | Google Support | Recommendation |
|---|---|---|---|
| JSON-LD | Easy (standalone block) | Preferred by Google | Use this |
| Microdata | Hard (inline in HTML) | Supported but older | Only if legacy system requires |
| RDFa | Hard (inline in HTML) | Least supported | Avoid |
JSON-LD requires no changes to your HTML structure. You embed a single script block in your page head or body, and Google reads it. It is easy to generate dynamically on the server side, and it is easy to validate.
Here is the minimum structured data you need for Merchant Center feed verification:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Blue Wireless Headphones Model X5",
"brand": {
"@type": "Brand",
"name": "AudioTech"
},
"gtin13": "1234567890123",
"offers": {
"@type": "Offer",
"url": "https://example.com/product/blue-headphones-x5",
"priceCurrency": "EUR",
"price": "129.99",
"priceValidUntil": "2027-12-31",
"availability": "https://schema.org/InStock",
"itemCondition": "https://schema.org/NewCondition"
}
}
</script>
What each field does:
name: Product title. Should match your feed product title.brand: Brand name. Must be a string or Brand object.gtin13: 13-digit barcode (EAN-13). Must match your feed GTIN exactly. If you do not have a GTIN, use mpn (manufacturer part number) or sku instead.priceCurrency: Currency code (EUR, USD, GBP, etc.). Must match your feed.price: The numeric price as a string. Must match your feed price, including whether tax is included.availability: Stock status (InStock, OutOfStock, PreOrder, etc.).itemCondition: NewCondition, UsedCondition, or RefurbishedCondition.If you sell the same product in multiple colors or sizes with different prices, use an array of offers:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "T-Shirt Available in Multiple Colors",
"offers": [
{
"@type": "Offer",
"url": "https://example.com/tshirt?color=red",
"priceCurrency": "EUR",
"price": "19.99",
"availability": "https://schema.org/InStock"
},
{
"@type": "Offer",
"url": "https://example.com/tshirt?color=blue",
"priceCurrency": "EUR",
"price": "19.99",
"availability": "https://schema.org/InStock"
}
]
}
However, the simplest approach is to include schema for only one variant (usually the default) and let Google read the variant prices from your feed. Only use multiple offers if you want to surface variant prices directly on Google Shopping.
If your prices are calculated by JavaScript after the page loads, Google may not see the current price. Always render the price on the server side in the JSON-LD block. If you use JavaScript to update prices dynamically (A/B testing, personalized pricing, sales), update the JSON-LD server-side with each page request:
If you want JavaScript to update the price Google sees, you must either (a) render JSON-LD server-side for each user, or (b) update the JSON-LD script tag dynamically and ensure your rendering framework triggers a re-render that Google's crawler can detect.
If you have a sale price, use the price field for the current sale price and add a separate priceCurrency and price under an AggregateOffer to show the original price:
{
"@type": "Offer",
"priceCurrency": "EUR",
"price": "99.99",
"priceValidUntil": "2026-12-31",
"priceReduction": "30",
"priceCurrency": "EUR"
}
Google reads the price field as the active price for Merchant Center. The priceReduction is optional but helps Google understand that this is a temporary discount.
Before deploying structured data to production, validate it using Google's Rich Results Test:
https://search.google.com/test/rich-resultsThe test tells you if Google can parse your JSON-LD. It does not check whether your price matches your feed (that happens later in Merchant Center), but it ensures the markup is syntactically correct.
The biggest source of Merchant Center disapprovals is a mismatch between feed data and page data. Here is how to prevent it:
This ensures data is never out of sync. If your system does not yet work this way, at minimum:
After you add or fix structured data markup on your product pages, you do not need to reupload your entire Merchant Center feed. But you should:
In Merchant Center, if a product was previously flagged for a data mismatch, it will be re-evaluated once Google recrawls the page with the corrected markup.
| Mistake | Impact | Fix |
|---|---|---|
| Price is a number (99.99) instead of a string ("99.99") | Google may not parse it correctly | Wrap price in quotes: "price": "99.99" |
| Missing priceCurrency | Google cannot determine currency | Always include "priceCurrency": "EUR" (or your currency) |
| Price includes currency symbol (e.g., "99.99 EUR") | Parse errors | Separate: "price": "99.99", "priceCurrency": "EUR" |
| Availability value is a string like "available" instead of schema URL | Misinterpreted | Use "https://schema.org/InStock" or "https://schema.org/OutOfStock" |
| Price in JSON-LD does not match feed price | Merchant Center disapproval | Sync database, feed, and markup |
| GTIN in JSON-LD does not match feed GTIN | Product suppression | Use exact same GTIN in both |
| Multiple JSON-LD blocks on one page with conflicting data | Google reads first block, confusion | One Product block per page |
If you have accurate structured data on your product pages, Google can display your products in organic search results without you running paid Shopping ads. This is called a free product listing. To be eligible:
Free listings do not cost per click, but they show below paid Shopping ads. Still, if your markup is solid, it is worth enabling free listings as an additional traffic source.
The same JSON-LD pattern works for most products, but some categories require additional fields:
isbn, author, datePublishedcolor, size (or use multiple offers with variant options)mpn (manufacturer part number) if no GTINitemCondition to "https://schema.org/UsedCondition"The core fields (name, price, currency, availability, brand, GTIN) remain the same. Add category-specific fields only if your system supports them.
Follow this checklist to implement markup correctly:
You add markup today, but Google does not immediately re-evaluate your feed. Here is the timeline:
If products are still flagged after 5 days, check Merchant Center for specific errors. Often, there is still a mismatch somewhere, or the feed itself has an error independent of the markup.
In 2026, Google expects every e-commerce site to have proper structured data markup. It is not just nice to have. It directly impacts your Merchant Center feed approval rate and your eligibility for free product listings and rich results.
If you are currently running Shopping ads without markup, add it. If you have markup but get regular disapprovals, audit it against your feed. If prices or GTINs do not match, no amount of other optimization will fix the problem.
Start with the minimal schema template from earlier in this guide. Get it correct on 10 products. Validate it. Then scale to your entire catalog. Your Merchant Center health will improve immediately.
Scan Your Site for Structured Data Issues