- Web
- Android
- iOS
Primer Checkout Web uses two types of configuration: component properties (HTML attributes) and SDK options (JavaScript object).
Copy
Ask AI
const checkout = document.querySelector('primer-checkout');
// Component properties - use setAttribute()
checkout.setAttribute('client-token', 'your-token');
// SDK options - assign directly
checkout.options = {
locale: 'en-GB',
card: { cardholderName: { required: true } }
};
The Android SDK uses
PrimerSettings to configure checkout behavior. Pass it when creating the checkout controller:Copy
Ask AI
val checkout = rememberPrimerCheckoutController(
clientToken = clientToken,
settings = PrimerSettings().apply {
locale = Locale("fr", "FR")
uiOptions.dismissalMechanism = listOf(DismissalMechanism.CLOSE_BUTTON)
},
)
The iOS SDK uses
PrimerSettings and PrimerCheckoutTheme to configure checkout behavior and appearance. Pass them when creating PrimerCheckout:Copy
Ask AI
PrimerCheckout(
clientToken: clientToken,
primerSettings: PrimerSettings(paymentHandling: .auto),
primerTheme: PrimerCheckoutTheme(
colors: ColorOverrides(primerColorBrand: .blue)
)
)
Configuration Overview
- Web
- Android
- iOS
| Type | How to Set | Examples |
|---|---|---|
| Component Properties | setAttribute() | client-token, custom-styles, loader-disabled |
| SDK Options | Direct assignment to .options | locale, card, vault, applePay |
Don’t mix them up. Component properties must use
setAttribute(). SDK options must be assigned directly to .options.| Type | How to Set | Examples |
|---|---|---|
| Client token | rememberPrimerCheckoutController(clientToken) | Authentication token |
| Settings | PrimerSettings object | locale, uiOptions, paymentMethodOptions, debugOptions |
| Theme | PrimerTheme parameter on composable | PrimerCheckoutSheet(theme = ...) |
Theming is not part of
PrimerSettings. Pass PrimerTheme directly to PrimerCheckoutSheet or PrimerCheckoutHost. See Styling Guide.| Type | How to Set | Examples |
|---|---|---|
| Client token | PrimerCheckout(clientToken:) | Authentication token |
| Settings | PrimerSettings parameter | paymentHandling, uiOptions, paymentMethodOptions |
| Theme | PrimerCheckoutTheme parameter | colors, radius, spacing, typography |
Theming is not part of
PrimerSettings. Pass PrimerCheckoutTheme as a separate parameter to PrimerCheckout or PrimerCheckoutPresenter. See Styling Guide.Component Properties / Client Token
The client token authenticates your checkout session. Obtain this by creating a client session.- Web
- Android
- iOS
client-token (required)
Copy
Ask AI
// ✅ Correct
checkout.setAttribute('client-token', 'your-client-token');
// ❌ Wrong - won't work
checkout.clientToken = 'your-token';
Copy
Ask AI
<!-- Or set directly in HTML -->
<primer-checkout client-token="your-client-token"></primer-checkout>
custom-styles
JSON string containing CSS variables for theming.Copy
Ask AI
const styles = {
primerColorBrand: '#4a6cf7',
primerTypographyBrand: 'Inter, sans-serif'
};
checkout.setAttribute('custom-styles', JSON.stringify(styles));
See Styling Guide for available properties.
loader-disabled
Disables the default loading spinner.Copy
Ask AI
checkout.setAttribute('loader-disabled', 'true');
Pass the client token directly when creating the checkout controller:
Copy
Ask AI
val checkout = rememberPrimerCheckoutController(
clientToken = clientToken,
)
Pass the client token directly when creating
PrimerCheckout:Copy
Ask AI
// SwiftUI
PrimerCheckout(clientToken: clientToken)
// UIKit
PrimerCheckoutPresenter.presentCheckout(
clientToken: clientToken,
from: viewController,
primerSettings: PrimerSettings(),
primerTheme: PrimerCheckoutTheme()
)
SDK Options / Settings
- Web
- Android
- iOS
SDK options configure checkout behavior. Assign a JavaScript object directly to the
options property.Copy
Ask AI
// ✅ Correct - assign directly
checkout.options = {
locale: 'en-GB',
card: { cardholderName: { required: true } }
};
// ❌ Wrong - don't use setAttribute for options
checkout.setAttribute('options', JSON.stringify({...}));
For the complete list of available options, see the SDK Options Reference.
PrimerSettings configures the SDK behavior for a checkout session. Pass it when creating the controller.Copy
Ask AI
val checkout = rememberPrimerCheckoutController(
clientToken = clientToken,
settings = PrimerSettings().apply {
locale = Locale("fr", "FR")
uiOptions.dismissalMechanism = listOf(DismissalMechanism.CLOSE_BUTTON)
paymentMethodOptions.redirectScheme = "myapp"
},
)
For the complete list of available options, see the SDK Options Reference.
PrimerSettings configures the SDK behavior for a checkout session. Pass it when creating PrimerCheckout.Copy
Ask AI
let settings = PrimerSettings(
paymentHandling: .auto,
uiOptions: PrimerUIOptions(),
paymentMethodOptions: PrimerPaymentMethodOptions()
)
PrimerCheckout(
clientToken: clientToken,
primerSettings: settings
)
For the complete list of available options, see the SDK Options Reference.
Common Patterns
- Web
- Android
- iOS
Set Locale
Copy
Ask AI
checkout.options = {
locale: 'en-GB'
};
Supported locales
Enable Specific Payment Methods
Copy
Ask AI
import { PaymentMethodType } from '@primer-io/primer-js';
checkout.options = {
enabledPaymentMethods: [
PaymentMethodType.PAYMENT_CARD,
PaymentMethodType.PAYPAL,
PaymentMethodType.ADYEN_BLIK
]
};
Pre-fill Cardholder Name
Copy
Ask AI
checkout.options = {
card: {
cardholderName: {
required: true,
visible: true,
defaultValue: 'John Doe'
}
}
};
primer.setCardholderName() instead.Enable Vault (Saved Payment Methods)
Copy
Ask AI
checkout.options = {
vault: {
enabled: true
}
};
Configure Apple Pay Button
Copy
Ask AI
checkout.options = {
applePay: {
buttonType: 'buy',
buttonStyle: 'black'
}
};
Configure Google Pay Button
Copy
Ask AI
checkout.options = {
googlePay: {
buttonType: 'buy',
buttonColor: 'black',
captureBillingAddress: true
}
};
Set Locale
Copy
Ask AI
settings = PrimerSettings().apply {
locale = Locale("fr", "FR")
}
Locale.getDefault() (device locale). Controls SDK-internal strings and currency formatting.Custom Success/Error Screens
Replace the default success and error screens with your own composables via slot parameters:Copy
Ask AI
PrimerCheckoutSheet(
checkout = checkout,
success = { checkoutData ->
MyCustomSuccessScreen(checkoutData)
},
error = { error ->
MyCustomErrorScreen(error)
},
)
Configure Dismissal Behavior
Copy
Ask AI
settings = PrimerSettings().apply {
uiOptions.dismissalMechanism = listOf(DismissalMechanism.CLOSE_BUTTON)
}
| Value | Behavior |
|---|---|
GESTURES | Swipe-to-dismiss (default) |
CLOSE_BUTTON | Explicit close button |
listOf(DismissalMechanism.GESTURES, DismissalMechanism.CLOSE_BUTTON).Configure Google Pay
Copy
Ask AI
settings = PrimerSettings().apply {
paymentMethodOptions.googlePayOptions = PrimerGooglePayOptions(
merchantName = "My Store",
captureBillingAddress = true,
emailAddressRequired = true,
buttonStyle = GooglePayButtonStyle.BLACK,
)
}
Set Redirect Scheme
Required for redirect-based payment methods (PayPal, Klarna, etc.):Copy
Ask AI
settings = PrimerSettings().apply {
paymentMethodOptions.redirectScheme = "myapp"
}
Set Payment Handling
Copy
Ask AI
let settings = PrimerSettings(paymentHandling: .auto)
| Value | Behavior |
|---|---|
.auto | Primer handles the full payment flow (recommended) |
.manual | Primer returns a token for server-side processing |
Customize Splash and Error Screens
Handle results yourself instead of showing the SDK’s built-in screens:Copy
Ask AI
PrimerCheckout(
clientToken: clientToken,
scope: { checkoutScope in
checkoutScope.splashScreen = {
AnyView(ProgressView("Loading..."))
}
checkoutScope.errorScreen = { message in
AnyView(Text(message).foregroundColor(.red))
}
}
)
Configure Theme Colors
Copy
Ask AI
let theme = PrimerCheckoutTheme(
colors: ColorOverrides(
primerColorBrand: .blue,
primerColorBackground: .white
)
)
Handle Completion
Copy
Ask AI
PrimerCheckout(
clientToken: clientToken,
onCompletion: { state in
switch state {
case .success(let result):
print("Payment: \(result.payment?.id ?? "")")
case .failure(let error):
print("Failed: \(error.errorId)")
case .dismissed:
print("Dismissed")
default:
break
}
}
)
Complete Example
- Web
- Android
- iOS
Copy
Ask AI
import { PaymentMethodType } from '@primer-io/primer-js';
const checkout = document.querySelector('primer-checkout');
// 1. Component properties
checkout.setAttribute('client-token', 'your-client-token');
checkout.setAttribute('custom-styles', JSON.stringify({
primerColorBrand: '#4a6cf7'
}));
// 2. SDK options
checkout.options = {
locale: 'en-GB',
enabledPaymentMethods: [
PaymentMethodType.PAYMENT_CARD,
PaymentMethodType.PAYPAL
],
card: {
cardholderName: {
required: true,
visible: true
}
},
vault: {
enabled: true
}
};
Copy
Ask AI
@Composable
fun CheckoutScreen(clientToken: String) {
val checkout = rememberPrimerCheckoutController(
clientToken = clientToken,
settings = PrimerSettings().apply {
locale = Locale("fr", "FR")
uiOptions.dismissalMechanism = listOf(DismissalMechanism.CLOSE_BUTTON)
paymentMethodOptions.redirectScheme = "myapp"
paymentMethodOptions.googlePayOptions = PrimerGooglePayOptions(
merchantName = "My Store",
captureBillingAddress = true,
)
},
)
PrimerCheckoutSheet(
checkout = checkout,
success = { checkoutData -> MySuccessScreen(checkoutData) },
error = { error -> MyErrorScreen(error) },
onEvent = { event ->
when (event) {
is PrimerCheckoutEvent.Success -> navigateToConfirmation(event.checkoutData)
is PrimerCheckoutEvent.Failure -> {
Log.e("Checkout", "Failed: ${event.error.description}")
}
}
},
onDismiss = {
navigateBack()
},
)
}
Copy
Ask AI
private let primerSettings = PrimerSettings(paymentHandling: .auto)
private let primerTheme = PrimerCheckoutTheme(
colors: ColorOverrides(primerColorBrand: .blue),
radius: RadiusOverrides(primerRadiusMedium: 12)
)
struct CheckoutView: View {
let clientToken: String
var body: some View {
PrimerCheckout(
clientToken: clientToken,
primerSettings: primerSettings,
primerTheme: primerTheme,
scope: { checkoutScope in
checkoutScope.splashScreen = {
AnyView(ProgressView("Loading..."))
}
},
onCompletion: { state in
switch state {
case .success(let result):
print("Payment: \(result.payment?.id ?? "")")
case .failure(let error):
print("Failed: \(error.errorId)")
case .dismissed:
print("Dismissed")
default:
break
}
}
)
}
}
Framework-Specific Patterns
- Web
- Android
- iOS
- Vanilla JS
- React
- Next.js / SSR
Copy
Ask AI
document.addEventListener('DOMContentLoaded', () => {
const checkout = document.querySelector('primer-checkout');
checkout.setAttribute('client-token', 'your-token');
checkout.options = { locale: 'en-GB' };
});
Copy
Ask AI
const SDK_OPTIONS = { locale: 'en-GB' };
function CheckoutPage() {
return (
<primer-checkout
client-token="your-token"
options={SDK_OPTIONS}
/>
);
}
See React Integration Guide for stable references and React 18/19 differences.
Copy
Ask AI
'use client';
import { useEffect } from 'react';
import { loadPrimer } from '@primer-io/primer-js';
const SDK_OPTIONS = { locale: 'en-GB' };
export default function CheckoutPage() {
useEffect(() => {
loadPrimer();
}, []);
return (
<primer-checkout
client-token="your-token"
options={SDK_OPTIONS}
/>
);
}
See SSR Guide for framework-specific patterns.
The Android SDK uses standard Jetpack Compose patterns. Configuration is passed when creating the checkout controller:See the Best Practices guide for Compose-specific patterns.
Copy
Ask AI
@Composable
fun CheckoutScreen(clientToken: String) {
val checkout = rememberPrimerCheckoutController(
clientToken = clientToken,
settings = PrimerSettings().apply {
paymentMethodOptions.redirectScheme = "myapp"
},
)
PrimerCheckoutSheet(
checkout = checkout,
onEvent = { /* ... */ },
)
}
- SwiftUI
- UIKit
Copy
Ask AI
struct CheckoutView: View {
let clientToken: String
var body: some View {
PrimerCheckout(
clientToken: clientToken,
primerSettings: PrimerSettings(paymentHandling: .auto),
onCompletion: { state in
// Handle result
}
)
}
}
See the Best Practices guide for SwiftUI-specific patterns.
Copy
Ask AI
class CheckoutViewController: UIViewController, PrimerCheckoutPresenterDelegate {
func showCheckout() {
PrimerCheckoutPresenter.shared.delegate = self
PrimerCheckoutPresenter.presentCheckout(
clientToken: clientToken,
from: self,
primerSettings: PrimerSettings(paymentHandling: .auto),
primerTheme: PrimerCheckoutTheme()
)
}
func primerCheckoutPresenterDidCompleteWithSuccess(_ result: PaymentResult) {
// Navigate to confirmation
}
func primerCheckoutPresenterDidFailWithError(_ error: PrimerError) {
print("Failed: \(error.errorId)")
}
func primerCheckoutPresenterDidDismiss() {
print("Dismissed")
}
}
See UIKit Integration Guide for more details.
Advanced Configuration
- Web
- Android
- iOS
Headless Vault
Headless Vault
Build custom vault UIs while retaining full vault functionality. Enable headless mode:Then use
Copy
Ask AI
checkout.options = {
vault: {
enabled: true,
headless: true
}
};
onVaultedMethodsUpdate, vault.createCvvInput(), and vault.startPayment() to build your custom UI.Headless Vault Implementation Guide
External Submit Button
External Submit Button
Use your own submit button instead of the built-in one:
Copy
Ask AI
checkout.options = {
submitButton: {
useBuiltInButton: false
}
};
// Trigger submission from your button
document.getElementById('my-button').addEventListener('click', () => {
document.dispatchEvent(new CustomEvent('primer:card-submit', {
bubbles: true,
composed: true
}));
});
External Submit Button Recipe
Show Amount on Button
Show Amount on Button
Display the payment amount on the submit button:
Copy
Ask AI
checkout.options = {
submitButton: {
amountVisible: true
}
};
Custom Submit Button
Custom Submit Button
Override the submit button slot in
PrimerCardForm:Copy
Ask AI
PrimerCardForm(
controller = cardFormController,
submitButton = {
Button(
onClick = { cardFormController.submit() },
enabled = formState.isFormValid && !formState.isLoading,
) {
Text("Pay")
}
},
)
External Submit Button Recipe
Google Pay with Shipping
Google Pay with Shipping
Configure Google Pay to collect billing address, email, and shipping:
Copy
Ask AI
settings = PrimerSettings().apply {
paymentMethodOptions.googlePayOptions = PrimerGooglePayOptions(
merchantName = "My Store",
captureBillingAddress = true,
emailAddressRequired = true,
shippingAddressParameters = PrimerGoogleShippingAddressParameters(
phoneNumberRequired = true,
),
requireShippingMethod = true,
)
}
Stripe ACH Mandate
Stripe ACH Mandate
Configure mandate data for Stripe ACH payments:
Copy
Ask AI
settings = PrimerSettings().apply {
paymentMethodOptions.stripeOptions = PrimerStripeOptions(
mandateData = MandateData.TemplateMandateData(merchantName = "My Store"),
)
}
3DS Configuration
3DS Configuration
Set the 3DS App Requestor URL:
Copy
Ask AI
settings = PrimerSettings().apply {
paymentMethodOptions.threeDsOptions = PrimerThreeDsOptions(
threeDsAppRequestorUrl = "https://mystore.com",
)
}
Custom Splash and Loading Screens
Custom Splash and Loading Screens
Replace the default splash and loading screens via scope customization:
Copy
Ask AI
PrimerCheckout(
clientToken: clientToken,
scope: { checkoutScope in
checkoutScope.splashScreen = {
AnyView(
VStack {
ProgressView()
Text("Preparing checkout...")
}
)
}
checkoutScope.loadingScreen = {
AnyView(ProgressView("Processing payment..."))
}
}
)
Custom Container
Custom Container
Wrap all checkout content in a custom container:
Copy
Ask AI
PrimerCheckout(
clientToken: clientToken,
scope: { checkoutScope in
checkoutScope.container = { content in
AnyView(
VStack {
Text("Secure Checkout").font(.headline)
content()
}
.padding()
)
}
}
)
Custom Card Form Submit Button
Custom Card Form Submit Button
Override the card form submit button:
Copy
Ask AI
PrimerCheckout(
clientToken: clientToken,
scope: { checkoutScope in
if let cardScope: PrimerCardFormScope = checkoutScope.getPaymentMethodScope(PrimerCardFormScope.self) {
cardScope.submitButton = {
AnyView(
Button("Pay Now") {
cardScope.submit()
}
)
}
}
}
)
Custom Submit Button Recipe
See also
Web SDK Options Reference
Complete list of all available Web options
Android SDK Reference
Android SDK API documentation
Events Guide
Handle payment success, failure, and state changes
Styling
Customize colors, fonts, and spacing