ProductGroup Schema

How to use ProductGroup schema to group product variants (size, color, material) with hasVariant, variesBy, and productGroupID — plus the item_group_id difference and why Bing doesn't support it.

First published: Jun 27, 2026 · Last updated: Jul 20, 2026 · Advanced
demand #29 in Structured Data#59 in On-Page#267 in Technical SEO#360 on the site

ProductGroup schema wraps a set of Product variants — a shirt's sizes and colors — under one parent so Google understands they're options of the same item, not separate products. It's additive: every variant is still a full Product with its own sku/gtin, price, and availability, and ProductGroup ties them together with hasVariant (nested, single-page sites), variesBy (which attributes differ), and productGroupID (the parent sku). The single most common mistake is writing variesBy as plain strings — it must use full schema.org URLs like https://schema.org/color; in my testing the JSON-LD still validates but the grouping doesn't trigger (Google doesn't document that failure mode, so verify it yourself). Two more traps: productGroupID (on-page schema) is not Merchant Center's item_group_id (a product-feed attribute) — separate systems, nothing auto-syncs them, so use matching values deliberately; and Bing doesn't consume ProductGroup markup at all (per Microsoft's Fabrice Canel, Sept 2024, a reported statement, not a Microsoft doc). My rule with all schema holds here: implement it because it earns you a search feature, not because more markup is automatically better — it aids understanding and merchant-listing eligibility, it doesn't make a variant rank.

TL;DR — ProductGroup (Google’s Feb 2024 addition) wraps variant Product objects under one parent so Google understands “same item, different options.” It’s additive — each variant keeps full Product markup (sku/gtin, offers, image, availability). Link them with hasVariant (nested, single-page sites) or isVariantOf + inProductGroupWithID (flat, multi-page sites); declare the varying axes with variesBy — which must use full schema.orgSchema markup is code that uses the schema.org vocabulary to label what your content means so search engines can understand it and show rich results. It's most often written in JSON-LD, and it's not a direct ranking factor. URLs (https://schema.org/color), not plain strings (the #1 implementation mistake — validates either way, but grouping quietly won’t trigger in practice, which isn’t a documented Google behavior); and share a productGroupID (plain text parent sku, not a URL). productGroupID is not Merchant CenterGoogle Merchant Center (GMC) is a free platform where retailers upload and manage product data so their products can appear across Google — Shopping, organic Search product grids, Images, Lens, and AI surfaces. Since 2020 it powers free (organic) product listings, not just paid Shopping ads.’s item_group_id — separate systems, nothing auto-syncs them, so use matching values on purpose. Only name is strictly required. And Bing doesn’t consume ProductGroup at all (Fabrice Canel, Sept 2024). Schema aids understanding and merchant-listing eligibility — it isn’t a ranking factor.

Where this sits

This is the schema-implementation deep dive — the full JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal., the property-by-property reference, the Merchant Center reconciliation, and the troubleshooting. The upstream strategy question — should a given variant get its own indexable URL at all, and how do Shopify/WooCommerceWooCommerce SEO is optimizing a WooCommerce store — which runs as a free plugin on WordPress, not as a standalone platform — to rank in organic search. Because you control the whole stack (templates, URLs, plugins, server), the ceiling is high and the ways to misconfigure it are many./BigCommerceBigCommerce SEO is the technical, on-page, and content work you do on a store built on BigCommerce — a hosted SaaS ecommerce platform that ships with more native SEO controls than most of its rivals (editable robots.txt, custom URL structures, auto sitemaps, and automatic 301s), while still leaving faceted navigation, multi-storefront hreflang, and review schema for you to handle./Magento differ — is its own topic (product variant SEO). This article assumes you’ve already made those calls and now need the markup right. It also sits under the broader schema markupSchema markup is code that uses the schema.org vocabulary to label what your content means so search engines can understand it and show rich results. It's most often written in JSON-LD, and it's not a direct ranking factor. and structured dataStructured data is a standardized way of labeling page content (using the schema.org vocabulary in JSON-LD, Microdata, or RDFa) so search engines can understand its meaning. It's not a direct ranking factor — its value is rich results and entity understanding. hubs, and it’s a sibling of Product schemaProduct schema (schema.org/Product) is structured data that tells search engines a page's product name, price, availability, and reviews so it can appear in Shopping-style rich results. It's separate from a Google Merchant Center feed, though Google reconciles the two. (for a single, non-varying item, plain Product is all you need — ProductGroup is for a family of variants).

Why ProductGroup exists

Google’s own framing: “To help Google better understand which products are variations of the same parent product, use the ProductGroup class with associated properties variesBy, hasVariant, and productGroupID to group such variants together.” The motivating categories are exactly what you’d expect — “apparel, shoes, furniture, electronic devices, and luggage… sold in different variations (for example various sizes, colors, materials, or patterns).”

Evidence for this claim Google documents ProductGroup relationships including variesBy, hasVariant, productGroupID, and inverse variant references. Scope: Google Search product-variant requirements; use the pattern matching the site's URL architecture. Confidence: high · Verified: Google: Product variants

The payoff is eligibility, not ranking: “Adding this markup also makes your products eligible for display with variant information in merchant listing experiences.” Same caveat that applies to all structured data — it aids understanding and rich-result eligibility, it doesn’t move you up the results.

It’s additive — this is the mental model that prevents most mistakes

ProductGroup wraps Product; it doesn’t replace it. The ProductGroup object itself isn’t offered for sale — it has no single price, because “the coat” costs different amounts depending on which variant you buy. Every variant remains a full Product with its own sku/gtin, image, offers, and availability. If you find yourself trying to put a single offers/price on the ProductGroup, stop — that’s the tell that you’ve confused the wrapper for the thing being sold.

Evidence for this claim ProductGroup groups variant Product entities; it does not replace the Product data required for individual variants. Scope: Google Search product-variant guidance; each purchasable variant retains its relevant Product and Offer data. Confidence: high · Verified: Google: Product variants

The three core properties

ProductGroup adds the parent relationship; it never replaces the Product markup on each sellable variant. Source: Patrick Stox

A ProductGroup named Wool winter coat declares productGroupID 44E01 and variesBy values using full schema.org URLs for color and size. It connects to green small, green large, and blue small Product variants. Every variant keeps a unique SKU, Offer, image, and availability. The connection can use hasVariant in a nested model or isVariantOf in a flat model.

© Patrick Stox LLC · CC BY 4.0 ·

hasVariant (and isVariantOf)

hasVariant is “a nested Product property that is one of the variants of the ProductGroup property… A ProductGroup typically has multiple nested variant Product properties.” You put your variant Product objects inside the group.

The inverse also exists: “a variant Product property can reference back to its parent ProductGroup using the isVariantOf property on the Product property.” Which one you use depends on your site’s URL structureURL structure is how the parts of a web address — scheme, domain, path, query string, and fragment — are organized and formatted. It mostly affects crawling, usability, and how engines understand a page, not rankings directly. (next section).

variesBy — full schema.org URLs, not plain strings

variesBy declares “aspects by which the variants in the ProductGroup vary (for example, size or color).” The critical detail, verbatim from Google’s properties table: “Reference these variant-identifying properties through their full Schema.org URL.”

That means:

"variesBy": ["https://schema.org/size", "https://schema.org/color"]

not "variesBy": ["size", "color"]. This is the single most common implementation mistake in this entire topic. What’s documented: Google’s property table requires the full URL form — nothing more specific than that. What’s not documented: Google doesn’t publish what happens if you skip it. In my own testing and consistent with other practitioners’ reports, the JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. still passes syntax validation and nothing errors out, but the enhanced grouping behavior doesn’t trigger — treat that as a strongly observed pattern, not an official Google statement, and verify it against your own markup rather than taking it as gospel.

The supported dimensions are https://schema.org/color, https://schema.org/size, https://schema.org/suggestedAge, https://schema.org/suggestedGender, https://schema.org/material, and https://schema.org/pattern.

productGroupID — plain text, and not item_group_id

productGroupID is “the identifier of the product group (also known as the parent sku). This identifier must be provided for the ProductGroup property or, alternatively, using inProductGroupWithID property for variants.” It’s a plain text identifier — Google’s own example is "44E01"not a URL. Don’t over-generalize the variesBy “full schema.org URL” rule to this field; they’re different rules for different jobs.

One hard constraint: “If you provide the identifier for both the ProductGroup property and its variant Product properties, they must match.” Google’s docs state the requirement but don’t document what happens when it’s violated. Based on my own testing (not a documented Google failure mode), a typo or a template/environment leak that changes the value on one variant page drops that variant out of the group with no visible error — the page just stops being read as part of the family. Treat that as observed behavior worth verifying yourself, not an official spec.

Two implementation patterns: nested vs. flat

Your URL structureURL structure is how the parts of a web address — scheme, domain, path, query string, and fragment — are organized and formatted. It mostly affects crawling, usability, and how engines understand a page, not rankings directly. decides which pattern you use.

Single-page sites — nested (hasVariant). All variants are selectable on one URL (via dropdowns/swatches). “For single-page websites only: The URL (without variant selectors) where the ProductGroup property is located.” There’s exactly one canonical URL for the whole group, and you nest every variant Product inside the ProductGroup via hasVariant.

Multi-page sites — flat (isVariantOf + inProductGroupWithID). Each variant has its own dedicated URL. Here “this doesn’t apply since there is no single canonical URLHow search engines pick one canonical URL among duplicates and consolidate signals onto it. representing the ProductGroup property.” Each page must carry full, self-contained markup for the entities defined on that page — you don’t share one block across pages. Every variant Product references its parent with isVariantOf, and the group link is carried by inProductGroupWithID: “Each product group must have a unique ID in its corresponding structured data markup, specified with the inProductGroupWithID property.”

Either way, “Each variant must have a unique ID in its corresponding structured data markup (for example, using the sku or gtin properties).”

One more requirement people miss on multi-page setups: variants must be reachable by a distinct, preselectable URL. Google: “The site must have the ability to preselect each variant directly with a distinct URL (using URL query parameters), for example https://www.example.com/winter_coat/size=small&color=green.” A variant that only appears after a client-side click, with no URL to point at, can’t be validated or indexed as its own thing.

  • Required on ProductGroup: just name (e.g., "Wool winter coat").
  • Recommended: variesBy, hasVariant, productGroupID, brand, description, aggregateRating, review, hasAdultConsideration, and (single-page sites only) url.

Technically only name is required — but variesBy and productGroupID are functionally load-bearing. Skip them and the JSON-LD validates while the grouping behavior you wanted never shows up. (aggregateRating and review here are the same types you’d use standalone — see the AggregateRating and Review schemaReview schema (schema.org/Review) is structured data for a single critic's or user's evaluation of one specific thing — one author, one itemReviewed, one reviewRating — distinct from AggregateRating, which summarizes many reviews into an average. deep dives.)

productGroupID vs. Merchant Center’s item_group_id — the reconciliation nobody explains

This is the confusion point that most competitor content skips entirely, so it’s worth being precise.

  • productGroupID is a schema.org / on-page structured data field. It feeds organic Search’s understanding of the page.
  • item_group_id is a Google Merchant CenterGoogle Merchant Center (GMC) is a free platform where retailers upload and manage product data so their products can appear across Google — Shopping, organic Search product grids, Images, Lens, and AI surfaces. Since 2020 it powers free (organic) product listings, not just paid Shopping ads. product-feed attribute. Merchant Center: “Use the item group ID [item_group_id] attribute to group product variants in your product data.” It feeds Shopping ads and free listings.

They are two separate systems, and Google does not automatically sync them. Best practice — and this is echoed across the better third-party implementation guides — is to use the same identifier value for both, so your feed and your markup agree on which SKUs belong together. A mismatch doesn’t necessarily break either system outright, but it removes the reinforcing signal and can produce inconsistent grouping between Shopping surfaces and organic rich resultsRich results (formerly 'rich snippets') are enhanced search listings — stars, images, prices, breadcrumbs, video thumbnails, and more — that Google and Bing build from structured data. They're a display feature, not a ranking factor, and eligibility never guarantees they'll show..

(A footnote on casing: Merchant Center’s help sometimes writes productGroupId lowercase-d where Search Central’s docs use productGroupID. That’s a cosmetic inconsistency in Google’s own docs, not a mistake on your end — follow Search Central’s productGroupID in your JSON-LD.)

The consistency discipline here is the same one that governs canonicals and variant URLs generally: your signals should agree with each other, or you’re handing Google a reason to guess.

Bing does not support ProductGroup

Here’s the differentiator most guides get wrong or omit: Bing does not currently consume schema.org ProductGroup markup. Microsoft’s Fabrice Canel, responding directly to a question about whether Bing supports schema.org/ProductGroup, said Bing does not yet support it, but that it’s “on our radar” and the team is “closely monitoring its adoption.” (Reported by Search Engine Roundtable, covering a September 2024 exchange on X — a secondary report of a first-party statement, not a Microsoft doc, so treat it as such.)

Bing’s Webmaster Tools structured-data help is a generic overview of supported formats with no ProductGroup-, variesBy-, or productGroupID-specific content. Bing’s Shopping variant grouping runs through a feed-side itemGroupId field in Microsoft Advertising — the analog of Google’s item_group_id, not on-page schema. So: implement ProductGroup for Google, and handle Bing Shopping variants through the Microsoft Advertising feed, not markup.

A note on dynamic markup

Google’s own caution: “Be aware that dynamically-generated markup can make Shopping crawls less frequent and less reliable, which can be an issue for fast-changing content like product availability and price.” If your variant offers/availability are JS-injected, weigh that against server-renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. the markup for the fields that change often.

Validate before you ship

  • Rich Results Test — checks eligibility and surfaces required-property errors for the merchant-listing/variant experience.
  • Schema Markup Validator (schema.org) — validates the ProductGroup/Product types themselves, independent of Google features.
  • Search ConsoleGoogle's free tool for monitoring crawling, indexing, and search performance. — the merchant-listings/product-snippet enhancement reports show eligibility and errors at scale post-deploy; URL Inspection shows how a specific page was read.

Remember what “valid” does and doesn’t tell you: a plain-string variesBy passes validation and, in my testing, still doesn’t trigger grouping. Validation catches syntax and required-property gaps, not this kind of semantic failure (which Google doesn’t document either way) — for those, check by hand that your variesBy values are full URLs and your productGroupID matches across the group.

For where this fits the bigger picture, see the broader structured data and schema markup hubs this article lives under.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.