On your website
Embed an “Add to Wallet” button on your website with The Wallet Crew cinto SDK (Apple/Google detection + desktop fallback).
cinto is The Wallet Crew's JavaScript SDK for embedding Add to Wallet buttons on any web page. Use it to place an Add to Wallet button on any website — the SDK detects the device and renders the right call to action automatically.
On iOS, it shows Add to Apple Wallet. On Android, it shows Add to Google Wallet. On desktop, it can redirect to a hosted pass page or support a QR-based fallback.
Real-world examples
A loyalty account page shows one button for the logged-in customer card.
A gift card area shows one button per active gift card.
A ticketing page shows one button per ticket, not one button per order.

How website embed works
The integration is simple. A page loads the cinto SDK, then renders a button that resolves one pass.
That pass can be resolved in two ways:
with a known
passIdwith
externalIdentifiersand an optional HMAC
Each pass must be unique
This point is critical. A wallet pass is not a shared asset.
Each pass must represent one customer, one card, one ticket, or one entitlement instance. The button shown on a page must resolve the pass that belongs to the current context only.
For example:
a loyalty card page should resolve the current customer card
a ticket list should resolve one distinct pass per ticket
a gift card list should resolve one distinct pass per gift card
Never reuse the same static identifier value for every customer. If the same customerId, ticket id, or pass lookup value is hardcoded for all visitors, the same pass can be returned to everyone.
When externalIdentifiers are used, the identifier value must be unique enough to resolve exactly one pass. If a lookup returns several passes, the identifier strategy is not specific enough for website distribution.
What changes by device
The SDK renders the correct behavior automatically:
iOS: downloads the Apple Wallet pass
Android: opens the Google Wallet save flow
Desktop: redirects to a hosted pass page
This default can be overridden when needed with platform.
Example rendering
iOS

Android

Desktop

The desktop fallback opens a hosted pass page such as:

Desktop behavior can be customized to display a QR code instead of a standard button.
Choose how the button resolves the pass
The main implementation choice is the pass resolution method.
Use passId when the backend already knows the exact pass. Use externalIdentifiers when the website has access to a stable business identifier and the pass must be resolved dynamically.
Start with tenantId and environment
tenantId and environmentTwo SDK values are especially important:
tenantIdenvironment
tenantId is required. It is the tenant name in The Wallet Crew system. In the examples on this page, molia is the tenantId.
environment is the public base URL used by the SDK.
Use these values as follows:
Production:
https://<customDomain>the generichttps://app.neostore.cloudcan also be used when no custom domain has been configuredTesting / QA:
https://app-qa.neostore.cloud
If environment is omitted, the SDK uses https://app.neostore.cloud. This default is valid for production.
Option 1 — Resolve with passId
passIdThis is the simplest option. It works best when the backend already knows the exact pass to display.
Option 2 — Resolve with externalIdentifiers
externalIdentifiersThis option is useful when the page knows a stable business identifier, such as a loyalty id, a CRM id, or a ticket id, but does not know the passId yet.
The identifier must belong to the current customer or object. It must not be a shared constant.
When HMAC is used, the signature should be computed server-side with one of The Wallet Crew secrets.
For example, for a customerId of SC103010 and a secret of I1M8emrrJSns4Hnuibbm45eWfLQMosPGKSp1JzKsCrXeWmhjE8lZhxC2tfSRX5IJ, the HMAC value is:
8c5a9ebdd9b4ac8d2307cc34192f0faed441ef724c043162f0618784173d4d93
Reference tool: CyberChef
The HMAC secret must stay server-side. It must never be exposed in browser code.
Data attributes
Component usage
Identifier key casing in HTML
Browsers lowercase HTML attribute names. To preserve an uppercase character in an identifier key, prefix the character with _ in the attribute name.
Example:
y2.customer_Idbecomesy2.customerId
This rule only affects the HTML attribute name. It does not change the signed value.
Common behavior and options
Platform detection
When data-neostore-addToWalletButton is used, the component selects the right platform automatically:
desktopapplegoogle
To force a platform, set data-neostore-platform="desktop" or use the platform option in the component.
Language detection
The SDK uses the browser language by default. If the locale is not available, it falls back to English.
To force a language:
data attributes:
data-neostore-language="fr"component option:
language: "fr"
Vanilla Javascript example
Full options
Here is the list of full available options.
Styling
The rendered structure is:
a container provided by the website
a link with selector
.neostore-linkan image with selectors
.neostore-imgand.neostore-link-{{ platform }}
On desktop, the button can be fully customized. The key output is the hosted pass URL, so the default button can be replaced with a custom CTA or a QR code flow.
On mobile, the button should follow Apple and Google design guidelines. The branded asset, label, spacing, and overall presentation should stay compliant with each provider requirements.
Apple and Google button assets follow each provider guideline:
Desktop customization
On desktop, the most important output is the hosted pass URL. That URL can be used to render a QR code instead of the default redirect button.
Add analytics information
The button can send three source values that will be visible in the Pass:Installed event, the dashboard, and the Insights API.
tags: list of source tags.utm_sourceandutm_campaignare added automatically.medium: channel label such asecommoraccount.origin: source page URL. By default, the current page URL is used without query parameters.
All values are optional.
Retrieve passId when the pass already exists
passId when the pass already existsWhen the pass already exists, the website backend can look it up first, then render the button with the returned passId.
Third-party integration example
FAQ
Should the same button be reused for all customers?
No. The visual component can be reused, but the resolved pass must change with the current customer, ticket, or gift card context.
Should `passId` or `externalIdentifiers` be used?
Use passId when the backend already knows the exact pass. Use externalIdentifiers when the page has a stable identifier and the pass must be resolved dynamically.
Can several buttons be rendered on the same page?
Yes. This is common for ticket lists and gift card lists. Load the SDK once, then render one button per pass.
Can desktop show a QR code instead of a standard redirect?
Yes. The hosted pass URL can be used to render a QR code or another desktop-specific CTA.
When should a native app integration be used instead?
Use a native integration when the wallet flow starts inside an iOS or Android app. For that pattern, see On your mobile app.

