Use Case: Modification or customisations of an order must be completed prior to Checkout stage, however the regular purchasing experience of a customer should not be impacted.
Approach: Using Draft Orders through Shopify provides the bespoke 'custom order' requirements and business flexibility that we need, with custom line items and opportunity to adjust prices, line items, discounts and other variables at will.
Problem: Draft Orders can only be built manually by customer service agents, or programatically via the GraphQL API through an application. The customer also needs access to the generated 'Invoice URL' after Draft Order creation.
Not too long ago, prior to the Cart Transform API becoming available, it was fairly difficult to allow Customers to directly build 'custom' orders via the storefront and have those changes carry through to Checkout. You could leverage a 3rd Party App that built custom products/carts, or maybe use the cart.js to add/remove products and variants that were 'hidden' from regular view, but both had significant drawbacks in both maintenance and scalability. At any business level, the cart is one thing you really shouldn't be playing fast and loose with, arguably the crux of the purchase journey.
Around 2021, pre-Checkout Extensibility, I spoke to a (very) large D2C merchant in the UK about their unique approach towards providing free 'gifts' when an order met certain conditions, and they taught me this methodology which I'd genuinely never considered until then -- using Draft Orders' innate 'Invoice Link' feature as a replacement for the regular Checkout Flow.
As outlined in the above workflow, the steps are roughly:
-
Allow a customer to create and interact with their cart as normal. Guest or Logged In, the state of the customer doesn't matter.
-
In the background, have an app subscribed to
carts/create
andcarts/update
events via Webhooks. -
Have each
carts/create
event trigger a GraphQL API call to build a new DraftOrder for each new cart. -
Ensure cart session data is mapped and attributed to the created DraftOrder for later recall -- if it's also attached to a logged in customer, even better. Store this attribution in the DraftOrder and/or app managing carts.
-
If the customer or cart meets any conditions that require you to customise the order in some way (eg. modify pricing, attach extra products, add custom line items, etc.) then do so via the GraphQL API to the DraftOrder object in the background via the app.
-
Through a customised cart in the theme, remove the standard redirect from Cart to Checkout from any available customer actions. Instead, on purchase action click, make a call to the app handling carts and retrieve the Draft Order
invoiceUrl
parameter from the open Draft Order associated with the session. -
Pass that URL back to the storefront and redirect the customer to their unique
invoiceURL
to complete the DraftOrder through the same checkout process they expect.
When done properly, this looks like nothing at all to the customer. If you pair your API-initiated changes with visual changes to the storefront cart, (such as showing them they've reached a threshold and unlocked an upgrade or free item, etc.) then there is no tangible difference to their purchasing experience.
I thought for a little while about how best to show this in practice, and came up with a very low-fi example. No app, no session management, no api call to draft orders. Just three buttons on the cart, all doing different things:
-
The first button clicked is the standard, expected 'Checkout' button at the cart. It brings me exactly to the cart I've defined as a customer.
-
The second button clicked is a very simple empty draft order that features just a custom line item with a custom price. No customer account attached, no discount, no other products.
-
The third button clicked is a more fleshed-out draft order, with a customer attached, a custom line item, and a custom discount on that line item with an explanation as to why it's applied.
In this case, I'm just hard-coding a Draft Order invoice link to each button via the Theme Editor for example purposes, but try to imagine if the original/regular cart button was having it's redirection dynamically served depending on the conditions of the cart. Because the customer never sees the actual invoice link, they simply understand that they are being sent through to the Checkout.
There are a lot of quality of life things you can and should do here to make the experience better. It'd be a pretty jarring experience for example, if a customer got through to the invoice checkout, then backed out to the storefront and no longer saw your custom additions/changes reflected in their cart. Implementing a cart modification to mirror the Draft Order you've assigned to the customer would be a good idea, showing the additional items/discounts, etc.
Validation protections should be carefully implemented to ensure Invoices with customer accounts pre-attached are sent to the correct customer, and only when that customer has been verified as logged in.
One of the main reasons I like this approach is because it results in a regular ol' Shopify-created Order object when the customer completes their invoice checkout. Nothing downstream in other external systems has to change to accommodate this purchasing approach, as far as they're concerned, it's an order like any other.
It's relatively scalable too, as it uses Shopify's Webhooks and Checkout systems to do the bulk of the work. The one caveat I might call out is that at extremely high traffic periods (eg. a BFCM scenario), I have seen 3rd party apps that aren't scaled enough buckle under the volume of cart webhooks that Shopify can potentially send. Every app likes to say they can auto-scale, but trust me, they always overestimate their own resilience compared to Shopify's ability to scale. Subscribing to carts/update
especially shouldn't be taken lightly, as active customers on a site could easily be updating their carts dozens of times per session, quickly ballooning the events you're intaking.
A reminder going back to the beginning - this was an active and working solution for an above hundred-million dollar brand just a few years ago, and while I'd now replace their use case with a Cart Transform application, it is still a production-tested workflow. Not saying I wouldn't change some things, but it's worth re-establishing!
I'd love to hear what other applications you might imagine, given this approach. Give me shout if you think of something to add or consider!
âď¸