Salesforce Commerce Cloud (SFCC)
Add Apple Wallet and Google Wallet “Add to Wallet” buttons to a Salesforce Commerce Cloud storefront using a cartridge, server-side HMAC signing, and The Wallet Crew cinto SDK.
This integration explains how to add a unique “Add to Wallet” button to a Salesforce Commerce Cloud storefront. Common placements are the My Account area (loyalty or membership pass) and authenticated pages where a stable identifier is available (for example a gift card list). Pick & collect pages can also be a fit when a pickup pass is used as an in-store scan token.

A stable identifier available in the customer session is signed server-side, then passed to The Wallet Crew cinto SDK as an external identifier. This keeps the identifier exchange tamper-proof and avoids exposing secrets in storefront code.
Real-world examples
A loyalty program renders “Add to Wallet” in My Account for logged-in customers.
A gift card program renders one button per active gift card in the account wallet.
A pick & collect flow renders a pickup pass CTA on a dedicated pickup page, using a pickup reference as identifier.
For generic cinto SDK usage (pass id mode, platform detection, desktop QR customization), see On your website.
SFCC concepts used in this integration
Salesforce Commerce Cloud storefront code is packaged and deployed as cartridges. A cartridge can add controllers, scripts, templates, and configuration metadata, then be plugged into a site by adding it to the cartridge path.
This guide assumes one dedicated cartridge is created for The Wallet Crew integration, typically named like int_TheWalletCrew. The cartridge is then referenced by:
the storefront application (SFRA or SiteGenesis)
Business Manager configuration (site preferences and, optionally, custom objects)
Cartridge
A cartridge is the unit of deployment in SFCC. Cartridge order matters because SFCC resolves templates and scripts by scanning the cartridge path from left to right.
SFRA vs SiteGenesis
Both architectures can support the integration:
SFRA: controllers and ISML templates. The button is usually added in an account template or a remote include.
SiteGenesis: pipelines (legacy) and ISML templates. The button is usually added in a pipeline-rendered account page.
The security model stays identical. The HMAC is computed server-side and never in browser JavaScript.
How it works
The Wallet Crew cinto SDK renders the correct CTA based on device.
On iOS, the button downloads an Apple Wallet pass. On Android, it opens Google Wallet. On desktop, the SDK redirects to a hosted pass page that can be scanned or opened on mobile.
In this SFCC setup, the pass is retrieved using:
a pass type (example:
user)a stable SFCC identifier sent as an external identifier (example:
sfcc.customerNo)an HMAC signature that proves the identifier was issued by the Brand backend
The HMAC must be computed server-side. It must not be generated in the browser.
Prerequisites
A pass template and pass issuance already configured in The Wallet Crew.
The Wallet Crew tenant id available (used by the SDK script URL).
A stable identifier available on authenticated pages, such as:
SFCC
CustomerNo(typical for loyalty cards)pickup reference (typical for pick & collect pickup passes)
gift card id (when gift cards are stored in SFCC or a connected system)
The external identifier key name agreed during onboarding (example:
sfcc.customerNo).
Implement the integration as a cartridge
The typical pattern is:
Read the identifier in SFCC server-side code.
Compute an HMAC with the tenant secret.
Render a cinto container in the ISML template with identifier + HMAC.
Load the cinto SDK from
sdk.neostore.cloud.
Add the cartridge to the cartridge path
After deploying the integration cartridge to the instance, add it to the site’s cartridge path in Business Manager. The cartridge should be placed before the base storefront cartridge so overrides resolve correctly.
Exact Business Manager menu labels vary by SFCC version. The key point is the site-level cartridge path (not the global one).
Store tenant configuration as site preferences
Tenant values and secrets should remain server-side. In SFCC, this is typically done with custom site preferences.
At minimum, these values are usually required.
Recommended preferences (IDs, types, examples)
These values are typically created as site-level custom preferences (not organization-level).
theWalletCrewTenantId(String) Example:moliatheWalletCrewHmacSecret(Password) Example:I1M8emrrJSns4Hnuibbm45eWfLQMosPGKSp1JzKsCrXeWmhjE8lZhxC2tfSRX5IJtheWalletCrewDefaultPassType(String) Example:usertheWalletCrewExternalIdentifierKey(String) Example:sfcc.customerNotheWalletCrewLanguage(String, optional) Example:frWhen omitted, cinto uses browser language detection.
Keeping the secret as a Password preference helps prevent accidental disclosure in UI exports and screenshots.
The HMAC secret must not be stored in templates, content assets, or any client-side configuration.
Compute the HMAC server-side
SFCC server-side scripts can compute a SHA-256 HMAC using the tenant secret and the exact identifier value.
Common implementation choices:
a helper script exposed by the cartridge, used by account controllers
a decorator pattern that enriches the view model with
identifierandidentifierHmac
Caching must be handled carefully. Customer-specific pages should not share cached HTML across customers when the identifier is embedded in the markup.
Render the “Add to Wallet” button in ISML
The cinto SDK relies on:
one SDK loader script referencing the tenant id
one container element marked as an “Add to Wallet” button
a
passTypean external identifier key/value pair plus the server-side HMAC
The integration cartridge typically provides an ISML partial that can be included where needed (account dashboard, gift card list, pick & collect page).
External identifier conventions (casing + escaping)
The cinto SDK can retrieve a pass from an external identifier:
passType(example:user)externalIdentifier.key(example:sfcc.customerNo)externalIdentifier.value(example:00012345)externalIdentifier.hmac(HMAC-SHA256 of the value)
Recommended key naming convention
The most stable option is to avoid mixed case in identifier keys.
Keys are typically:
namespaced with a prefix like
sfcc.lowercase
using
_as separator when needed
Examples:
sfcc.customer_nosfcc.pickup_refsfcc.gift_card_id
If The Wallet Crew tenant is already configured with a mixed-case key, changing it can impact existing installations. A key naming change should be treated as a migration topic.
If a mixed-case key must be used in HTML attributes
Browsers treat HTML attribute names as lower case. cinto supports an escaping rule for uppercase characters in data-neostore-externalIdentifiers-... attributes:
Prefix an uppercase character with
_in the attribute name.y2.customer_Idis interpreted asy2.customerId.
Applied to SFCC examples:
Identifier key in The Wallet Crew:
sfcc.customerNoIdentifier key in HTML attributes:
sfcc.customer_No
This only affects the attribute name, not the signed value.
Copy/paste SFRA reference implementation (controller + ISML partial)
This reference implementation uses:
site preferences to store tenant configuration
a server-side HMAC helper
a remote include controller that renders an ISML partial
It is designed to be pasted into a dedicated cartridge (example: int_TheWalletCrew) and called from an account page.
Cartridge file layout
cartridge/scripts/TheWalletCrew/hmac.jscartridge/controllers/TheWalletCrew.jscartridge/templates/default/TheWalletCrew/addToWalletButton.isml
1) HMAC helper (cartridge/scripts/TheWalletCrew/hmac.js)
cartridge/scripts/TheWalletCrew/hmac.js)2) Controller (cartridge/controllers/TheWalletCrew.js)
cartridge/controllers/TheWalletCrew.js)This controller renders a widget that is safe to include as a remote include.
3) ISML partial (cartridge/templates/default/TheWalletCrew/addToWalletButton.isml)
cartridge/templates/default/TheWalletCrew/addToWalletButton.isml)The script loader must be included once per page. When several buttons are rendered on the same page, move the loader into a shared footer partial and keep only the <div data-neostore-addToWalletButton ...> markup in the widget template.
4) Include the widget in an account template
In SFRA, remote includes are commonly used to avoid polluting the main controller and to keep caching explicit.
Content Security Policy (CSP)
Some SFCC storefronts enforce a Content Security Policy that blocks third-party scripts by default. If the SDK script is blocked, allowlisting https://sdk.neostore.cloud for script-src is required.
In SFRA projects, CSP is often managed via middleware and response headers. The change should follow the project’s existing CSP strategy (report-only vs enforced).
Validate the result
Validation typically covers platform rendering and pass installation.
On iOS Safari, the CTA should display Add to Apple Wallet.
On Android Chrome, the CTA should display Add to Google Wallet.
On desktop, the CTA should redirect to a hosted pass page.
After installation, the pass should be visible in Apple Wallet or Google Wallet.
Troubleshooting
The button does not render
Common causes are a blocked SDK script (CSP) or missing markup. The rendered page should contain the SDK loader and the cinto container element.
Clicking the button leads to an error
This usually means the external identifier or HMAC does not match what The Wallet Crew expects. Confirm:
the external identifier key name matches the one configured for SFCC (example:
sfcc.customerNo)the identifier value matches exactly what is signed server-side (no trimming, formatting, or type changes)
the HMAC was computed with the correct tenant secret
The button renders for the wrong customer
This typically indicates HTML caching across sessions. Ensure that:
customer-specific pages are not cached at page level
remote includes used for account widgets are not cached across customers
any CDN layer respects session cookies for authenticated pages
FAQ
What is a cartridge in SFCC?
A cartridge is the deployable unit that contains storefront code and metadata. The site’s cartridge path defines which cartridges are active and in which order they are resolved.
Which identifier works best for loyalty cards?
The SFCC customer number (CustomerNo) is commonly used because it is stable and available on authenticated pages. A CRM id can also be used if it is persisted on the profile and stays stable over time.
Where should the tenant secret be stored in SFCC?
Custom site preferences are typically used because they stay server-side and can be managed per site. The secret should never be exposed in templates, content assets, or browser JavaScript.
Last updated

