À la Cart(e): Checkout Journey Revamp and Deep dive into Technicals

prashant sharma
Licious Technology
Published in
8 min readSep 7, 2023

--

At Licious, we are on a journey to transition from our 3-Page Checkout process to a Single-Page aka Single Click Checkout. We are making this change to enhance the checkout experience for users during their buying journey by minimising friction and touchpoints. This article provides details about the approach we have taken to consolidate multiple pages (cart, slot selection, address, and payment) in order to offer our users a seamless and lightning-fast checkout experience. Although we are still in the process and have not yet accomplished all the steps, it will provide an overall view of the approaches we are adopting.

The Old Approach: A multi-page Enigma

In the not-so-distant past, customers would navigate through a series of pages (cart, slot-selection, and payment in Licious context), where users could only do limited actions on each page. Below is the glimpse of old approach.

Old Checkout Flow

Technical Challenges:

Old Checkout Flow

Apart from the obvious issues of a customer to go to multiple pages, adding friction to the checkout journey, following are few technical issues:

  1. Every section on the page was sourced from distinct APIs, resulting in multiple calls from the front end that led to delays.
  2. Every section occupies a predefined position on the page, without any room for customization.
  3. Uneven user experience can occur due to varying response times of different APIs, particularly when there is no set page-level SLA.
  4. A significant delay was introduced due to numerous synchronous calls.
  5. Synchronous calls posed security vulnerabilities since one API’s response acted as input for another. This risked exposing business logic and provided an opportunity to intercept and manipulate a request’s content for fraudulent purposes.
  6. No Action specific Refresh of data. Any action causes full page refresh, eventually calling all the APIs again from FE.

The New Approach: Single Click Checkout

In the new strategy, beyond just enhancing the visual appeal, the initial two pages (shopping cart and slot selection) have been combined into a singular page. This streamlines the user experience by presenting a consolidated overview of products along with their estimated delivery times, reducing user friction.

New Checkout Flow

Technical Improvements:

New Checkout Flow

The new Checkout page is powered by single API Layer using Backend for Frontend (BFF) + Service aggregator patterns, also known as API aggregation or API orchestration, which offer several advantages compared to calling each API directly from the front end of an application. Let’s explore these advantages in detail:

  1. Reduced Front-End Complexity: Aggregating services on the back end simplifies the front-end codebase. Front-end developers no longer need to manage multiple service API calls, handle potential inconsistencies, and ensure smooth communication between various services. This reduces code complexity, making the front-end code more maintainable.
  2. Improved Performance: Aggregator patterns can enhance performance by minimizing the number of requests sent from the client-side. Aggregating data on the server side allows for efficient data retrieval, reducing the overall latency and improving the user experience.
  3. Minimized Data Transfer: Aggregation can minimize the amount of data transferred between the front end and back end. By selecting and combining only the necessary data, the back end can optimize the payload before sending it to the front end. This can result in faster load times and reduced bandwidth consumption.
  4. Enhanced Security: When APIs are directly called from the front end, sensitive data or authentication tokens might be exposed to potential attackers. This approach allows the back end to manage authentication and authorization, reducing the security risks associated with exposing sensitive information to the client.
  5. Centralized Auth, Logic and Error Handling: Aggregation enables centralized logic for combining data from different sources. This includes Auth, error handling, data formatting, and any required transformations. This centralization improves code consistency and reduces the chances of errors arising from duplicated logic across multiple front-end API calls. Each internal/downstream service call from Checkout Service, aka aggregator is behind a feature flag with defined timeout. Such sections seemlessly filtered and logged without any extra handling on FE.
  6. Flexibility and Versioning: Aggregation provides flexibility when dealing with changes in APIs. If an external API changes its structure or version, the aggregator can be updated to accommodate these changes, shielding the front-end application from needing immediate updates for each individual API change.
  7. Backend Integration Patterns: Aggregator patterns align with backend integration best practices. They enable microservices to expose aggregated data rather than raw data, allowing individual services to focus on their core functionality while presenting a unified interface to the front end.
  8. Future-Proofing: This new unified approach provides a layer of abstraction between the front end and external APIs. This can make it easier to integrate new APIs or services in the future without requiring significant changes to the front-end codebase. Any customization or ordering change in any section of the new page, would not require any app side changes, as this is controlled by backend now.
  9. Page Level SLA: Every section on the cart page holds distinct priorities. To ensure a seamless experience, a circuit breaker or Page Service Level Agreement (SLA) can be established. This mechanism filters out sections seamlessly if any downstream service experiences degradation.
Checkout Service HLD

Action Specific Refresh:

Numerous sections on the cart page may or may not be interconnected. For instance, adding an extra product could alter the anticipated delivery time, or adjusting the quantity of an item might enable or disable applicable coupons/offers. However, actions like adding a product shouldn’t influence the selected address. In scenarios where such actions are executed, providing users with the most up-to-date view is crucial for aiding their decision-making process. It’s logical to refresh only relevant sections instead of reloading the entire page.

In this approach, for every user action on checkout page, we pass only the sections that need to be refreshed. Apart from obvious advantages(less computation, lesser data over the network), when presented on applications or clients, this technique creates an appealing illusion that only new sections or information are being loaded, resulting in a seamlessly enjoyable experience. Response from API in every action, has the same response structure, although the response could be subset of full response.

Full Response vs Action Response
Action Specific Page Rendering

Risks and Disadvantages and how we handled them

Just as the saying goes, no approach is flawless, and this method also carries certain drawbacks and risks. Following are the such issues. Few of them we have handled as per the use case

Single Point of Failure:

Since the Checkout service is responsible for orchestrating and aggregating data from various services, if the aggregator itself fails, it can lead to a complete breakdown of the system. Given these reasons, it’s evident that this service holds a critical role in our ecosystem. While complete elimination of this risk might not be feasible, we have taken proactive steps to address it.

We’ve implemented robust logging and alerting mechanisms to swiftly identify and address potential issues. Specifically, we’ve set up alerts for each action, monitoring the response time and error rate of specific APIs, and established warning and critical thresholds for these alerts. To ensure rapid response, we have integrated these alerts across multiple channels, including Slack and phone calls, with well-defined escalation levels in place. This multi-channel approach enhances our ability to address issues promptly and effectively.

Increased Latency:

Aggregating data from multiple services can introduce additional latency, especially if services have varying response times. This can impact the overall performance of the application. This is where the concept of Page Level SLA and section-level timeouts becomes crucial. By enforcing SLAs at the page level and setting timeouts for individual sections, you can effectively manage and mitigate potential latency issues. These measures play a pivotal role in maintaining optimal application responsiveness and user satisfaction.

Complete Success

We’ve established a SLA for the checkout page (i.e. X Seconds) which acts as the timeout threshold for all section-specific APIs. Our approach prioritizes key sections like “Review Items,” “Slot and Bill Summary,” and “Address” — vital for users to complete their checkout. These sections are allotted a maximum of “X seconds.”

Partial Success (Service Degradation)

Additionally, we’ve implemented a feature flag system for each external service that caters to secondary sections. This feature flag allows us to quickly disable a specific section in the event of prolonged service degradation. By doing so, we can maintain the overall performance and response time of the checkout service, ensuring a smoother user experience while addressing any issues with specific sections as needed. This approach provides us with greater flexibility and control in managing service quality during checkout.

Maintenance Challenges:

As the number of integrated services increases, maintaining the aggregator can become complex. Changes in service APIs or data formats might require corresponding adjustments in the aggregator. To address this, a modular codebase approach can be adopted.

We’ve structured the codebase to maintain separate service layer for each downstream service. This segregation enhances maintainability by confining changes to specific service, minimizing the impact on the overall aggregator functionality.

Scalability Concerns:

If the aggregator becomes a performance bottleneck due to increased traffic, scaling it might be challenging, potentially affecting the overall scalability of the system.

Our deployment strategy leverages Kubernetes (K8s) to facilitate horizontal scaling, effectively mitigating concerns related to scalling in case of additional traffic.

However, in scenarios where scaling the aggregator independently becomes an issue, we have the option of a platform-level deployment. In this approach, akin to the classical Backend for Frontend (BFF) pattern, we can separate the BFF/Aggregator level for different platform as shown in following diagram.

Platform Level BFF Deployment

Conclusion

In this phase at Licious, our goal is to conduct numerous experiments with each of our new features, all while minimizing the need for frequent app or front-end releases. The strategic shift of key computations from the front end to the back end empowers us to achieve this objective, ensuring the best possible user experience.

As mentioned in the start, we are on a journey to move away from three page checkout to one page checkout. We have already completed the first step towards our goal, by merging cart and slot section page. On to the next one, soon…

--

--