Google's product data specification is the document every Shopping feed is judged against, and it is written like a tax form. More than sixty attributes, each with a requirement level that depends on the country, the category and the destination, with the examples buried under three levels of expandable sections. Most merchants read it once, give up, and let an app guess.
The guess is where disapprovals come from. If you understand what each attribute is for and what Google actually does with it, the error messages in Diagnostics stop being mysterious and most of them stop appearing at all. This guide walks the spec in plain English: what a feed is, the dozen attributes that matter, what Google checks on each one, where the value lives in a Shopify store, and the mistakes that get products rejected.
If you would rather have the mapping done for you, SnowPipe maps a Shopify, WooCommerce or BigCommerce catalog onto this spec and validates it before Google sees it. The rest of this post is the spec itself.
What a product feed actually is
A product feed is a table. One row per sellable item, one column per attribute. That is the entire mental model, and everything in the spec is a rule about one of those columns.
Three things about the table that are not obvious from the spec page:
A row is a variant, not a product. If a t-shirt comes in four sizes and three colors, Google wants twelve rows, each with its own id, its own price and availability, and a shared item_group_id that ties them back to one product. A feed that sends one row per Shopify product is the single most common structural mistake, and it produces a whole family of errors at once (wrong image for the variant, wrong price, "missing item_group_id").
The attribute names are the same no matter how you deliver the table. A tab-separated file, an XML file, a Google Sheet, a platform app, the older Content API for Shopping and its successor the Merchant API all carry the same attributes with the same rules. The delivery method decides how fast changes reach Google and how errors come back to you. It does not change what is required.
Google does not trust the table. After it parses your feed, it crawls your landing pages and fetches your images, and when what it finds disagrees with what you sent, the page wins and the product is flagged. A perfectly formed feed row can still be disapproved. Keep that in mind through everything below.
The seven attributes required on every product
These are required for every product, in every country, for every destination. If one is missing or malformed, the product does not go live.
| Attribute | What it is | Limits that bite | Where it lives in Shopify |
|---|---|---|---|
id | Your unique identifier for the row. | Max 50 characters. Never change it: a new id is a new product to Google, and the old one loses its history and review status. | Variant ID (not product ID) |
title | The product name shoppers see. | Max 150 characters, and the first 70 or so are what fits in an ad. No promotional text, no ALL CAPS. | Product title, usually with the variant title appended ("Trail Runner, Blue, 10") |
description | The product's description. | Max 5,000 characters. Plain text: Google strips or rejects HTML and ignores anything that is not about the product. | body_html, with the HTML stripped |
link | The landing page URL. | Must start with http:// or https://, must be on a domain you have verified and claimed in Merchant Center, and must land on the product as described, not a search page or a redirect loop. | Product URL with the ?variant= query so the page opens on the right variant |
image_link | The main product image URL. | At least 100 x 100 pixels (250 x 250 for apparel), under 64 megapixels and 16 MB. No watermarks, logos, promotional text or placeholders. Google fetches it, so it must be publicly reachable. | Variant image if one is set, otherwise the product's featured image |
availability | Whether it can be bought now. | Exactly one of in_stock, out_of_stock, preorder, backorder. Must match the landing page. | Derived from inventory_quantity and inventory_policy (a variant that allows overselling is in stock at zero) |
price | The price before any sale. | A number and an ISO 4217 currency, like 29.99 USD. Cannot be zero. Must match the landing page, in the country's currency, with tax handled the way that country expects (included in the EU, excluded in the US). | Variant price (or compare_at_price when a sale is on, see below) |
Two details on this table that cost people weeks:
Sale prices have their own attribute. When Shopify shows a crossed-out price, the crossed-out one is Google's price and the current one is sale_price. Sending the sale price as price and nothing as sale_price is accepted, but you lose the strikethrough in the ad and you create a mismatch the moment the sale ends. Add sale_price_effective_date if the sale has fixed dates.
The link and the image are fetched, not read. Google will follow your link and download your image_link. If your store blocks unknown user agents, serves a cookie wall, uses a staging domain, or returns the image through a signed URL that expires, the row is fine and the product is still disapproved. Google's image requirements cover the image side in detail; the link side mostly comes down to "does a logged-out visitor with no cookies see this product at this price".
Identity: brand, GTIN and MPN
Google uses product identifiers to match your listing to the same product from other sellers, which is what makes it show up in comparison listings and what lets Google attach reviews and specs it already has.
| Attribute | Required? | Rules |
|---|---|---|
brand | Required for all new products except books, movies and music recordings. | Max 70 characters. The manufacturer's brand, not your store name, unless you are the manufacturer. |
gtin | Required when the product has one assigned by the manufacturer, which is nearly every branded, mass-produced product. | 8, 12, 13 or 14 digits (GTIN-8, UPC, EAN, GTIN-14) or an ISBN. Google validates the check digit, so an internal SKU in this field is rejected. |
mpn | Required with brand when there is no GTIN. | Max 70 characters. The manufacturer's part number, which is often not your SKU. |
identifier_exists | Optional. | Set to no only for products that genuinely have no GTIN, MPN or brand: handmade, custom, vintage, store exclusives. Google disapproves a branded product that claims no, and the fix is the identifier, not the attribute. |
The practical rule: branded product, send brand plus gtin. Your own product with no barcode, send brand plus mpn, or identifier_exists: no with a brand. The GTIN requirements page lists the exceptions. In Shopify, brand is the product's Vendor field and the GTIN is the variant's barcode field, which is empty on most stores until someone fills it, and that empty field is the origin of the single most common Merchant Center error. Shopify has no MPN field; stores usually send the SKU, which is only right when the SKU is the manufacturer's number. The missing GTIN guide covers what to do about it.
Condition and variants
condition is required only when a product is not new: new, refurbished or used. Shopify has no condition field, so feeds default it to new, which is right for almost everyone and wrong for resale stores, who need a metafield.
item_group_id is what turns twelve rows back into one product. Every variant of a product gets the same value, max 50 characters, and Google uses it to show the color and size pickers in the listing and to avoid treating twelve near-identical rows as duplicates. In Shopify it is the product ID. It is required for variants in the same six countries that require the apparel attributes below, and harmless everywhere else, so always send it when a product has more than one variant.
Variant rows also need the attributes that make them different:
| Attribute | Values | Notes |
|---|---|---|
color | Free text, max 100 characters. Up to three colors joined with / for multicolor items. | Required for apparel in several countries including the US, the UK, Germany, France, Japan and Brazil. |
size | Free text, max 100 characters. | Same requirement as color. Use the size as it appears on the product ("M", "32x34", "10.5"). |
age_group | newborn, infant, toddler, kids, adult | Same requirement for apparel. |
gender | male, female, unisex | Same requirement for apparel. |
material, pattern | Free text | Optional, but they help Google match the product and they show up as filters. |
In Shopify these come from the variant's option values. The catch is that Shopify option names are whatever the merchant typed ("Colour", "Shade", "Size / Fit"), so a feed has to recognise which option is the color and which is the size rather than assume the names.
Category: Google's taxonomy versus yours
There are two category attributes and they do different jobs.
google_product_category is Google's own taxonomy of roughly 5,600 categories, submitted as either the numeric id or the full path (Apparel & Accessories > Shoes). Google uses it to decide which product this is for classification, which tax and policy rules apply, and whether the apparel attributes above are required. If you leave it blank Google assigns one, and if Google's classifier disagrees with what you sent, Google's choice wins. You still want to set it: the automatic assignment is often a parent category, and some categories (apparel, media) carry rules that only apply once Google knows the product is in them. Google's taxonomy page has the list, and if you just want to find the right id for a product, the free category lookup tool searches it by keyword.
product_type is your store's own category text, up to 750 characters, any taxonomy you like. Google does not use it for classification. It exists so you can segment campaigns: "all products where product_type starts with Clearance" is a product group you can bid on. In Shopify it is the product's Type field, or the collection, depending on how the store is organised.
Send both. Leaving product_type blank throws away free campaign structure; leaving google_product_category blank hands classification to a model that has not seen your product.
Shipping, tax and the account-level attributes
shipping and tax can be set per product in the feed or once for the whole account in Merchant Center settings. Almost everyone should set them at the account level and leave them out of the feed. The feed form (US:CA:Overnight:16.00 USD) exists for stores whose shipping genuinely differs per product, and it overrides the account setting for that product, which is a common source of "why does this one item show the wrong shipping" questions.
Tax is required in the US and must match what you charge at checkout. Outside the US the tax attribute is not used; in most other countries the price must include VAT, and Canada is the exception where it must exclude tax.
shipping_weight, shipping_length, shipping_width and shipping_height feed carrier-calculated rates. Shopify variant weight maps to shipping_weight; the dimensions usually need a metafield.
The attributes that control campaigns, not listings
A handful of attributes never appear in an ad. They exist to let you organise and control what Google does with the product.
custom_label_0throughcustom_label_4: five free-text slots, max 100 characters each, for anything you want to bid on separately: margin band, season, best-seller flag, supplier. These are the single most useful attributes in the spec for anyone running Shopping campaigns, and most feeds leave them empty.excluded_destinationandincluded_destination: which Google surfaces the product may appear on (Shopping ads, free listings, Display, YouTube). A product excluded from Shopping ads is not disapproved, it is invisible on purpose, which the excluded_destination guide explains in detail.adult:yesfor adult-only products. Google decides this on its own if you do not, and its decision is harder to reverse.multipackandis_bundle: tell Google when one row is several identical items or a merchant-assembled bundle, so the price-per-unit comparisons are fair.expiration_date: the day the product should stop showing. Independent of the 30-day feed expiry below.
What Google actually checks, in order
Knowing the attributes is half of it. The other half is knowing what happens to a row after you submit it, because each stage produces different errors.
- Parsing. The file or API payload is read. Unknown attribute names are ignored, a required attribute missing from every row disapproves every row, and malformed values (a price without a currency, a date in the wrong format) fail the row. These show up immediately.
- Item-level validation. Each row is checked against the requirement levels for its country and category: required attributes present, GTIN check digit valid, enumerated values spelled exactly, lengths within limits. These are the "missing required attribute" and "invalid value" errors in Diagnostics.
- Crawling. Google fetches
linkandimage_link. It compares the page's price and availability to the feed, checks that the image loads and is clean, and checks that the page is reachable from the country you are targeting. Mismatches here are the "automatic item updates" and "price mismatch" and "image not retrievable" family. They can take a day or more to appear because crawling is not instant. - Policy review. The product and the account are checked against the Shopping policies: restricted categories, prohibited claims, landing page quality, business information. New accounts sit in a review state for a few days before anything serves.
- Expiry. Every product expires 30 days after Google last received it, whether or not anything changed. A feed that is uploaded once and forgotten goes dark on day 31. The expired products guide has the details.
The reason this order matters: a feed that passes stages one and two can look perfectly healthy for a day and then shed half its products at stage three. Diagnostics shows all of it in one list, which is why the first question for any error is "which stage produced this". Google's diagnostics documentation breaks the issue types down by stage, though it does not call them that.
The mistakes that account for most disapprovals
Having watched a lot of feeds, the same handful of mistakes produce most of the volume. Each is a misreading of the spec rather than a bug.
- Product-level rows for variant-level products. One row per Shopify product, with the product ID as
id, the first variant's price, and noitem_group_id. Google sees a product whose landing page shows different prices depending on the option selected, and disapproves it for a price mismatch. - SKU in the
gtinfield. The check digit fails and Google rejects it as an invalid identifier. SKUs belong inmpnif anywhere. - Price with the wrong tax treatment. A US store sending tax-inclusive prices, or an EU store sending tax-exclusive ones, mismatches the landing page by exactly the tax rate. The invalid price guide walks through the currency and formatting side.
- HTML in
description. Shopify'sbody_htmlis HTML. Sent raw, the tags count toward the 5,000-character limit and Google may reject the value. - Keyword-stuffed or promotional titles. "FREE SHIPPING!! Best Running Shoe 2026 Nike Adidas" fails the title policy. Google's title guidance is short and specific: brand, product, distinguishing attributes, nothing else.
- Images with text or on a white-label CDN that blocks bots. The row is fine; the fetch fails. The image_link_broken guide covers diagnosis.
- A feed that stops updating. Everything expires on day 31. Nothing in Diagnostics warns you on day 30.
How SnowPipe applies the spec
SnowPipe exists because the mapping above is the same for every store and nobody should have to do it by hand. It reads a Shopify, WooCommerce or BigCommerce catalog, expands products into one row per variant with the right item_group_id, and maps the fields in this post onto the Google attributes with a default template you can edit, backed by a field spec that encodes the limits and enumerations above. Prices and sale prices are separated the way Google wants them, body_html is stripped to text, the variant barcode becomes gtin and is checked against the GS1 check digit before it is sent, and options named Color, Colour or Size are mapped to color and size automatically, with any other option name mapped by hand in the field mapper. Products with no google_product_category get one from AI categorization against the same taxonomy the lookup tool searches. The result is validated against the spec before export, so a missing required attribute is reported to you rather than to Google, and it is written through the Merchant API on the schedule you set, so nothing expires on day 31.
Frequently asked questions
Which Google Merchant Center attributes are required for every product?
Seven attributes are required on every product: id, title, description, link, image_link, availability and price. Brand and a GTIN are required for most branded products, condition is required when a product is not new, and item_group_id is required when you submit variants of one product. Apparel in several countries also needs color, size, age_group and gender.
Does the attribute list change if I use the Merchant API instead of a feed file?
No. The attribute names, formats and requirement levels in the product data specification apply however you deliver the data: a TSV or XML file, a Google Sheet, the Content API for Shopping, its successor the Merchant API, or a platform app. The delivery method only changes how often the data arrives and how errors are reported back.
What is the difference between google_product_category and product_type?
google_product_category is Google's own taxonomy, submitted as a numeric id or the full path, and Google uses it to decide how a product is classified, taxed and policed. product_type is your own store's category text; Google ignores it for classification but you can use it to build campaign groups and bid differently per category.
Why does Google disapprove a product when my feed has every required attribute?
Because Google also crawls the landing page and the image. If the price or availability on the page differs from the feed, the image cannot be fetched or carries promotional text, or the landing page redirects or blocks Googlebot, the product is disapproved even though the feed row is complete.
How often do I need to resubmit a Google Merchant Center feed?
Every product expires 30 days after Google last received it unless it is refreshed, and prices or stock that change on your site should reach Google before a shopper sees the old value. In practice that means a daily feed at minimum, and an update on every price or inventory change if you can automate it.
Ready to stop hand-mapping the spec?
Try SnowPipe free: connect your store and get accurate Google/Facebook syncs in minutes. Or book a 15-min demo and I'll walk you through your specific setup.