← All Developer Interviews

B2C Commerce Developer Interview Questions

Salesforce Certified B2C Commerce Developer — 25 Expert Q&As

🛒 B2C Commerce 25 Questions Detailed Answers Free
SFRA & Architecture OCAPI & SCAPI ISML & Templating Business Manager Headless Commerce

SFRA (Storefront Reference Architecture) is a modern MVC-based framework for building B2C Commerce storefronts. It was introduced to replace the older SiteGenesis architecture, which was a monolithic, tightly coupled codebase that was difficult to customise and upgrade.

SFRA provides:

  1. A clean MVC pattern — controllers handle routing and logic, models encapsulate data, ISML templates produce HTML output
  2. CommonJS-based server-side modules for better code organisation
  3. Extensibility through cartridge inheritance and the server middleware pattern
  4. Non-destructive customisation via server.append(), server.prepend(), and module.superModule
  5. Better support for headless and API-first commerce implementations

The key advantage is that custom cartridges override or extend SFRA behaviour without modifying the base code, making platform upgrades far easier and reducing merge conflicts.

The cartridge path is a colon-separated list of cartridge names configured in Business Manager under Administration > Sites > Manage Sites > [Site] > Settings. It controls how B2C Commerce resolves server-side scripts, ISML templates, and static files.

Resolution works left to right — the platform searches each cartridge from left to right until it finds the requested resource. The first match wins. A typical cartridge path looks like:

app_custom:plugin_wishlist:app_storefront_base:modules

Order matters because:

  1. Custom cartridges must be to the LEFT of SFRA base cartridges so their overrides are discovered first
  2. Plugin cartridges should come before the base but after the custom app cartridge
  3. Shared utility cartridges (like modules) typically go last

If a cartridge is missing from the path entirely, its scripts and templates are invisible to the platform — this is a common cause of 404 errors during development.

Legacy pipelines were XML-based visual workflows consisting of interconnected nodes (start nodes, script nodes, decision nodes) that controlled storefront logic in SiteGenesis. They were difficult to unit-test, version-control, and extend without forking the entire pipeline.

SFRA controllers are JavaScript modules following an Express.js-inspired pattern:

  1. Routes are registered with server.get('routeName', middleware, handler) or server.post()
  2. Each step is a middleware function that receives (req, res, next) and calls next() to pass control forward
  3. The final middleware calls res.render('templatePath', viewModel) or res.json(data)
  4. Custom cartridges extend routes via server.extend() combined with server.append() or server.prepend()

Controllers are plain JavaScript files, making them easy to lint, unit-test, and track in git. Pipelines are deprecated but still supported in legacy implementations.

OCAPI (Open Commerce API) has two primary document types serving different purposes:

  1. Shop API — the customer-facing storefront API for product search, category browsing, basket management, checkout, and customer account operations. It operates in the context of a shopper session or guest token. Used by the storefront frontend or headless clients acting on behalf of a shopper.
  2. Data API — the back-office integration API for reading and writing product catalogs, orders, customer profiles, inventory, and site configuration. It requires Business Manager user credentials or a client credentials grant and is not intended for direct shopper interactions.

Both APIs use REST + JSON and OAuth 2.0 authentication, but their access scopes, permissions, and intended consumers differ significantly. Mixing up Data API and Shop API endpoints is a common mistake in integrations.

SCAPI (Salesforce Commerce API) is the next-generation REST API for B2C Commerce, specifically designed for headless storefronts. Key differences from OCAPI include:

  1. Modern authentication — SCAPI uses SLAS (Shopper Login and API Access Service) with OAuth 2.0 PKCE flows, replacing OCAPI's session-based shopper authentication
  2. Decomposed API families — Shopper Products, Shopper Baskets, Shopper Orders, Shopper Login, Shopper Search — each independently versioned
  3. OpenAPI specification — SCAPI ships with a full OpenAPI 3.0 spec, enabling SDK generation and better developer tooling
  4. Commerce SDK — Salesforce provides official JavaScript/TypeScript SDKs for SCAPI, simplifying headless development

For new headless implementations, SCAPI is the recommended approach. OCAPI remains supported for existing integrations but receives fewer enhancements.

SFRA implements the Model-View-Controller pattern across three cartridge sub-directories:

  1. Model (cartridge/models/) — JavaScript modules that encapsulate business logic and transform raw commerce objects (products, baskets, orders) into clean view models. They interact with B2C Commerce scripting APIs and expose simple properties to the controller.
  2. Controller (cartridge/controllers/) — JavaScript files that register HTTP routes, call model methods to get view model data, and pass that data to a template via res.render().
  3. View (cartridge/templates/) — ISML files that generate HTML using data from pdict.

The pdict (Pipeline Dictionary) is the data object that flows from controller to template. When a controller calls res.render('path/template.isml', { product: productModel }), the second argument is merged into pdict. In the ISML template, you access it as ${pdict.product.name} or via <isprint value="${pdict.product.price}">.

module.superModule is a B2C Commerce mechanism that loads the same-named module from the next cartridge down in the cartridge path. It enables model inheritance without copying and forking code.

A typical use case:

  1. SFRA provides app_storefront_base/cartridge/models/product/fullProduct.js with standard product properties
  2. Your custom cartridge creates app_custom/cartridge/models/product/fullProduct.js
  3. At the top of your file: var base = module.superModule; then base.call(this, product, options); to inherit the base model
  4. You then add extra properties (e.g., loyalty points, subscription flag) to this

Without module.superModule, you would have to copy the entire base file and maintain it separately through every SFRA upgrade — a major maintenance burden. Using superModule keeps customisations upgrade-safe.

These three methods allow a custom cartridge to modify existing controller routes without redefining them from scratch. They are used after calling server.extend(require('controller/TargetController')):

  1. server.append() — adds new middleware that runs AFTER all existing middleware steps in the route. Use this to post-process the view model, inject extra data into pdict, or trigger a side effect (such as logging or loyalty points update) after the main logic completes.
  2. server.prepend() — inserts new middleware BEFORE all existing steps. Use this for pre-processing such as authentication checks, A/B test routing, or input sanitisation.
  3. server.replace() — completely replaces all existing middleware for the named route with new middleware. Use this only when the original logic should not run at all. It is the most brittle option and can break with SFRA upgrades if the replaced logic changes.

In most cases, append or prepend are preferred over replace as they are less likely to conflict with future SFRA updates.

A hook in B2C Commerce is a named extension point that allows cartridges to plug custom logic into the platform without modifying core code. Hooks are registered in a cartridge's package.json under a hooks property that points to a JSON file listing hook IDs and JavaScript module paths.

For payment integration, the platform defines the hook group dw.order.payment with the following key hook points:

  1. Handle — called when the customer submits payment information on the billing step; used to save payment instrument data to the basket
  2. Authorize — called when the order is being placed; used to call the payment gateway and capture or authorise funds
  3. ValidatePaymentInstruments — validates stored payment instruments on the basket

The custom payment cartridge implements these methods, and the Payment Processor is registered in Business Manager under Merchant Tools > Ordering > Payment Processors. The storefront checkout then routes to the custom processor based on the payment method selected.

Page Designer is a Business Manager feature that allows merchandisers to build and publish storefront pages using a visual drag-and-drop editor — no developer involvement required for day-to-day content management.

Developers support Page Designer by creating components with three parts:

  1. JSON meta file (cartridge/experience/components/) — defines the component's editable attributes (text fields, image selectors, colour pickers) and their types
  2. ISML rendering template (cartridge/experience/components/) — renders the component HTML using the attribute values set by the merchandiser
  3. Optional client-side JavaScript — handles any interactive behaviour in the browser

Developers also define page types (in cartridge/experience/pages/) that set the overall layout structure (e.g., hero + grid + banner zones). Once deployed, merchandisers compose pages from the available component library and publish them to the live storefront without code changes.

B2C Commerce uses a structured hierarchy for products that have multiple purchasable variations (such as a shirt available in multiple sizes and colours):

  1. Master product — defines the variation attributes (e.g., size, colour) and their allowed values. The master itself is never added to the cart. The product detail page typically displays the master, allowing the customer to select attributes.
  2. Variant — a specific combination of variation attribute values (e.g., size Large, colour Blue). Only variants are purchasable. Each variant has its own SKU, inventory record, and optionally its own price in the pricebook.
  3. Variation group — an optional intermediate product that groups variants sharing one common attribute value (e.g., all Blue variants regardless of size). Useful for displaying colour swatches that link to a pre-filtered view.

In SFRA, the Product Detail Page controller fetches the master, renders variation selectors, and updates to the specific variant as the customer makes selections via AJAX.

A custom object is a developer-defined structured data type for storing application data that does not fit into B2C Commerce's standard objects (Product, Order, Customer, Basket). Custom object types are created in Business Manager under Administration > Site Development > Custom Object Types.

Each type defines named attributes with data types (string, integer, boolean, enum). Records are created and queried using the dw.object.CustomObjectMgr API.

Good use cases include:

  1. Loyalty programme member records
  2. Subscription tier definitions
  3. Integration state tracking (e.g., last sync timestamps)
  4. Configuration tables too complex for site preferences

Custom objects are subject to platform storage quotas, so high-volume data (millions of records) should be stored in an external database. For reporting or analytics-heavy data, an external system is also preferred since B2C Commerce's query capabilities for custom objects are limited.

These two concepts are often confused but serve distinct purposes:

  1. Content asset — a standalone piece of managed HTML content (banner, legal text, promotional copy) created and edited in Business Manager under Merchant Tools > Content > Content Assets. A content asset is static until a merchandiser edits it. It is rendered by including it in a template using <iscontentasset> or via a content slot.
  2. Content slot — a named placeholder defined in an ISML template. Merchandisers configure what appears in each slot via campaign-controlled slot configurations in Business Manager. The same template location can show different content to different customer groups or during different date ranges without any code change.

The key distinction: content assets are "what" to show; content slots are "where and when" to show it. Content slots enable personalisation and campaign scheduling on top of content assets (or product recommendations).

B2C Commerce supports edge caching at the platform level. When a page response is cached, subsequent requests for the same URL are served from the cache without executing server-side scripts, significantly improving performance.

Developers control caching in SFRA controllers by setting properties on the response object:

  1. res.cachePeriod = 2; and res.cachePeriodUnit = 'hours'; — caches the full page for 2 hours
  2. Setting res.personalized = true; marks a response as personalised and disables shared caching

In ISML templates, the <iscache> tag with type="relative" and hour attributes can also control cache duration at the template level.

Best practice: enable caching on product display pages, category pages, and the homepage. Disable it (or set very short TTLs) on the cart, checkout, account pages, and any page with personalised content. Incorrectly caching a personalised page is a security and correctness risk.

WebDAV (Web Distributed Authoring and Versioning) is the HTTPS-based file protocol used to transfer files between a developer's machine and the B2C Commerce platform. It functions like a remote file system mounted over HTTPS.

Developers use WebDAV for:

  1. Code deployment — uploading cartridge zip files to /on/demandware.servlet/webdav/Sites/Cartridges/[version]/
  2. Static content — managing images, CSS, and client-side JS in the Impex folder
  3. Data import/export — placing XML import files in /on/demandware.servlet/webdav/Sites/Impex/src/ for processing by jobs
  4. Log retrieval — reading server logs from /on/demandware.servlet/webdav/Sites/Logs/

Common WebDAV clients include Cyberduck and the Prophet Debugger VS Code extension. WebDAV access requires a Business Manager user with the WebDAV Services permission. Many CI/CD pipelines use the sfcc-ci CLI to automate code uploads via WebDAV.

The server module is the central SFRA framework object imported at the top of every controller file:

var server = require('server');

It exposes the following key methods:

  1. Route registrationserver.get(name, ...middleware), server.post(name, ...middleware), server.use(name, ...middleware) for any HTTP method
  2. Route inheritanceserver.extend(require('controllers/TargetController')) imports all routes from another controller into the current one, enabling extension
  3. Route modificationserver.append(name, ...middleware), server.prepend(name, ...middleware), server.replace(name, ...middleware) modify inherited routes
  4. Exportsmodule.exports = server.exports() at the end of every controller file exposes registered routes to the B2C Commerce router

Each middleware function in a route receives (req, res, next) — call next() to advance, next(true) to stop the chain and render the current response.

Promotions and campaigns are configured entirely in Business Manager under Merchant Tools > Marketing > Promotions and Campaigns. Their relationship is:

  1. Promotion — defines the discount rule: what qualifies (trigger conditions, e.g., minimum order value, specific categories, buy-X-get-Y) and what the shopper receives (percentage off, fixed amount, free shipping, free gift). A promotion on its own is inactive until linked to a campaign.
  2. Campaign — groups one or more promotions with scheduling (start date, end date), customer group targeting, and source code / coupon code requirements. A promotion fires only if it belongs to an active campaign whose conditions are met at checkout time.

This separation allows the same promotion rule to be reused across multiple campaigns with different timing (e.g., Black Friday campaign vs. loyalty member campaign). Developers can also query active promotions programmatically via the dw.campaign.PromotionMgr API for custom UI indicators or loyalty integrations.

SLAS (Shopper Login and API Access Service) is the OAuth 2.0-based identity service that underpins SCAPI authentication for headless B2C storefronts.

SLAS provides two primary authentication flows:

  1. Guest shopper flow (Public Client with PKCE) — allows anonymous shoppers to interact with the SCAPI without an account. The frontend app exchanges a PKCE code challenge/verifier for a short-lived access token.
  2. Registered customer flow — allows a logged-in customer to authenticate, receive an access token and refresh token, and maintain an authenticated session across API calls.

SLAS is important for headless because:

  1. Traditional B2C Commerce authentication relied on server-side sessions managed by ISML — unsuitable for stateless API calls from React, Vue, or mobile apps
  2. SLAS tokens are short-lived, cryptographically signed JWTs, reducing the risk of session hijacking
  3. It provides a unified, standards-based auth layer that integrates with Salesforce Identity and external IdPs

B2C Commerce provides several debugging approaches at different layers:

  1. Storefront Toolkit — a browser overlay activated by appending ?dwft=true or via Business Manager toggle. Shows cache status, content slot assignments, pipeline/controller execution times, and a live log tail for the current request.
  2. Prophet Debugger (VS Code extension) — connects to the B2C Commerce Script Debugger API to enable step-through debugging of server-side JavaScript. Set breakpoints in controller and model files and inspect variables in the VS Code Debug panel.
  3. Custom logging — use var Logger = require('dw/system/Logger'); then Logger.error('Message: {0}', value); to write to log files. Logs are accessible via Business Manager under Administration > Site Development > Development Setup > Log Files or via WebDAV.
  4. ISML errors — ISML template errors appear inline in the browser during development mode and in the error log in production.

The B2C Commerce Service framework is a managed approach to calling external HTTP, FTP, and SOAP services from server-side scripts. Services are configured in Business Manager under Operations > Services with URL, credentials, timeout, and mock mode settings.

In code, services are instantiated using LocalServiceRegistry.createService() (for cartridge-registered services) and called via service.call(params).

The service framework provides:

  1. Connection pooling — reuses HTTP connections for performance
  2. Timeout enforcement — prevents hanging server-side threads from blocking all quota threads
  3. Circuit breaker — automatically disables a service if it starts failing and prevents cascading failures
  4. Logging — automatically logs call duration, response codes, and errors to the custom log files
  5. Mock mode — allows development and testing without calling live external APIs

Using the service framework for all external calls is a platform best practice and is enforced by Salesforce's code review for LINK cartridge certification.

The Basket is the in-session shopping cart object managed by the dw.order.BasketMgr API. Its lifecycle during checkout:

  1. Creation — when a customer first adds a product, BasketMgr.getCurrentOrNewBasket() creates a basket and associates it with the session
  2. Population — cart and checkout controllers add product line items, apply coupons, set shipping address, select shipping method, and attach payment instruments to the basket
  3. Validation — at each checkout step, controllers validate the basket state (e.g., inventory check, payment validation) before proceeding
  4. Order placementCOPlaceOrder calls the checkout hook which calls BasketMgr.placeOrder(basket), converting the basket into a persisted Order object
  5. Basket deletion — after successful order placement, the basket is automatically deleted from the session
  6. Abandonment — if the session expires before checkout, the basket is abandoned and eventually purged by a platform job

B2C Commerce supports multiple sites within a single organisation (realm), each independently configured. A single cartridge codebase can power multiple sites with different branding, languages, and catalogs.

Each site can have its own:

  1. Domain and URL mapping configured in Business Manager
  2. Locale and currency — the default locale and a list of supported locales per site
  3. Catalog — product and category structure specific to that market
  4. Pricebook — prices per currency or customer group
  5. Inventory list — stock quantities per location
  6. Cartridge path — allowing site-specific overrides for one site without affecting others
  7. Site preferences — configuration values overriding global defaults

Translatable strings are managed in resource bundles — properties files in cartridge/templates/resources/ with locale suffixes (e.g., content_de.properties). Templates access them via Resource.msg('key', 'bundle', null).

B2C Commerce uses a Code Version model for deployments, allowing code to be staged and activated without downtime:

  1. Package — zip the cartridge directory (e.g., app_custom.zip containing the app_custom/ folder at the root)
  2. Upload — transfer the zip to the target environment via WebDAV at /on/demandware.servlet/webdav/Sites/Cartridges/[version_label]/
  3. Extract — in Business Manager, navigate to Administration > Code Deployment, select the code version, and deploy or extract the uploaded zip
  4. Update cartridge path — if new cartridges were added, update the cartridge path for each affected site in Business Manager
  5. Activate code version — switch the active code version to make the new code live. The previous version remains available for instant rollback.

Most teams automate these steps using the sfcc-ci CLI and GitHub Actions or Jenkins pipelines, combining upload, extraction, and activation into a single CI/CD workflow.

Both product sets and bundles are types that group multiple products together, but they behave differently for the shopper and in the cart:

  1. Product set — a curated collection of products displayed together on a single page (e.g., "complete the look" or "shop the outfit"). Each component is purchased independently — the shopper can add all, some, or none to the cart. Each component becomes a separate line item in the basket at its own price.
  2. Bundle — a group of products sold as a single combined unit at an aggregate or discounted price. All components are added to the basket together as a single line item. The shopper cannot partially purchase a bundle — it is all or nothing.

In the product catalog, set and bundle products have their own product type (ProductSet and Bundle), and the SFRA Product Detail Page controller handles each type differently — rendering either individual "add to cart" buttons per component or a single "add bundle to cart" button.

A B2C Commerce Job is a server-side process that executes one or more steps either on a configurable schedule or on demand. Jobs are configured in Business Manager under Administration > Operations > Jobs. They are commonly used for:

  1. Catalog, inventory, and price feed imports from external systems
  2. Order data exports to ERP or fulfilment systems
  3. Search index rebuilding after catalog updates
  4. Batch order processing and custom data maintenance

To create a custom job step:

  1. Write a JavaScript module in cartridge/scripts/jobsteps/myStep.js that exports an execute(parameters, stepExecution) function. The function performs the work and returns a Status object indicating success or failure.
  2. Register the step by creating a job step configuration (via XML import or directly in Business Manager) that maps the step ID to the script path and exposed parameter names.
  3. In Business Manager, create a new Job, add the custom step from the step picker, configure parameters, and set the schedule or trigger.

Ready to test your knowledge?

Take the full 50-question B2C Commerce Developer mock test and get an instant score.

🛒 Take the Mock Test ← All Developer Interviews