--- title: Product Feeds description: Required source fields, recommendations, and examples for product feeds. slug: indexing/feeds/products docKind: reference hub: luigisbox-ai --- Product feeds contain the primary searchable and recommendable objects in your catalog. The canonical catalog type for these records is exactly `product`. ## Core fields | Source field | Type | Requirement | Description | |---|---|---|---| | `id` | String | Required | Type-prefixed product identifier, such as `product/sku-1001`. Use the same identity in analytics events. | | `title` | String | Required | Product name used for matching and display. | | `url` | String | Recommended | Canonical product detail page URL. | The configured mapping produces the required catalog fields: ```json { "@id": "product/sku-1001", "@type": "product", "@title": "Blue Cotton T-Shirt" } ``` See [Types and IDs](/concepts/catalog-object-model/#types-and-ids) for identity and prefix rules. ## Recommended source fields ### Display | Source field | Type | Requirement | Description | |---|---|---|---| | `image_url` | String | Optional | Main product image URL. | | `description` | String | Optional | Product description for matching and result display. | ### Pricing and availability | Source field | Type | Requirement | Description | |---|---|---|---| | `price` | Number | Optional | Selling price without a currency symbol. | | `list_price` | Number | Optional | Reference or list price before discounts. | | `availability` | Number | Optional | `1` for orderable and `0` for unavailable. | ### Classification | Source field | Type | Requirement | Description | |---|---|---|---| | `brand` | String | Optional | Stable brand ID mapped to a canonical `@brand` reference. | | `category` | String or array | Optional | Stable category ID or IDs mapped to canonical `@category` references. | For new integrations, prefer stable category IDs. Category name paths such as `Men > Shirts` can be mapped for existing exports, but they are harder to keep stable. ### Identification | Source field | Type | Requirement | Description | |---|---|---|---| | `product_code` | String | Optional | SKU, product code, or internal product number. | | `ean` | String | Optional | Barcode or EAN. | ### Variants | Source field | Type | Requirement | Description | |---|---|---|---| | `group_id` | String or number | Optional | Stable value shared by every product in one variant group; mapped to the canonical string `@group_id`. | | `group_primary` | Boolean | Optional | Whether the product is primary for its group; mapped to `@group_primary`. | Every variant remains a complete product with its own `id`. Variant records do not need to be adjacent or ordered in the feed. If a group has no primary product, set `group_primary` to false for all its products. If the field is omitted, `@group_primary` remains absent. A standalone product omits both variant fields. Luigi's Box does not merge a primary product's attributes into its variants. Each product is validated independently and uniqueness across a group is not enforced; send at most one primary product per group. Configure `group_id_field` and, for feeds with an explicit boolean, `group_primary_field` with the names of the source attributes that carry these values. Their values are copied into `@group_id` and `@group_primary`; the original source attributes stay unchanged. For a feed without an explicit group-primary boolean, configure `group_primary_attribute_name` instead of `group_primary_field`. That attribute and the configured group ID are normalized and compared for every product: equal values write `@group_primary: true`, different values write `false`. This source attribute is independent of the product's configured identity. If either comparison value is absent, no group-primary decision is made and the field is omitted. The direct and comparison-based group-primary selectors are mutually exclusive in one feed configuration. Luigi's Box derives `lbx:group_id` and `lbx:group_primary` for every product. They copy `@group_id` and `@group_primary` when present; otherwise `lbx:group_id` falls back to the untyped identity part of the product's own `@id` and `lbx:group_primary` falls back to `false`. XML and CSV scalar values are parsed as strings. For a configured group-primary field, Luigi's Box normalizes common values such as `true`/`false`, `yes`/`no`, or `1`/`0` to a boolean. JSON feeds should use native `true` and `false` values. Numeric group IDs are converted to strings and surrounding whitespace is removed for feeds. If a feed value cannot be converted to the required type, the optional field is omitted instead of the product being rejected, and the derived `lbx:` attribute uses its fallback. An update that sets `group_primary` to `true` must include `group_id` in the same update. ```json { "products": [ { "id": "product/t-shirt-blue-m", "title": "Blue Cotton T-Shirt, M", "group_id": "northwear-t-shirt-1001", "group_primary": true, "color": "blue", "size": "M" }, { "id": "product/t-shirt-blue-l", "title": "Blue Cotton T-Shirt, L", "group_id": "northwear-t-shirt-1001", "group_primary": false, "color": "blue", "size": "L" } ] } ``` The configured mapping produces the registered variant fields: ```json { "@id": "product/t-shirt-blue-m", "@type": "product", "@title": "Blue Cotton T-Shirt, M", "@group_id": "northwear-t-shirt-1001", "@group_primary": true } ``` Add any other source attributes that help discovery, such as color, material, size, style, compatibility, season, or collection. The configured mapping produces the registered catalog fields. Fields such as `url`, `image_url`, `description`, `price`, `list_price`, `availability`, `product_code`, and `ean` are ordinary public attributes, not registered `@` fields. ## Restrictions - Use consistent field types across all records. ## Examples ```xml product/sku-1001 <![CDATA[Blue Cotton T-Shirt]]> https://example.com/products/blue-cotton-t-shirt https://cdn.example.com/products/sku-1001.jpg 29.90 39.90 1 brand/northwear category/cat-t-shirts ``` ```json { "products": [ { "id": "product/sku-1001", "title": "Blue Cotton T-Shirt", "url": "https://example.com/products/blue-cotton-t-shirt", "image_url": "https://cdn.example.com/products/sku-1001.jpg", "price": 29.90, "list_price": 39.90, "availability": 1, "brand": "brand/northwear", "category": ["category/cat-t-shirts"] } ] } ``` ```csv id,title,url,image_url,price,list_price,availability,brand,category product/sku-1001,Blue Cotton T-Shirt,https://example.com/products/blue-cotton-t-shirt,https://cdn.example.com/products/sku-1001.jpg,29.90,39.90,1,brand/northwear,category/cat-t-shirts ``` After mapping, product-to-category and product-to-brand relationships use typed references. Other source attributes remain ordinary public catalog attributes: ```json { "@id": "product/sku-1001", "@type": "product", "@title": "Blue Cotton T-Shirt", "@category": ["category/cat-t-shirts"], "@brand": "brand/northwear", "url": "https://example.com/products/blue-cotton-t-shirt", "image_url": "https://cdn.example.com/products/sku-1001.jpg", "price": 29.90, "list_price": 39.90, "availability": 1 } ``` ## Repeated and nested values XML and JSON can represent repeated and nested values. CSV columns contain one value, so use XML or JSON for multiple images, categories, or structured attributes. ```xml product/sku-1001 Blue Cotton T-Shirt https://cdn.example.com/sku-1001-front.jpg https://cdn.example.com/sku-1001-back.jpg 42 64 ``` ```json { "id": "product/sku-1001", "title": "Blue Cotton T-Shirt", "image_url": [ "https://cdn.example.com/sku-1001-front.jpg", "https://cdn.example.com/sku-1001-back.jpg" ], "dimensions": { "width": 42, "height": 64 } } ``` ## See also - [Feeds overview](/indexing/feeds/) - [Catalog object model](/concepts/catalog-object-model/) - [Category feeds](/indexing/feeds/categories/) - [Brand feeds](/indexing/feeds/brands/) - [Feed troubleshooting](/indexing/feeds/troubleshooting/)