Feed Import

Feed import is a recommended primary path to a complete catalog: it covers every product in your feed, with zero shopper-browser cost.

Feed import lets you point A vs B at a URL where your store already publishes a product feed, then choose how often to fetch it. A vs B polls the URL on your chosen schedule, parses any products that changed, and updates the Live Catalog, no manual uploads, no code changes each time your catalog changes.

Supported formats

FormatStatus
Google Merchant Center XMLSupported
CSV / TSVSupported

Both formats use the same field meanings: they are just different file layouts. The Google Merchant Center XML format (RSS 2.0 with the g: namespace) is the same file you already send to Google Shopping. CSV (or tab-separated TSV) is the right pick if your store or agency works in spreadsheets and exports a column-based file instead.

Because the two formats share the exact same mapping rules, the same products produce the same catalog entries whether you feed us XML or CSV.

Configuring a feed

On the Product catalog page, open Connect your store, then the Product feed card, then + Add product feed. You will be asked for:

SettingNotes
Feed URLMust be HTTPS. An http:// address is refused with "Feed URL must start with https://". A vs B fetches this URL on your chosen cadence. The URL must be publicly accessible or accessible from Cloudflare's network.
FormatSelect Google Merchant Center XML or CSV / TSV to match your file.
Poll cadenceHow often A vs B should check for changes: Hourly, Every 6 hours, or Daily.
Default currencyOptional 3-letter code (for example USD). Leave it blank to use your project's default currency.

Select Register feed to save. This does not fetch the feed straight away: the source starts out Never synced and picks up on the next hourly sweep (see below). For an immediate first import, open the source's row in Catalog source health and select Sync now.

  1. Paste your feed's HTTPS URL here.
  2. Pick the format that matches your file.
  3. Choose how often A vs B should check the feed for changes.

Poll cadence

A vs B runs a feed sweep every hour. On each sweep, it checks which feed rows are due based on their configured cadence:

  • Hourly: fetched on every sweep
  • Every 6 hours: fetched when at least 6 hours have passed since the last successful fetch
  • Daily: fetched when at least 24 hours have passed

Choose a cadence that matches how often your inventory or pricing actually changes. Hourly is appropriate for stores with frequent price changes or stock fluctuations. Daily is usually fine for stores with stable catalogs.

How changes are detected

A vs B does not parse and compare every product on every poll. Before doing any work, it computes a hash of the feed body and compares it to the hash from the previous fetch. If the feed has not changed, the sweep skips parsing and moves on: your catalog is already up to date.

When the hash differs, A vs B parses the full feed and upserts any products through the freshest-wins merge. Only the fields present in the feed are written; fields the feed does not include are left as they are from any higher-priority source.

Google Merchant Center XML field mapping

A vs B maps the standard g: namespace fields to the Live Catalog:

Feed fieldCatalog fieldNotes
g:idskuThe stable product identifier. For grouped items, g:item_group_id becomes the parent SKU.
titletitleStandard RSS <title> element.
descriptiondescriptionStandard RSS <description> element.
linkhrefProduct page URL.
g:image_linkimageMain product image.
g:brandbrandBrand or manufacturer.
g:product_typecategoryProduct type string.
g:google_product_categorycategoriesAdded as the first entry in the categories list.
g:priceprice or compareAtPriceWhen g:sale_price is also present, g:price becomes the compare-at (was) price.
g:sale_pricepriceWins over g:price as the live selling price when present.
g:availabilityavailabilityin_stock, out_of_stock, preorder. backorder maps to preorder.
g:custom_label_0 through g:custom_label_4customFieldsStored as custom_label_0 etc. in the product's custom fields.

Price strings use the format "19.99 USD" (amount, space, ISO currency code). A vs B reads the currency code from the string and converts to minor units using the correct exponent for that currency.

Variant grouping

Items sharing the same g:item_group_id are collapsed into a single parent product with variants:

  • The parent sku is the g:item_group_id.
  • Each item in the group becomes a variant with variantSku = its own g:id.
  • Variant-level options (g:color, g:size, g:material) are captured as the variant's option map.
  • The parent's price is the minimum variant price across the group.
  • If any variant is in_stock, the parent is in_stock.

Standalone items (no g:item_group_id) are treated as individual products.

CSV / TSV field mapping

A CSV feed is a plain table: the first row is the column headers, and every row after that is one product (or one variant). A vs B accepts the same column names Google uses for its CSV product feed, so any file that works for Google Shopping works here too.

ColumnCatalog fieldNotes
idskuRequired. For grouped items, item group id becomes the parent SKU.
item group idparent skuOptional. Rows sharing this value collapse into one product with variants.
titletitle
descriptiondescription
linkhrefProduct page URL.
image linkimageMain product image.
brandbrand
product typecategory
google product categorycategoriesAdded as the first category entry.
priceprice or compareAtPriceWhen sale price is also present, this becomes the compare-at (was) price.
sale pricepriceWins as the live selling price when present.
availabilityavailabilityin_stock, out_of_stock, preorder. backorder maps to preorder.
color, size, materialvariant options
custom label 0 … custom label 4customFields

A few things to know:

  • Comma or tab. A vs B detects automatically whether your file uses commas (CSV) or tabs (TSV): both work.
  • Header names are forgiving. Capitalisation, spaces vs underscores, and an optional g: prefix are all accepted, so Image Link, image_link, and g:image_link all mean the same thing.
  • Quoted values. A value containing a comma, quote, or line break must be wrapped in double quotes, with any inner quotes doubled ("a ""quoted"" word"): the standard spreadsheet CSV rules.
  • Prices use the same "19.99 USD" format as the XML feed (amount, space, ISO currency code).
  • Rows without an id are skipped. A file with no id column at all is rejected with a clear error.

Matching your own column names

A vs B already reads through capitalisation, spaces-vs-underscores, and an optional g: prefix, so Image Link, image_link, and g:image_link all mean the same thing to it.

For a column whose name means something different, like Product Name or Cost, tell A vs B what it is with Column mapping on the add-feed form:

  1. Set the format to CSV / TSV. The mapping section appears.
  2. Type your column header on the left, exactly as it appears in your file.
  3. Pick the A vs B field it means on the right.
  4. Add a row for each column you need to translate, then register the feed.

You only need a row for headers that do not already use a standard name. Everything else is read automatically.

A few things to know:

  • Editing a feed keeps its mapping. Re-opening the form on a registered feed shows the mapping that is live, so changing the poll cadence never quietly drops it.
  • Two rows naming the same column: the last one wins, and the form tells you when that happens.
  • XML feeds have nothing to map. Google Merchant Center XML uses Google's own field names, so the mapping section is hidden for that format, and a mapping is not saved with an XML feed.

Feed source health

The Product catalog page's Catalog source health table shows a row for each configured feed:

  • Last synced: when the last successful parse ran
  • Products seen: how many product records were in the most recent feed
  • Status: Never synced (registered but no sweep has run yet), OK, Syncing…, or Error
  1. The status badge: Never synced, OK, Syncing…, or Error.
  2. How many products the last successful poll saw.

An Error status means the last fetch or parse failed. The error message appears in the row. Common causes:

  • The feed URL returned a non-200 response (check that the URL is correct and publicly accessible)
  • The XML or CSV was malformed
  • The selected format doesn't match the file (for example, the format is set to CSV but the file is actually XML)
  • A CSV file has no id column (map your product-id column to id under Column mapping, or rename it in your export)

A vs B continues retrying on the configured cadence regardless of errors.

Priority in the freshest-wins merge

Feed writes are tagged source feed. In the merge order:

Plain text
live_event > shopify > push_api ≈ feed > upload
Plain text1 line

A feed write always wins over an uploaded dataset baseline. A Shopify webhook update always wins over a feed write, no matter which one is newer. A feed write and a Push API write are equally trusted: whichever one lands most recently wins. For price and stock specifically, the most recent write wins regardless of source, including a real-time browser price observation, so a fresh on-page price can outrank even a Shopify update for that one field.

Products that drop out of the feed are removed automatically

If a product is missing from a complete, successful poll of your feed, A vs B removes it from the Live Catalog, as long as your feed is still the source that owns that product (a higher-priority source like Shopify keeps its own products even if your feed stops listing them). A vs B never removes anything on a product's first-ever poll, since there is nothing yet to compare against, and it refuses to remove more than half your catalog in a single poll: a feed that suddenly returns almost nothing is more likely broken than genuinely emptied, so A vs B flags it as an error instead of deleting in bulk.

Was this helpful?