Checkout flow and best practices
Learn how the Checkout and Payment flow operates as well as some of the best practices for utilizing Checkout.
After completing this page, you should be able to:
- Identify Checkout best practices.
How to initialize Checkout
As mentioned in our documentation, you can initialize Checkout in two ways depending on the Checkout mode you use:
- Complete Checkout mode uses the
checkoutFlow
method. - Payment Only mode uses the
paymentFlow
method.
Let's take a look at each in turn.
Complete Checkout mode
In the following diagram, we show the typical flow between the browser, Backend For Frontend (BFF), Checkout API, and Checkout Session when creating a Session and initializing the checkout.
After these steps, the browser should be displaying the checkout with the customer's Cart information. The following image is what we should expect to see in the browser at this stage. This example checkout is using the default styles.
Next, in the browser, the customer will add their shipping and billing information and apply any discount codes.
Next, let's go through the flow, where the customer requests the payment step and completes the checkout.
Calling the checkoutFlow method and completing the checkout
Payment Only mode
The Payment Only mode offers greater flexibility by letting you independently manage the payment information user interface (UI). You choose when and where it appears, using a dedicated method. The rest of the checkout payment flow follows the same process as the Complete Checkout mode.
Best practices
To best utilize Checkout, we recommend the following best practices.
Checkout URL State
We recommend using the Cart ID as part of the path: example.com/checkout/{cart-id}
. We don’t recommend using the Session ID, because the lifetime of this ID is short (1 hour) and it’s not possible to generate a new Session ID from an expired session. However, we can create as many sessions as we may need, so long as we have the Cart ID.
The ability to generate a new session for the same Customer is crucial. Customers don't always convert in a single browsing session. By utilizing unique checkout URLs, businesses can leverage marketing tools to target customers and guide them back to the same checkout page multiple times, increasing the likelihood of conversion.
You should trigger this URL change and update the browser History API when you receive the CheckoutStarted Message (step 1 in the preceding Complete Checkout mode diagram).
When the checkout is completed, the SDK will emit the checkout_completed
Message (see the Complete Checkout mode diagram). This Message includes the Order ID, giving us enough information to query the Order and render the Order confirmation page.
Using Custom IDs instead of Cart ID's
Alternatively, you can employ custom identifiers for your checkout. However, if you choose this approach, ensure you have a mechanism to efficiently map your custom ID back to the corresponding Cart ID. This mapping is crucial for instantiating new checkoutFlow
or paymentFlow
instances with little latency overhead.
You can take a number of approaches with regards to the URL paths you create:
Using the same ID for checkout and Order confirmation URL
Some business requirements may necessitate using the same identifier for both the checkout and order confirmation pages. This could mean that we design our URLs to look like the following:
example.com/checkout/{cart-id}
example.com/checkout/success/{cart-id}
Let's explore how to query the newly created Order using the checkout ID (in this case, the Cart ID).
Querying the Order by Cart ID
To render the order confirmation page, we need to retrieve the Order from Composable Commerce. To retrieve the Order, you can query the Orders HTTP endpoint using the associated Cart ID. For example:
HTTP Order resource:
GET /orders?where=cart(id="f1b7effe-9718-4e1b-b03f-3ebed5452267")
GraphQL for Order resource:
query Orders {orders(where: "cart(id = \"f1b7effe-9718-4e1b-b03f-3ebed5452267\")") {results {idcustomer {firstNamelastNamemiddleNametitlelocalesalutationversionidcreatedAt}lineItems {productIdnamequantity}}}}
Using the Order ID is the simplest option because we can pass the known Order ID to the Order endpoint and get the Order. Remember that the CheckoutCompleted Message tells us what the Order ID is.
Using a custom ID example.com/checkout/success/{custom-id}
You may use your own ID generator to have control over how the Order number looks or have another system that generates these values, for example, an Enterprise Resource Planning or Order Management System. Generating this ID will not be as instantaneous as the Composable Commerce Order ID. You will need to consider how you handle this whilst loading the order success page. Consider reading our Foundry guide on Generating a Unique Order Number.
When using custom order numbers, a critical decision point arises: when to generate and assign the order number to the new Order. This timing significantly impacts your order confirmation flow.
Let's analyze the two primary approaches:
Generating and assigning Order number before displying the Confirmation page:
Process:
- As soon as the customer completes checkout (
checkout_completed
message emitted), you setOrderNumber on the Order. - Redirect the user to the order confirmation page, including the
orderNumber
in the URL:example.com/checkout/success/{orderNumber}
.
- As soon as the customer completes checkout (
Advantages:
- The order number follows your internal conventions and can be more human readable than a UUID.
Disadvantages:
- The process of setting the Order number will slightly delay the process of displaying the order confirmation page.
Assigning Order number after confirmation (on demand):
Process:
- Redirect the user to a generic order confirmation page, for example,
example.com/checkout/success
after the checkout completion. - On this page, initiate an asynchronous request to your backend.
- This backend request generates the custom order number and uses
setOrderNumber
to assign it to the Order.
- Redirect the user to a generic order confirmation page, for example,
Advantages:
No additional latency in displaying the Order confirmation page.
Potential for user perception issues: the first time the customer views the order confirmation page, they will not see the orderNumber. This could cause some confusion for the customer.
Remember to carefully consider the trade-offs and potential issues associated with each approach. Thoroughly test your implementation to ensure data consistency and a smooth user experience.
Payment Only mode
When using the Payment Only mode, you must ensure that it is always the last step in the checkout process. This is because the Payment Only flow creates the Payment and Order.
Messages as events
The SDK exposes Messages as events. These events are very helpful for your application, providing insights into the checkout process. For example, you can receive notifications about errors, checkout completion, or any other relevant updates.
You can also leverage these events to create data layer events for your analytics tools. It is important to understand each of these Messages and handle them in your application code for a smooth customer experience.
Thus far we have discussed how Messages can be used for knowing when the checkout process starts and ends so that we can update the experience being shown to the customer. Take some time to review all of the Message types.
Payment lifecycle
The payment lifecycle within your commerce solution involves several stages, from authorization to potential refunds. Understanding these stages and how to manage them is crucial for a smooth customer experience.
Refund
Refunds become necessary when you need to return captured funds to the customer. This could be due to:
- Customer returns
- Damaged or incorrect goods received
- Other situations requiring reimbursement
Refunds can be partial or full, but the total refund amount cannot exceed the initially captured amount. You can initiate refunds through the Checkout Payment Intents API using the refundPayment
action.
Your responsibilities
In the commercetools ecosystem, Checkout creates the Order and manages the payment lifecycle, including updating the Payment record with information such as transactions and payment status.
However, Checkout does not manage the orderState
, which represents the state of the Order in the order processing workflow and indicates whether the Order is in an Open
, Confirmed
, Complete
, or Canceled
state. Updating the orderState
typically requires explicit actions that are separate from the payment process, such as fulfilling the Order, shipping the goods, or handling returns. Because of this, you are responsible for determining when and how to update orderState
.