Nobody abandons a checkout because of one catastrophic delay. They abandon it the way you leave a slow queue: after the third small wait, each individually forgivable. A tap that thinks for 400 ms. A shipping calculation that spins. A payment form that assembles itself in stages. None of it crashes; all of it accumulates into a feeling — this shop is struggling — and feelings are what carts die of.
The fix is not “make it faster”, which is a wish. The fix is a budget: a named number for every step, measured on real phones, enforced like a spending limit. Here is the one we use, and how to hold a checkout to it.
The budget
- Add to cart → visible feedback: 100 ms. This is an interaction, not a page load. The button must acknowledge instantly — optimistic UI, then reconcile. If INP on this button exceeds 200 ms, a third-party script is usually squatting on the main thread.
- Cart page render: 600 ms to LCP. The cart is a reading page; treat it like one. No reason to fetch client-side what the server already knows.
- Address and shipping updates: 300 ms each. Shipping calculators that call a carrier API on every keystroke are the classic offender. Debounce, cache by postcode prefix, precompute the common regions.
- Payment form ready: 500 ms. Hosted fields or redirect, the visitor must see a usable form fast. Preconnect to the payment origin the moment the cart renders — the TLS handshake to your PSP should be history before anyone clicks “pay”.
- Pay tap → visible progress: 100 ms. The scariest moment in e-commerce is the second after tapping Pay. The button must change state instantly; the authorization can take its two seconds behind honest feedback.
- Confirmation page: 600 ms. The order exists; say so quickly. Receipts, upsells and analytics arrive after the reassurance, not before it — the confirmation should never wait for your email provider.
Total ceremony across six steps: roughly 600 ms of perceived waiting beyond reading and typing. Ambitious? We hold our own store's server responses under 100 ms, and the constraint is engineering discipline, not exotic infrastructure.
Measuring with zero tooling budget
Chrome DevTools, mobile emulation, “Fast 4G” throttling — walk the checkout while recording a performance trace. Every budget line appears as a labeled span if you look: long tasks, network waterfalls, the layout shift when the payment iframe lands. Do it quarterly, on the cheapest Android you can borrow, because that is where your customers live. The trace does not argue and has no favorite vendor.
Where the milliseconds hide
- Third-party scripts on checkout pages. The full audit is its own article on this blog; the checkout deserves the strictest allowlist on the site. Marketing pixels have no business watching someone type a card number.
- Client-side re-fetching. Carts that ask the server “what's in the cart?” right after the server rendered the cart. Ship the state you already have.
- Sequential API choreography. Address validation, then tax, then shipping, then stock — each waiting for the last. Most can run in parallel; the waterfall is habit, not necessity.
- Unwarmed payment origins. A single
preconnecttag routinely saves 200–400 ms on mobile. One line. We keep finding checkouts without it.
Make it a contract clause
A budget nobody enforces is a mood board. Put the six numbers into the definition of done, verify them in CI against the built app, and treat regressions like failing tests — because that is what they are. Our own pipeline refuses to deploy when smoke checks fail; the checkout budget deserves the same rank as correctness. To the customer, slow and broken are the same emotion at different volumes.
