By Shehab Waleed, Founder, Cairo Studio 3 min read
Maison Gacha sells a small range of objects from its website, in French and English. The design showed a three step checkout on the site itself: a shipping address, a choice of carrier with prices, and a card form, followed by a confirmation page. We built it as drawn, and the work is part of our Maison Gacha project.
Then we connected the shop to Shopify, and most of those screens turned out to be either repeated or pretend.
What each step was really doing
On a standard Shopify plan, the hosted checkout is one flow: contact, then shipping, then payment. You can send a customer into it. You cannot take parts out of it and run them on your own pages.
So our address form collected an address that Shopify then asked for again. The carrier picker offered Colissimo, Chronopost and pickup at prices we calculated ourselves, and none of that choice reached Shopify, which works out real rates at its own checkout. The card form, built to match the design before payments were connected, moved the customer to a confirmation page without charging anyone.
Real orders went through Shopify, so nobody was charged wrongly. But a page that looks like it takes payment and does not is a liability on any shop, however finished it looks.
What the checkout page became
The page is now a recap of the cart: items, quantities, the subtotal and a line saying shipping is calculated at payment. One button creates a Shopify cart and sends the customer to Shopify’s checkout. In simplified form:
const res = await fetch('/api/checkout', {
method: 'POST',
body: JSON.stringify({ lines })
});
const { checkoutUrl, cartId } = await res.json();
localStorage.setItem('pendingCart', cartId);
location.href = checkoutUrl;The 50 euro free shipping teaser went too, because it belonged to the shipping prices we had invented. Carts saved before the Shopify connection were dropped on load, since their items had no Shopify variant to buy.
Emptying the cart after payment
Handing checkout to Shopify leaves one gap. The customer pays on Shopify’s pages and our site never hears about it. When they come back, their cart is still full.
The answer was in how Shopify treats carts: once a cart’s checkout completes, Shopify deletes the cart. So on the next visit, the site asks whether the cart it sent to checkout still exists. If it is gone, the order went through, and the local cart is cleared.
const pending = localStorage.getItem('pendingCart');
if (pending) {
localStorage.removeItem('pendingCart');
const res = await fetch(
`/api/checkout?cartId=${pending}`
);
const { exists } = await res.json();
if (exists === false) clearCart();
}Two details matter. The check runs once: the saved id is removed after the first answer either way, so a checkout someone abandoned can never empty their cart weeks later. And any error keeps the cart, because an emptied cart is worse than a full one.
What we would do differently
Ask how payment works before building any checkout screen. The design was reasonable for a shop that owns its checkout. This one did not, and knowing that on day one would have saved three screens. We wrote earlier about when we build a shop at all.
