React Native

Add the Trustly UI to React Native mobile apps
View as Markdown

The Trustly React Native SDK allows you to build a bank authorization workflow in your mobile app. You can use the SDK to initiate a bank authorization flow using either the Select Bank Widget or the Trustly Lightbox.

The SDK handles the complexities of OAuth flows and bank redirection, ensuring a seamless user experience on both iOS and Android.

Prerequisites

Authentication flow

The following diagram illustrates how the Trustly SDK manages the secure transition between your application, the SDK, and the banking institution.

StepDescription
AAuthentication session launch
The SDK opens a secure system overlay. On iOS, this is ASWebAuthenticationSession. On Android, this uses Custom Tabs or direct App-to-App switching.
BApp redirection
The bank redirects the user back to your application using the configured Universal Link (iOS) or App Link (Android). For example, https://yourdomain.com/trustly-return. The OS verifies the domain and brings your app to the foreground.
CSDK handoff
Your app detects the return and the SDK verifies the transaction status, triggering the onReturn function defined in your component.

Add the package

To install the core Trustly SDK, which includes the Lightbox UI components and the native bridges required to communicate with banking apps, go to your project’s root directory and run the following command:

$npm install @trustlyinc/trustly-react-native

Then install the required peer dependencies:

$npm install react react-native react-native-inappbrowser-reborn react-native-webview @react-native-async-storage/async-storage react-native-get-random-values --legacy-peer-deps

Install iOS CocoaPods

If you are building for iOS, you must install the CocoaPods dependencies to integrate the SDK’s native modules. Navigate to your iOS directory and run:

$cd ios && pod install && cd ..

To handle bank logins securely, the Trustly SDK uses ASWebAuthenticationSession on iOS and direct App-to-App interactions on Android. You must configure a Universal Link (iOS) or App Link (Android) to handle redirects back to your app after a user authenticates with their bank. Pass your deep link URL as metadata.deepLinkUrl in establishData.

If your app does not already have a Universal Link (iOS) or App Link (Android) configured, you must set one up. Without it, users will not be automatically redirected to your app after logging in on a mobile banking app.

iOS

Universal Links use standard HTTPS URLs to return users directly to your app after bank authentication. Unlike custom URL schemes, they are verified against your domain — preventing other apps from intercepting them — and fall back to your website if the app isn’t installed.

Define the associated domains

Create a JSON file named apple-app-site-association and host it at one of the following locations on your server:

  • Root: https://yourdomain.com/apple-app-site-association
  • Subdirectory: https://yourdomain.com/.well-known/apple-app-site-association

Server requirements:

  • Served over HTTPS.
  • Content-Type header set to application/json.
  • Filename must have no extension.
1{
2 "applinks": {
3 "apps": [
4 "ABCDE12345.com.yourcompany.YourApp"
5 ],
6 "details": [
7 {
8 "appID": "ABCDE12345.com.yourcompany.YourApp",
9 "paths": [
10 "/trustly-return",
11 "*"
12 ]
13 }
14 ]
15 }
16}
KeyDescription
appsAn array of application identifiers. Detailed matching is handled in details.
appIDYour app’s unique identifier in the format <Team ID>.<Bundle Identifier>. Find your Team ID in the Apple Developer Portal.
pathsURL paths the app should handle. Use * as a catch-all, or NOT /path to exclude a path from opening the app.

Verify your server returns the correct Content-Type:

$curl -I https://yourdomain.com/.well-known/apple-app-site-association

Add the Associated Domains entitlement

  1. Open your project in Xcode and select your application target.
  2. Go to Signing & Capabilities.
  3. Click + Capability and select Associated Domains.
  4. Add your domains, prefixed with applinks::
applinks:yourdomain.com
applinks:www.yourdomain.com

Adding this capability automatically inserts the com.apple.developer.associated-domains key into your app’s entitlements file.

Unlike standard deep link routing, the Trustly SDK manages the return from the bank natively. On iOS, the SDK leverages ASWebAuthenticationSession via the InAppBrowser module. This securely overlays the bank’s login page and intercepts the redirect URL at the OS level once authentication is complete.

Because of this native integration, you do not need to manually intercept the URL in your AppDelegate or add React Native Linking event listeners.

To ensure the return works seamlessly:

  • Make sure your configured Universal Link matches the deepLinkUrl value you pass in the establishData object.
  • Once the bank redirects the user to this URL, the SDK will automatically capture the callback, dismiss the secure browser, and trigger the onReturn or onCancel functions defined in your TrustlyLightbox component.
1<TrustlyLightbox
2 establishData={establishData}
3 onReturn={() => {
4 // Called automatically when the bank redirects back to your app
5 }}
6 onCancel={() => {
7 // Called automatically if the user cancels
8 }}
9/>

Android

Android App Links use standard HTTPS URLs to return users directly to your app after bank authentication. Unlike custom URL schemes, App Links are verified against your domain via Digital Asset Links, preventing other apps from intercepting them, and fall back to your website if the app isn’t installed.

Create a JSON file named assetlinks.json and host it at: https://yourdomain.com/.well-known/assetlinks.json

Server requirements:

  • Served over HTTPS.
  • Content-Type header set to application/json.
1[
2 {
3 "relation": [
4 "delegate_permission/common.handle_all_urls"
5 ],
6 "target": {
7 "namespace": "android_app",
8 "package_name": "com.yourcompany.yourapp",
9 "sha256_cert_fingerprints": [
10 "4A:34:B4:72:DE:F7:..."
11 ]
12 }
13 }
14]
KeyDescription
relationPermissions being granted. Use delegate_permission/common.handle_all_urls for deep links.
namespaceThe namespace of your application. Typically android_app.
package_nameThe unique application ID defined in your build.gradle file.
sha256_cert_fingerprintsThe SHA-256 fingerprint of your app’s signing certificate. Retrieve it with keytool or via the signingReport Gradle task in Android Studio.

Verify your server returns the correct Content-Type:

$curl -I https://yourdomain.com/.well-known/assetlinks.json

Configure the manifest

Add an intent filter with autoVerify="true" to your AndroidManifest.xml. Android uses the following attributes to handle App Links:

  • android:exported="true" — Required to allow your activity to be started by external app links.
  • android:autoVerify="true" — Instructs Android to verify your domain ownership by checking assetlinks.json at install time.
  • <data> elements — Define the HTTPS scheme, domain, and path that trigger your activity.
1<activity
2 android:name="com.trustly.rnsdk.TrustlyRedirectActivity"
3 android:exported="true">
4
5 <intent-filter android:autoVerify="true">
6 <action android:name="android.intent.action.VIEW" />
7 <category android:name="android.intent.category.DEFAULT" />
8 <category android:name="android.intent.category.BROWSABLE" />
9
10 <!-- App Links -->
11 <data android:scheme="https" android:host="yourdomain.com" android:pathPrefix="/trustly-return" />
12 </intent-filter>
13
14</activity>

Create the establishData object

To initialize the Trustly Lightbox, you must create an establishData object. This object acts as the configuration payload for the SDK and includes transaction details and the requestSignature, which must be generated by your backend for security. For more information, see Generate request signatures.

You define the establishData object within your main component — for example, App.tsx or the screen that handles the payment logic.

1const establishData = {
2 accessId: "YOUR_ACCESS_ID",
3 merchantId: "YOUR_MERCHANT_ID",
4 requestSignature: "GENERATED_HASH_FROM_BACKEND",
5 description: "Transaction description",
6 merchantReference: "UNIQUE_TRANSACTION_REF",
7 amount: "1.00",
8 paymentType: "Retrieval",
9 currency: "USD",
10 returnUrl: "/returnUrl",
11 cancelUrl: "/cancelUrl",
12 customer: {
13 name: "John Doe",
14 address: { country: "US" }
15 },
16 metadata: {
17 deepLinkUrl: Platform.OS === "android" ?
18 "intent://yourdomain.com/trustly-return/#Intent;scheme=https;end" :
19 "https://yourdomain.com/trustly-return",
20 },
21 env: "sandbox"
22};

When using the sandbox environment, set the env property to sandbox. Before publishing your production application, remove the env property.

Required properties

PropertyTypeDescription
accessIdstringThe Access ID provided by Trustly.
merchantIdstringYour Merchant ID.
requestSignaturestringA signature generated by your backend to validate the request.
merchantReferencestringA unique reference for the transaction.
amountstringThe transaction amount. For example, 10.00.
currencystringThe currency code. For example, USD.
paymentTypestringThe type of payment. For example, Retrieval or Deferred.
returnUrlstringThe URL path to return to on success.
cancelUrlstringThe URL path to return to on cancel.
metadata.deepLinkUrlstringYour Universal Link (iOS) or App Link (Android). For example, https://yourdomain.com/trustly-return.

Add the SDK components

You can integrate the SDK in two ways: displaying the Bank Selection Widget first, or launching the Trustly Lightbox directly.

Display the Select Bank Widget

Add TrustlyWidget to your component’s return statement to allow users to select their bank directly within your app’s UI.

The onBankSelected callback triggers a state change. You must use this state to conditionally render the TrustlyLightbox component, as shown in the following example.

1import React, { useState } from 'react';
2import { View } from 'react-native';
3import { TrustlyWidget, TrustlyLightbox } from 'trustly-react-native';
4
5// const establishData = { ... } // See "Create the establishData object" above
6
7const PaymentScreen = () => {
8 const [lightboxData, setLightboxData] = useState(null);
9 const [selectedBankId, setSelectedBankId] = useState(null);
10 const [showLightbox, setShowLightbox] = useState(false);
11
12 const handleBankSelected = (bankId, updatedEstablishData) => {
13 setSelectedBankId(bankId);
14 setLightboxData(updatedEstablishData);
15 setShowLightbox(true);
16 };
17
18 const handleReturn = () => {
19 console.log('Authorization completed');
20 setShowLightbox(false);
21 };
22
23 const handleCancel = () => {
24 console.log('User canceled');
25 setShowLightbox(false);
26 };
27
28 return (
29 <View>
30 {/* Show Widget only when Lightbox is NOT active */}
31 {!showLightbox && (
32 <TrustlyWidget
33 establishData={establishData}
34 onBankSelected={handleBankSelected}
35 />
36 )}
37
38 {/* Conditionally render Lightbox based on state */}
39 {showLightbox && (
40 <TrustlyLightbox
41 establishData={lightboxData}
42 paymentProviderId={selectedBankId}
43 onReturn={handleReturn}
44 onCancel={handleCancel}
45 />
46 )}
47 </View>
48 );
49};

Launch the Trustly Lightbox

Add the following code to your component’s return statement to bypass the Select Bank Widget and launch the Trustly Lightbox immediately or from your own custom button:

1import { TrustlyLightbox } from 'trustly-react-native';
2
3// Inside your component render
4<TrustlyLightbox
5 establishData={establishData}
6 onReturn={handleReturn}
7 onCancel={handleCancel}
8/>

Handle callbacks

Define the callback functions inside your component to handle the transaction result.

Ensure the state setter (for example, setShowLightbox) matches the variable name defined in your component’s state.

1// Place these functions inside your component, before the return statement
2const handleReturn = () => {
3 console.log('Authorization completed successfully');
4 setShowLightbox(false);
5 // Navigate to success screen
6};
7
8const handleCancel = () => {
9 console.log('User canceled the process');
10 setShowLightbox(false);
11 // Navigate to cancel screen or close modal
12};

Troubleshooting

Use the information provided here to resolve configuration and integration issues on iOS and Android platforms.

iOS

  • App does not return after auth: Verify that the metadata.deepLinkUrl in your establishData matches a path covered by your apple-app-site-association file and that the Associated Domains entitlement is configured in Xcode.

  • Universal Link opens browser instead of app: Confirm your server is serving apple-app-site-association over HTTPS with Content-Type: application/json and no file extension.

  • CocoaPods architecture errors on Apple Silicon: React Native 0.79+ supports arm64 natively. If you encounter incompatible architecture errors or FFI gem issues during pod install, try running the command with the arch -x86_64 prefix as a fallback:

    $cd ios && arch -x86_64 pod install && cd ..

Android

  • App Link not working: Confirm android:autoVerify="true" is set on your intent filter and your assetlinks.json is reachable at https://yourdomain.com/.well-known/assetlinks.json with the correct Content-Type: application/json.

  • WebView not loading: Ensure you have requested internet permissions in AndroidManifest.xml:

    1<uses-permission android:name="android.permission.INTERNET" />

General

  • Signature error: Ensure the requestSignature is being generated correctly by your backend using your access key. See Generate request signatures.

  • Module not found: If you encounter resolution errors, try resetting your cache:

    $npm start -- --reset-cache