Return Policy and Shipping Schema for Magento 2
Shopping surfaces use two schema.org fields to answer “how much is delivery” and “can I return it”: shippingDetails and hasMerchantReturnPolicy. Magento, Luma and Hyvä emit neither. Put your standard policy on the Organization once, add product-level markup only where a product differs, and keep both in line with the policy pages shoppers see.
Tell machines your delivery cost and return window the same way your policy pages tell people.
Two levels: store-wide and per product
| Store-wide (Organization) | Per product (Offer) | |
|---|---|---|
| Returns | hasMerchantReturnPolicy → MerchantReturnPolicy | hasMerchantReturnPolicy on the Offer |
| Shipping | hasShippingService → ShippingService (supported by Google since November 2025) | shippingDetails → OfferShippingDetails |
| Use for | Your standard policy, once, on the page that describes it | Only the products that differ |
| Properties | The full set | A subset |
Google’s order of precedence, strongest first: Content API account settings, then settings in Merchant Center or under Shipping and returns in Search Console, then product-level markup, then organization-level markup. So if both markups exist, the product-level one wins – and Search Console settings override both. Google recommends putting the store-wide policy on the single page that describes it, not on every page.
Store-wide policy
{
"@context": "https://schema.org",
"@type": "Organization",
"@id": "https://shop.example/#organization",
"name": "Example Store",
"url": "https://shop.example/",
"hasMerchantReturnPolicy": {
"@type": "MerchantReturnPolicy",
"applicableCountry": ["NL", "BE", "DE"],
"returnPolicyCountry": "NL",
"returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
"merchantReturnDays": 30,
"returnMethod": "https://schema.org/ReturnByMail",
"returnFees": "https://schema.org/FreeReturn"
},
"hasShippingService": {
"@type": "ShippingService",
"shippingConditions": {
"@type": "ShippingConditions",
"shippingDestination": { "@type": "DefinedRegion", "addressCountry": "NL" },
"shippingRate": { "@type": "MonetaryAmount", "value": 4.95, "currency": "EUR" },
"transitTime": { "@type": "ServicePeriod",
"duration": { "@type": "QuantitativeValue", "minValue": 1, "maxValue": 2, "unitCode": "DAY" } }
}
}
}
A product that differs
Free shipping and no returns on one item:
"offers": {
"@type": "Offer",
"price": "89.00",
"priceCurrency": "EUR",
"availability": "https://schema.org/InStock",
"shippingDetails": {
"@type": "OfferShippingDetails",
"shippingRate": { "@type": "MonetaryAmount", "value": "0", "currency": "EUR" },
"shippingDestination": { "@type": "DefinedRegion", "addressCountry": "NL" },
"deliveryTime": {
"@type": "ShippingDeliveryTime",
"handlingTime": { "@type": "QuantitativeValue", "minValue": 0, "maxValue": 1, "unitCode": "DAY" },
"transitTime": { "@type": "QuantitativeValue", "minValue": 1, "maxValue": 2, "unitCode": "DAY" }
}
},
"hasMerchantReturnPolicy": {
"@type": "MerchantReturnPolicy",
"applicableCountry": "NL",
"returnPolicyCategory": "https://schema.org/MerchantReturnNotPermitted"
}
}
Where the values come from in Magento
| Value | Magento source |
|---|---|
| Return window, method, fees | Your returns CMS page. Magento has no structured return-policy setting, so the values have to be configured once |
| Countries | General → Country Options → Allow Countries |
| Shipping rates | Your shipping methods: table rates, flat rate, free-shipping threshold |
| Handling and transit time | Your warehouse and carrier promises – not stored in Magento by default |
| Product exceptions | A product attribute, for example “non-returnable” |
Neither Luma nor Hyvä emits these fields. angeo/module-rich-data adds shippingDetails and hasMerchantReturnPolicy to the Product JSON-LD from admin settings.
Rules that keep it trustworthy
- Markup must match the visible policy. If the returns page says 14 days and the schema says 30, fix one of them.
- One source of truth. Generate the values from configuration, not by hand in templates.
- Same data in the feed. Your ACP product feed and Merchant Center should say the same thing.
- Link the policy pages from your agents.md and llms.txt, so agents quote the real terms.
Questions
- What is hasMerchantReturnPolicy?
- A schema.org property that links an Organization or an Offer to a MerchantReturnPolicy: the countries, return window, method and fees. Google uses it for merchant listings.
- Should the return policy be on the Organization or the Offer?
- Put your standard policy on the Organization once. Use the Offer only for products that differ. If both exist, Google uses the product-level policy.
- What is the difference between shippingDetails and hasShippingService?
- shippingDetails (OfferShippingDetails) is shipping for one offer. hasShippingService (ShippingService) is the store-wide shipping policy on the Organization, supported by Google since November 2025.
- Does Magento output return and shipping schema?
- No. Neither Luma nor Hyvä emits these fields by default. Add them with a module or your own server-rendered JSON-LD.
- What if Search Console shipping settings and structured data disagree?
- Google uses the Search Console settings; they take precedence over structured data.
Related
- Product JSON-LD for AI search
- What Hyvä emits as product schema
- offers.availability – definition
- Entity @id – definition
- Module: JSON-LD schema for Magento 2