Cart merge strategies

Learn how to manage anonymous Cart data upon Customer sign-in by using automatic merging strategies or custom logic.

Ask about this Page
Copy for LLM
View as Markdown

After completing this page, you should be able to:

  • Compare the MergeWithExistingCustomerCart and UseAsNewActiveCustomerCart modes to determine the appropriate automatic Cart merge strategy.

  • Analyze business requirements to decide between using the built-in anonymousCartSignInMode and implementing custom Cart merge logic.

When a user signs in, you must make sure that any anonymous Cart they were using is correctly managed. A seamless transition of the Cart's contents is critical for user experience. This section details the two primary strategies for managing Cart data upon sign-in: using the built-in anonymousCartSignInMode for automatic merging and implementing custom merge logic for more complex scenarios.

Use anonymousCartSignInMode

The CustomerSignIn and MyCustomerSignIn types provide the anonymousCartSignInMode field to control how an anonymous Cart is handled when its owner signs in. This is the most direct method to manage Cart transitions.

The available modes are as follows:

  • MergeWithExistingCustomerCart: merges the Line Items of an anonymous Cart with the Customer's existing active Cart. If the Customer has an active Cart with a shipping address, tax rates are recalculated based on that address before merging. If the Customer has no active Cart, then the anonymous Cart becomes their new active Cart.
  • UseAsNewActiveCustomerCart: the anonymous Cart becomes the Customer's new active Cart. Tax recalculation depends on the Customer's previous active Cart:
    • No previous active Cart: taxes are recalculated.
    • Previous active Cart without shipping address: taxes are not recalculated.
    • Previous active Cart with shipping address: taxes are recalculated only if the anonymous Cart lacks a shipping address.

How merge modes work

The shipping address is critical because it determines whether tax rates need to be recalculated during the merge process. This is important because these changes can directly impact the prices your Customers see. The presence or absence of a shipping address doesn't prevent items from being merged—it only affects tax recalculation.

For example, if a Customer browses anonymously from California (10% tax) and then signs in with a saved New York address (8.875% tax), the MergeWithExistingCustomerCart mode will recalculate prices using the New York tax rate before merging the items. This ensures the Customer sees accurate pricing based on their delivery location immediately after sign-in.
For the complete tax recalculation behavior in each scenario, see the MergeWithExistingCustomerCart and UseAsNewActiveCustomerCart mode specifications in the API reference.

Line Item matching logic

When merging Carts, the system uses a two-step process to determine which Line Items to merge:

Step 1: Key conflict detection The system first checks if any Line Items in the anonymous Cart have keys that match Line Items in the Customer's Cart but represent different products or variants. If a key conflict is detected, those items from the anonymous Cart are not merged and remain in the anonymous Cart.
Step 2: Property-based matching If no key conflicts exist, Line Items are matched based on their properties: product, variant, channels, custom fields, and price mode. Keys are not considered in this matching logic. This means two identical Line Items with different keys will be merged, with the higher quantity retained.
For the complete matching rules and all merge scenarios, see the Merge rules section in the API reference.

Choosing the right merge mode

Use the following table to determine which merge mode fits your business requirements:

AspectMergeWithExistingCustomerCartUseAsNewActiveCustomerCart
ResultCombines Line Items from both Carts into oneReplaces the Customer's Cart with the anonymous Cart
Use whenCustomers should keep items from both sessionsAnonymous session represents the Customer's current intent
Tax recalculationYes, if active Cart has a shipping addressConditional: Yes if no active Cart; No if active Cart lacks shipping address; Yes if active Cart has shipping address but only if anonymous Cart lacks one
Previous active CartUpdated with merged itemsDisassociated but not deleted

Example - Comparison of Cart merging strategies

The following example demonstrates both merge modes in action, showing how each mode affects the final Cart contents when a Customer signs in.

Assume that the anonymous Cart (anon-cart-1) contains one Zen Speaker X item and the Customer's existing active cart (cust-cart-A) contains one Zen Tablet Y item.
import { apiRoot } from '../../client'; // Assuming apiRoot is initialized and exported here
import {
  CustomerSignInResult,
  AnonymousCartSignInMode,
} from '@commercetools/platform-sdk'; // Import necessary types

async function simulateLoginAndCartHandlingInStore(
  storeKey: string,
  email: string,
  password: string,
  anonymousCartId: string,
  mode: AnonymousCartSignInMode
): Promise<CustomerSignInResult> {
  try {
    const requestBody = {
      email: email,
      password: password,
      anonymousCartId: anonymousCartId, // This is always a string as per function signature
      anonymousCartSignInMode: mode,
    };

    console.log(
      `\n--- Attempting in-store login for ${email} with anonymous cart ${anonymousCartId} using mode: ${mode} for store "${storeKey}" ---`
    );
    const loginResponse = await apiRoot
      .inStoreKeyWithStoreKeyValue({ storeKey: storeKey })
      .login()
      .post({
        body: requestBody,
      })
      .execute();

    const signInResult: CustomerSignInResult = loginResponse.body; // Explicitly type the response body
    console.log(
      `In-Store Login successful. Customer: ${signInResult.customer.email}`
    );
    console.log(`Active Cart ID: ${signInResult.cart?.id}`);
    if (signInResult.cart?.lineItems) {
      console.log('Cart Line Items:');
      signInResult.cart.lineItems.forEach((item) => {
        // Ensure name is accessed safely, as it's a LocalizedString
        console.log(`  - ${item.name['en-US']} (Quantity: ${item.quantity})`);
      });
    }
    return signInResult;
  } catch (error: any) {
    // Type 'any' for caught error for now because stricter typing for HTTP errors can be complex
    console.error(
      `In-Store Login failed with mode ${mode} for store "${storeKey}":`,
      error
    );
    throw error;
  }
}

(async () => {
  const davidEmail = 'david.shopper@example.com';
  const davidPassword = 'DavidSecurePass!';
  const anonCartId = 'anon-cart-1'; // Anonymous Cart: 1x Zen Speaker X
  const ELECTRONICS_HIGH_TECH_STORE_KEY = 'electronics-high-tech-store';

  // David's existing active Cart: 1x Zen Tablet Y

  // Scenario 1: MergeWithExistingCustomerCart
  // Result: Active Cart contains 1x Zen Speaker X AND 1x Zen Tablet Y
  try {
    await simulateLoginAndCartHandlingInStore(
      ELECTRONICS_HIGH_TECH_STORE_KEY,
      davidEmail,
      davidPassword,
      anonCartId,
      'MergeWithExistingCustomerCart'
    );
  } catch (e) {
    console.error(
      `Failed to simulate MergeWithExistingCustomerCart scenario for store ${ELECTRONICS_HIGH_TECH_STORE_KEY}.`
    );
    /* handle error */
  }

  // Scenario 2: UseAsNewActiveCustomerCart
  // Result: Active Cart contains ONLY 1x Zen Speaker X (previous Cart disassociated)
  try {
    await simulateLoginAndCartHandlingInStore(
      ELECTRONICS_HIGH_TECH_STORE_KEY,
      davidEmail,
      davidPassword,
      anonCartId,
      'UseAsNewActiveCustomerCart'
    );
  } catch (e) {
    console.error(
      `Failed to simulate UseAsNewActiveCustomerCart scenario for store ${ELECTRONICS_HIGH_TECH_STORE_KEY}.`
    );
    /* handle error */
  }
})();

Implement custom Cart merging logic

While the built-in merge modes handle most scenarios and use cases, some business requirements need more control. In these cases, you can implement custom Cart merging logic for specific needs.

When to use custom Cart merging logic

Consider implementing custom Cart merging logic if you need to:

  • Apply complex business rules: merge only items from specific categories or add duplicate products as separate Line Items instead of increasing quantity.
  • Allow Customer selection: present both Carts to the user and let them choose which items to keep.
  • Merge custom data: handle complex merging of custom fields on Carts or Line Items.
  • Custom conflict resolution: go beyond the default behavior for handling Cart conflicts.

How to implement custom Cart merging logic

A custom Cart merging process involves these steps:

  1. Sign in without anonymousCartId: call the login endpoint with only credentials to prevent automatic merging and retrieve the customerId and activeCart.
  2. Fetch both Carts: retrieve the anonymous Cart ID from the client (for example, a cookie) and fetch both Carts to compare their contents.
  3. Apply your merge logic: use Cart update actions (addLineItem, changeLineItemQuantity, removeLineItem, setCustomField) to build the final merged Cart according to your business rules.
  4. Clean up: optionally delete the anonymous Cart after successful merging.

Custom Cart merging offers maximum flexibility but introduces complexity in development, testing, and maintenance. Use it only when the built-in modes don't meet your requirements.

Key takeaways

  • Use anonymousCartSignInMode on sign-in to control how anonymous Carts are handled automatically.
  • Choose MergeWithExistingCustomerCart when Customers should keep items from both their anonymous and logged-in sessions.
  • Choose UseAsNewActiveCustomerCart when the anonymous session represents the Customer's current intent and should replace their existing Cart.
  • Tax recalculation during merge depends on whether the Customer's active Cart has a shipping address—this impacts the final prices Customers see.
  • Line Items are matched by properties (product, variant, channels) not keys, so identical items with different keys will merge.
  • For complex business rules like conditional merging or Customer-driven selection, implement custom Cart merging logic in your backend.
  • See the Cart merge API reference for complete technical specifications.

Test your knowledge