# Product feeds

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

Source: https://shopassist.coec.dk/docs/install/generic/product-feeds · Updated 2026-10-01

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 [#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 [#fields]

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

| Field                                                                             | Used as                                                                                    | Rules                                               |
| --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | --------------------------------------------------- |
| `id`                                                                              | Variant id (product id without `item_group_id`)                                            | Required                                            |
| `item_group_id`                                                                   | Product id                                                                                 | Groups variants                                     |
| `title`                                                                           | Variant title; the product title is the common prefix of the group (or `sa:product_title`) |                                                     |
| `description`                                                                     | Product description                                                                        | HTML is sanitized                                   |
| `link`                                                                            | Product URL                                                                                | HTTPS, on one of your allowed domains               |
| `image_link`, `additional_image_link`                                             | Images                                                                                     | HTTPS; up to 10 additional                          |
| `availability`                                                                    | Stock status                                                                               | `in_stock`, `out_of_stock`, `backorder`, `preorder` |
| `price`, `sale_price`, `sale_price_effective_date`                                | Price, sale price and sale window                                                          | Currency must equal the feed currency               |
| `brand`, `gtin`, `mpn`                                                            | Brand, GTIN, attributes                                                                    |                                                     |
| `color`, `size`, `material`, `pattern`                                            | Variant options when they differ in the group                                              |                                                     |
| `product_type`                                                                    | Category path (`A > B > C`)                                                                |                                                     |
| `product_detail`, `product_highlight`                                             | Attributes the assistant can answer from                                                   |                                                     |
| `sa:sku`, `sa:quantity`                                                           | SKU and stock quantity                                                                     | Quantity is an integer ≥ 0                          |
| `sa:compare_at_is_reference`                                                      | `true` when the regular price is the lowest price of the last 30 days                      | See [prices](/docs/guardrails/prices#attestation)   |
| `sa:add_to_cart_url`, `sa:tag`, `sa:rating`, `sa:rating_count`, `sa:is_published` | Cart URL, tags, rating, visibility                                                         |                                                     |

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

```xml
<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 [#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]

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.

```json
{
  "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 [#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 [#auth]

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](/docs/security/egress-ips), so you can allowlist them. Redirects are not followed: use the final URL.

## ETag and caching [#etag]

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 [#full-replace]

* 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`](/docs/troubleshooting/sync-issues#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 [#local-inventory]

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

| Field                         | Used as                                                                     |
| ----------------------------- | --------------------------------------------------------------------------- |
| `store_code`                  | Location id (unknown codes create a location you complete in the dashboard) |
| `id`                          | Variant id or SKU                                                           |
| `quantity`                    | Stock in that store                                                         |
| `availability`                | `in_stock`, `limited_availability`, `on_display_to_order`, `out_of_stock`   |
| `pickup_method`, `pickup_sla` | Pickup options                                                              |

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