This guide will show you how to use Klarna Mobile SDK to implement Express Checkout in your React Native mobile application, providing a fast and simple shopping experience for your users.
Please review this brief guide first to ensure you are prepared to offer this integration to your customers.

Klarna Express Checkout Button
Before you integrate Express Checkout, confirm the following:
For a Mobile SDK integration your Payment Server and Mobile App must work together to offer one-click checkout experience:
The right placement of the Express button can significantly enhance your user experience, leading to higher conversion rates and increased sales.

You can place the Express checkout button at multiple stages of the shopping journey.
To learn more about placements, check out this section.
npm install react-native-klarna-inapp-sdk --save
yarn add react-native-klarna-inapp-sdk
Check the npm package page for the latest release.
Add the Klarna Maven repository to your app's android/build.gradle:
allprojects {
repositories {
// ... existing repositories ...
maven {
url 'https://x.klarnacdn.net/mobile-sdk/'
}
}
}
React Native 0.59+: Third-party Gradle repositories may not be automatically recognized. The Maven entry above is <bold>required — without it, the Android build will fail to resolve Klarna SDK dependencies.</bold>
Install the CocoaPods dependencies:cd ios && pod install
Klarna purchase flows may require authorization in external apps (e.g. bank apps) or hand over to the Klarna app. Set up a custom URL scheme so the customer can return to your app seamlessly.
myApp).returnUrl including :// (e.g. "myApp://" or "myApp://klarna-redirect").To enable seamless handover to the Klarna app, add the Klarna app schemes to LSApplicationQueriesSchemes in your Info.plist:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>klarna</string>
<string>klarnaconsent</string>
</array>
Create an instance of the KlarnaExpressCheckoutButton when your cart page or product detail page is loaded. This ensures that the button is readily available for user interaction. Depending on your integration setup, you can create and initiate the Express Checkout button using either a Client-Side Session or a Server-Side Session:
Once the button is created, add it to your screen. This involves adding the button to the appropriate view hierarchy in your application's user interface:
Session type discrimination: The component detects the session type from the shape of the sessionOptions object. If it contains a clientId property, a client-side session is used. If it contains a clientToken property, a server-side session is used.
| Parameter | Type | Required | Description |
|---|---|---|---|
| object | Yes | Either { clientId: string } for client-side sessions or { clientToken: string } for server-side sessions. See Session options. |
| string | Yes | Locale for the button text and purchase flow (e.g. "en-US"). See supported locales. |
| KlarnaEnvironment | Yes |
KlarnaEnvironment.Playground. |
| KlarnaRegion | Yes | Geographical region for API requests: KlarnaRegion.EU, KlarnaRegion.NA, or KlarnaRegion.OC. |
| string | Yes | Deep link URL for returning to your app from external apps/browsers (e.g. "myApp://klarna-redirect"). Must include :// after the scheme name. |
| KlarnaButtonTheme | No | Button colour theme. Defaults to KlarnaButtonTheme.Dark. |
| KlarnaButtonShape | No | Button shape. Defaults to KlarnaButtonShape.RoundedRect. |
| KlarnaButtonStyle | No | Button fill style. Defaults to KlarnaButtonStyle.Filled. |
| boolean | No | Whether the authorization should automatically be finalized. Defaults to true. Set to false if you need a separate finalize step. |
| boolean | No | Whether Klarna should collect the customer's shipping address. Defaults to false. |
| string | No | JSON string with order details to update the session. Required for client-side sessions; optional for server-side sessions. |
| (response) => void | No | Called when the customer authorizes the payment. See Handle authorization. |
| (error) => void | No | Called when an error occurs. See Error handling. |
| ViewStyle | No | Standard React Native view style. Width defaults to 100%; height auto-sizes (default 48dp). |
| Parameter | Type | Description |
|---|---|---|
| string | Partner client ID from the Merchant Portal. |
| Parameter | Type | Description |
|---|---|---|
| string | Client token generated by your backend. |
When the customer clicks the Express Checkout button and completes the Klarna purchase flow, the onAuthorized callback fires with an authorization response. Extract the authorizationToken and send it to your backend to create the order.
<KlarnaExpressCheckoutView
// ... session and style props ...
onAuthorized={(response) => {
if (response.approved && response.authorizationToken) {
// Authorization successful — send token to your backend
createOrder(response.authorizationToken, response.collectedShippingAddress);
}
if (response.finalizedRequired) {
// Finalization needed (only when autoFinalize is false)
// Use response.clientToken with KlarnaPaymentView to finalize
finalizePayment(response.clientToken);| Parameter | Type | Description |
|---|---|---|
| boolean | Whether the payment was approved. |
| boolean | Whether the payment is still available for authorization. |
| boolean | Whether the session requires finalization (only when autoFinalize is false). |
| string | The authorization token to use when creating the order. Valid for 60 minutes. |
| string | Client token for the session, used for finalization if needed. |
| string | The Klarna Payments session ID. |
| string | JSON string with the shipping address collected during the session (if collectShippingAddress was true). |
| string | Merchant reference provided in session creation. |
| string | Additional merchant reference provided in session creation. |
60-minute expiry: The authorizationToken is valid for 60 minutes. Create the order on your backend immediately after receiving the authorization. If the token expires, request a new authorization.
If the session needs to be finalized, you’ll need to perform this last step to get an authorization token from your checkout confirmation screen. This can be done via KlarnaPaymentView, using the clientToken from KlarnaExpressCheckoutButtonAuthorizationResponse to initialize the view and calling finalize method of that view.
This is only required of autoFinalize is set to false in session options.
Once you have the authorization token from the mobile app, create the order on your server using the Klarna Payments API. If you collected the shipping address, ensure it matches in the order creation request.
<POST {apiUrl}/payments/v1/authorizations/{authorizationToken}/order
Content-Type: application/json
Authorization: Basic YOUR_CREDENTIALS
{
"purchase_country": "US",
"purchase_currency": "USD",
"order_amount": 50000,
"order_tax_amount": 0,
"order_lines": [
{
"name": "Classic Running Shoes",
"quantity": 1,
"unit_price": 50000,
"total_amount": 50000,
"total_tax_amount": 0
}
],
"shipping_address": {
"given_name": "John",
"family_name": "Doe",
"email": "john@doe.com",
"street_address": "Lombard St 10",
"postal_code": "90210",
"city": "Beverly Hills",
"region": "CA",
"country": "US",
"phone": "+15551234567"
}
}
When the order is created successfully, you receive:
{
"order_id": "3eaeb557-5e30-47f8-b840-b8d987f5945d",
"redirect_url": "https://payments.klarna.com/redirect/...",
"fraud_status": "ACCEPTED",
"authorized_payment_method": "invoice"
}
| Parameter | Description |
|---|---|
| Use to capture or refund the order via the Order Management API |
| URL to redirect the customer for Klarna cookie placement (faster future checkouts). |
|
PENDING, or REJECTED. |
| The payment method chosen by the customer. |
// server.js (Node.js / Express)
app.post('/api/create-order', async (req, res) => {
const { authorizationToken, shippingAddress, cart } = req.body;
const klarnaRes = await fetch(
`https://api.klarna.com/payments/v1/authorizations/${authorizationToken}/order`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Basic ${KLARNA_CREDENTIALS}`,
},
body: JSON.stringify({ Common order creation errors:
• NOT_FOUND — Authorization token expired (>60 minutes). Request a new authorization.
• BAD_VALUE — Data modified after authorization (e.g. changed cart, mismatched address).
• REJECTED — Cart updated in a way that triggers re-authorization.
Customise the Express Checkout button appearance using the theme, shape, and buttonStyle props.
| Value | Enum | Description |
|---|---|---|
|
| Dark button on light backgrounds. Default. |
|
| Light/white button on dark backgrounds. |
|
| Automatically selects based on the device's light/dark mode. |
| Value | Enum | Description |
|---|---|---|
|
| Rounded rectangle. Default. |
|
| Fully rounded pill shape. |
|
| Square corners. |
| Value | Enum | Description |
|---|---|---|
|
| Solid background fill. Default. |
|
| Transparent background with a border. Useful on all background colours. |
Sizing: The recommended button height is 48dp (minimum 40dp). The component defaults to 48dp if the native button hasn't reported its intrinsic size yet. Make the button the same width and height as other payment buttons in your checkout layout.

Dark theme (default)

Light theme

KlarnaButtonShape.rounded_rect

KlarnaButtonShape.pill

KlarnaButtonShape.rectangle

Outlined style
Provide an onError callback to handle errors from the Express Checkout button. The callback receives a KlarnaMobileSDKError object:
interface KlarnaMobileSDKError {
readonly isFatal: boolean; // If fatal, the button should not be shown further
readonly message: string; // Human-readable error description
readonly name: string; // Error type identifier
}
| Error Name | Description | Fatal |
|---|---|---|
| The client ID is not valid (null or blank). | Yes |
| The client token is not valid (null or blank). | Yes |
| Internal delegate reference was lost. | Yes |
| An Express Checkout flow is already in progress. | No |
| The authorization process failed. | No |
| The button could not be rendered. | Yes |
| Authorization response could not be parsed. | No |
| Failed to create the native button instance. | Yes |
<KlarnaExpressCheckoutView
// ... props ...
onError={(error) => {
if (error.isFatal) {
// Fatal — hide the button, show alternative checkout
setShowExpressCheckout(false);
console.error(`[KEC Fatal] ${error.name}: ${error.message}`);
} else {
// Non-fatal — log and optionally inform the user
console.warn(`[KEC Warning] ${error.name}: ${error.message}`);
}
}}A complete screen showing the Express Checkout button on a product detail page:
import React, { useState } from 'react';
import { View, Text, ScrollView, Alert, StyleSheet } from 'react-native';
import {
KlarnaExpressCheckoutView,
KlarnaEnvironment,
KlarnaRegion,
KlarnaButtonTheme,
KlarnaButtonShape,
KlarnaButtonStyle,
} from 'react-native-klarna-inapp-sdk';
const CLIENT_ID = 'your-client-id';
const orderData = {
purchase_country: 'US',
purchase_currency: 'USD',
order_amount: 50000,
order_tax_amount: 0,
order_lines: [
{
name: 'Classic Running Shoes',
quantity: 1,
unit_price: 50000,
total_amount: 50000,
total_tax_amount: 0,
},
],
};
export default function ProductDetailScreen() {
const [orderComplete, setOrderComplete] = useState(false);
const [showButton, setShowButton] = useState(true);
const handleAuthorized = async (response) => {
if (!response.approved || !response.authorizationToken) {
return;
}
try {
const res = await fetch('https://yourserver.com/api/create-order', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
authorizationToken: response.authorizationToken,
shippingAddress: response.collectedShippingAddress
? JSON.parse(response.collectedShippingAddress)
: null,
cart: orderData,
}),
});
const order = await res.json();
setOrderComplete(true);
Alert.alert('Order Created', `Order ID: ${order.orderId}`);
} catch (err) {
Alert.alert('Error', 'Failed to create order');
}
};
return (
<ScrollView style={styles.screen}>
<View style={styles.product}>
Classic Running Shoes
$500.00
</View>
{showButton && !orderComplete && (
<View style={styles.buttonContainer}>
<KlarnaExpressCheckoutView
sessionOptions={{ clientId: CLIENT_ID }}
locale="en-US"
environment={KlarnaEnvironment.Playground}
region={KlarnaRegion.NA}
returnUrl="myApp://klarna-redirect"
theme={KlarnaButtonTheme.Dark}
shape={KlarnaButtonShape.RoundedRect}
buttonStyle={KlarnaButtonStyle.Filled}
autoFinalize={true}
collectShippingAddress={true}
sessionData={JSON.stringify(orderData)}
onAuthorized={handleAuthorized}
onError={(error) => {
if (error.isFatal) {
setShowButton(false);
}
console.error(`KEC: ${error.name}: ${error.message}`);
}}
/>
</View>
)}
{orderComplete && (
Order confirmed!
)}
</ScrollView>
);
}
const styles = StyleSheet.create({
screen: { flex: 1, backgroundColor: '#fff' },
product: { padding: 16 },
name: { fontSize: 24, fontWeight: '700', marginBottom: 4 },
price: { fontSize: 20, color: '#333', marginBottom: 16 },
buttonContainer: { paddingHorizontal: 16, minHeight: 68 },
confirmation: {
fontSize: 18, fontWeight: '600', color: '#177a3e',
textAlign: 'center', marginTop: 24,
},
});
clientId is valid and the domain is allowlisted in the Klarna Portal.environment is set to Playground for testing.returnUrl is correctly configured and opens your app.build.gradle.pod install has been run; URL scheme and LSApplicationQueriesSchemes are configured.onAuthorized callback receives a valid authorizationToken.onError callback is wired up and errors are logged.collectShippingAddress is true, verify the address is returned in collectedShippingAddress.autoFinalize is false, verify finalizedRequired is true and finalization works via KlarnaPaymentView.| Symptom | Likely cause | Fix |
|---|---|---|
| Button doesn't render | Invalid clientId or clientToken. | Verify credentials. Check onError for InvalidClientID / InvalidClientToken. |
| "We couldn't load the next screen" error | Domain not allowlisted in Klarna Portal. | Add your domain under Payment settings → Client Identifiers → Allowed Origins. |
| Android build fails | Missing Klarna Maven repository. | Add maven { url 'https://x.klarnacdn.net/mobile-sdk/' } to build.gradle. |
| Can't return to app after bank auth |
://. | Verify URL scheme in Xcode/Android and ensure returnUrl includes ://. |
Order creation fails with NOT_FOUND | Authorization token expired (>60 minutes). | Create the order immediately after authorization. Request a new auth if expired. |
Order creation fails with BAD_VALUE | Cart or address modified after authorization. | Keep cart data consistent between authorization and order creation. |
| User tapped the button while a flow is already running. | Non-fatal. The SDK prevents concurrent flows. No action needed. |
Klarna Mobile SDK provides a full suite of mobile-first integrations, including Klarna products like:
![]() | ![]() | ![]() |
| Sign in with Klarna | On-site Messaging | Payments |
Complete your integration with