How to Customize the Checkout Controller Logic in Adyen Salesforce Commerce Cloud

You can customize the checkout controller logic in the Adyen SFRA integration by extending the base Checkout.js controller in a custom cartridge and using server.prepend, server.append, or server.replace to inject, augment, or override the default checkout.begin middleware that handles basket preparation and view data injection.

The checkout flow in the Adyen Salesforce Commerce Cloud integration is built on SFRA's Server API, providing a flexible architecture for merchants to inject custom business rules. Understanding how to customize the checkout controller logic allows you to modify basket handling, add promotional content, or implement custom validations without modifying core Adyen files. This approach ensures your customizations remain upgrade-safe when new versions of the adyen-salesforce-commerce-cloud repository are released.

Understanding the Checkout Controller Architecture

The Adyen SFRA integration organizes checkout logic into distinct layers that work together to process the checkout request. The default controller (int_adyen_SFRA/cartridge/controllers/Checkout.js) prepends the standard checkout Begin route with middleware functions before handing control to the original SFRA checkout implementation.

Layer Purpose Relevant Files
Controller Declares the route (Begin) and wires middleware. controllers/Checkout.js
Middleware (prepend) Runs before the original SFRA Begin logic – adds CSRF, consent tracking, and the Adyen‑specific checkout.begin middleware. controllers/Checkout.js (prepend list)
Checkout Begin Middleware Contains the Adyen‑specific logic that prepares the basket, restores a cached order, and injects view data (adyen object). controllers/middlewares/checkout/begin.js
Utility Modules Provide configuration (adyenConfigs), helper functions (adyenHelper), logging, and saved‑card handling. adyen/utils/*, adyen/logs/*, adyen/scripts/payments/updateSavedCards.js

Because Server's prepend/append/replace methods are used, you can customize the checkout flow in three ways without touching the core Adyen files:

  1. Add a new middleware before or after the existing one.
  2. Replace the default checkout.begin middleware with your own implementation.
  3. Create a new controller in a custom cartridge that overrides the original controller (SFCC picks the first controller it finds in the cartridge path).

All three approaches are supported by the SFRA server API and keep your changes upgrade‑safe.

Customization Strategies

Prepending Custom Middleware

Use server.prepend('Begin', ...) to execute your logic before the Adyen checkout initialization. This is ideal for injecting view data, setting session variables, or performing early validation checks.

Appending Additional Logic

Use server.append('Begin', ...) to run code after the standard checkout logic completes. This works well for post-processing tasks, analytics tracking, or modifying the response data after Adyen has prepared the checkout view.

Replacing the Default Behavior

Use server.replace('Begin', ...) to completely override the checkout begin logic. This removes the original checkout.begin middleware from the execution chain, giving you full control over basket preparation and view data injection.

Creating a Custom Controller Override

Place a new Checkout.js controller in a custom cartridge that extends module.superModule. SFCC resolves controllers by cartridge path priority, so your version will override the Adyen controller while still allowing you to call the parent implementation when needed.

Implementation Examples

Injecting Promotional Content

The following example demonstrates how to prepend a custom middleware that injects promotional banner data into the view before the Adyen checkout logic executes.

// src/cartridges/custom_adyen/cartridge/controllers/Checkout.js
const server = require('server');
const csrfProtection = require('*/cartridge/scripts/middleware/csrf');
const consentTracking = require('*/cartridge/scripts/middleware/consentTracking');
const { checkout } = require('*/cartridge/controllers/middlewares/index');

// Extend the base Checkout controller
server.extend(module.superModule);

/**
 * Simple middleware that adds a banner flag to the view data.
 */
function addPromoBanner(req, res, next) {
    const viewData = res.getViewData();
    viewData.promoBanner = {
        title: 'Free shipping over $50',
        color: '#ff6600'
    };
    res.setViewData(viewData);
    return next();
}

// Prepend the standard middleware chain and then insert our banner middleware
server.prepend(
    'Begin',
    server.middleware.https,
    consentTracking.consent,
    csrfProtection.generateToken,
    addPromoBanner,            // <-- our custom step
    checkout.begin             // original Adyen checkout logic
);

module.exports = server.exports();

This file overrides the original controller by extending module.superModule and injects a new step (addPromoBanner) before the Adyen checkout begins.

Implementing Custom Basket Validation

To completely replace the default checkout begin logic with custom validation, use server.replace to intercept the request before the standard Adyen middleware executes.

// src/cartridges/custom_adyen/cartridge/controllers/Checkout.js
const server = require('server');
const BasketMgr = require('dw/order/BasketMgr');
const URLUtils   = require('dw/web/URLUtils');

// Extend base controller (optional – needed only if you still want to expose other routes)
server.extend(module.superModule);

/**
 * Completely custom checkout begin logic.
 */
function myBegin(req, res, next) {
    // Example: force a specific basket condition
    const basket = BasketMgr.getCurrentBasket();
    if (basket && basket.productLineItems.length === 0) {
        // Redirect to cart if empty
        res.redirect(URLUtils.url('Cart-Show'));
        return next();
    }

    // Add any custom view data needed by your front‑end
    const viewData = res.getViewData();
    viewData.custom = { foo: 'bar' };
    res.setViewData(viewData);

    // Continue with the rest of the pipeline (or finish here)
    return next();
}

// Replace the original Begin route
server.replace('Begin', server.middleware.https, myBegin);

module.exports = server.exports();

Using server.replace removes the Adyen checkout.begin middleware entirely, allowing you to define any checkout start logic you need.

Extending the Existing Begin Middleware

For scenarios where you want to keep the existing Adyen behavior but add supplementary validation, create a wrapper middleware that invokes the original logic before applying your custom rules.

// src/cartridges/custom_adyen/cartridge/controllers/middlewares/checkout/begin.js
const originalBegin = require('*/cartridge/controllers/middlewares/checkout/begin');

/**
 * Wrapper that runs the original logic and then performs additional checks.
 */
function beginWithExtraChecks(req, res, next) {
    // Run the standard Adyen begin logic first
    originalBegin(req, res, function () {
        // After the original logic, add a custom validation
        const basket = req.currentBasket;
        if (basket && basket.totalGrossPrice.value > 1000) {
            // Example: flag high‑value orders for manual review
            req.session.privacyCache.set('highValueOrder', true);
        }
        return next();
    });
}

module.exports = beginWithExtraChecks;

By re‑exporting a wrapper, you keep the existing Adyen behavior intact while appending your own business rules.

Key Source Files Reference

The following files constitute the core checkout logic in the Adyen SFRA integration:

File Role Link
src/cartridges/int_adyen_SFRA/cartridge/controllers/Checkout.js – base controller that prepends middleware Checkout.js
src/cartridges/int_adyen_SFRA/cartridge/controllers/middlewares/checkout/begin.js – Adyen checkout begin middleware (basket restore, view‑data injection) begin.js
src/cartridges/int_adyen_SFRA/cartridge/controllers/middlewares/index.js – aggregates all checkout middleware functions index.js
src/cartridges/int_adyen_SFRA/cartridge/utils/adyenConfigs.js – configuration retrieval (client key, environment, etc.) adyenConfigs.js
src/cartridges/int_adyen_SFRA/cartridge/adyen/utils/adyenHelper.js – helper for environment handling adyenHelper.js
src/cartridges/int_adyen_SFRA/cartridge/scripts/payments/updateSavedCards.js – saved‑card handling used in the begin middleware updateSavedCards.js

Summary

  • Extend the base controller by creating a Checkout.js in your custom cartridge that calls server.extend(module.superModule).
  • Use server.prepend to inject custom middleware before the Adyen checkout logic executes, ideal for adding view data or early validation.
  • Use server.append to run additional logic after the standard checkout processing completes, suitable for analytics or post-processing.
  • Use server.replace to completely override the Begin route and implement bespoke checkout initialization logic.
  • Wrap existing middleware to retain Adyen's basket restoration and saved-card handling while appending your own business rules.
  • Maintain upgrade compatibility by placing all customizations in a separate cartridge rather than modifying files in int_adyen_SFRA.

Frequently Asked Questions

How do I add a custom validation step before the Adyen checkout begins?

Create a custom cartridge with a Checkout.js controller that extends module.superModule. Use server.prepend('Begin', ...) to register your validation middleware before the checkout.begin middleware. Your function can inspect the basket via BasketMgr.getCurrentBasket() and either call next() to proceed or res.redirect() to abort the checkout flow.

Can I override the Adyen checkout logic completely without losing basket restoration?

Yes. Use server.replace('Begin', ...) in your custom controller to substitute the entire middleware chain. If you require Adyen's basket restoration and saved-card functionality, import the original begin.js middleware from */cartridge/controllers/middlewares/checkout/begin and invoke it within your custom logic before applying your modifications.

What is the difference between server.prepend and server.append in SFRA?

server.prepend executes your middleware before the original route logic runs, making it ideal for pre-processing tasks like validation or view data injection. server.append executes after the original logic completes, which is useful for post-processing, analytics tracking, or modifying response data after Adyen has prepared the checkout view.

Where should I place my custom checkout controller to ensure it overrides the Adyen default?

Place your Checkout.js file in a custom cartridge (e.g., app_custom_adyen) under the path cartridge/controllers/Checkout.js. In Business Manager, ensure your custom cartridge appears before int_adyen_SFRA in the site cartridge path. SFCC resolves controllers from left to right, so the first match in the path hierarchy takes precedence.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →