This sample application demonstrates how to integrate the Spreedly Web SDK into your payment flow. Use it as a reference implementation for collecting card data, recaching CVVs, processing 3D Secure authentication, handling offsite payments etc.
- Overview
- Prerequisites
- Loading the SDK
- Authentication
- Choosing an Integration
- Quick Start: Tokenize a Card
- Available Payment Flows
- Security
- Documentation
- Running the Sample App
The Spreedly Web SDK lets you collect payment card data securely without it ever touching your servers. Card numbers and CVVs are captured inside Spreedly-hosted iframes, tokenized through the Spreedly API, and returned to your page as a payment method token that you can use for transactions.
The SDK offers two integration options:
| Integration | Description | Best for |
|---|---|---|
| Hosted Fields | Individual secure input fields (card number, CVV) that you embed into your own form | Full control over form layout, styling, and UX |
| Express Checkout | A pre-built, drop-in payment form with built-in validation and styling | Quick integration with minimal front-end code |
Both options provide the same security guarantees — card data never touches your DOM.
Before integrating the SDK, you need a merchant account and then secure credentials to load the SDKs: More details on Merchant Account More details on Securing the SDK
Include the SDK via a <script> tag from the Spreedly CDN. Choose the script that matches your integration:
<script src="https://core.spreedly.com/checkout/sdk/{version}/index.js"></script><script src="https://core.spreedly.com/checkout/elements/{version}/express-checkout.js"></script>Replace {version} with:
| Channel | Description | Example |
|---|---|---|
| A specific version | Pinned release (recommended for production) | 3.0.1 |
rc |
Latest release candidate | rc |
stable |
Current stable release | stable |
The SDK uses certificate-based authentication. Each SDK initialization requires five parameters:
| Parameter | Description |
|---|---|
environment_key |
Your Spreedly environment key |
certificate_token |
Your certificate token |
nonce |
A unique value (UUID) generated per session |
timestamp |
Current UTC timestamp (seconds since epoch) |
signature |
HMAC signature of nonce + timestamp + certificate_token, signed with your private key |
const crypto = require('crypto');
app.get('/api/auth', (req, res) => {
const certificateToken = process.env.CERTIFICATE_TOKEN;
const privateKey = process.env.PRIVATE_KEY;
const environmentKey = process.env.ENVIRONMENT_KEY;
const nonce = crypto.randomUUID();
const timestamp = Math.floor(Date.now() / 1000);
const sign = crypto.createSign('SHA256');
sign.write(`${nonce}${timestamp}${certificateToken}`);
const signature = sign.sign(privateKey, 'base64');
res.json({
environment_key: environmentKey,
certificate_token: certificateToken,
nonce,
timestamp: String(timestamp),
signature,
});
});const authResponse = await fetch('/api/auth');
const authDetails = await authResponse.json();
// authDetails now contains: environment_key, certificate_token, nonce, timestamp, signature| Consideration | Hosted Fields | Express Checkout |
|---|---|---|
| Form layout | You build and control the entire form | Pre-built form provided by the SDK |
| Styling | CSS applied to field containers; input styles via SDK API | API-based customization (colors, typography, button, per-field styles) |
| PCI scope | Number and CVV in iframes; name, expiry on your page | All fields inside the iframe |
| Submission | You call sdk.submit() with form data |
User clicks submit inside the iframe |
| Render modes | Inline fields only | Embedded in a container or as a modal dialog |
For a detailed comparison, see Tokenization Overview.
<!-- 1. Container elements for the secure fields -->
<div id="card-number"></div>
<div id="cvv"></div>
<input type="text" id="first-name" placeholder="First name" />
<input type="text" id="last-name" placeholder="Last name" />
<input type="text" id="month" placeholder="MM" />
<input type="text" id="year" placeholder="YYYY" />
<button id="pay-btn">Pay</button>
<!-- 2. Load the SDK -->
<script src="https://core.spreedly.com/checkout/sdk/{version}/index.js"></script>
<script>
// 3. Fetch auth details from your backend
fetch('/api/auth')
.then(res => res.json())
.then(authDetails => {
// 4. Initialize the SDK
const sdk = new SpreedlyHostedFields(authDetails);
// 5. Listen for events
sdk.on('ready', () => {
console.log('SDK ready — fields are loaded');
});
sdk.on('tokenGenerated', (response) => {
const token = response.tokenResponse.payment_method.token;
console.log('Payment method token:', token);
// Send this token to your backend to create a transaction
});
sdk.on('error', (error) => {
console.error('Error:', error);
});
// 6. Mount the secure fields
sdk.inAppElements({
number: { containerId: 'card-number' },
cvv: { containerId: 'cvv' },
});
// 7. Submit on button click
document.getElementById('pay-btn').addEventListener('click', () => {
sdk.submit({
first_name: document.getElementById('first-name').value,
last_name: document.getElementById('last-name').value,
month: document.getElementById('month').value,
year: document.getElementById('year').value,
});
});
});
</script><!-- 1. Container for the payment form -->
<div id="checkout-container"></div>
<!-- 2. Load the SDK -->
<script src="https://core.spreedly.com/checkout/elements/{version}/express-checkout.js"></script>
<script>
// 3. Fetch auth details from your backend
fetch('/api/auth')
.then(res => res.json())
.then(authDetails => {
// 4. Initialize the SDK
const sdk = new SpreedlyExpressCheckout(authDetails);
// 5. Listen for events
sdk.on('ready', () => {
console.log('SDK ready — form is loaded');
});
sdk.on('tokenGenerated', (response) => {
const token = response.tokenResponse.payment_method.token;
console.log('Payment method token:', token);
// Send this token to your backend to create a transaction
});
sdk.on('error', (error) => {
console.error('Error:', error);
});
// 6. Mount the payment form
sdk.expressCheckout({
parentContainerId: 'checkout-container',
});
});
</script>This sample app demonstrates the following payment flows:
| Flow | Description | Documentation |
|---|---|---|
| Tokenize a Card | Collect card details and create a payment method token | Hosted Fields Guide, Express Checkout Guide |
| Recache CVV | Update the CVV for a previously retained payment method | Recaching Guide |
| Purchase with 3DS (Global) | Purchase with Spreedly-managed 3D Secure authentication | 3DS Global Guide |
| Purchase with 3DS (Gateway Specific) | Purchase with gateway-managed 3D Secure | 3DS Gateway Specific Guide |
| Offsite Payments | PayPal, PIX, Boleto via transparent redirect or API | General Offsite Guide |
| Braintree APM | PayPal and Venmo via Braintree | Braintree Guide |
| Stripe APM | iDEAL, Bancontact, SEPA via Stripe | Stripe APM Guide |
When integrating the SDK into your production application:
- Use SRI (Subresource Integrity) — Always include the
integrityattribute when loading the SDK script to verify the file hasn't been tampered with. SRI hashes are published with each release. - Configure CSP (Content Security Policy) — Allow
frame-src,script-src, andconnect-srcforhttps://core.spreedly.com. - Serve over HTTPS — The SDK requires a secure context.
- Never expose your private key — Auth credentials (
nonce,timestamp,signature) must be generated on your backend.
<script
src="https://core.spreedly.com/checkout/sdk/{version}/index.js"
integrity="sha384-{HASH_FROM_SRI_MANIFEST}"
crossorigin="anonymous"
></script>| Document | Description |
|---|---|
| Tokenization Overview | Compare Hosted Fields vs Express Checkout |
| 3DS Overview | Compare Global vs Gateway Specific 3DS |
| Offsite Payments Overview | Compare General, Braintree APM, and Stripe APM |
| Testing Guide | Test card numbers and how to verify each flow |
- Clone the repository:
git clone <repository-url>
cd web-sdk-sample-app- Install dependencies:
npm install- Start the development server:
npm run build
npm run start- Open
http://localhost:3000in your browser.
- The landing page lets you choose between Hosted Fields and Express Checkout.
- Select a payment flow (tokenize, recache, purchase, 3DS, offsite)
- The app loads the appropriate SDK and renders the chosen flow
- Auth credentials are fetched from the sample app's backend (
/api/v1/auth/params) - Results (tokens, errors, transaction details) are displayed in the UI
| Card Type | Number | CVV | Expiry |
|---|---|---|---|
| Visa | 4111111111111111 | 123 | Any future date |
| Mastercard | 5555555555554444 | 123 | Any future date |
| American Express | 378282246310005 | 1234 | Any future date |
For a complete list of test data, see Spreedly Test Data.
- Support Home: Troubleshoot
- Help Center: Submit a request
- Security Issues: See Security Document