/ AI Schema Fixes / Rich Results

How to Fix Rich Result Eligibility Gaps

Schema that passes schema.org validation can still fail Google's Rich Results Test. Schema.org checks required properties; Google adds recommended properties that unlock rich-snippet features — star ratings, prices, images in the SERP. AI schema generators often produce the minimum valid schema, missing the recommendations. This guide maps the gaps by schema type and the data sources to populate them.

1. Required vs recommended

schema.org REQUIRED      → minimum for the type to validate
Google REQUIRED          → minimum for rich results (stricter)
Google RECOMMENDED       → strengthens eligibility, improves snippet
Google PREFERRED         → optimal rich-snippet display

AI generators usually hit schema.org REQUIRED. Hitting Google RECOMMENDED requires explicit data passed in.

2. Per-type gaps (Article)

PropertyRequiredRecommended
headline
datePublished
author (Person)
image (1200×630+ ideal)
dateModified
publisher (Organization)
mainEntityOfPage

3. Per-type gaps (Product)

PropertyRequiredRecommended
name
image
offers (price, currency, availability)
aggregateRating✓ (unlocks star snippet)
review
brand
sku / gtin / mpn
offers.priceValidUntil
offers.shippingDetails
offers.hasMerchantReturnPolicy

4. Per-type gaps (Recipe)

PropertyRequiredRecommended
name
image
recipeIngredient
recipeInstructions
author
datePublished
prepTime
cookTime
totalTime
recipeYield
nutrition✓ (unlocks nutrition snippet)
aggregateRating✓ (unlocks star snippet)
video✓ (video carousel eligibility)

5. Per-type gaps (Event)

PropertyRequiredRecommended
name
startDate
location (Place)
endDate
image
description
offers (price, availability, url)✓ (unlocks ticket snippet)
performer
organizer
eventStatus
eventAttendanceMode

6. Per-type gaps (LocalBusiness)

PropertyRequiredRecommended
name
address (PostalAddress)
telephone
image
openingHoursSpecification
geo (lat/long)
priceRange
aggregateRating
servesCuisine (FoodEstablishment)
menu (FoodEstablishment)

7. Source the data, not the schema

AI generators don't invent data — they format what you give them. The fix is feeding the generator the missing fields:

// Bad: generator infers from prose
const schema = await ai.generateProductSchema(htmlContent);
// Output may have name, price, but no aggregateRating, no shipping

// Good: explicit data from product DB
const product = await db.getProduct(productId);
const reviews = await db.getReviewSummary(productId);
const shipping = await calculateShipping(productId);

const schema = await ai.generateProductSchema({
  content: htmlContent,
  data: {
    name: product.name,
    sku: product.sku,
    gtin: product.gtin,
    brand: product.brand,
    image: product.images,
    offers: {
      price: product.price,
      priceCurrency: product.currency,
      priceValidUntil: product.priceValidUntil,
      availability: product.stockStatus,
      shippingDetails: shipping,
      hasMerchantReturnPolicy: product.returnPolicy
    },
    aggregateRating: reviews.summary,
    review: reviews.recent.slice(0, 3)
  }
});
// Now generator can output the recommended properties because the data exists

8. Post-process to add common recommendations

// Auto-fill commonly-missed properties from site config
function enrichSchema(schema, siteConfig) {
  function walk(obj) {
    if (!obj || typeof obj !== 'object') return;
    
    if (obj['@type'] === 'Article' || obj['@type'] === 'BlogPosting') {
      // Ensure recommended fields
      if (!obj.publisher) obj.publisher = { '@id': siteConfig.orgId };
      if (!obj.mainEntityOfPage) obj.mainEntityOfPage = obj.url || obj['@id'];
      if (!obj.dateModified && obj.datePublished) obj.dateModified = obj.datePublished;
    }
    
    if (obj['@type'] === 'Product') {
      // Common missing: brand from site, sku from URL
      if (!obj.brand && siteConfig.defaultBrand) obj.brand = siteConfig.defaultBrand;
    }
    
    for (const v of Object.values(obj)) {
      if (typeof v === 'object') walk(v);
    }
  }
  walk(schema);
  return schema;
}

9. Validate eligibility

Step 1
Rich Results Test
search.google.com/test/rich-results — paste URL or markup. Reports both errors (block rich results) and warnings (block enhanced snippets). Target: 0 errors, 0 warnings.
Step 2
Search Console enhancement reports
Search Console → Enhancements → per content type (Products, Recipes, Articles, etc). Aggregate view of what's valid, what has warnings, what's invalid across your indexed pages. Trend over time tells you whether deploys are improving or regressing.
Step 3
Programmatic check at build time
// Map of recommended properties per type
const RECOMMENDED = {
  Article: ['image', 'dateModified', 'publisher', 'mainEntityOfPage'],
  Product: ['aggregateRating', 'brand', 'sku', 'offers.priceValidUntil'],
  Recipe: ['author', 'prepTime', 'cookTime', 'recipeYield', 'nutrition'],
  Event: ['endDate', 'image', 'offers', 'organizer'],
  LocalBusiness: ['telephone', 'openingHoursSpecification', 'geo', 'priceRange']
};

function checkRecommended(schema) {
  const warnings = [];
  function walk(obj, path = '') {
    if (!obj || typeof obj !== 'object') return;
    const type = Array.isArray(obj['@type']) ? obj['@type'][0] : obj['@type'];
    if (RECOMMENDED[type]) {
      for (const prop of RECOMMENDED[type]) {
        const val = prop.includes('.') 
          ? getNested(obj, prop) 
          : obj[prop];
        if (!val) warnings.push(`${path}${type}: missing recommended "${prop}"`);
      }
    }
    for (const [k, v] of Object.entries(obj)) {
      if (typeof v === 'object') walk(v, `${path}${k}.`);
    }
  }
  walk(schema);
  return warnings;
}
💡 Don't chase 100% recommended-property completion if the data doesn't exist. Inventing aggregateRating with fake ratings is worse than omitting it — Google detects and penalises. Hit recommended for fields where you have real data; skip the rest cleanly. Partial recommended is better than complete fake.

🤖 Re-run AI Schema Generator

Validate Rich Results eligibility.

Run AI Schema Generator →
Related Guides: AI Schema Fixes  ·  Fix Required Fields  ·  Fix Schema References  ·  Fix JSON-LD Coverage
💬 Got a problem?