Skip to content
ShopAssist Docs
InstallOther sites (Generic)

Product feeds

Google Shopping XML, CSV and JSON feeds for Generic stores: supported fields, schedules, authentication, ETag caching and full-replace semantics.

Applies to: Generic · WooCommerce · PrestaShopView as Markdown

ShopAssist pulls feeds from your server on a schedule. A store can have up to 10 feeds: a primary products feed, translation feeds, extra-currency feeds and local inventory feeds.

Formats

| Format | Use when | Notes | | ------------------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | | Google Shopping XML (RSS 2.0 or Atom) | You already have a Merchant Center feed | Elements in the g: namespace; extensions in xmlns:sa="https://shopassist.coec.dk/ns/feed/1" | | CSV | Spreadsheet or ERP exports | Delimiter detected (, ; tab |), UTF-8 (with or without BOM), Windows-1252 or ISO-8859-1 | | JSON / JSON Lines | Your own REST endpoint or export | Needs a field mapping (below) |

Feeds may be gzip- or deflate-compressed. ZIP archives are not supported.

Google Shopping fields

Each <item> is one variant; items with the same item_group_id form one product.

FieldUsed asRules
idVariant id (product id without item_group_id)Required
item_group_idProduct idGroups variants
titleVariant title; the product title is the common prefix of the group (or sa:product_title)
descriptionProduct descriptionHTML is sanitized
linkProduct URLHTTPS, on one of your allowed domains
image_link, additional_image_linkImagesHTTPS; up to 10 additional
availabilityStock statusin_stock, out_of_stock, backorder, preorder
price, sale_price, sale_price_effective_datePrice, sale price and sale windowCurrency must equal the feed currency
brand, gtin, mpnBrand, GTIN, attributes
color, size, material, patternVariant options when they differ in the group
product_typeCategory path (A > B > C)
product_detail, product_highlightAttributes the assistant can answer from
sa:sku, sa:quantitySKU and stock quantityQuantity is an integer ≥ 0
sa:compare_at_is_referencetrue when the regular price is the lowest price of the last 30 daysSee prices
sa:add_to_cart_url, sa:tag, sa:rating, sa:rating_count, sa:is_publishedCart URL, tags, rating, visibility

custom_label_*, shipping, tax and promotion fields are ignored.

<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0" xmlns:sa="https://shopassist.coec.dk/ns/feed/1">
  <channel>
    <item>
      <g:id>SHIRT-42-BLUE</g:id>
      <g:item_group_id>SHIRT-42</g:item_group_id>
      <g:title>Linen shirt – Blue</g:title>
      <g:link>https://shop.example.com/products/linen-shirt</g:link>
      <g:image_link>https://shop.example.com/img/linen-blue.jpg</g:image_link>
      <g:availability>in_stock</g:availability>
      <g:price>499.00 DKK</g:price>
      <g:color>Blue</g:color>
      <sa:quantity>12</sa:quantity>
    </item>
  </channel>
</rss>

CSV

Use the Google field names as column headers (id, title, image link, g:price all work; ShopAssist extensions use the sa_ prefix, for example sa_quantity). Multi-value cells: additional_image_link, sa_tag and gtin are split on commas. If your headers differ, map them in the feed settings, for example {"id": "SKU", "price": "Pris", "availability": "Lager"}.

JSON

JSON feeds need a mapping that selects the records and maps fields with a small JSONPath subset ($, @, .name, [0], [*], and filters like [?(@.visible == true)]). Transforms such as trim, int, decimal, cents, money, url and map:<name> convert values. Pagination follows a next-page URL or a page parameter.

{
  "version": 1,
  "format": "json",
  "records": "$.data.products[*]",
  "record_kind": "product",
  "fields": {
    "external_id": "@.id",
    "title": { "path": "@.name", "transforms": ["trim"] },
    "url": { "path": "@.permalink", "transforms": ["url"] }
  },
  "variants": {
    "records": "@.variants[*]",
    "fields": {
      "external_id": "@.id",
      "sku": "@.sku",
      "price": { "path": "@.price_cents", "transforms": ["cents"] },
      "available_qty": { "path": "@.stock", "transforms": ["int"] }
    }
  }
}

Use Test feed in the dashboard to fetch the feed and see up to 20 mapped samples with errors before you save.

Schedules

Each feed is fetched every schedule_minutes (at least 60). A forced refetch runs every night regardless of caching. You can start a run manually in Catalog → Sync.

Authentication

Feeds can be public, use HTTP Basic authentication or a custom header (for example Authorization: Bearer … or X-Api-Key). Credentials are stored encrypted and never shown again; changing the feed's host removes them. ShopAssist fetches feeds from its egress IPs, so you can allowlist them. Redirects are not followed: use the final URL.

ETag and caching

ShopAssist sends If-None-Match and If-Modified-Since. A 304 Not Modified answer completes the run without changes, which keeps scheduled runs cheap for large feeds.

Full feeds and deltas

  • A full primary feed is authoritative: products missing from a successful run are removed. If more than half of your products would disappear at once, ShopAssist stops and asks you to confirm (catalog_shrink_suspected).
  • A full primary feed also blocks product pushes through the Push API (409 feed_authoritative), because the next feed run would undo them.
  • A delta feed only adds and updates. Remove products with the Push API products:delete or a full feed.
  • An empty feed that previously had products is treated as an error; nothing is removed.

Local inventory feeds

A local inventory feed carries stock per store, in Google's local inventory format (XML or CSV) or JSON:

FieldUsed as
store_codeLocation id (unknown codes create a location you complete in the dashboard)
idVariant id or SKU
quantityStock in that store
availabilityin_stock, limited_availability, on_display_to_order, out_of_stock
pickup_method, pickup_slaPickup options

Local inventory feeds also work for WooCommerce and PrestaShop stores that have no stock per store in the platform.

Last updated on

On this page