Replace Processor iFrames
Own your card data by replacing processor iFrames with modern agnostic elements.When handling payments, merchants often rely on processor-specific iFrames to collect cardholder data securely. However, this approach can lead to vendor lock-in, limiting flexibility and control over payment processing. To future-proof their business, merchants need a solution that enables seamless processor switching and true data ownership. Basis Theory empowers businesses to replace processor iFrames with vault-agnostic secure elements, unlocking greater freedom and scalability.
In this guide, you'll learn how to set up Basis Theory SDKs to capture cards in a frontend application, Web or Mobile, and securely store the cardholder data as flexible and agnostic token intents within your Basis Theory vault.
Alternative/Local Payment Methods
This guide focuses on replacing processor iFrames for collecting cardholder data using agnostic secure elements. If you need to tokenize other credential types, refer to the links below:
If you also support alternative and local payment methods (APMs/LPMs) like SEPA, iDEAL, Boleto, and WeChat Pay, you can remove tokenizable payment methods (such as cards) from your PSP’s frontend components while keeping non-tokenizable options as-is.
Getting Started
To get started, you will need to create a Basis Theory Account and a TEST Tenant.
Public Application
You will need a Public Application for your frontend. Click here to create one using the Basis Theory Customer Portal.
This will create an application with the following Access Controls:
- Permissions:
token-intent:create
Configure Elements SDK
Basis Theory Elements are available for the following technologies. Click below for detailed instructions on how to install and configure them.
Add Card Elements to your Page
Once installed and configured, add the Card Elements to your application. This will enable your users to type in their card data in your form, while ensuring your systems never come in contact with the data.
CardElement
with Javascript or React.- JavaScript
- React
- iOS
- Android
- React Native
<div id="cardNumber"></div>
<div style="display: flex;">
<div id="cardExpirationDate" style="width: 100%;"></div>
<div id="cardVerificationCode" style="width: 100%;"></div>
</div>
import { basistheory } from '@basis-theory/web-elements';
let bt;
let cardNumberElement;
let cardExpirationDateElement;
let cardVerificationCodeElement;
async function init() {
bt = await basistheory('<API_KEY>');
// Creates Elements instances
cardNumberElement = bt.createElement('cardNumber', {
targetId: 'myCardNumber' // (custom) used for tracking validation errors
});
cardExpirationDateElement = bt.createElement('cardExpirationDate', {
targetId: 'myCardExpiration'
});
cardVerificationCodeElement = bt.createElement('cardVerificationCode', {
targetId: 'myCardVerification'
});
// Mounts Elements in the DOM in parallel
await Promise.all([
cardNumberElement.mount('#cardNumber'),
cardExpirationDateElement.mount('#cardExpirationDate'),
cardVerificationCodeElement.mount('#cardVerificationCode'),
]);
// Binds card brand to verification code element
cardNumberElement.on('change', ({ cardBrand }) => {
cardVerificationCodeElement.update({ cardBrand });
});
}
init();
import React, { useRef, useState } from 'react';
import {
BasisTheoryProvider,
CardNumberElement,
CardExpirationDateElement,
CardVerificationCodeElement,
useBasisTheory,
} from '@basis-theory/react-elements';
export default function App() {
const { bt } = useBasisTheory('<PUBLIC_API_KEY>');
// Refs to get access to the Elements instance
const cardNumberRef = useRef(null);
const cardExpirationRef = useRef(null);
const cardVerificationRef = useRef(null);
// stores the current card brand in state, to pass to CardVerificationCodeElement
const [cardBrand, setCardBrand] = useState();
return (
<BasisTheoryProvider bt={bt}>
<CardNumberElement
id="myCardNumber"
ref={cardNumberRef}
onChange={({ cardBrand }) => setCardBrand(cardBrand)}
/>
<div style={{ display: 'flex' }}>
<div style={{ width: "100%" }}>
<CardExpirationDateElement
id="myCardExpiration"
ref={cardExpirationRef}
/>
</div>
<div style={{ width: "100%" }}>
<CardVerificationCodeElement
id="myCardVerification"
ref={cardVerificationRef}
cardBrand={cardBrand}
/>
</div>
</div>
</BasisTheoryProvider>
);
}
Implementation snippets are coming soon.
Please check our SDKs for examples.
Implementation snippets are coming soon.
Please check our SDKs for examples.
import React, { useRef } from "react";
import { Button, SafeAreaView, ScrollView, StatusBar, StyleSheet, View } from "react-native";
import type { BTRef } from "@basis-theory/react-native-elements";
import {
CardNumberElement,
CardExpirationDateElement,
CardVerificationCodeElement,
useBasisTheory
} from "@basis-theory/react-native-elements";
const App = (): JSX.Element => {
const { bt } = useBasisTheory('<PUBLIC_API_KEY>');
// Refs to get access to the Elements instance
const cardNumberRef = useRef<BTRef>(null);
const cardExpirationDateRef = useRef<BTRef>(null);
const cardVerificationCodeRef = useRef<BTRef>(null);
return (
<SafeAreaView>
<StatusBar />
<ScrollView contentInsetAdjustmentBehavior="automatic">
<View style={styles.viewContainer}>
<CardNumberElement btRef={cardNumberRef} placeholder="Card Number" style={styles.elements} />
<CardExpirationDateElement btRef={cardExpirationDateRef} placeholder="Card Expiration Date" style={styles.elements} />
<CardVerificationCodeElement btRef={cardVerificationCodeRef} placeholder="CVC" style={styles.elements} />
</View>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
cardNumber: {
backgroundColor: "#eeeeee",
borderColor: "blue",
borderWidth: 2,
color: "purple",
height: 40,
margin: 12,
padding: 10,
},
viewContainer: {
display: "flex",
flexDirection: "column",
marginTop: 32,
},
});
export default App;
Tokenization
Now that you are securely capturing the cardholder data in your user-facing application(s), it is time to post it to create a Token Intent, which temporarily stores the card information and can be later converted to a long-term Token.
To do this, we will invoke the Create Token Intent endpoint from the SDK, passing the Card Elements as data points in the payload. This will securely create a card
token intent by transferring the card information from the frontend Elements to the Basis Theory API, where the data will be strongly encrypted and stored in a compliant environment.
Add a submit function along with a button to trigger it:
- JavaScript
- React
- iOS
- Android
- React Native
<div id="cardNumber"></div>
<div style="display: flex;">
<div id="cardExpirationDate" style="width: 100%;"></div>
<div id="cardVerificationCode" style="width: 100%;"></div>
</div>
<button id="submit">Submit</button>
import { BasisTheory } from '@basis-theory/basis-theory-js';
let bt;
let cardNumberElement;
let cardExpirationDateElement;
let cardVerificationCodeElement;
async function init () {
...
document.getElementById("submit").addEventListener("click", submit);
}
async function submit () {
try {
const intent = await bt.tokenIntents.create({
type: 'card',
data: {
number: cardNumberElement,
expiration_month: cardExpirationDateElement.month(),
expiration_year: cardExpirationDateElement.year(),
cvc: cardVerificationCodeElement,
}
});
// TODO post the intent object to your backend
} catch (error) {
console.error(error);
}
}
init();
import React, { useRef, useState } from 'react';
import {
BasisTheoryProvider,
CardNumberElement,
CardExpirationDateElement,
CardVerificationCodeElement,
useBasisTheory,
} from '@basis-theory/basis-theory-react';
export default function App() {
const { bt } = useBasisTheory('<PUBLIC_API_KEY>');
// Refs to get access to the Elements instance
const cardNumberRef = useRef(null);
const cardExpirationRef = useRef(null);
const cardVerificationRef = useRef(null);
// stores the current card brand in state, to pass to CardVerificationCodeElement
const [cardBrand, setCardBrand] = useState();
const submit = async () => {
try {
const intent = await bt?.tokenIntents.create({
type: 'card',
data: {
number: cardNumberRef.current,
expiration_month: cardExpirationRef.current.month(),
expiration_year: cardExpirationRef.current.year(),
cvc: cardVerificationRef.current,
}
});
// TODO post the intent object to your backend
} catch (error) {
console.error(error);
}
}
return (
<BasisTheoryProvider bt={bt}>
...
<button onClick={submit}>Submit</button>
</BasisTheoryProvider>
);
}
Implementation snippets are coming soon.
Please check our SDKs for examples.
Implementation snippets are coming soon.
Please check our SDKs for examples.
import React, { useRef } from "react";
import { Button, SafeAreaView, ScrollView, StatusBar, StyleSheet, View } from "react-native";
import type { BTRef } from "@basis-theory/react-native-elements";
import {
CardNumberElement,
CardExpirationDateElement,
CardVerificationCodeElement,
useBasisTheory
} from "@basis-theory/react-native-elements";
const App = (): JSX.Element => {
const { bt } = useBasisTheory('<PUBLIC_API_KEY>');
// Refs to get access to the Elements instance
const cardNumberRef = useRef<BTRef>(null);
const cardExpirationDateRef = useRef<BTRef>(null);
const cardVerificationCodeRef = useRef<BTRef>(null);
const submit = async () => {
try {
const intent = await bt?.tokenIntents.create({
type: 'card',
data: {
number: cardNumberRef.current,
expiration_month: cardExpirationRef.current.month(),
expiration_year: cardExpirationRef.current.year(),
cvc: cardVerificationRef.current,
}
});
// TODO post the intent object to your backend
} catch (error) {
console.error(error);
}
}
return (
<SafeAreaView>
<StatusBar />
<ScrollView contentInsetAdjustmentBehavior="automatic">
<View style={styles.viewContainer}>
<CardNumberElement btRef={cardNumberRef} placeholder="Card Number" style={styles.elements} />
<CardExpirationDateElement btRef={cardExpirationDateRef} placeholder="Card Expiration Date" style={styles.elements} />
<CardVerificationCodeElement btRef={cardVerificationCodeRef} placeholder="CVC" style={styles.elements} />
</View>
<Button onPress={submit} title="Submit" />
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
cardNumber: {
backgroundColor: "#eeeeee",
borderColor: "blue",
borderWidth: 2,
color: "purple",
height: 40,
margin: 12,
padding: 10,
},
viewContainer: {
display: "flex",
flexDirection: "column",
marginTop: 32,
},
});
export default App;
The created Token Intent is a short-lived tokenized card
object which carries only non-sensitive information following the Token Intent Object specification:
{
"id": "d2cbc1b4-5c3a-45a3-9ee2-392a1c475ab4",
"type": "card",
"tenant_id": "4aee08b9-5557-474b-a120-252e01fc7b0f",
"fingerprint": "BKJYqf2tcvhTHSXN7EvBJLviN3PBYRgwoJgce8VAfnSr",
"card": {
"bin": "424242",
"last4": "4242",
"expiration_month": 10,
"expiration_year": 2028,
"brand": "visa",
"funding": "credit",
"authentication": "sca_required",
"issuer_country": {
"alpha2": "GB",
"name": "UNITED KINGDOM OF GREAT BRITAIN AND NORTHERN IRELAND",
"numeric": "826"
}
},
"created_by": "0bc89db5-fadd-4d57-af93-10472e35ebd3",
"created_at": "2025-03-10T14:23:56.5580574+00:00",
"expires_at": "2025-03-11T14:23:56.5580575+00:00"
}
Authentication
Once the Token Intent has been created, merchants may need to authenticate the cardholder to comply with PSD2’s Strong Customer Authentication (SCA) requirements and reduce fraud. The specific authentication steps depend on the card’s region, issuer requirements, and the merchant’s risk strategy.
3D Secure
3D Secure (3DS) is the standard protocol for meeting PSD2 SCA requirements in Europe and enhancing fraud prevention globally. It introduces an additional verification step, such as a one-time password (OTP) or biometric authentication. SCA exemptions may apply for certain transactions, such as low-risk or merchant-initiated payments. Implementing 3DS2 ensures compliance while keeping checkout friction minimal.
if (intent.card.authentication === 'sca_required') {
// trigger the 3DS authentication flow
}
Next Steps
Now that you’ve replaced processor iFrames with agnostic secure elements, the next step is to process payments using your newly tokenized card data. Check out the following guides to complete your integration:
- Verify a Card – Ensure the card is valid by performing a $0 auth.
- Charge a Card – Process a payment using the stored token.