Product Data for AI: What an LLM Needs From a Catalog
Which product fields does an LLM actually need, and how complete are they? A look at two real samples of 100 products each, with the gaps to plan for and a short filter that prepares a catalog for a model.
A language model can write well about a product it has never seen, which is the problem. Without a catalog behind it, it will guess the price, the stock and the specs. Product data for AI is the set of fields that stops the guessing. This article looks at which fields a model actually needs and how complete they are in practice, using two samples pulled from the Affiliate.com product search on October 28, 2026.
What the model needs from a catalog
- Identity. Is listing A the same product as listing B? A barcode answers this, and a name rarely does.
- Price with a currency. A number alone cannot be compared or quoted.
- Availability. A recommendation is only useful if the item can be bought.
- Attributes. Brand, category, color and size let it answer follow-up questions without inventing them.
How complete the fields are
The two samples are the top 100 results for “wireless headphones” and “women’s jacket”. They are not random, so they show what a typical search returns and not the whole catalog.
| Field | What the model uses it for | Headphones sample | Jacket sample |
|---|---|---|---|
| Name, price and currency | Describe the item and what it costs | 100% | 100% |
| Image and description | Give the model text to summarize | 100% | 100% |
| Brand | Name the maker correctly | 95% | 97% |
| Category | Know what kind of product it is | 97% | 89% |
| Barcode | Tell whether two listings are the same product | 85% | 60% |
| Manufacturer part number | A second identifier when a barcode is missing | 13% | 53% |
| Availability known | Avoid recommending what cannot be bought | 93% | 73% |
| Color | Answer “does it come in black?” | 50% | 71% |
| Size | Answer “do you have it in a medium?” | not used | 57% |
| Stock quantity | Say how many are left | 1% | 2% |
- The basics are always there. Name, price, currency, image and description were present on all 200 records.
- Identifiers vary by category. Barcodes cover 85% of the headphones and 60% of the jackets. Part numbers are the opposite, at 13% and 53%, so using both helps. The identifier governance post covers how to choose.
- Stock counts are almost never given. Only 1% and 2% of the records had a quantity. A model can say a product is in stock, and it cannot say how many are left.
- Availability is unknown more often for jackets. It was known for 93% of the headphones and 73% of the jackets.
Three things a model should not be left to guess
- Currency. Each sample mixed 8 currencies. Comparing 26.90 in euros with 470 in Australian dollars as if they were the same unit would produce nonsense.
- Repeat listings. 21 of the 100 headphone records and 29 of the 100 jacket records repeated a name already in the sample. Without a barcode, the model counts one product several times.
- Category labels. They can be wrong. One pair of wireless headphones was filed under portable electronic games. Treat category as a hint and not as a fact.
Preparing a catalog for a model
Ask only for the fields the model will use, which keeps the context short. This request is the jacket search.
{
"search": [
{ "field": "any", "value": "women's jacket", "operator": "LIKE" }
],
"fields": ["name", "brand", "category", "identifiers.barcode", "identifiers.mpn",
"final_price", "currency", "availability", "color", "size", "merchant.name"],
"per_page": 100
}
The script then keeps the records a model can use safely and groups them by barcode, so each product appears once with its offers.
function toModelContext(records) {
const usable = records.filter(r =>
r.identifiers?.barcode && // identity: the same barcode means the same product
r.availability === 'InStock' && // do not offer what cannot be bought
typeof r.final_price === 'number' &&
r.currency // a price without a currency is not safe to compare
);
const byBarcode = new Map();
for (const r of usable) {
const key = r.identifiers.barcode;
if (!byBarcode.has(key)) byBarcode.set(key, []);
byBarcode.get(key).push(r);
}
return [...byBarcode.values()].map(offers => ({
name: offers[0].name,
brand: offers[0].brand,
offers: offers.map(o => ({ price: o.final_price, currency: o.currency, merchant: o.merchant.name })),
}));
}
Run on the headphone sample, it keeps 76 of 100 records and groups them into 66 products, 6 of which have more than one offer. On the jacket sample it keeps 33 of 100 and groups them into 32 products, 1 with more than one offer. The records it drops are the ones a model would otherwise have to guess about.
Things to keep in mind
- Pass fields, not pages. Merchant descriptions are long, with a median near 550 characters here, and some are in another language. Structured fields are shorter and easier for a model to use. The RAG post explains the approach.
- Read the data when the question is asked. Prices and stock change, as covered in grounding recommendations in live merchant data.
- Build the product set first. Filtering on barcode, merchant and price before the model sees anything is described in building AI-ready product sets.
- Say what is missing. If a record has no stock count or no size, the model should say so and not fill the gap.
The short version: a model needs identity, a priced currency, availability and a few attributes, and the data has most of them most of the time. The gaps are predictable, so a short filter before the model sees the catalog handles them.