Skip to Content

Product schema missing a nested Offer

What Is This Issue

Product schema is present on a product page, but the nested Offer schema is missing or incomplete. The Offer schema provides critical pricing and availability information that enables rich results showing price, availability status, and price validity.

Without a properly structured Offer:

  • Google cannot display price and availability in product rich results
  • Price drop badges won’t appear in search results
  • Availability status (In Stock, Out of Stock, Preorder) won’t be shown
  • Users may click through to products with outdated pricing information

A complete Offer schema should be nested inside Product schema and include: price, priceCurrency, availability, priceValidUntil, url, and optionally priceSpecification, hasMerchantReturnPolicy, shippingDetails, etc.

Why Is This Important

Offer schema is essential for e-commerce SEO and user experience:

  • Product rich results: Enables price, availability, and review stars in search results
  • Price drop badges: Google shows “Price drop” badges when priceValidUntil is set
  • Availability signals: Helps users see if products are in stock before clicking
  • Conversion optimization: Users are more likely to click when they see current pricing
  • AI search readiness: AI engines use Offer data to answer pricing queries accurately

Resolving this issue improves your e-commerce SEO health score by ensuring product pricing information is properly structured for search engines and AI systems.

How XeoPix Detects This

XeoPix follows these logical steps to detect missing or incomplete Offer schema:

  1. Find Product schema: The crawler identifies pages with Product schema blocks

  2. Check for offers property: The crawler examines whether the Product schema has an offers property

  3. Validate Offer structure: If offers exists, the crawler checks:

    • Is it an object or array?
    • Does it have @type set to Offer or AggregateOffer?
  4. Check required properties: The crawler verifies the Offer has:

    • price (or lowPrice/highPrice for AggregateOffer)
    • priceCurrency
    • availability
  5. Check recommended properties: The crawler also looks for:

    • priceValidUntil
    • url
    • seller
  6. Trigger conditions: The issue is flagged when:

    • Product schema exists BUT offers property is missing
    • offers exists but price is missing
    • offers exists but priceCurrency is missing
    • offers exists but availability is missing or uses invalid values

How To Fix

  1. Locate Product schema: Find pages with Product schema (check your product detail pages)

  2. Add or complete the offers property in your Product schema:

    { "@context": "https://schema.org", "@type": "Product", "name": "Product Name", "description": "Product description", "offers": { "@type": "Offer", "price": "29.99", "priceCurrency": "USD", "availability": "https://schema.org/InStock", "priceValidUntil": "2024-12-31", "url": "https://example.com/product-page", "seller": { "@type": "Organization", "name": "Store Name" } } }
  3. Use correct values for key properties:

    • price: Numeric value as string (e.g., “29.99”)
    • priceCurrency: ISO 4217 currency code (e.g., “USD”, “EUR”, “GBP”)
    • availability: Use Schema.org URLs: https://schema.org/InStock, https://schema.org/OutOfStock, https://schema.org/PreOrder, etc.
    • priceValidUntil: ISO 8601 date format (e.g., “2024-12-31”)
  4. For multiple offers, use AggregateOffer:

    "offers": { "@type": "AggregateOffer", "lowPrice": "29.99", "highPrice": "49.99", "priceCurrency": "USD", "offerCount": "5" }
  5. Validate with Google’s Rich Results Test

What We Store

Storage Level

Page Level — This issue is evaluated for each individual URL that contains structured data.


Database Table / Prisma Model

PageStructuredData


Stored Fields

FieldTypeDescription
schemaTypeSchemaTypeThe type of schema (e.g., Organization, Person)
schemaFormatSchemaFormatThe format of the schema (JSON-LD, Microdata, RDFa)
schemaIdentifierString?Unique identifier for the schema
rawJsonJson?The raw JSON-LD or structured data content
schemaErrorsJson?Array of validation errors found in the schema
isValidSchemaBoolean?Whether the schema is valid according to validation
missingFieldsJson?Array of required fields that are missing

Detection Dependencies

  • The following data sources are required to evaluate this issue:
  • HTML Document — The crawler parses the HTML to find structured data (JSON-LD, Microdata, RDFa)
  • Structured Data Validation — The extracted schema is validated against Schema.org definitions
  • Schema Parser — JSON-LD scripts, Microdata attributes, and RDFa markup are parsed

Examples

Example 1: Missing Offer Schema in Product

Problematic state (Product without Offer):

{ "@context": "https://schema.org", "@type": "Product", "name": "Wireless Headphones", "description": "High-quality wireless headphones with noise cancellation" }

Missing offers property

Corrected state:

{ "@context": "https://schema.org", "@type": "Product", "name": "Wireless Headphones", "description": "High-quality wireless headphones with noise cancellation", "offers": { "@type": "Offer", "price": "199.99", "priceCurrency": "USD", "availability": "https://schema.org/InStock", "priceValidUntil": "2024-12-31", "url": "https://example.com/headphones" } }

Example 2: Incomplete Offer Schema

Problematic state (missing required properties):

{ "@context": "https://schema.org", "@type": "Product", "name": "Smartphone", "offers": { "@type": "Offer", "price": "599.99" } }

Missing priceCurrency and availability

Corrected state:

{ "@context": "https://schema.org", "@type": "Product", "name": "Smartphone", "offers": { "@type": "Offer", "price": "599.99", "priceCurrency": "USD", "availability": "https://schema.org/InStock" } }

Example 3: AggregateOffer for Multiple Offers

Corrected state (multiple sellers):

{ "@context": "https://schema.org", "@type": "Product", "name": "Running Shoes", "offers": { "@type": "AggregateOffer", "lowPrice": "89.99", "highPrice": "129.99", "priceCurrency": "USD", "offerCount": "5", "availability": "https://schema.org/InStock" } }

Unit Test

Test File

xeopix-crawling-v2/__tests__/seo-audit-checks/structuredDataRichResults/issue-155-offer-schema-nested.test.js

Purpose

Validates that the crawler correctly validates Product schemas with nested Offer schemas and does not report false positives when the nested Offer has required properties.

Tested Function

runStructuredDataRichResults()

Issue Information

  • Issue Number: 155
  • Issue Code: offer_schema_nested
  • Toggle Group: structuredDataRichResults

Test Scenarios

Positive Test Cases

  • Valid nested Offer: Product schema has an offers property with a nested Offer containing price and priceCurrency — no issue reported.

Negative Test Cases

None — the test only validates that valid schemas pass.

Boundary Cases

None.

Edge Cases

  • Empty HTML: <html></html> — no crash.

Expected Outcome

Pass

Issue should not be reported when a Product schema has a valid nested Offer with price and priceCurrency.

Fail

No negative test cases are defined.

Validation

  • Correct pass-through of valid nested Offer schemas
  • Graceful handling of empty HTML
  • xeopix-crawling-v2/toggleGroups/structuredDataRichResults.js
  • xeopix-crawling-v2/issueCodes.js
  • xeopix-crawling-v2/utils/context.js
  • xeopix-crawling-v2/utils/issues.js
  • xeopix-crawling-v2/utils/schema.js

Coverage Summary

  • Covers valid nested Offer schema detection
  • Covers empty HTML resilience

References

Last updated on