Merging Carts When A Customer Logs In: Problems, Solutions and Recommendations

Today I would like to look into the case when a customer, having items in their authenticated shopping cart, but browsing the site anonymously, as a guest, creates a new shopping cart, and then log in. The question is what should happen to the items in the account-linked carts versus the items in the anonymous carts. For merchants, there is a reason behind merging carts, and that is in wanting the customers not to forget the products they intended to buy earlier. From the customer’s perspective, having extra items in the cart after logging in may be confusing and undesired, especially if done during the checkout process and especially if the shopping carts are large and complex.   There are five possible solutions:
  • Non-interactive
    • “Session cart priority”. If a customer has an anonymous cart, the account-linked shopping cart will be ignored after the login. If an anonymous cart is empty, the shopping cart contains the items from the account-linked cart.
    • “Cart Archive”: Replacing the old cart with the latest cart; moving the contents of the old cart to the wish list or archived carts list and inform the user about the actions done,
    • “Merge”Combine the shopping carts together so the user still has a single shopping cart, and the merged cart replaces the old account-linked cart, and inform the user about the changes,
    • “Multiple carts”: Merging carts by default, but letting the customer undo the operation and restore one of two saved carts, “anonymous/guest” and “old account-linked”.
  • Interactive:
    • “Interactive” Explaining the situation to the customer and letting him decide what he wants to do, namely, which cart to keep or if he wants to merge them:
      • You have items both in your present cart. But you also have items stored in a previous cart. Would you like to:
        • with your present items
        • your saved items into your present purchase
I find the “Merge” and “Multiple carts” as the best options. The second strategy is explained at the end of this article as an “experimental solution”. It is not enough to explain how additional items appeared in the cart, but also let the customer decide which of the shopping carts they want to keep or merge. In SAP Commerce, the default strategy is “Restoring an account-linked cart only if the anonymous cart is empty”, which it titled as “Merge” on the list above.  The idea is simple: SAP Commerce ignores an account-linked cart if a session cart is present. The alternative SAP Commerce’s out-of-the-box strategy is about merging the account-linked and anonymous carts so that the resulting account-linked cart contains all their unique items combined together. However, it is not designed to be interactive: you can’t pause the operation to let the customer decide. Such online stores as Amazon, eBay, Target, Etsy, Walmart, Aliexpress, Barnes and Noble use this approach too. More specifically, they use “a silent cart merge”: the cart from the session is combined with the cart from the account after the customer is logged in without any messages or popups. Using merging carts functionality raises new questions and challenges. For example, if you have the same SKU in both carts, how many products should be in the final cart after merging is done? Common sense tells us that the right answer is one product in the amount of two pieces. That is exactly how I ordered two iPhone6 cases instead of one I needed a month ago. If one or more products are not available at the time of cart recalculation, SAP Commerce simply removes them from the shopping cart and inform the user. This simple strategy is used by default. Is it correct? If it works well for the most cases, for some business and setups, such as online grocery stores or B2B portals, you may find it inappropriate. For such cases, consider an alternative approach, in which the products are marked as temporarily unavailable and the system offers substitute products instead of unavailable ones. Marking products as unavailable instead of removing them from the shopping cart has another advantage: the unavailable products can be back in stock next time the customer visits the website. Also, you need to check the case when incompatible (mutually exclusive) products exist in the basket after the merge. The products should remain in the basket, but your shop should notify the customer and prevent the order from being completed until the incompatible product has been removed. If anonymous customers are able to change the state of their shopping cart by adding a coupon or specifying the delivery details, the merge process may become challenging if the session and account-linked cart configurations are in conflict. If the anonymous cart already has a coupon code, the coupon code of the new cart should be discarded. Yet another question is often raised: should we restore the anonymous cart after the customer signs out? Of course, the cart must be emptied at the end of the session. The rationale is the following:
  • leaving the account-linked cart doesn’t seem right because of security and privacy considerations and
  • restoring the anonymous cart is not correct too, because one of the products from the original cart or the whole cart can be already purchased by the end of the customer session

SAP Commerce Out-of-the-box Merging Carts Strategy: Architecture and implementation details

  To use mergingCartRestorationStrategy
  • create a your-customized-addon extension
  • add the following code in the your-customized-addon-web-spring.xml <alias name=”mergingCartRestorationStrategy” alias=”cartRestorationStrategy”/>
  • Install the addon via ant addoninstall -Daddonnames=”customized-addon extension” -DaddonStorefront.yacceleratorstorefront=”your acceleratorstorefront”
Let’s look closer at how it is implemented under the hood. A customer logs in the system. Spring security config defines the bean responsible for success login scenario, that is loginGuidAuthenticationSuccessHandler. This bean is linked to the class/method GUIDAuthenticationSuccessHandler.onAuthenticationSuccess(request, response, auth). In this class, the system sets up cookies and pass the baton to StorefrontAuthenticationSuccessHandler.onAuthenticationSuccess (request, response, auth). If the user is not from the admin group, the system attempts to restore a cart by calling CartRestorationStrategy.restoreCart(request). So, to activate a merging cart strategy, you need to change a cartRestorationStrategy parameter of the defaultLoginAuthenticationSuccessHandler bean in <yourstorefront>/web/webroot/WEB-INF/config/spring-security-config.xml Scenario 1. DefaultCartRestorationStrategy (“Restoring an account-linked cart only if the anonymous cart is empty”). The restoreCart method of this strategy checks if the current shopping cart is empty or not. If it is empty, the latest account-linked cart will be restored. Otherwise, nothing will be changed (the session cart will be untouched, as is). Scenario 2. MergingCartRestorationStrategy (“Restoring an account-linked cart only if the anonymous cart is empty” The case when both a session cart and account-linked cart exist is processed by restoreCart in the mergingCartRestorationStrategy. The system finds the most recent cart (let’s name it “A”) for the current user and the current website and merge it with the session cart (let’s name it “B”). The process has the following steps:
  • Recreates a new session cart (let’s name it “B*” from the current session cart (B)
    • Removes all payment transactions linked to the cart B
    • Re-generates cart GUID for B*
    • Recalculates the cart B* (entries, totals, discounts, taxes…) via commerceCartCalculationStrategy
      • If any entries aren’t available, they won’t be added
    • Updates promotions on B*
    • Executing cart calculation hooks (“before” and “after”) on B*
  • Recalculates the cart (B*) again (entries, totals, discounts, taxes…) via commerceCartCalculationStrategy. This time for the new cart object which is a duplicate of the original session cart.
  • Update promotions again on B*. This time for the new cart object which is a duplicate of the original session cart.
  • Calculates external taxes if needed
  • Merges a recreated session cart (B*) with an account-linked cart (A, the most recent if more than one)
    • Special processing for entry groups (if any)
    • Move all cart entries from the account-linked cart (A) to the current session cart (B*)
    • Remove old session cart (B)
  • The merged cart is a union of A and B,  C=A+B*;
  • Recalculates the resulting cart (A+B*)
  • Calculate (A+B*) cart [again] via commerceCartCalculationStrategy
  • Update promotions again on A+B*.
In terms of performance, merging carts could be slow and resource-intensive, because your shopping is recalculated against different sets of products several times within a single session. As you see from the process above, the shopping cart is recalculated three times.  Moreover, in fact, there are another three times outside this process, that makes six recalculations per session. In all these six calls, cart recalculation is followed by applying promotions process which is also slow and CPU and memory intensive, especially for large carts and a big number of promotions. I recommend to include this scenario in your performance tests and plan and implement the changes if necessary. How to reproduce:
  • Prerequisites:
    • Account-linked cart – 6 items
    • Anonymous cart – 1 item
  • Scenario:
    • A customer signs in having 6 items in the account-linked cart and 1 item in the session cart.
  • Totally, after the customer logged in, the following methods are called six times (!):
    • calculateEntries, calculateTotals, updatePromotions – 6 times
      • First – From onAuthenticationSuccess →  loginSuccess →  updateSessionCurrency → setSessionCurrency -> recalculateCart → calculateEntries
      • Second –  From onAuthenticationSuccess → loginSuccess -> recalculateCart → calculateEntries
      • Third – From onAuthenticationSuccess → restoreCart (mergingCartRestorationStrategy) → restoreCartAndMerge → restoreCart (service) → restoreCart (DefaultCommerceCartRestorationStrategy) → recalculateCart  → calculateEntries
      • Fourth – From onAuthenticationSuccess → restoreCart (mergingCartRestorationStrategy) → restoreCartAndMerge → restoreCart (service) → restoreCart (DefaultCommerceCartRestorationStrategy) → calculateCart  → calculateEntries
      • Five – From onAuthenticationSuccess → restoreCart (mergingCartRestorationStrategy) → restoreCartAndMerge → restoreCart (service) → restoreCart (DefaultCommerceCartRestorationStrategy) → recalculateCart  → recalculate → calculateEntries
      • Six – From onAuthenticationSuccess → restoreCart (mergingCartRestorationStrategy) → restoreCartAndMerge → restoreCart (service) → restoreCart (DefaultCommerceCartRestorationStrategy) → recalculateCart  → calculate → calculateEntries

Alternative solution: Undo/Multiple carts

I consider this solution as experimental. I haven’t seen any live shops using this approach. If you know any, please let me know. In this solution, the carts are automatically merged too, but the difference is in the way what the customer can do afterwards. If the carts are merged, the customer is redirected to the shopping cart page where they can undo the operation and restore one of two saved carts, “anonymous/guest” and “old account-linked” or leave things as is. If the customer decided to merge the carts, clear out the anonymous cart and move the items to the account-linked cart. If the user chose to keep the carts separate, let the customer continue shopping with the account-linked cart. Once the user signs out (or he is automatically signed out), revert to the anonymous cart. If implemented right, this could be a really slick feature unique to SAP Commerce.

Leave a Reply