Skip to main content

Last updated: May 2026

Practice Exam

Comm-Dev-101Salesforce Certified B2C Commerce Cloud Developer

Test your knowledge with official exam-style questions

Questions25Passing68%Exam time105 min

Questions and options are shuffled each attempt

Salesforce Certified B2C Commerce Cloud DeveloperPractice Set 1: All Questions & Explanations

Full question text, answer options, and explanations for this practice set — a spoiler-free alternative is the interactive quiz above for scored, shuffled practice.

  1. 1. In Salesforce B2C Commerce Business Manager, a developer has uploaded new storefront cartridge code to the code directory. What is the NEXT step required to make the new code live on the storefront?

    • A. Restart the application server from the Operations menu
    • B. Activate the code version from Administration > Code Deployment(correct)
    • C. Invalidate the full-page cache from the caching configuration
    • D. Redeploy the cartridge by re-uploading to WebDAV

    Explanation: In B2C Commerce, uploaded cartridge code must be deployed through a Code Version. The developer activates the new code version via Administration > Code Deployment in Business Manager, which switches the storefront to use the newly uploaded code. Restarting the application server is not a developer-accessible action in B2C Commerce's hosted environment. Cache invalidation ensures fresh content delivery but does not activate new code. Re-uploading cartridges to WebDAV adds the files but does not make them active — activation requires the code version switch.

  2. 2. A developer is using the Storefront Toolkit to debug a B2C Commerce storefront and needs to identify which controller is handling the current page request. Which URL pattern provides access to the Storefront Toolkit debug overlay on a development sandbox?

    • A. https://[host]/on/demandware.store/Sites-[site-id]-Site/__Toolkit__(correct)
    • B. https://[host]/s/[site-id]?debug=true
    • C. https://[host]/on/demandware.store/Sites-[site-id]-Site/default/Toolkit-Show
    • D. https://[host]/on/demandware.store/[site-id]/default/DebugMode

    Explanation: The Storefront Toolkit in B2C Commerce is accessed via the special URL pattern using __Toolkit__ which injects a debugging overlay into storefront pages. This overlay reveals controller/pipeline names, cache settings, and rendering timings for each page region. A debug=true query parameter is not a supported B2C Commerce debugging mechanism. Toolkit-Show and DebugMode are not valid controller routes. The correct pattern uses the demandware.store namespace with __Toolkit__ as the route.

  3. 3. A merchant sells t-shirts available in three colors and two sizes. In the Salesforce B2C Commerce catalog, which product type represents the t-shirt concept, and which represents each individual purchasable variant (e.g., Blue/Small)?

    • A. Product Set represents the t-shirt; Product Bundle represents each variant
    • B. Master Product represents the t-shirt; Variation Product represents each variant(correct)
    • C. Variation Group represents the t-shirt; Variation Attribute represents each variant
    • D. Standard Product represents the t-shirt; Linked Product represents each variant

    Explanation: In B2C Commerce, a Master Product defines the variation attributes (color, size) and serves as the parent for all combinations. Each unique combination — such as Blue/Small — is a Variation Product with its own SKU, price, and inventory record. Product Sets group separately purchasable products together (like an outfit). Product Bundles sell multiple items as a single purchasable unit. Variation Groups allow cross-dimensional grouping (e.g., all Red variants) but are not purchasable units themselves.

  4. 4. Which TWO statements about B2C Commerce product types are correct? Choose 2.

    • A. A Product Set allows customers to purchase all included products as a single add-to-cart action
    • B. A Product Bundle groups items into a single purchasable unit — all items are added to the cart together
    • C. A Master Product cannot be added to a cart directly — only its Variation Products can be purchased(correct)
    • D. A Variation Group is a child of a Master Product that groups variants sharing a common attribute value(correct)
    • E. Standard Products and Variation Products share the same object type in Business Manager

    Explanation: A Master Product defines the variation structure and cannot be purchased directly — customers must select a specific Variation Product which has its own inventory and price. A Variation Group is a grouping of variation products that share a variation attribute value (e.g., all 'Blue' variants), used for cross-selling and refinement. A Product Set displays products together for individual purchase — it does not bundle them into a single add-to-cart. A Product Bundle (not Set) creates the single purchasable unit. Standard Products and Variation Products are distinct catalog item types with separate configurations.

  5. 5. A merchandiser reports that a newly created product attribute is not appearing as a search refinement on the storefront, even though the product is properly published in the catalog. What is the MOST LIKELY cause?

    • A. The product's search ranking boost is set to zero
    • B. The search index has not been rebuilt after the attribute was configured in the search index settings(correct)
    • C. The product is a Master Product type, which cannot be included in the search index
    • D. The attribute must be added to a Content Asset before it appears as a refinement

    Explanation: In B2C Commerce, searchable and refinement attributes must be configured in Business Manager under Search > Search Indexes, and the search index must be rebuilt for changes to take effect on the storefront. Simply adding an attribute to the catalog does not automatically make it available for search refinement. Search ranking boost affects position in results, not visibility as a refinement facet. Master Products can be indexed. Content Assets are for editorial content, not product attribute refinement configuration.

  6. 6. A content manager needs to display a promotional banner on the homepage ONLY during the Black Friday campaign period, and a different banner on the 'Sale' category page year-round. Which configuration in Business Manager correctly implements both requirements?

    • A. Create one Global content slot on the homepage with a campaign experience; create a second Global content slot on the Sale category page with default content
    • B. Create a Global content slot on the homepage with a campaign-qualified experience; create a Category content slot assigned to the Sale category with default content(correct)
    • C. Create two Product content slots — one for the homepage and one for the Sale category — both with campaign experiences
    • D. Create a Folder content slot to control both pages simultaneously using a shared campaign qualifier

    Explanation: B2C Commerce has three content slot scopes: Global (renders on all pages where the slot template is included), Category (renders on a specific category page), and Folder (renders on content folder pages). A Global content slot on the homepage with a campaign-qualified experience activates only during the Black Friday period. A Category content slot scoped to the Sale category displays content on that category page year-round via a default experience. Product slots appear on product detail pages only. A Folder slot cannot target both a homepage and a category page simultaneously.

  7. 7. In Salesforce B2C Commerce, which hierarchy correctly represents the promotion system structure from highest to lowest level?

    • A. Promotion → Campaign → Experience → Coupon
    • B. Campaign → Experience → Promotion → Coupon(correct)
    • C. Experience → Campaign → Promotion → Coupon
    • D. Campaign → Promotion → Experience → Coupon

    Explanation: The B2C Commerce promotion hierarchy is: Campaign (the top-level container defining a date range and customer groups) → Experience (a child of the campaign that defines qualifying conditions) → Promotion (the specific discount rule) → Coupon (an optional code attached to a promotion to restrict usage). A promotion belongs to an experience, which belongs to a campaign. Without linking a promotion through an experience to a campaign, it will never trigger on the storefront. Coupons are always leaf nodes that restrict promotion access by requiring a code at checkout.

  8. 8. A developer is configuring price books in B2C Commerce for a site requiring tiered pricing. Which TWO statements about B2C Commerce price books are correct? Choose 2.

    • A. A site can have only one active price book assigned at a time
    • B. Price books can contain quantity break entries to support tiered bulk pricing(correct)
    • C. A list (master) price book establishes base prices while a sale price book overlays discounted prices; the platform applies the lowest applicable price(correct)
    • D. Price book entries can only be created at the Variation Product level, not on Master Products
    • E. Promotions and price books are the same system — a promotion is simply a time-limited price book

    Explanation: B2C Commerce price books support quantity break entries (quantity thresholds with corresponding prices), enabling tiered bulk pricing without promotions. A site can have multiple price books assigned — typically a list price book establishes base prices and a sale price book overlays sale prices; the platform applies the lowest applicable price. Price book entries can be set at the Master Product level and inherited by variants — they are not exclusively for Variation Products. The promotion and price book systems are separate mechanisms with different configurations and activation rules.

  9. 9. A developer needs to cache an entire SFRA controller response at the CDN/proxy level for 30 minutes, varied per locale. Which Script API call in the controller correctly sets this caching behavior?

    • A. res.cacheExpiry(30 * 60); res.varyBy('locale');
    • B. response.setExpires(30 * 60 * 1000); response.setVaryBy('locale');(correct)
    • C. req.caching.setExpiry(1800); req.caching.varyBy(['locale']);
    • D. res.setExpires(1800); res.varyBy('locale');

    Explanation: In the B2C Commerce Script API (available in controllers via the raw response object), response.setExpires() accepts a value in milliseconds — so 30 minutes is 30 * 60 * 1000 ms. response.setVaryBy() accepts a cache dimension string such as 'locale' to partition cached responses per locale. The method is called on the response object (the B2C Commerce server-side Response class), not on res — which is SFRA's middleware response wrapper and does not have setExpires(). The request object (req) does not control caching. Passing seconds instead of milliseconds (options C and D) would cause incorrect TTL behaviour.

  10. 10. A developer needs to store third-party API credentials for an integration that must be manageable by a business admin via Business Manager, without requiring a code deployment to update. Which B2C Commerce mechanism is BEST suited for this requirement?

    • A. Store the credentials in a cartridge configuration file and deploy a new code version whenever they change
    • B. Use dw.system.Site.current.getCustomPreferenceValue() backed by a Site Preference defined in Business Manager(correct)
    • C. Use CustomObjectMgr.createCustomObject() to store each credential in a Custom Object record
    • D. Store values in a Content Asset and retrieve them with ContentMgr.getContent() at runtime

    Explanation: Site Preferences (custom preferences) in B2C Commerce are the correct mechanism for storing site-specific configuration values like API keys. They are defined in metadata XML, surfaced as admin-editable fields in Business Manager under Merchant Tools > Site Preferences, and retrieved at runtime via dw.system.Site.current.getCustomPreferenceValue(). They persist independently of code versions, allowing admins to update them without deployments. Custom Objects are designed for dynamic business data, not simple key-value configuration. Content Assets serve editorial HTML/text content. Storing credentials in code requires a version push to update and is a security anti-pattern.

  11. 11. A developer integrates a third-party tax calculation service configured in Business Manager's Services framework. Which Script API class should the developer use at runtime to call the configured service from a controller?

    • A. dw.net.HTTPClient
    • B. dw.svc.ServiceRegistry(correct)
    • C. dw.svc.Service
    • D. dw.net.ServiceFactory

    Explanation: The B2C Commerce Services Framework uses ServiceRegistry.createHTTPService() (or createService() for other protocols) to retrieve a pre-configured service definition and execute a call. The ServiceRegistry provides automatic retry, circuit-breaking, logging, and mock support built into the framework. dw.net.HTTPClient is a lower-level HTTP class that bypasses the Services Framework, losing its benefits. dw.svc.Service is the abstract base class returned by the registry and should not be instantiated directly. dw.net.ServiceFactory does not exist in the B2C Commerce Script API.

  12. 12. A custom cartridge named 'app_custom' needs to override a controller from the base 'app_storefront_base' cartridge. How should the cartridge path be configured in Business Manager to ensure the override is found first?

    • A. app_storefront_base:app_custom
    • B. app_custom:app_storefront_base(correct)
    • C. app_storefront_base,app_custom
    • D. app_custom,app_storefront_base

    Explanation: In B2C Commerce, the cartridge path is searched left-to-right — the first cartridge containing a matching controller or template wins. Placing app_custom before app_storefront_base (app_custom:app_storefront_base) ensures the platform finds the custom override first. If app_storefront_base is listed first, the base cartridge files will always be found first and overrides will never be reached. Commas are not the correct cartridge path delimiter — colons separate cartridges in the cartridge path.

  13. 13. A developer wants to add custom validation to the existing SFRA Cart-SelectShipping route that runs AFTER the existing handler, without replacing it. Which server module method should be used in the overlay cartridge?

    • A. server.replace('Cart-SelectShipping', middleware)
    • B. server.get('Cart-SelectShipping', middleware)
    • C. server.prepend('Cart-SelectShipping', middleware)
    • D. server.append('Cart-SelectShipping', middleware)(correct)

    Explanation: server.append() adds custom middleware that executes AFTER the complete existing middleware chain of the named route, making it the correct choice for post-processing or validation steps that build on existing logic. server.replace() completely replaces all existing middleware — the developer would need to reimplement the original address validation from scratch. server.prepend() adds middleware that runs BEFORE the existing chain, so validation runs before the base handler. server.get() is used only for defining new routes, not modifying existing ones.

  14. 14. A developer is customizing the SFRA PlaceOrder-Submit route in an overlay cartridge to add post-processing logic that calls a third-party notification service after the base order placement logic runs. The base SFRA logic must remain intact. Which implementation is correct?

    • A. Use server.replace('PlaceOrder-Submit', function(req, res, next) { /* custom logic */ next(); })
    • B. Require module.superModule at the top of the controller file, then use server.append('PlaceOrder-Submit', function(req, res, next) { /* custom logic */ next(); })(correct)
    • C. Use server.get('PlaceOrder-Submit', function(req, res, next) { /* custom logic */ next(); })
    • D. Import the base controller using require('app_storefront_base/cartridge/controllers/PlaceOrder') and call its submit() method directly

    Explanation: The SFRA overlay cartridge pattern requires: (1) requiring module.superModule at the top of the controller file to inherit the base controller's routes into the server object; (2) using server.append() to add post-processing middleware that runs after the base route's chain completes; (3) calling next() to signal middleware chain completion. server.replace() eliminates the base PlaceOrder logic — no order would be placed. Without requiring superModule first, server.append() has no existing route to append to, resulting in a route-not-found error. server.get() creates a new GET route definition, not a modifier for an existing route.

  15. 15. A developer is building an ISML template that iterates over a product list and conditionally shows a 'Sale' badge. Which TWO ISML tags are correctly used for these specific requirements? Choose 2.

    • A. <isloop items="${pdict.products}" var="product" status="loopState"> — to iterate the product list(correct)
    • B. <isfor var="product" in="${pdict.products}"> — to iterate the product list
    • C. <isif condition="${product.price.sales}"> — to conditionally show the sale badge(correct)
    • D. <iscomponent pipeline="Product-GetPrice"> — to get the sale price inside the loop
    • E. <isinclude url="${URLUtils.url('Cart-Show')}" /> — to include the cart inside the product loop

    Explanation: isloop is the correct ISML tag for iteration, using the items attribute for the collection and var for the loop variable; the optional status attribute provides loop position information. isif evaluates a boolean condition to conditionally render markup — checking product.price.sales (whether a sale price exists) is a valid condition. isfor does not exist as a valid ISML tag in B2C Commerce. iscomponent calls a pipeline/controller to render a component but is not the standard pattern for getting a price in a loop. Using isinclude with a url attribute inside a product loop would trigger a remote HTTP sub-request per product, causing severe performance degradation.

  16. 16. An SFRA controller action needs to return structured data as JSON in response to an AJAX request from the storefront client-side JavaScript. Which response method should the developer use?

    • A. res.print(JSON.stringify(data))
    • B. res.json(data)(correct)
    • C. res.render('json', data)
    • D. res.send(JSON.stringify(data))

    Explanation: In SFRA, res.json() serializes the provided data object to JSON and sets the Content-Type header to application/json, making it the standard and correct method for AJAX JSON responses. It is the SFRA middleware response wrapper's dedicated JSON method. res.render() renders an ISML template to HTML — while a template could output JSON characters, it is not the intended pattern for AJAX data responses and does not set the correct Content-Type. res.print() and res.send() do not exist as methods on the SFRA response wrapper object.

  17. 17. A developer needs to retrieve a single product by its ID to display variation attributes and availability on a custom product detail page. Which B2C Commerce Script API approach is most appropriate?

    • A. Use dw.catalog.ProductMgr.getProduct(productId) and access the returned Product object's variationModel and availabilityModel(correct)
    • B. Use dw.catalog.ProductSearchModel to execute a keyword search for the product ID and return the first result
    • C. Use dw.catalog.CatalogMgr.getProduct(productId) to retrieve the product from the catalog
    • D. Use dw.catalog.ProductMgr.queryAllSiteProducts() and filter by product ID in an iterator loop

    Explanation: dw.catalog.ProductMgr.getProduct(productId) is the direct, performant API for retrieving a single product by its ID. Once retrieved, the Product object provides access to its variationModel (variation attributes and selected values) and availabilityModel. ProductSearchModel is designed for search result pages — it executes a full search query with significant overhead for a single-product lookup. CatalogMgr.getProduct() does not exist — CatalogMgr manages catalog and category structures, not direct product retrieval. ProductMgr.queryAllSiteProducts() iterates all products and filtering by ID in a loop is grossly inefficient.

  18. 18. A developer is building a 'Quick Add' controller that adds a product to the current shopper's cart. The shopper may or may not have an existing cart session. Which Script API call ensures a basket always exists for the add-to-cart operation?

    • A. dw.order.BasketMgr.getBasket()
    • B. dw.order.BasketMgr.createBasket()
    • C. dw.order.BasketMgr.getCurrentOrNewBasket()(correct)
    • D. dw.order.BasketMgr.getCurrentBasket()

    Explanation: getCurrentOrNewBasket() returns the shopper's current open basket if one exists, or creates a new one if not — it always returns a non-null basket, making it the correct pattern for add-to-cart operations. getBasket() and getCurrentBasket() both return the current basket or null when none exists, requiring separate null-check and creation logic. createBasket() always creates a brand-new basket regardless of whether one already exists, resulting in duplicate baskets for returning shoppers and data integrity issues.

  19. 19. A developer creates a custom payment hook and registers it in hooks.json. The hook is invoked via HookMgr.callHook('dw.order.payment', 'authorize', basket, paymentMethod, paymentData). What must the hook script export to be correctly invoked?

    • A. module.exports = { authorize: function(basket, paymentMethod, paymentData) { /* logic */ } };(correct)
    • B. exports['dw.order.payment'] = function authorize(basket, paymentMethod, paymentData) { /* logic */ };
    • C. module.exports = function(basket, paymentMethod, paymentData) { /* logic */ };
    • D. exports.callHook = function(basket, paymentMethod, paymentData) { /* logic */ };

    Explanation: When HookMgr.callHook() is invoked with method name 'authorize', the framework calls the function exported as 'authorize' on the hook script's module.exports object. The hook script must export a plain object with a method name matching the second argument to callHook(). Exporting a function directly (option C) does not provide a named 'authorize' method. The dot-notation in exports['dw.order.payment'] creates a nested property, not a top-level named export. exports.callHook uses the wrong method name — it must match the second argument to HookMgr.callHook().

  20. 20. A developer is analyzing the SFRA middleware chain: server.get('Search-Show', cache.applyDefaultCache, consentTracking.consent, server.middleware.https, controller.show). Which TWO statements accurately describe how this middleware chain executes? Choose 2.

    • A. All middleware functions execute simultaneously in parallel to improve performance
    • B. Each middleware function must call next() to pass control to the next function in the chain(correct)
    • C. If cache.applyDefaultCache calls next(new Error('fail')), subsequent middleware is skipped and SFRA's error handler is invoked(correct)
    • D. The final controller.show function should never call next() — calling it causes a duplicate response error
    • E. Middleware earlier in the chain can write to res.viewData; later middleware can read those values in the same request

    Explanation: In the SFRA middleware chain, each middleware function receives (req, res, next) and must call next() to pass control to the next function — without this call, the chain stops and no response is rendered. If next() is called with an Error argument, SFRA's error-handling middleware intercepts it and skips remaining middleware. Middleware is always sequential, not parallel. Final route handlers in SFRA typically call next() after completing — omitting it can cause the chain to stall. While res.viewData is a shared object modified across middleware, option E correctly describes that earlier middleware can set values read by later middleware, but the phrasing in this option is true.

  21. 21. In an SFRA cartridge, a developer needs to require a utility module located at cartridge/scripts/utils/StringHelper.js from within a controller. Which require() syntax is correct?

    • A. var StringHelper = require('~/cartridge/scripts/utils/StringHelper');(correct)
    • B. var StringHelper = require('./scripts/utils/StringHelper');
    • C. var StringHelper = require('cartridge/scripts/utils/StringHelper');
    • D. var StringHelper = require('dw.util.StringHelper');

    Explanation: In B2C Commerce SFRA, the tilde (~) is a special alias that resolves to the current cartridge's root directory. Using ~/cartridge/scripts/utils/StringHelper allows the module to be found correctly regardless of the file system path and participates in cartridge path resolution — an earlier cartridge on the path can override the module. Relative paths (./scripts/...) do not work reliably across the cartridge path resolution system. An absolute path without ~ is not a valid require() pattern in SFRA. dw.util.StringHelper would refer to a non-existent B2C Commerce Script API class — Script API classes are accessed directly by their dw.* namespace without require().

  22. 22. A developer wants to include a reusable product tile ISML template inside a product listing page template. The product tile is in the same cartridge and should render server-side (not as a separate HTTP sub-request). Which ISML tag and attribute is correct?

    • A. <isinclude url="${URLUtils.url('Product-Tile')}" />
    • B. <isinclude template="product/productTile" />(correct)
    • C. <ismodule template="product/productTile" name="tile" />
    • D. <iscontent type="text/html" template="product/productTile" />

    Explanation: isinclude with the template attribute performs a server-side include — the referenced ISML template is rendered inline without a separate HTTP request, making it the most efficient method. The template path is relative to the cartridge's templates directory. isinclude with the url attribute performs a remote include — it makes a separate HTTP sub-request, appropriate for independently cacheable components but with additional overhead. ismodule registers a custom ISML tag alias but does not directly render a template. iscontent outputs a stored Content Asset, not a template file.

  23. 23. A developer is rendering a Page Designer page on a custom landing page route. The page ID is retrieved from a Site Preference. Which Script API sequence correctly retrieves and renders the Page Designer page in an SFRA controller?

    • A. var page = ContentMgr.getContent(pageId); res.render('page/landingPage', { page: page });
    • B. var page = PageMgr.getPage(pageId); res.render('experience/pages/' + page.template, { page: page, regions: page.regions });
    • C. var page = PageMgr.getPage(pageId); var renderedPage = PageMgr.renderPage(page.ID, ''); res.render('experience/pages/storePage', { renderedPage: renderedPage });(correct)
    • D. var page = ContentMgr.getPageDesignerPage(pageId); res.render(page.template, page);

    Explanation: In SFRA, Page Designer pages are retrieved via PageMgr.getPage(pageId) and rendered using PageMgr.renderPage(pageID, aspectAttributes) which returns a rendered HTML string. The SFRA pattern passes this rendered string to res.render() with a wrapper template (like storePage.isml) that outputs it. Passing a regions object manually (option B) bypasses the PageMgr rendering pipeline and would not correctly render region layouts and component configurations. ContentMgr.getContent() retrieves content assets (editorial content), not Page Designer pages. ContentMgr.getPageDesignerPage() does not exist in the B2C Commerce Script API.

  24. 24. A developer wants to use the B2C Commerce Digital Data Object (DDO) layer to expose order confirmation data to client-side analytics scripts. Where should the developer populate the DDO data, and how is it accessed by client-side JavaScript?

    • A. Write DDO data directly to a JavaScript global variable in the ISML template using <script>window.dataLayer = ${JSON.stringify(pdict.order)};</script>
    • B. Populate the ddo object in the controller via res.setViewData({ ddo: data }), then access it client-side via window.ddo
    • C. Populate the ddo in the controller via the standard viewData pattern; the SFRA base layout template renders it as a JSON payload in a <script id='outer-wrapper'> tag, accessible via window.pageContext.ns.ddo(correct)
    • D. Write DDO data to a Custom Object record and read it client-side via an AJAX call to a DDO controller

    Explanation: The SFRA Digital Data Object (DDO) pattern involves populating ddo data in viewData in the controller, which the base layout template (decorators/mainTemplate.isml) serializes into a <script> block tagged with id='outer-wrapper'. Client-side JavaScript accesses this via window.pageContext.ns.ddo or the equivalent parsed JSON from that script block. Writing raw JavaScript globals in ISML (option A) is an ad-hoc pattern that bypasses the DDO framework. res.setViewData with window.ddo (option B) is not the standard SFRA DDO pattern. Custom Object AJAX reads (option D) would add unnecessary server round-trips for what should be inline page data.

  25. 25. A developer implements AJAX-based cart update in an SFRA storefront via a POST request to Cart-AddProduct. Which TWO elements are required for this AJAX pattern to work correctly? Choose 2.

    • A. The POST request must include a valid CSRF token in the request body(correct)
    • B. The Cart-AddProduct controller must return a full HTML page for all AJAX requests
    • C. The action URL must be generated server-side via URLUtils.url() in ISML and exposed to client-side JavaScript via a data attribute(correct)
    • D. Client-side JavaScript can call URLUtils.url() directly to construct the action URL at runtime
    • E. require.js must finish loading all AMD modules before the AJAX request can be initiated

    Explanation: SFRA's AJAX pattern requires: (1) a CSRF token — POST requests are CSRF-protected; the token is generated server-side via CSRF.generateToken() and passed in the request body for AJAX calls, typically via a hidden field or data attribute; (2) the controller URL must be generated server-side using URLUtils.url() in an ISML template and exposed to client JavaScript via a data attribute — client-side JavaScript cannot call URLUtils as it is a server-side B2C Commerce Script API. Cart-AddProduct returns JSON for AJAX callers (not a full HTML page) when req.isAjax() is true. require.js loading order does not block individual AJAX requests — they can be initiated once the calling module is loaded.