# Google Shopping vs OpenAI: feed requirements compared

OpenAI is the least Google-like channel documented here. Half the core attributes carry a different name, price is one string with the currency inside it, variants use a different grouping shape, and the feed is pushed over SFTP rather than fetched from a URL you host.

- **Canonical URL:** https://www.feedlab.io/knowledge/compare/google-shopping-vs-openai
- **Last reviewed:** 18 September 2026
- **Source:** feedlab knowledge base
- **Licence:** free to quote and cite with attribution to feedlab


## Short answer

Treat this as a new feed rather than a rename of your Google one. The mapping logic transfers, because it is the same catalogue answering the same questions, but the field names, the price format, the variant structure and the delivery method all change. Budget for a pipeline change, not a column change.

## Attributes treated differently

| Attribute | Google Shopping | OpenAI |
| --- | --- | --- |
| `brand` | Required in some cases | Required |
| `condition` | Required in some cases | Optional |
| `custom_label_0` | Optional (`custom_label_0`) | Optional (`ads_metadata`) |
| `google_product_category` | Recommended (`google_product_category`) | Optional (`product_category`) |
| `gtin` | Required in some cases | Optional |
| `id` | Required (`id`) | Required (`item_id`) |
| `identifier_exists` | Optional | Not supported |
| `image_link` | Required (`image_link`) | Required (`image_url`) |
| `item_group_id` | Required in some cases (`item_group_id`) | Optional (`group_id`) |
| `link` | Required (`link`) | Required (`url`) |
| `mpn` | Required in some cases | Optional |

## Every attribute, side by side

| Attribute | Google Shopping | OpenAI |
| --- | --- | --- |
| `availability` | Required | Required |
| `brand` | Required in some cases | Required |
| `condition` | Required in some cases | Optional |
| `custom_label_0` | Optional | Optional |
| `description` | Required | Required |
| `google_product_category` | Recommended | Optional |
| `gtin` | Required in some cases | Optional |
| `id` | Required | Required |
| `identifier_exists` | Optional | Not supported |
| `image_link` | Required | Required |
| `item_group_id` | Required in some cases | Optional |
| `link` | Required | Required |
| `mpn` | Required in some cases | Optional |
| `price` | Required | Required |
| `sale_price` | Optional | Optional |
| `title` | Required | Required |


## Differences a table cannot show

### You push the feed, OpenAI does not fetch it

Google takes a feed URL and re-fetches it on a schedule you choose. OpenAI issues an SFTP endpoint and expects full catalogue snapshots pushed to it on a predictable cadence of at least daily. Every other channel here needs a URL; this one needs a delivery step, which is the single biggest difference between the two.

### Six of the core fields are named differently

id becomes item_id, link becomes url, image_link becomes image_url, item_group_id becomes group_id, google_product_category becomes product_category and custom labels move into ads_metadata. None of this changes what you send, but all of it changes the file, and a Google feed pointed at OpenAI unchanged carries almost no recognisable columns.

### Price is a single string with the currency in it

The price attribute is a decimal amount, a space, then an uppercase ISO 4217 code, so "79.99 USD" rather than an amount in one column and a currency somewhere else. Shopify holds the amount and the currency apart, so this is a formatting rule rather than a field you can map straight across, and it applies to sale prices too.

### Variants use a different shape entirely

Google groups variants with item_group_id and leaves it there. OpenAI groups them with group_id, flags the parent relationship with listing_has_variations, and describes the variation with a variant_dict mapping option names to values. A feed already mapped for Google needs this rebuilt rather than renamed.

### seller_name is required and no Shopify field holds it

Alongside the expected identity, price and availability fields, the specification requires seller_name. Nothing on a Shopify product carries it, so it has to come from a static value set once for the store. It is the clearest example of a required attribute that is a property of the merchant rather than the product.

### Snapshots age out rather than going stale

Google expires product data after 30 days. OpenAI retains its most recently processed record for up to 14 days, so a catalogue that stops being pushed disappears sooner. Because the cadence is push rather than pull, a failed job is also silent unless you monitor it yourself.




## Reusing one feed for the other channel

1. **Build the delivery step first** — Get a snapshot landing on the SFTP endpoint on a schedule before worrying about field-level polish. Delivery is the part with no analogue in your existing setup, so it is the part most likely to hold the launch up.
2. **Rename the six fields as a mapping, not a find and replace** — item_id, url, image_url, group_id, product_category and ads_metadata all carry values you already produce. Keep one internal mapping and render the channel names at publish time, so the Google feed does not drift away from the OpenAI one as either specification changes.
3. **Reformat every price into amount plus currency code** — Concatenate the decimal amount, a space and the uppercase ISO code, and apply the same rule to sale prices. Check what happens to a zero-decimal currency and to a price with a thousands separator, because both are easy to get wrong once and never notice.
4. **Rebuild the variant relationship** — Map group_id from the Shopify product id, set listing_has_variations where a product has more than one variant, and build variant_dict from the option names and values Shopify already stores. This is real work rather than renaming, and it is what makes variants usable in a shopping answer.
5. **Set seller_name once, at the store level** — It is a static value for the whole catalogue. Set it deliberately rather than deriving it from vendor, which is a product field and will be wrong the moment you stock someone else's brand.
6. **Monitor the push, because nothing else will** — A fetched feed fails visibly: the channel tells you it could not read your URL. A pushed snapshot that never leaves your side fails silently until the 14-day retention runs out. Alert on the job, not on the channel.







## Frequently asked questions

### Can I send my Google Shopping feed to OpenAI?

Not as it stands. Six of the core attributes are named differently, price has to be a single string with the currency code inside it, variants use group_id with listing_has_variations and variant_dict, and the file is pushed over SFTP rather than fetched from a URL.

### How does the OpenAI product feed get delivered?

You push full catalogue snapshots to an SFTP endpoint OpenAI issues you, on a predictable cadence of at least daily. It is the only channel documented here that does not fetch a feed URL you host.

### What price format does the OpenAI feed use?

A decimal amount, a space, then an uppercase ISO 4217 currency code, for example "79.99 USD". Shopify stores the amount and the currency separately, so the two have to be joined at generation time.

### Why does the OpenAI feed need seller_name?

Because a shopping answer needs to say who is selling the item, and that is a property of your store rather than of the product. No Shopify product field holds it, so set it as a static value for the whole catalogue.




## Primary sources

- [Google: Product data specification](https://support.google.com/merchants/answer/7052112)
- [OpenAI: Product feed required fields](https://developers.openai.com/commerce/specs/file-upload/products)



