Teifi×Rack Attack
Catalog API

Fitment, expressed as products & variants

External agents shop a Shopify store through its Catalog API — and the Catalog API speaks one language: products and variants. Fitment only becomes agent-usable once it is mapped onto those records. That mapping is the work Teifi does.

Two ways to model fitment

Not every catalog handles this the same way. Two patterns dominate:

Variants as fitment rows

e.g. DECKED

Each year/make/model/trim combination becomes a separate product variant. Fitment is implicit in the variant title. This works with the Catalog API out of the box — agents can read the variant name and infer compatibility.

The trade-off: variant counts explode, the SKU list becomes unwieldy, and there is no structured YMM graph to query — fitment logic lives in the variant title string, not in a queryable layer.

Works natively with Catalog API · no extra layer needed
Structured YMM + fitment graph

Rack Attack × Teifi

Fitment lives in a dedicated graph — Year / Make / Model / body style / roof type — that resolves to the correct products and variants. The catalog stays clean and each record represents a real product, not a fitment row.

Agents get structured, queryable fitment plus the Catalog API's product/variant records. The trade-off: it needs a layer that maps the graph onto the Catalog API — which is what Teifi builds.

Explicit logic · cleaner catalog · needs a mapping layer

Which one fits you? It depends on catalog scale

Limited manufacturer (e.g. DECKED).A narrow product line — each product fits a bounded set of trucks — so fitment-as-variants stays within Shopify's 2,048 variants/product and a small SKU count. The variant approach is workable.
Reseller / distributor (e.g. RealTruck, Rack Attack). Thousands of SKUs across many brands × thousands of vehicles. Variants-as-fitment explodes catalog size and width— past the 2,048-variants/product cap, ballooning product/variant counts and option matrices. It doesn't scale.

Rule of thumb: narrow manufacturer → variants can work; broad reseller / distributor → a fitment graph is required. Rack Attack is the latter — which is exactly why fitment lives in the graph, not the variant matrix.

How Teifi feeds the Catalog API

Teifi Parts holds the vehicle-fitment graph and resolves any Year/Make/Model/body/roof query to the exact component SKUs. Teifi Bridge keeps those components synced into Shopify as products and variants — with fitment metafields attached — so the Catalog API can serve agent-ready, fitment-aware records to any external consumer.

Fitment graph
Teifi Parts
YMM → SKU resolution
synced by
Teifi Bridge
Products & Variants
Shopify
with fitment metafields
Catalog API
Shopify
structured, queryable
External agents
ChatGPT · Copilot
consume product/variant records

Kits as bundles — and why fitment isn't a variant

A rack “system” is a kit. To make it one buyable thing for the Shop app and UCP/MCP agents, each system is a real Shopify bundle product created with productBundleCreate — the parent variant is the sellable SKU, and its components (towers, fit kit, bars, lock) expand at checkout with inventory and fulfillment derived from each part. UCP and the Shop app see one product, not a pile of parts.

How many variants a bundle creates

A bundle's variants are the cartesian product of its real config options — e.g. bar color × bar length — bounded by 3 options, 30 components, and Shopify's 2,048 variants/product limit.

Example: Black/Silver × 127cm/150cm = 4 variants. Vehicle is neveran option — so the count stays tiny, and there's no practical cap on the number of bundles (one per system).

Don't encode fitment as variants

Thousands of systems × every Year / Make / Model / body / roof type = billions of combinations. A variant-per-vehicle catalog is impossible to build and pointless to maintain.

So where does fitment live? (the join question)

UCP / the Catalog API has no native vehicle-fitment field. Its filters are price, availability, shipping, condition, shop, and category (taxonomy) — there is nothing to “join” a Year/Make/Model onto, and product metafields aren't exposed for compatibility. So fitment can't (and shouldn't) ride on the product or variant.

Instead it lives in a separate fitment graph (Teifi Parts), exposed as its own tool / MCP. The agent resolves the vehicle → the set of fitting kit / product IDs first, then hands those IDs to UCP (lookup_catalog / get_product) to read price & availability and check out. The join happens at the agent layer, by product ID — not inside the catalog.

Net: bundles model the kit (a handful of variants); the fitment graph maps vehicle → kit. Two systems joined by ID — never a variant per vehicle.

Two discovery channels — and you need both

“Find a roof rack for a 2026 F-150” can reach the merchant two different ways. They're separate systems with separate rules, and fitment has to be made legible to each — neither one indexes the fitment graph for you.

1 · UCP / Catalog API — the agent-buyable channel

The catalog only exposes products, variants, and collections (+ taxonomy + ML metadata). No metaobjects, no metafields, no fitment field. So the vehicle-group primitive here is the Collection: a Roof Racks — 2026 Ford F-150 collection (generated from the fitment graph) makes a vehicle query resolve to the buyable bundles — products carry collections[] in the feed.

2 · Metaobject landing pages — the web-crawl / AEO channel

A metaobject definition with the renderable + onlineStore capabilities turns each entry into a crawlable page (/pages/<handle>/<entry>) with SEO meta — and Shopify lists them in the sitemap (SitemapResourceMetaobject). That's how Google and ChatGPT-browse find a vehicle-specific page. A vehicle metaobject → one landing page per vehicle.

The limits that shape the strategy

  • · Up to 1,000,000 entries per metaobject definition — so a vehicle page per YMM is technically possible.
  • · Sitemap caps at 50,000 URLs/file (Shopify auto-paginates) — not the real blocker.
  • · A URL-redirect cap (canCreateRedirects) can gate publishing that many pages.
  • · Crawl / index budget is the true ceiling — a million thin pages won't rank.

So the winning play is demand-prioritized, fitment-graph-driven pages + collections — not brute-forcing every combination. Collections feed UCP; renderable metaobject pages feed web crawl; the fitment graph (Teifi Parts) drives both; bundles transact. One source of truth, two channels.

Live: catalog records for a 2020 Toyota Tacoma (naked roof)

The fitment graph resolved this vehicle to the fitting rack systems; each component below is a real Shopify product variant — the unit the Catalog API serves to agents. Fetched server-side at request time via get_catalog_for_vehicle.

Thule Edge Clamp (Set of 4) Roof Rack Systemby Thule
7 components
ProductSKUPriceVariant ID
Thule Edge Clamp (Set of 4)Thule Edge Clamp (Set of 4)
720501$359.95…Variant/45589023293497
Thule Evo Fit Kit 5107Thule Evo Fit Kit 5107
145107$159.95…Variant/45592208310329
Thule WingBar Edge 104 cm (41 in.) Black (1 pack)Thule WingBar Edge 104 cm (41 in.) Black (1 pack)
721520$144.95…Variant/45589023785017
Thule WingBar Edge 104 cm (41 in.) Silver (1 pack)Thule WingBar Edge 104 cm (41 in.) Silver (1 pack)
721500$144.95…Variant/45589025587257
Thule WingBar Edge 104 cm (41 in.) Black (1 pack)Thule WingBar Edge 104 cm (41 in.) Black (1 pack)
721520$144.95…Variant/45589023785017
Thule WingBar Edge 104 cm (41 in.) Silver (1 pack)Thule WingBar Edge 104 cm (41 in.) Silver (1 pack)
721500$144.95…Variant/45589025587257
Thule 544 4-pack Lock Cores
not resolved
Thule Evo Clamp (Set of 4) Roof Rack Systemby Thule
6 components
ProductSKUPriceVariant ID
Thule Evo Clamp (Set of 4)Thule Evo Clamp (Set of 4)
710501$264.95…Variant/45592492539961
Thule Evo Fit Kit 5107Thule Evo Fit Kit 5107
145107$159.95…Variant/45592208310329
Thule Squarebar 135 (53in.) (Pair)Thule Squarebar 135 (53in.) (Pair)
712400$179.95…Variant/45592492900409
Thule Wingbar Evo 135 cm (53 in.) Black (Pair)Thule Wingbar Evo 135 cm (53 in.) Black (Pair)
711420$279.95…Variant/45592492736569
Thule Wingbar Evo 135 cm (53 in.) Silver (Pair)Thule Wingbar Evo 135 cm (53 in.) Silver (Pair)
711400$279.95…Variant/45592492703801
Thule 544 4-pack Lock Cores
not resolved
Yakima BaseLine Towers (with New Covers) (Set of 4) Roof Rack Systemby Yakima
13 components
ProductSKUPriceVariant ID
Yakima 50 Inch CoreBar (Pair)Yakima 50 Inch CoreBar (Pair)
8000421$228.95…Variant/45591055401017
Yakima 50 Inch JetStream - Black (Pair)Yakima 50 Inch JetStream - Black (Pair)
8000425$269.95…Variant/45591057825849
Yakima 50 Inch JetStream - Silver (Pair)Yakima 50 Inch JetStream - Silver (Pair)
8000428$269.95…Variant/45591059726393
Yakima 60 Inch CoreBar (Pair)Yakima 60 Inch CoreBar (Pair)
8000422$228.95…Variant/45591055859769
Yakima 60 Inch JetStream - Black (Pair)Yakima 60 Inch JetStream - Black (Pair)
8000426$269.95…Variant/45591058382905
Yakima 60 Inch JetStream - Silver (Pair)Yakima 60 Inch JetStream - Silver (Pair)
8000429$269.95…Variant/45591060348985
Yakima 70 Inch CoreBar (Pair)Yakima 70 Inch CoreBar (Pair)
8000423$228.95…Variant/45591057137721
Yakima 70 Inch JetStream - Black (Pair)
8000427not resolved
Yakima 70 Inch JetStream - Silver (Pair)
8000430not resolved
Yakima BaseClip 128 (Set of 2)
8006128not resolved
Yakima BaseClip 145 (Set of 2)
8006145not resolved
Yakima BaseLine Towers (with New Covers) (Set of 4)
8000162not resolved
Yakima 4 Pack SKS Cores
not resolved

Every row is a real Shopify variant — the unit the Catalog API serves to agents. Fitment chose which ones apply. The gid://shopify/ProductVariant/… IDs are live GIDs from the Rack Attack catalog.

Fitment is only agent-usable once it speaks products & variants

The Catalog API is the canonical channel for agentic commerce on Shopify — and it exposes exactly one currency: product and variant records. Teifi's stack closes the gap between a vehicle fitment graph and the records agents actually consume. The live table above is the proof: a 2020 Toyota Tacoma query, resolved to real Shopify GIDs, ready for any agent to act on.