What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
What is your developer-dependent CMS actually costing you? Calculate your costs and get a full report
Architecture
Commerce platform for catalog, prices and checkout, Agility for pages and the story around products: who owns what, linking content to products by ID, caching by data type, preview and failure modes.
In headless commerce, a commerce platform owns the catalog and the transaction, and Agility owns the content around it: landing pages, campaigns, buying guides, editorial and the story on each product page. The front end combines the two at render time.
The rule that keeps this architecture healthy: every piece of data has one owner. Agility stores references to products, not copies of their prices or stock.
| Data | Owner | Why |
|---|---|---|
| Products, variants, SKUs, categories | Commerce platform | It is the system of record for what you sell |
| Prices, promotions, inventory | Commerce platform | They change constantly and must be correct at checkout |
| Cart, checkout, orders, customer accounts | Commerce platform | Transactional data never belongs in a CMS |
| Pages, navigation, landing pages, campaigns | Agility | Marketers build and change them without a release |
| Rich product storytelling, buying guides, editorial | Agility | Structured content with workflow, preview and locales |
| Which products a page or article features | Agility, as product IDs | Editors choose products; the front end looks them up |
| Component | Owned by | Role |
|---|---|---|
| Commerce platform | Your commerce vendor | Catalog, pricing, inventory, cart and checkout APIs |
| Agility instance | Agility (you configure it) | Pages and content, with product reference fields |
| Product picker field (optional) | Agility app | Lets editors search the catalog and pick products inside Agility. Apps exist for BigCommerce and Commercetools |
| Front end | You | Renders Agility pages, and fetches product data for the IDs they reference |
| Revalidation endpoints | You | One for Agility webhooks, one for your commerce platform's events |
Store an identifier for each product in the content item, and look the product up when you render. If you don't use a picker app, a text field holding the product ID or SKU works. Building a Content Hub recommends also storing a human-readable value, such as the product name, so editors can see what was picked.
The picker apps save the selected product to the content item as a JSON string with the product's ID, SKU, name, path, description and image URLs (see each app's page for the exact structure). It holds no price or stock, and its other values are as they were when the editor picked the product. Treat it as a reference plus a label for editors, and read current product data, prices and stock from the commerce platform.
// A content item from Agility with a product picker field
const raw = item.fields.featuredProduct // JSON string saved by the picker
const picked = raw ? JSON.parse(raw) : null // keep only the ID from it
const product = picked ? await commerce.getProduct(picked.id) : null // your commerce client
| Step | From | To | What happens |
|---|---|---|---|
| 1 | Browser | Your host | A cached page shell is returned |
| 2 | Your app | Agility (through your cache) | The page, its components and the product IDs they reference |
| 3 | Your app | Commerce API (through a short cache) | Product names, images, prices and stock for those IDs |
| 4 | Browser | Commerce API or your server | Cart, live inventory and checkout, never cached |
| 5 | Agility | Your webhook endpoint | Content changes clear content tags |
| 6 | Commerce platform | Your webhook endpoint | Product, price and inventory changes clear product tags |
| Data | Cache for | Clear on |
|---|---|---|
| Agility pages and content | A long time | Agility webhooks |
| Product descriptions and images | A long time | Commerce product events |
| Prices and promotions | Short, or not at all | Commerce price events |
| Inventory | Not cached, or seconds | Read at request time or in the browser |
| Cart, checkout, account | Never | Not applicable |
Tag cached product data by product ID. Then a page that features a product is cleared both when an editor changes the page and when the product changes.
Agility preview shows the latest saved content. Product data still comes from the live commerce catalog, unless your commerce platform has a staging catalog you point preview at. Decide this explicitly: an editor previewing a campaign for a product that isn't live yet needs a preview catalog, or the page will show the product as missing.
| What goes wrong | Effect | Design for it |
|---|---|---|
| A featured product is deleted or unpublished in the commerce platform | A broken card or a page error | Treat a missing product as normal: hide the card, and report it so editors can replace it |
| Prices copied into Agility | Wrong prices on the site | Store IDs only. Read prices from the commerce platform |
| The commerce API is slow or down | Content pages fail to render | Render the content without product data and mark products unavailable. Never let product calls block the whole page |
| The Agility API is slow or down | New pages can't render | Cached and prerendered pages keep serving. See Handle Rate Limits and Outages Gracefully |
| A product launch publishes many items at once | Many webhooks at once | Queue webhook work and clear caches in batches |
| Product IDs differ between commerce environments | Preview shows the wrong products or none | Use the same IDs in every environment, or map them in your front end |