Use Case

Ecommerce Schema Markup Guide

Product rich results — with pricing, availability, and star ratings — require complete Schema.org markup. A single missing property costs you the feature snippet. SchemaCheck validates every required field across your entire catalog.

What Google requires for Product rich results

Google's Product rich results (pricing, availability, ratings in search) require specific fields. SchemaCheck validates all of them with per-property error messages and fix suggestions.

PropertyRequired?What SchemaCheck checks
nameRequiredNon-empty string
imageRequiredValid URL or ImageObject
offersRequired for pricingHas price, priceCurrency, availability
offers.priceRequiredNumeric string or number
offers.priceCurrencyRequiredISO 4217 currency code (USD, EUR, GBP…)
offers.availabilityRequiredSchema.org InStock / OutOfStock URL
aggregateRatingRecommendedHas ratingValue and reviewCount/ratingCount
brandRecommendedOrganization or Brand with name
descriptionRecommendedNon-empty string
skuRecommendedString identifier

Before and after

Here's a typical incomplete Product schema that fails rich results, and what the corrected version looks like.

json
// Before: incomplete Product schema (missing required properties for Google Shopping)
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Wireless Noise-Cancelling Headphones",
  "description": "Premium audio with 30-hour battery life."
}

// SchemaCheck response:
// errors: ["name ✓", "offers ✗ — required for rich results", "image ✗ — required for rich results"]
// rich_result_eligible: false
// score: 20/100

// After: complete Product schema
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Wireless Noise-Cancelling Headphones",
  "description": "Premium audio with 30-hour battery life.",
  "image": "https://example.com/headphones.jpg",
  "brand": { "@type": "Brand", "name": "SoundCo" },
  "offers": {
    "@type": "Offer",
    "price": "299.99",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock",
    "url": "https://example.com/products/headphones"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.7",
    "reviewCount": "1284"
  }
}

// SchemaCheck response:
// errors: []
// rich_result_eligible: true
// score: 100/100

Shopify Product Schema — Audit Your Entire Catalog

Pull every product URL from the Shopify Admin API and validate each one. Run weekly as a cron job and alert on new errors.

typescript
// Validate every product in your Shopify store via the Admin API
import Shopify from "@shopify/shopify-api";

const shop = "your-store.myshopify.com";
const accessToken = process.env.SHOPIFY_ACCESS_TOKEN;
const schemaKey = process.env.SCHEMACHECK_API_KEY;

// Fetch all product URLs from Shopify
async function getAllProductUrls(): Promise<string[]> {
  const response = await fetch(
    `https://${shop}/admin/api/2024-01/products.json?fields=handle&limit=250`,
    { headers: { "X-Shopify-Access-Token": accessToken! } }
  );
  const { products } = await response.json();
  return products.map((p: { handle: string }) => `https://${shop}/products/${p.handle}`);
}

// Validate a single product URL
async function validateProduct(url: string) {
  const res = await fetch(
    `https://schemacheck.dev/api/v1/validate?url=${encodeURIComponent(url)}&access_key=${schemaKey}`
  );
  return res.json();
}

// Run audit
const urls = await getAllProductUrls();
console.log(`Validating ${urls.length} products...`);

const issues: Array<{ url: string; errors: number; missingProps: string[] }> = [];

for (const url of urls) {
  const result = await validateProduct(url);
  if (!result.success) continue;

  const productSchema = result.schemas.find((s: { type: string }) => s.type === "Product");
  if (productSchema && productSchema.errors.length > 0) {
    issues.push({
      url,
      errors: productSchema.errors.length,
      missingProps: productSchema.properties_missing_required,
    });
  }
}

console.log(`\n${issues.length} products with schema errors:`);
issues.forEach((i) => console.log(`  ${i.url} — missing: ${i.missingProps.join(", ")}`));

Validate on WooCommerce publish

Use a publish webhook to validate product schema the moment it goes live. Send a Slack alert if required properties are missing.

typescript
// WordPress / WooCommerce publish webhook
// Validate schema every time a product is published or updated

addEventListener("fetch", (event) => {
  event.respondWith(handlePublishHook(event.request));
});

async function handlePublishHook(request: Request): Promise<Response> {
  const { post_id, post_type, permalink } = await request.json();

  // Only validate product and post types that have schema
  if (!["product", "post", "page"].includes(post_type)) {
    return new Response("skipped", { status: 200 });
  }

  // Give WordPress a moment to publish before fetching
  await new Promise((r) => setTimeout(r, 3000));

  const result = await fetch(
    `https://schemacheck.dev/api/v1/validate?url=${encodeURIComponent(permalink)}&access_key=${SCHEMACHECK_API_KEY}`
  ).then((r) => r.json());

  if (!result.success) return new Response("validation skipped", { status: 200 });

  const errors = result.schemas.flatMap((s) => s.errors);

  if (errors.length > 0) {
    // Send Slack alert
    await fetch(SLACK_WEBHOOK_URL, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        text: `⚠️ Schema errors on newly published ${post_type}: ${permalink}`,
        attachments: errors.map((e) => ({
          color: "danger",
          text: `${e.property}: ${e.message}\nFix: ${e.fix}`,
        })),
      }),
    });
  }

  return new Response(JSON.stringify({ errors: errors.length, score: result.summary.score }));
}

“Our product team kept removing the offers block from product descriptions to 'clean up' the page. SchemaCheck in CI blocked those PRs automatically — we recovered 18% of our Google Shopping impressions within two weeks.”

— Engineering manager at a direct-to-consumer brand (name withheld)

Protect your Google Shopping visibility

Free plan — 100 validations/month. Enough to validate your top products daily.

Related