---
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
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/)