Offer Schema

No Comments
Offer schema
TL;DR: Offer schema is the part of Product structured data that tells Google the price, currency, and availability of a thing you sell. Miss it and your product loses eligibility for price and stock rich results. Get it right and your listing earns real estate that plain blue links do not.
Check code
RI-032
Type
schema.org/Offer
Lives inside
Product
Unlocks
Price rich result
Format
JSON-LD

Product schema without an Offer is a car without wheels. I see it constantly: an ecommerce team adds Product markup, ships it, and then wonders why Search Console reports the item as invalid or why no price ever shows in the SERP. The reason is almost always a missing or malformed Offer. This is the block that carries the numbers that actually matter to a shopper, so it is the block Google is strictest about.

What Offer schema is

Offer is a schema.org type that represents an item being made available for sale under specific terms: what it costs, in what currency, and whether you can buy it right now. In Google's Product structured data, an Offer (or an AggregateOffer when a product spans a price range) is a required nested property. It sits inside the Product object and answers the shopper's three real questions: how much, in what money, and can I get it.

You almost always deliver it as JSON-LD in a script tag. Microdata still works, but JSON-LD is what Google recommends and what is easiest to maintain because it lives in one place instead of being sprayed through your HTML attributes.

The properties that matter

PropertyRequired?What it holds
priceYesNumber only, no currency symbol, dot decimal
priceCurrencyYesISO 4217 code such as USD, EUR, GBP
availabilityRecommendedA schema.org URL like InStock or OutOfStock
priceValidUntilRecommendedDate the price expires, useful for sales
urlRecommendedDirect link to the buyable product page
itemConditionOptionalNew, Used, Refurbished condition URL

The two that break most implementations are price and priceCurrency. Google wants a bare number for price. If you feed it "$49.99" or "49,99" with a comma, validation fails. Currency has to be the three-letter ISO 4217 code, not a symbol.

A minimal valid example

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Trail Runner GTX",
  "image": "https://example.com/shoe.jpg",
  "offers": {
    "@type": "Offer",
    "price": "119.00",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "url": "https://example.com/trail-runner-gtx"
  }
}
</script>

Why it matters for SEO

Structured data does not lift your rankings by itself. What it does is make you eligible for enhanced results, and eligibility is the whole game here. A product with valid Offer data can show price and availability directly in the search result, which changes the click math before anyone lands on your page. A shopper who already sees the price and an in-stock badge is a warmer click than one guessing.

There is a second, growing reason. Google Shopping, the Merchant Center free listings, and AI-driven shopping surfaces all lean on clean product data. If your Offer is wrong, you are not just losing a rich snippet, you can be dropped from those surfaces entirely. Accurate price and availability is table stakes for being in the conversation.

How to detect problems

Run Rich Results Test Offer detected? No Add offers block to Product Yes price valid? Number, ISO currency, availability set = pass

  • Google Rich Results Test: paste a product URL or the raw markup. It tells you if the Offer is detected and flags missing price or currency.
  • Search Console: the Products enhancement report lists invalid items at scale across your whole catalog, not just one URL.
  • Schema Markup Validator (schema.org): checks that your JSON-LD is structurally correct even for properties Google does not surface.
  • Screaming Frog: crawl with structured data validation enabled to find product pages that lack an offers block entirely.

How to fix it step by step

  1. Confirm the Product wrapper exists and that your Offer is nested inside it under the offers key, not sitting on its own.
  2. Set price as a bare number. Strip currency symbols and use a dot decimal. Pull it from the same source of truth as your visible price so they never disagree.
  3. Add priceCurrency as the correct ISO 4217 code for that store or region.
  4. Set availability to the matching schema.org URL and wire it to your real inventory so it flips to OutOfStock when stock runs out. Claiming InStock on a sold-out product is the fastest way to earn a manual eyebrow-raise and annoyed shoppers.
  5. Match the markup to the visible page. Google requires that structured data reflect what the user actually sees. A hidden or stale price is a policy violation.
  6. Revalidate in the Rich Results Test, then watch the Search Console Products report clear over the next crawl cycle.
DO
  • Nest Offer inside Product under the offers key
  • Use a plain number for price and an ISO 4217 currency
  • Wire availability to live inventory
  • Keep markup identical to the visible price
  • Validate with the Rich Results Test after every change
DON'T
  • Write price as "$49.99" or with a comma decimal
  • Use a currency symbol instead of the ISO code
  • Leave availability hard-coded to InStock forever
  • Mark up a price the shopper cannot see on the page
  • Ship Product schema with no offers block at all

What good looks like

Good is every buyable product page carrying a valid Offer, price as a clean number, currency in ISO form, availability that tracks real stock, and a Search Console Products report with zero invalid items. Your listings show price and an in-stock signal in the SERP, and your feed to Merchant Center and shopping surfaces stops throwing mismatches. Nothing flashy, just consistent, and consistency is what compounds.

FAQ

Offer or AggregateOffer, which do I use?
Use a single Offer when the product has one price. Use AggregateOffer when it spans a range, for example a shirt sold in several variants at different prices. AggregateOffer takes lowPrice, highPrice, and priceCurrency.
Does adding Offer schema guarantee a price rich result?
No. Valid markup makes you eligible, but Google decides when to show enhanced results. Correct data is necessary, not a promise.
Do I need priceValidUntil?
It is recommended, especially for sale prices. It tells Google when the current price expires. Without it, Google may treat a stale price as unreliable and drop the enhancement.
JSON-LD or microdata?
JSON-LD. Google recommends it, and it keeps your structured data in one script block instead of tangled through your HTML, which makes it far easier to maintain and audit.
What if my markup price differs from the page price?
Fix it immediately. Google requires structured data to match what the user sees. A mismatch risks a manual action and, more practically, breaks trust when a shopper clicks a price that is not real.
Product markup throwing errors across your catalog?

Schema issues rarely live alone. An advanced audit maps every invalid Offer, feed mismatch, and eligibility gap so your listings compete on the surfaces that convert.

Get an advanced SEO audit

Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.

About SEO ProCheck

Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.

Work With Me

Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.

Subscribe to our newsletter!

More from our blog