Most ecommerce schema guides stop at Product, Offer, and Review, then treat shipping and return terms as an afterthought worth one sentence buried in a code comment. That’s a real gap, because Google now surfaces shipping cost and return windows directly in the search result, not just price and star ratings.
This guide covers all four properly, with working code for each one, not just the three everyone already covers.
Schema markup doesn’t move your rankings. It controls whether Google is willing to show a rich result, stars, price, shipping badges, once you’re already visible for a search. That distinction matters because it’s easy to treat schema like a ranking hack, and it isn’t one. It’s an eligibility mechanism. Get it wrong and you don’t rank lower, you just lose the visual real estate that makes your listing stand out from the plain blue link next to it.
Google’s own structured data guidelines for ecommerce lay out exactly which schema types it actually supports for online stores, which is worth knowing before you start writing JSON-LD, since not every property Schema.org defines is one Google actually consumes for rich results.
This is also a different technical layer than something like does site speed affect your rankings the same way, which affects crawling and user experience rather than rich result eligibility, and it’s increasingly relevant to how AI search reads structured data too, not just traditional Google results.
This kind of granular, field-by-field implementation work is exactly the layer our Authority Engine™ handles for ecommerce clients who’d rather not audit every product page by hand.

Google’s actual requirement is narrower than most checklists suggest: a name field, plus at least one of offers, review, or aggregateRating. Everything else on the long list of “recommended” properties is exactly that, recommended, not required. Schema.org’s Product type reference (nofollow) lists dozens of possible properties, but most stores only need a handful of them working correctly. Here’s a clean, working example with the fields that matter most in practice:
{
“@context”: “https://schema.org/”,
“@type”: “Product”,
“name”: “Merino Wool Crew Socks”,
“image”: “https://example.com/images/merino-crew-socks.jpg”,
“sku”: “MWS-001-BLK”,
“gtin13”: “0123456789012”,
“brand”: {
“@type”: “Brand”,
“name”: “Example Co”
},
“offers”: {
“@type”: “Offer”,
“price”: “18.00”,
“priceCurrency”: “USD”,
“availability”: “https://schema.org/InStock”,
“url”: “https://example.com/products/merino-crew-socks”
}
}
The gtin13 field is worth calling out specifically. It’s not required for basic rich results, but without a GTIN, UPC, or ISBN, your products aren’t eligible for Google’s enhanced Merchant Listing experience, which is a meaningful gap if you’re competing in Google Shopping surfaces. If you manufacture your own products and don’t have one, you can apply for one through GS1 directly. If you resell branded products, use the manufacturer’s own GTIN rather than inventing one, mismatched identifiers cause the same kind of validation problems as mismatched pricing.
The Offer object is where schema breaks down over time, not on launch day. Price, currency, and availability need to match what’s actually on the page, and Google cross-validates this. If your page shows “Out of Stock” but your JSON-LD still says InStock, Google treats that as a mismatch, not a minor inconsistency.
priceValidUntil is the single most common, avoidable cause of lost rich results in this section. Set it once during a sale and forget to update it, and Google may start suppressing the price display once that date passes, even if the actual price on the page is still correct.
{
“@type”: “Offer”,
“price”: “18.00”,
“priceCurrency”: “USD”,
“priceValidUntil”: “2026-12-31”,
“availability”: “https://schema.org/InStock”,
“itemCondition”: “https://schema.org/NewCondition”,
“url”: “https://example.com/products/merino-crew-socks”
}
Run this through Google’s Rich Results Test after any bulk price update. It’s the fastest way to catch a stale date before Google does, rather than finding out weeks later when a customer mentions your listing looks different than it used to.
AggregateRating and individual Review markup do different jobs. AggregateRating is what actually produces the star rating shoppers see in the SERP, it’s a rollup, not a single opinion. Individual Review entries add supporting detail but aren’t what triggers the stars on their own.
{
“@type”: “AggregateRating”,
“ratingValue”: “4.7”,
“reviewCount”: “38”
}
One practical note before you add this: there’s no official minimum Google publishes, but the reasonable convention is to wait until you have at least 5-10 genuine reviews before adding AggregateRating, rather than shipping it with one or two reviews that don’t represent a real pattern yet. And this one is non-negotiable rather than a style preference: fabricated or incentivized reviews inside structured data are a real suppression and manual-action risk, not a scare tactic.
Google’s guidelines are explicit that structured data has to reflect actual, unmanipulated review content, and applying AggregateRating to a page with no visible reviews at all is one of the fastest ways to trigger a manual action.
This is the piece almost every other guide treats as an afterthought, and it’s becoming one of the more visible trust signals Google shows directly in search. Shoppers increasingly see shipping cost and return windows before they ever click through, which means this schema is doing real pre-click persuasion work, not just backend bookkeeping.
A shopper comparing two nearly identical listings will often choose the one that already tells them shipping is free and returns are easy, before either page even loads.
OfferShippingDetails nests inside your Offer block:
{
“@type”: “OfferShippingDetails”,
“shippingRate”: {
“@type”: “MonetaryAmount”,
“value”: “5.00”,
“currency”: “USD”
},
“shippingDestination”: {
“@type”: “DefinedRegion”,
“addressCountry”: “US”
},
“deliveryTime”: {
“@type”: “ShippingDeliveryTime”,
“handlingTime”: {
“@type”: “QuantitativeValue”,
“minValue”: 0,
“maxValue”: 1,
“unitCode”: “DAY”
},
“transitTime”: {
“@type”: “QuantitativeValue”,
“minValue”: 2,
“maxValue”: 5,
“unitCode”: “DAY”
}
}
}
MerchantReturnPolicy works the same way, nested under hasMerchantReturnPolicy inside the Offer:
{
“@type”: “MerchantReturnPolicy”,
“applicableCountry”: “US”,
“returnPolicyCategory”: “https://schema.org/MerchantReturnFiniteReturnWindow”,
“merchantReturnDays”: 30,
“returnMethod”: “https://schema.org/ReturnByMail”,
“returnFees”: “https://schema.org/FreeReturn”
}
Neither of these is new territory in Schema.org’s vocabulary, but they’re consistently the last thing implemented, if they get implemented at all. If your store already has Product, Offer, and Review schema working cleanly, this is very likely the actual gap left on the table, and it’s one of the few remaining places where implementing something correctly puts you ahead of most of your competition simply because most stores still haven’t bothered.
A few failure patterns show up over and over, and they’re specific enough to check for directly rather than guess at.
Duplicate schema is the most common one. It happens when your theme, your SEO plugin, and a manual code snippet all output Product schema on the same page at once. Google sees multiple conflicting Product blocks and may ignore all of them rather than picking one. Pick a single source for your schema and turn the others off.
Schema on category or collection pages is another recurring mistake. Product schema belongs on individual product pages only, a listing page showing twenty products isn’t a single product, and marking it up as one is a guideline violation, not just a technical oversight.
And the most basic one: data mismatches between what’s visible on the page and what’s in your JSON-LD, wrong price, wrong stock status, stale return window. Google cross-checks this, and a mismatch is exactly the kind of thing that quietly suppresses a rich result without an obvious error message telling you why. We saw a version of this same principle play out in the TANDA conversion case study, where fixing quiet technical mismatches, not a single dramatic overhaul, was what actually moved the needle on conversion. The same logic that applies to index bloat applies here: these are the fixes that don’t look impressive individually but compound because nobody else bothers to check for them.
If you want a second opinion on whether your implementation is actually clean, a full ecommerce SEO audit will catch exactly this kind of mismatch before it costs you a rich result.
If you’re running a smaller catalog with a handful of product types, working through this guide product page by product page is genuinely reasonable. Copy the code blocks, adjust the fields, validate each one.
Where it gets harder is at scale is when you have dozens, hundreds, or thousands of SKUs, prices and availability changing daily, multiple people touching the CMS, and schema quietly going stale on pages nobody’s looked at in months. That’s the point where manual checking stops being realistic, and it’s the layer our Authority Engine™ is built to operate at continuously rather than as a one-time fix. Instead of auditing schema once and hoping it stays correct, it’s treated as part of an ongoing system, alongside content, backlinks, and the rest of your technical foundation, so a stale priceValidUntil date or a duplicate schema block doesn’t sit unnoticed for months. If that kind of ongoing coverage is what you’re after rather than a single audit, that’s the difference between a fix and SEO built for lead generation that keeps checking after the initial cleanup.
Not sure if your schema is actually eligible for rich results right now? A free website SEO audit will show you exactly what’s missing rather than leaving you to guess from a Rich Results Test warning that doesn’t explain itself.
If you want the fuller picture beyond just the technical layer, from building topical authority to the rest of what makes an ecommerce site rank, that’s the broader work an ecommerce SEO engagement covers.
© Curious Fortune Media – All Rights Reserved – Terms and Conditions – Privacy Policy – Accessibility Statement