What Is ProductGroup Schema? The Complete Guide (2026)

Saar Twito9 min read
Saar Twito
Saar TwitoFounder & SEO Engineer

Hi, I'm Saar - a software engineer, SEO specialist, and lecturer who loves building tools and teaching tech.

View author profile →

What Is ProductGroup Schema?

ProductGroup schema is a type of structured data — defined in the Schema.org ProductGroup vocabulary — that marks up a family of product variants that differ only in specific, well-described ways such as color, size, or material. A t-shirt sold in 3 colors × 4 sizes is one ProductGroup containing 12 Product variants. Google uses ProductGroup markup to display variant-aware cards in Merchant Listings, letting shoppers filter by size or color directly in search results.

TL;DR
  • Required by Google: name on the ProductGroup. Each variant Product must also carry all standard Product required fields (name, image, offers with price and priceCurrency)
  • Greadme also requires: productGroupID (unique stable ID for the group) — error if missing
  • Key recommended: variesBy (what differs between variants), hasVariant (the variant Product array), brand, description
  • variesBy accepts 6 Google-supported values: color, size, material, pattern, suggestedAge, suggestedGender — use full Schema.org URIs
  • Each variant must have a unique sku or gtin and an offers.url that deep-links directly to that variant

ProductGroup vs. Product: What Is the Difference?

ProductGroup and Product serve different roles in the structured data hierarchy:

ConceptProductGroupProduct
What it representsThe product family (e.g., "Wool Winter Coat")A specific purchasable variant (e.g., "Wool Winter Coat — Green, Size M")
Can it be purchased?No — it is a container, not a purchasable itemYes — each variant has its own price and availability
Rich result eligibilityEnables variant display in Merchant ListingsEligible for Product Snippets and Merchant Listings
RelationshipHas hasVariant → Product childrenHas isVariantOf → ProductGroup parent

The ProductGroup entity itself is not sold — only its child Product variants are. Rich result eligibility (Product Snippets, Merchant Listings) flows through the child Products, not the ProductGroup directly.

Required Properties

PropertyGreadme rule
nameError if missing (−15 pts). The product family name — use the shared name across variants (e.g., "Wool Winter Coat"), not a variant-specific name
productGroupIDError if missing (−15 pts). A unique stable identifier for the group (also called the parent SKU). Used by variant Products to reference the group via inProductGroupWithID. Must not change when the listing is updated

Note: Google's documentation only requires name on the ProductGroup itself. Greadme additionally requires productGroupID because without it, variants cannot correctly reference the group and Merchant Listings eligibility is severely reduced.

Recommended Properties

PropertyNotes
hasVariantArray of Product objects representing each variant. Greadme warns and deducts 10 points if missing. Each variant needs name, image, and offers
variesByDeclares which properties differ between variants. Use full Schema.org URIs (see variesBy section below)
brandBrand object with name. Set once at the ProductGroup level — does not need to be repeated on each variant
descriptionA group-level description shared by all variants. Variant-level descriptions should be more specific
aggregateRatingRating representing all variants combined. Must follow Review snippet guidelines (ratingValue, ratingCount)
urlOnly for single-page implementations — the base canonical URL without any variant pre-selected. Omit on multi-page setups where each variant has its own page

variesBy: The Six Supported Values

The variesBy property tells Google which attributes distinguish one variant from another. Google's documentation explicitly supports six values. Always use the full Schema.org URI form:

Value (full URI)Use for
https://schema.org/colorVariants differing by color
https://schema.org/sizeVariants differing by size (clothing, shoes, etc.)
https://schema.org/materialVariants differing by material (cotton vs. wool, etc.)
https://schema.org/patternVariants differing by pattern (striped, solid, plaid)
https://schema.org/suggestedAgeVariants differing by intended age range (children's sizes)
https://schema.org/suggestedGenderVariants differing by gender (men's vs. women's fit)

Values outside this list are not documented as supported by Google. Using multiple values is valid — e.g., ["https://schema.org/color", "https://schema.org/size"] for a product that varies by both.

Two Implementation Approaches

Google supports two structural patterns for linking ProductGroups to their variant Products:

ApproachHow it worksBest for
Nested (hasVariant)All variant Products are embedded inside the ProductGroup's hasVariant array on one pageSingle-page product listings where all variants share one URL
Separate pages (isVariantOf)Each variant Product lives on its own page and references the parent group via isVariantOf or inProductGroupWithIDMulti-page setups where each variant has a dedicated canonical URL

Do not mix the two approaches on the same page. On multi-page setups, each variant page must carry complete, self-contained structured data. Google explicitly requires that every variant has a unique URL that directly pre-selects that variant (via query parameters or similar).

ProductGroup Schema Code Example

A single-page ProductGroup with nested variants using the hasVariant approach:

{
  "@context": "https://schema.org",
  "@type": "ProductGroup",
  "name": "Wool Winter Coat",
  "productGroupID": "WC-2026",
  "description": "A warm wool coat available in multiple colors and sizes.",
  "brand": {
    "@type": "Brand",
    "name": "NorthStyle"
  },
  "variesBy": [
    "https://schema.org/color",
    "https://schema.org/size"
  ],
  "hasVariant": [
    {
      "@type": "Product",
      "name": "Wool Winter Coat — Green, Small",
      "sku": "WC-GRN-S",
      "color": "Green",
      "size": "S",
      "image": "https://example.com/coat-green-s.jpg",
      "offers": {
        "@type": "Offer",
        "price": "249.00",
        "priceCurrency": "USD",
        "availability": "https://schema.org/InStock",
        "url": "https://example.com/coat?color=green&size=s"
      }
    },
    {
      "@type": "Product",
      "name": "Wool Winter Coat — Green, Medium",
      "sku": "WC-GRN-M",
      "color": "Green",
      "size": "M",
      "image": "https://example.com/coat-green-m.jpg",
      "offers": {
        "@type": "Offer",
        "price": "249.00",
        "priceCurrency": "USD",
        "availability": "https://schema.org/InStock",
        "url": "https://example.com/coat?color=green&size=m"
      }
    }
  ]
}

Variant Requirements: What Each Product Needs

Each Product inside hasVariant (or referencing the group via isVariantOf) must be fully self-contained. Greadme validates each variant individually:

PropertyStatusNotes
nameRequiredVariant-specific name (include the differentiating attribute, e.g. color and size)
imageRequiredVariant-specific product image
offersRequiredOffer with price (greater than 0), priceCurrency (ISO 4217), and url deep-linking to this specific variant
sku or gtinRequired by GoogleEvery variant must have a unique identifier. Google requires this for Merchant Listings eligibility
offers.urlRequired by GoogleMust deep-link directly to this variant (e.g. via query parameters). Google requires the site to support direct variant pre-selection via URL
offers.availabilityRecommendedStrongly recommended for Merchant Listings. Use full Schema.org URIs: InStock, OutOfStock, PreOrder, etc.
color / size / etc.RecommendedThe specific value for whichever properties are declared in variesBy

Common Mistakes to Avoid

  • Missing productGroupID: Greadme errors on this (−15 pts). Without a stable group ID, variants cannot reference the group via inProductGroupWithID, breaking the variant linkage.
  • Missing hasVariant: A ProductGroup with no variants listed is technically valid schema but defeats the purpose. Greadme warns and deducts 10 points.
  • Price of 0 on a variant offer: Greadme errors on variant offers with a price of 0 or below. This is stricter than the standard Product validator, which accepts 0 for free products. ProductGroup variants are expected to be purchasable items with a real price.
  • Variant offers.url not deep-linking to the variant: Google requires each variant's offer URL to directly pre-select that specific variant (via query parameters or similar). Pointing all variants to the same base URL fails this requirement.
  • No unique identifier on variants: Every variant must have a unique sku or gtin. Variants sharing an identifier cannot be individually tracked in Merchant Listings.
  • Using variesBy values outside the 6 supported: Google documents exactly 6 values. Custom values are ignored. Use the full Schema.org URI form for each — short names like "color" (without the URI) may not be parsed correctly.
  • Setting url on a multi-page implementation: The url property on ProductGroup is only for single-page setups where all variants share one canonical URL. On multi-page implementations, omit it — each variant page provides its own URL.
  • Repeating brand on every variant: Set brand once at the ProductGroup level. Google does not require it to be repeated on each child Product.

How Greadme Validates ProductGroup Schema

Greadme runs a dedicated ProductGroup validator that checks both the group-level properties and each individual variant. The score starts at 100:

IssuePoints lost
Missing name−15
Missing productGroupID−15
Missing hasVariant−10
Variant issues (missing name, image, offers, price, or priceCurrency)−3 per issue, capped at −30 total
Case-sensitive property name error (e.g. HasVariant instead of hasVariant)−8 per field

Greadme also reports a Merchant Listings eligibility count — the number of variants that have a valid offer (price greater than 0, currency, and Offer type). Only eligible variants count toward Merchant Listings display.

Frequently Asked Questions

Does ProductGroup schema replace Product schema?

No. ProductGroup wraps Product variants — you still need full Product structured data on each variant. ProductGroup organizes the group and describes what varies; the individual Products carry the purchasable details (price, availability, image, identifier). If your product has no variants, use plain Product schema instead.

Can I use isVariantOf and hasVariant together on the same page?

Google documents two distinct approaches — nested (hasVariant on ProductGroup) and separate pages (isVariantOf on Product). Do not mix them haphazardly on a single page. On a single-page implementation, use the nested hasVariant approach. On separate variant pages, use isVariantOf or inProductGroupWithID to reference the parent group.

Do I need to repeat brand and description on every variant?

No. Properties set at the ProductGroup level — including brand, description, and aggregateRating — apply to the group as a whole and do not need to be duplicated on each child Product. Variant-specific properties (color, size, sku, image, offers) belong on the individual Products.

Is ProductGroup eligible for Product Snippets in Google Search?

Rich result eligibility (Product Snippets, Merchant Listings) lives at the Product variant level, not at the ProductGroup level. ProductGroup enables variant-aware display in Merchant Listings — shoppers can filter by size or color directly in search — but the underlying eligibility requirements (price, availability, unique identifier) must be met by each child Product.