Retail & E-commerce// definition

The cart token: the one object a storefront can never serve from cache

In short

A cart is 2 things: an identity token held by the browser, and a document held by the server. The token names the cart, it does not contain it — which is why a cart response is personal to one shopper, can never sit in a shared cache, and why signing in on a second device forces a merge decision that quietly loses items when nobody has written the rule down.

Key takeaways

  • The cart token is identity, not contents. The browser holds an id; the server holds the document it names.
  • A cart moves through 4 states: created on first add, anonymous, merged at sign-in, retired at order creation.
  • Any response whose body depends on the cart id must be uncacheable or keyed on that id — including a server-rendered cart badge.
  • Merge by variant with quantity as the maximum, not the sum, or a shopper who added the same item on 2 devices gets 2 of it.
  • Carts on a shared device are the failure nobody tests: the cookie outlives the person who created it.

A cart is an identity token plus a server-held document. The browser stores an opaque id, usually in a cookie or in local storage; the server stores the lines, the totals and whatever customer is attached. The token names the cart. It does not contain it, and it is not a session in the login sense — a cart exists long before anybody signs in.

That definition does the explanatory work for the rest of a storefront. Every other page is the same for everyone who asks for it, so it can be built once and served from a cache. The cart differs for every holder of a token, so it cannot. There is no configuration that makes it cacheable — only a choice about where the uncacheable part sits.

The four states a cart moves through

  1. Created. The first add-to-cart mints an id and writes it to the browser. Nothing exists before that, which is why an empty cart costs the server nothing.
  2. Anonymous. The document accumulates lines with no customer attached. Most carts live and die entirely in this state.
  3. Merged. Sign-in produces 2 carts — the anonymous one in this browser and whatever the customer already had — and something has to reconcile them. This is where contents disappear.
  4. Retired. Order creation ends the cart's life. The order becomes the record, the cart id must be cleared from the browser, and a stale id left in place is how a paid-for basket reappears an hour later.

The same cart, seen from four places

SituationBrowserServerWhat the shopper sees
First add to cartA new id, written to a cookieA cart document with 1 line, no customerOne item
Same browser, next dayThe same id, if the cookie survivedThe same document, if it has not expiredThe same item — or nothing, if either side dropped it
Second device, not signed inA different idA second, unrelated cartAn empty cart, and nothing is wrong
Signs in on the second deviceThe id it already had2 carts to reconcileWhatever your merge rule decided — usually undocumented
Shared device, a second person signs inThe first person's id, still in the cookieAn anonymous cart holding somebody else's itemsAnother household member's basket, merged into theirs
Order placedThe id should be clearedThe cart is retired; the order is the recordAn empty cart, unless the id was left behind
What the browser holds, what the server holds, and what the shopper sees

Rows 3 and 4 are what support tickets are made of. A shopper who added items on a phone and then opened a laptop has not lost anything: they were never signed in, so 2 browsers held 2 ids and therefore 2 carts. Nothing can be recovered because nothing was shared. Saying so plainly in the interface is cheaper than any amount of engineering.

The merge rule, written down

Sign-in forces a decision with 3 plausible answers, and most builds pick one by accident. Customer-cart-wins silently discards what the shopper just added — the worst outcome, because those items are the most recent and the most intended. Anonymous-cart-wins throws away a cart built deliberately on another day. A union keeps both and needs a quantity rule.

Why nothing on this path can be cached

Two failure classes follow from the definition, and both are caching failures rather than cart failures. The first is a cached cart fragment: a response whose body depends on the cart id, served from a shared cache to whoever asks next. The cart endpoint is the easy half — everyone marks it private. The hard half is a product page that renders a cart-count badge on the server, because that response is now personalised and an edge cache will hand it to the next visitor.

The token names the cart. It does not contain it. Every cart bug that surprises a team is that sentence, arriving late.

Where the cart stops being the cart

The cart's authority ends at checkout. Once a shopper commits, the totals stop being a live calculation and become terms, and the object carrying the money is a different one with its own scope and expiry: the payment token that carries an allowance. A mismatch between what the cart showed and what the page showed is its own diagnosis: the cart price does not match the page price.

Most of the difficulty in a headless build concentrates in this 1 object, because it is the only place identity, freshness and personalisation arrive together. Writing its states and its merge rule down before the first sprint is MVP and product build work, and it sits at the centre of storefront architecture and platform choice within software for retail and ecommerce.

Frequently asked questions

Short answers to the follow-ups this page tends to raise.

Why do cart contents differ between a shopper's phone and their laptop?

Because an anonymous cart is identified by a token stored in one browser, and a second browser has a different token and therefore a different cart. Nothing has been lost and nothing can be recovered — the 2 carts were never connected. They converge only when the shopper signs in on both devices, at which point your merge rule decides what the combined cart contains.

How long should a cart token live?

Long enough to survive a considered purchase and short enough that a shared device does not leak a basket — days rather than months for the browser token, with the server document expiring on its own schedule. Set the 2 lifetimes independently: a browser id that outlives its server document produces the 'my cart vanished' report, and the reverse produces stale carts nobody can explain.

Can a cart response be cached at the edge if we vary on the cart cookie?

Technically yes, practically no. Keying a shared cache on a token that is unique per shopper gives you a cache with a hit rate near zero and an entry per visitor, which costs more than it saves and adds a class of bug where one misconfigured key serves the wrong basket. Mark it private and spend the effort on shortening the round trip instead.

Should the cart be stored on the client instead of the server?

No, not as the source of truth. A client-only cart cannot be repriced, cannot check availability and cannot survive a device change, so every serious storefront ends up with a server document anyway. Keeping a local copy as an optimistic cache for instant feedback is worth doing, provided the server response always wins on conflict.

  • headless commerce
  • cart
  • caching
  • storefront architecture
// shipped work

The work behind this page

Builds from our portfolio that this page draws on.

Working on something in this space?

Tell us where you are in a sentence or two. We'll tell you honestly whether we're the right team, and what a sensible first slice of the work looks like.

Start the conversation