**TL;DR.** Google's 2026 Product rich result requirements added `hasMerchantReturnPolicy` and `shippingDetails` as fields needed for rich snippet eligibility. Products without them lose price, availability, and review stars in search results. Ordiko emits both by default once you configure store-level policies; competitors require theme/plugin work.

## What changed in 2026

Through 2024 and 2025, Google rolled out new requirements for Product structured data. The 2026 baseline:

| Field                           | Required for rich result? | Effect if missing                     |
| ------------------------------- | ------------------------- | ------------------------------------- |
| `name`, `image`, `description`  | Yes (long-standing)        | Result not eligible                   |
| `offers.price`, `priceCurrency` | Yes (long-standing)        | Price snippet hidden                  |
| `offers.availability`            | Yes (long-standing)        | Availability not shown                |
| `aggregateRating` or `review`    | Recommended                 | Star rating not shown                 |
| **`hasMerchantReturnPolicy`**    | **Yes (2026)**             | **Rich result not eligible**          |
| **`offers.shippingDetails`**     | **Yes (2026)**             | **Rich result not eligible**          |
| `brand`, `sku`, `gtin`           | Recommended                 | Reduces credibility / matching         |
| `material`, `color`, `size`      | Recommended                 | Reduces filterability                  |

Source: [Google Search Central — Product structured data](https://developers.google.com/search/docs/appearance/structured-data/product).

## hasMerchantReturnPolicy

The complete field structure:

```json
{
  "@type": "MerchantReturnPolicy",
  "@id": "https://example.com/#return-policy",
  "applicableCountry": ["US", "CA"],
  "returnPolicyCountry": "US",
  "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
  "merchantReturnDays": 30,
  "returnMethod": "https://schema.org/ReturnByMail",
  "returnFees": "https://schema.org/FreeReturn"
}
```

Valid values:

- `returnPolicyCategory`: `MerchantReturnFiniteReturnWindow`, `MerchantReturnUnlimitedWindow`, `MerchantReturnNotPermitted`, `MerchantReturnUnspecified`.
- `returnMethod`: `ReturnByMail`, `ReturnInStore`, `ReturnAtKiosk`.
- `returnFees`: `FreeReturn`, `OriginalShippingFees`, `ReturnFeesCustomerResponsibility`, `RestockingFees`, `ReturnShippingFees`.

If you have a 30-day free return policy by mail (the common consumer-friendly default):

```json
{
  "@type": "MerchantReturnPolicy",
  "applicableCountry": ["US", "CA"],
  "returnPolicyCountry": "US",
  "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
  "merchantReturnDays": 30,
  "returnMethod": "https://schema.org/ReturnByMail",
  "returnFees": "https://schema.org/FreeReturn"
}
```

## shippingDetails

The complete field structure:

```json
{
  "@type": "OfferShippingDetails",
  "shippingRate": {
    "@type": "MonetaryAmount",
    "value": "4.99",
    "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"
    }
  }
}
```

Emit one `shippingDetails` per destination region you serve. A US-Canada store ships to two destinations, so two entries.

## Reference pattern (recommended)

Defining return policy and shipping per product produces verbose HTML. The cleaner pattern is to define them once on `Organization` schema with stable `@id`s and reference them from each Product:

```json
// Once on every page (or just home):
{
  "@type": "Organization",
  "@id": "https://example.com/#organization",
  "name": "Example Store",
  "hasMerchantReturnPolicy": {
    "@type": "MerchantReturnPolicy",
    "@id": "https://example.com/#return-policy",
    "applicableCountry": ["US", "CA"],
    "returnPolicyCountry": "US",
    "returnPolicyCategory": "https://schema.org/MerchantReturnFiniteReturnWindow",
    "merchantReturnDays": 30,
    "returnMethod": "https://schema.org/ReturnByMail",
    "returnFees": "https://schema.org/FreeReturn"
  }
}

// Per Product page:
{
  "@type": "Product",
  "name": "Leather Bag",
  "offers": {
    "@type": "Offer",
    "price": "149.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "hasMerchantReturnPolicy": { "@id": "https://example.com/#return-policy" },
    "shippingDetails": { "@id": "https://example.com/#shipping-us" }
  }
}
```

This validates exactly the same as inline policies but keeps each PDP smaller and easier to cache.

## Per-product overrides

Some products need exceptions:

- **Oversized items** (furniture, mattresses): different return policy (often `OriginalShippingFees`).
- **Hazmat** (batteries, aerosols): `MerchantReturnNotPermitted` or in-store-only.
- **Custom-made** (engraving, monograms): `MerchantReturnNotPermitted`.
- **Digital products**: `MerchantReturnNotPermitted`.

Override at the product level:

```ts
// Pseudocode for an Ordiko product
{
  id: "prod_xyz",
  slug: "custom-engraved-watch",
  returnPolicy: {
    category: "MerchantReturnNotPermitted",
    applicableCountry: ["US"],
  },
}
```

The resolver order: product override → store policy → none.

## Validating

1. **Per-page**: [Google Rich Results Test](https://search.google.com/test/rich-results) on representative PDPs. Confirm "eligible" with no warnings about return/shipping.
2. **At scale**: [Schema Markup Validator](https://validator.schema.org) for syntax.
3. **In production**: Google Search Console → Enhancements → Products → coverage report.

## How Ordiko implements this

Ordiko emits `hasMerchantReturnPolicy` and `shippingDetails` on every PDP automatically once you configure:

- **Settings → SEO → Return Policy** (one form, ~5 fields).
- **Settings → SEO → Shipping Policies** (one row per destination).

The resolver in `src/lib/seo/return-policy.ts` cascades: product override → store policy → none. The renderer emits the reference pattern with stable `@id`s on Organization.

No theme work. No plugins. No JSON-LD writing.

## Common mistakes

1. **Inline duplication of return policy on every product.** Validates but produces 10–50KB of redundant JSON per PDP. Use the reference pattern.
2. **Missing `applicableCountry`.** This is required. Specify the countries the policy applies to.
3. **Wrong category enum.** Use the full URL (`https://schema.org/MerchantReturnFiniteReturnWindow`), not the short name.
4. **Shipping policies that don't match visible shipping rates.** Schema and page content must agree or Google suppresses the rich result.
5. **No shipping policy at all.** Even free-shipping stores must emit `shippingDetails` with a `shippingRate.value` of `0`.

## FAQ

**When did hasMerchantReturnPolicy become required?**
Google announced the requirement in 2024 with enforcement rolling out through 2025 and early 2026. As of 2026, missing hasMerchantReturnPolicy on Product schema results in lost rich-result eligibility — your product no longer shows price, availability, or review stars in SERPs.

**Can I emit a single policy for the whole store?**
Yes. Define hasMerchantReturnPolicy once on the Organization schema with a stable @id, then reference it from each Product offer's hasMerchantReturnPolicy via @id. This is the cleanest pattern and what Ordiko emits by default.

**What if my products have different shipping rules?**
Override per product. Most stores have 90%+ of products on the same policy and 5–10% needing overrides (oversized, hazmat, custom-made). Ordiko supports nullable per-product policy that falls back to store policy.

**Does this affect AI search citations?**
Yes, indirectly. AI engines (Perplexity, ChatGPT, Claude) parse the same JSON-LD Google does. Complete return and shipping policies improve citability — AI engines prefer pages with comprehensive structured data because they can answer user questions directly.
