Who this is for. The commerce implementer and the developer who gets the "my cart emptied" ticket. Afterwards you know where a cart lives, what finds it again, and the order in which to check the causes when it goes missing.
A cart is a record
A cart is a row in the database with an id and a uuid, which is what the browser and the API use to name it. Because it is a record and not session data, it survives the session, can be restored from a link, can be merged into an account at sign-in, and can be inspected by staff. It holds:
- Items: each with the SKU (
productCode), the product's name, a quantity, the amount, discount and tax, whether it is still available, and optional attributes such as an engraving (item attributes). - Discount codes, and the discounts that applied.
- Totals: the sum of the available items, less discounts, plus tax. A cart has no shipping; that arrives with the checkout.
- A currency, set by the first item added and cleared when the cart is emptied (currencies).
- Messages: short-lived notices such as "Item has been added" (cart messages).
- A person, once the shopper is signed in or has given an email address. A person has at most one cart.
When a cart is created, and when it goes
A cart is saved the first time something needs it: an item being added, the /cart page, or a template reading $_cart. Until then a visitor has no cart, and GET /cdna-api/cart answers 404.
A background clean-up deletes carts that have not changed for Lifetime (Carts.lifetime, 15552000 seconds, which is 180 days) and do not belong to a member: a guest's cart, with no person or with a person who has no login. A signed-in member's cart is kept however old it is. When an order is placed, the items bought leave the cart, and a cart left empty is deleted (From checkout to order).
The cart cookie
The browser finds its cart through a cookie named cart, whose value is the cart's uuid. Its attributes:
| Attribute | Value | Consequence |
|---|---|---|
| Secure | Yes | Never sent over plain HTTP: a site served without HTTPS starts a new cart on every request |
| HttpOnly | Yes | Scripts cannot read it; ask the API for the cart instead |
| SameSite | Lax | Sent on top-level navigation from another site, so a shopper arriving from an email keeps their cart |
| Domain | None (this host only) | Not shared between www.example.com and example.com, or between staging and live |
| Expires | Carts.lifetime from the last time it was set (180 days) | Set again on every request that loads the cart through the cookie, so an active shopper's cookie does not run out |
The cookie is cleared when the visitor signs out. API requests that name a cart by its uuid (/cdna-api/cart/<uuid>/…) neither read nor set it.
"My cart emptied": the diagnosis
Check the causes in this order; the first three explain most reports:
- A different hostname. The shopper moved between
wwwand the bare domain, or a link sent them to another hostname of the site. Redirect every hostname to one. - Plain HTTP somewhere. A page or environment served over
http://never stores the cookie. - They signed out, or are signed in on one device and not another. Sign-out clears the cookie; a member's cart comes back when they sign in again.
- They bought it. Items bought leave the cart; a cart left empty is deleted.
- A different browser, a private window, or cleared cookies. A guest's cart can then only come back through its restore link.
- It expired: a guest cart untouched for 180 days.
To see which, open the browser's developer tools and compare the cart cookie before and after the moment it empties, and note the hostname and scheme in the address bar. If the uuid is unchanged, ask the API for that cart (GET /cdna-api/cart/<uuid>): a 404 means the record was deleted, a cart with no items means it was emptied or bought.