Attributes are what let a machine reason about a product instead of pattern-matching its title. They are category-specific, normalised to a shared vocabulary and unit system, and they carry where each value came from.
| Field | Type | Notes |
|---|---|---|
| key ·always | string | Namespaced within the category: apparel.size, electronics.battery_hours. |
| value ·always | any | Typed — string, number, boolean or array. |
| unit | string | null | SI where applicable. Values are converted, not merely labelled. |
| source | enum | declared | parsed | inferred. Declared came from a structured field; parsed came from title or description; inferred was derived. |
| confidence | float | Lower for parsed and inferred. Filter on it before using an attribute in a hard constraint. |
| is_axis | bool | True when this attribute is what varies between variants. |
{
"attributes": [
{ "key": "electronics.anc", "value": true, "source": "declared", "confidence": 1.0 },
{ "key": "electronics.battery_hours", "value": 30, "unit": "h",
"source": "parsed", "confidence": 0.88 },
{ "key": "electronics.compatible_with", "value": ["Galaxy S25 FE"],
"source": "declared", "confidence": 1.0, "is_axis": true },
{ "key": "general.weight", "value": 250, "unit": "g",
"source": "declared", "confidence": 1.0 }
]
}Measured across nine industries, the dominant variant axes were: apparel Size; home Colour and Size; jewellery Material, Stone and Length; beauty Scent and Size; electronics Device, Colour and Status. A single flat attribute schema cannot serve those, which is why the vocabulary is namespaced per category.
In electronics and auto parts the crucial axis is what a thing fits. We observed a phone-case catalogue whose primary axis was literally 'Device'. Fitment lives in attributes so a comparison never crosses a compatibility boundary because two titles looked alike.
Real storefront tags in our sample included '50EmployeeDiscount', 'BFCM40' and 'DFS check' — internal operations leaking into a public field. Tags are a weak search signal and worthless for identity, so they are kept separate from attributes entirely.