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

> Customize Adyen checkout controller logic in Salesforce Commerce Cloud. Extend Checkout.js with server.prepend, server.append or server.replace for flexible integration.

- Repository: [Adyen/adyen-salesforce-commerce-cloud](https://github.com/adyen/adyen-salesforce-commerce-cloud)
- Tags: how-to-guide
- Published: 2026-02-23

---

**You can customize the checkout controller logic in the Adyen SFRA integration by extending the base [`Checkout.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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.

```javascript
// 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.

```javascript
// 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.

```javascript
// 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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/controllers/Checkout.js) – base controller that prepends middleware | ✅ | [Checkout.js](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/controllers/Checkout.js) |
| [`src/cartridges/int_adyen_SFRA/cartridge/controllers/middlewares/checkout/begin.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/controllers/middlewares/checkout/begin.js) – Adyen checkout begin middleware (basket restore, view‑data injection) | ✅ | [begin.js](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/controllers/middlewares/checkout/begin.js) |
| [`src/cartridges/int_adyen_SFRA/cartridge/controllers/middlewares/index.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/controllers/middlewares/index.js) – aggregates all checkout middleware functions | ✅ | [index.js](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/controllers/middlewares/index.js) |
| [`src/cartridges/int_adyen_SFRA/cartridge/utils/adyenConfigs.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/utils/adyenConfigs.js) – configuration retrieval (client key, environment, etc.) | ✅ | [adyenConfigs.js](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/adyen/utils/adyenConfigs.js) |
| [`src/cartridges/int_adyen_SFRA/cartridge/adyen/utils/adyenHelper.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/adyen/utils/adyenHelper.js) – helper for environment handling | ✅ | [adyenHelper.js](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/adyen/utils/adyenHelper.js) |
| [`src/cartridges/int_adyen_SFRA/cartridge/scripts/payments/updateSavedCards.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/scripts/payments/updateSavedCards.js) – saved‑card handling used in the begin middleware | ✅ | [updateSavedCards.js](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/scripts/payments/updateSavedCards.js) |

## Summary

- **Extend the base controller** by creating a [`Checkout.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/Checkout.js) file in a custom cartridge (e.g., `app_custom_adyen`) under the path [`cartridge/controllers/Checkout.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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.