Shopify variants and item_group_id
How Shopify's product/variant model maps to Google's item_group_id, why every variant is its own offer, and the variant mistakes that fragment your Shopping performance.
In Google Shopping, every sellable variant, each colour/size combination, is its own product offer with its own ID, price and availability. item_group_id is the thread that tells Google 'these 24 offers are one dress'. Shopify's Product → Variants structure maps onto this naturally, but only if the feed sends variant-level data and groups it correctly.
Two models, one mapping
Shopify: a Product holds up to three Options (say Colour and Size) whose combinations define Variants (Shopify caps a product at 2,048 variants). Each variant carries its own price, SKU, barcode, weight, image and inventory.
Google: there are no "products with options": only flat offers. Each offer is one buyable thing. item_group_id is a plain string that groups offers into a family so Google can show one tile and let the shopper pick colour/size on the product page.
The mapping is exactly as simple as it looks (variant → offer id, product → item_group_id) and yet it's one of the most commonly broken parts of Shopify feeds, because everything else has to be variant-level too for the grouping to mean anything.
What variant-level actually requires
For each variant offer, the feed must carry that variant's own:
price/sale_price: size-based pricing is common; a group sharing one price when variants differ triggers mismatch disapprovals on the variants that differ.availability: the whole point of variant offers: the sold-out 10 goes out of stock while the 12 keeps serving. Product-level availability wastes spend on unbuyable clicks or hides sellable stock.link: with the variant preselected (?variant=123...), so Google's crawler lands on a page showing the price and stock state the feed claimed.image_link: the variant's colour, not the hero shot.color/size: parsed from the variant's option values, normalised to Google's expectations.gtin: the variant's own barcode.
Deep dive The failure modes, ranked by damage
- Splitting a family across item_group_ids (e.g. after a re-import assigns new product IDs, or a "same dress, new season" duplicate listing): Google treats them as unrelated products, review signals and performance history fragment, and the variants compete against each other in the auction.
- Merging unrelated products into one group ("all mugs" under one item_group_id): Google expects group members to differ only in variant attributes; unrelated members confuse serving and can suppress the group.
- Stable IDs matter more than pretty IDs.
item_group_idshould be the Shopify Product ID (immutable), not the handle (editable) and not the title (definitely editable). Every time a group ID changes, accumulated performance resets: a silent tax on stores that rebuild feeds casually. - Option-name drift: Google needs
colorandsize, but Shopify options are free-text names per product. A catalog with "Colour", "Color", "Shade" and "Finish" across products needs normalisation in the feed layer, or half your variants ship without acolorattribute and lose attribute-filtered impressions. - The 2,048-variant / multi-option edge: products using all three options (Colour × Size × Length) still map fine (each combination is one offer) but check that your pipeline sends all three as separate attributes (
color,size, plus e.g.size_type/custom) rather than concatenating into one.
How /tools handles this
The Optimise sync reads Shopify variants natively: item_group_id from the immutable product ID, per-variant price/stock/image/barcode, option-name normalisation into color/size regardless of what the options were called, and variant relationship checks in the Feed Health Score so broken groups surface before Google notices. For catalogs whose variant structure itself is messy (duplicate listings per colour, families split across products), the Variant Builder can define the correct relationships at the feed layer: again without touching your Shopify data.
Frequently asked questions
Should I send every variant or one per product?
For apparel and anything where variants differ in colour/size/material, send every variant with a shared item_group_id, Google requires it in apparel categories and rewards it everywhere shoppers search by attribute ("red midi dress size 10").
Do all variants need their own GTIN?
Each variant with its own barcode gets its own GTIN, which in practice is every variant, since barcodes exist at the sellable-unit level. Sharing one GTIN across sizes is a disapproval magnet.
Google shows the wrong colour image for my variants, why?
Your feed is sending the product-level image for every variant instead of each variant's own image. Assign per-variant images in Shopify (at least one per colour) and make sure the feed maps variant image, falling back to product image only when unset.