Vue Storefront Cart API: Server Persistence vs LocalStorage Trade‑offs
Explore Vue Storefront's Cart API, the useCart composable, and the trade‑offs between BigCommerce's server‑side cookie and a localStorage mirror for offline resilience.
11 Aug 2026, 00:05 UTC

The problem: keeping a cart alive without leaking credentials
When you build a headless storefront with Vue Storefront and BigCommerce, the cart is the first piece of state that must survive page reloads, network hiccups, and user logins. BigCommerce stores the cart in a server‑side cookie, but that cookie is only sent with requests that carry the storefront token. Exposing that token on the client opens a security hole, so most teams route cart calls through a serverless proxy. At the same time, developers often add a localStorage fallback so the cart feels instant when the network is slow. The tension is real: two sources of truth can diverge, especially after a user logs out and back in.
How the built‑in Cart API works
Vue Storefront ships a thin REST wrapper around BigCommerce’s storefront cart endpoints:
- GET /api/storefront/cart – returns the current cart object.
- POST /api/storefront/cart/items – adds a line item (requires
variantIdandquantity). - PUT /api/storefront/cart/items/{lineItemId} – updates quantity.
- DELETE /api/storefront/cart/items/{lineItemId} – removes a line item.
All endpoints expect the BigCommerce storefront token in the Authorization header. In a production build you should never place that token in browser code; instead, create a small serverless function (e.g., Netlify Functions, Vercel API routes) that forwards the request with the token attached.
The useCart() composable – reactive wrapper
Vue Storefront’s useCart() hook hides the HTTP details and returns a reactive cart object plus helper methods:
import { useCart } from '@vue-storefront/bigcommerce';
const { cart, load, addItem, updateItemQty, removeItem } = useCart();
// Load the cart on app start (usually in a layout or App.vue)
await load();
The hook automatically syncs with the backend after every mutation, so the UI updates without extra effort. It also accepts an optional persist configuration flag that tells the composable to mirror the cart into localStorage under the key vs-cart.
Worked example: adding a product with variants
Assume a product has two variants (size M, size L) with variant IDs v-1001 and v-1002. The following snippet adds a size M item, then bumps the quantity to 3.
// In a component method or composable
async function addMediumShirt() {
// 1️⃣ Add the variant (quantity defaults to 1)
await addItem({
variantId: 'v-1001',
quantity: 1
});
// 2️⃣ Increase quantity to 3
const line = cart.value.items.find(i => i.variantId === 'v-1001');
if (line) {
await updateItemQty(line.id, 3);
}
}
What happens under the hood
addItemPOSTs{ variantId: 'v-1001', quantity: 1 }to/api/storefront/cart/itemsvia your serverless proxy.- BigCommerce validates stock. If only 2 units are available, the API returns
400with{ message: 'Insufficient inventory' }. - On success, the reactive
cartupdates, triggering any bound UI. updateItemQtysends a PUT to/api/storefront/cart/items/{line.id}with{ quantity: 3 }.
You can verify the flow by opening the browser Network tab and filtering for /api/storefront/cart. You should see the POST and PUT requests with the exact payloads above.
Persistence trade‑off: server cookie vs. localStorage
| Aspect | Server‑side cookie (default) | localStorage mirror (opt‑in) |
|---|---|---|
| Survives browser close | Yes (cookie is HttpOnly, tied to session) | Yes (persists until cleared) |
| Works offline | No | Yes (read‑only view) |
| Risk of stale data after logout | Low – cookie cleared by BigCommerce | High – must manually clear on logout |
| Security exposure | Token never touches client | Only cart JSON stored, no token |
Enabling the mirror is as simple as:
const { cart, load } = useCart({
persist: true // writes to localStorage after each sync
});
Limitation: if a user logs out, the BigCommerce cookie is invalidated but the localStorage copy remains. On the next login the composable will load the stale local copy first, then overwrite it once the server responds – a brief flash of old items. The fix is to wipe the mirror on logout:
function logout() {
localStorage.removeItem('vs-cart');
// call your auth logout endpoint
}
Diagnostic checklist
- Network inspection – confirm POST/PUT to
/api/storefront/cart/itemswith correctvariantIdandquantity. - Reactive state logging – add
watch(cart, v => console.log('cart:', v), { deep: true })in dev tools to see real‑time updates. - Stock shortage simulation – in BigCommerce admin reduce the variant’s inventory to 0, then call
addItemagain; expect a 400 response and an error message in the console.
Actionable next steps
- Wrap every cart endpoint in a serverless proxy that injects the BigCommerce storefront token (keep the token out of the bundle).
- Enable
persist: trueonly if you need offline readability; otherwise rely on the cookie. - Add a logout handler that calls
localStorage.removeItem('vs-cart')before redirecting. - Run the three diagnostic checks above after each deploy to catch regressions early.
By keeping the token server‑side and treating localStorage as a disposable cache, you get the perceived speed of a local cart without the risk of stale or duplicated state.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.