abconvert, the client your stack guide creates from the request. The attributes describe the visitor, so create that client where you change the cart, not in a page a cache shares.
Write the attributes
Write the SDK’s attributes when you create the cart, each time you update it, and on your cart page when they changed. One call covers every test the visitor is in, whatever its type. Shopify replaces the cart’s whole attribute list on every update, so send the attributes the cart already has together with ABConvert’s. Keep every attribute whose key the SDK did not return, and let the SDK’s values replace the rest. Both methods return only ABConvert’s attributes. Pass the values to the Storefront API’scartLinesAdd and cartAttributesUpdate mutations, or to your framework’s cart helper that calls them:
Server (cart action)
userErrors. When the attribute update reports one, the cart still carries its old attributes, so return the error to your cart as you do for a failed add to cart instead of sending the visitor to checkout.
A cart keeps a test’s attributes until the SDK returns different values for them. Nothing has to remove them: ABConvert ignores an ended test’s attributes, and a request on which your tests could not load returns only the marker described in Loading and failures, which leaves the cart’s test groups in place.
Prices by country
If you passcountry to the client, give the cart the same country in its buyer identity. Shopify prices the order by the cart’s country and ABConvert sets the test price by the country in the attributes, so the two must agree. When the visitor switches country, update the buyer identity and ABConvert’s attributes in the same action. See Prices by country.
On your cart page
Checkout charges what the cart attributes say. A test you launch after the visitor’s last cart change shows its price on your cart page, but the cart does not carry it yet. Compare the attributes when you render the cart, and write them when they differ:Server (cart page)
checkoutUrl from any page, run the same check in the server action or route handler that returns the drawer’s cart, so the button never carries attributes older than the prices the drawer shows. Price the drawer there too, with the client made from the request.
Show what checkout charges
Once a cart carries ABConvert’s attributes, Shopify prices it with the test price. In the Storefront API, a line’s cost (cost.amountPerQuantity) and the cart’s subtotal (cost.subtotalAmount) already include it, while the product variant’s own price does not. Show the line cost in your cart and drawer: it is what checkout charges, even in the minutes after you launch or end a test.
getPriceByVariantId.
Express checkout
A visitor can reach checkout without your cart page. Whether the test applies depends on how the button creates the checkout.Server (cart action)
Checkout URLs
getCheckoutUrl() builds a Shopify cart permalink that carries the visitor’s test groups. The visitor lands in checkout with the test applied, and you make no Storefront API call.
Server or browser
- It cannot sell a subscription. Create a cart for those. A price test does not change the price of a subscription product, on your storefront as on a theme store.
- It carries cart line attributes for the first line only. Its cart attributes still cover every line, so the test applies to the whole order.
Common mistakes
- Writing the attributes once. A cart created before a test launched has none for it, so your cart page shows the test price and checkout charges the original. The fix: write them each time you create or update the cart, and on your cart page or drawer when they changed.
- Replacing the cart’s other attributes. Shopify replaces the whole list on every update. The fix: send the attributes the cart has and ABConvert’s together, as in Write the attributes.
- Sending the visitor to checkout after a failed update. The cart still carries its old attributes, so checkout charges the old price. The fix: read
userErrorsand show the cart again. - Sharing or caching a checkout URL. Everyone who opens it lands in the same test group. The fix: build the URL when you render the button.