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
priceValidUntilis 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:
-
Find Product schema: The crawler identifies pages with
Productschema blocks -
Check for
offersproperty: The crawler examines whether the Product schema has anoffersproperty -
Validate Offer structure: If
offersexists, the crawler checks:- Is it an object or array?
- Does it have
@typeset toOfferorAggregateOffer?
-
Check required properties: The crawler verifies the Offer has:
price(orlowPrice/highPricefor AggregateOffer)priceCurrencyavailability
-
Check recommended properties: The crawler also looks for:
priceValidUntilurlseller
-
Trigger conditions: The issue is flagged when:
- Product schema exists BUT
offersproperty is missing offersexists butpriceis missingoffersexists butpriceCurrencyis missingoffersexists butavailabilityis missing or uses invalid values
- Product schema exists BUT
How To Fix
-
Locate Product schema: Find pages with
Productschema (check your product detail pages) -
Add or complete the
offersproperty 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" } } } -
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”)
-
For multiple offers, use
AggregateOffer:"offers": { "@type": "AggregateOffer", "lowPrice": "29.99", "highPrice": "49.99", "priceCurrency": "USD", "offerCount": "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
| Field | Type | Description |
|---|---|---|
| schemaType | SchemaType | The type of schema (e.g., Organization, Person) |
| schemaFormat | SchemaFormat | The format of the schema (JSON-LD, Microdata, RDFa) |
| schemaIdentifier | String? | Unique identifier for the schema |
| rawJson | Json? | The raw JSON-LD or structured data content |
| schemaErrors | Json? | Array of validation errors found in the schema |
| isValidSchema | Boolean? | Whether the schema is valid according to validation |
| missingFields | Json? | 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
offersproperty with a nestedOffercontainingpriceandpriceCurrency— 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
Related Production Files
xeopix-crawling-v2/toggleGroups/structuredDataRichResults.jsxeopix-crawling-v2/issueCodes.jsxeopix-crawling-v2/utils/context.jsxeopix-crawling-v2/utils/issues.jsxeopix-crawling-v2/utils/schema.js
Coverage Summary
- Covers valid nested Offer schema detection
- Covers empty HTML resilience
References
- Google: Product Structured Data — Google Search Central
- Schema.org: Offer — Schema.org
- Schema.org: AggregateOffer — Schema.org