# Set up your integration Set up a Stripe Terminal SDK or server-driven integration to accept in-person payments. # React Native > Terminal’s React Native library is in [public preview](https://docs.stripe.com/release-phases.md) and in active development. Please report any issues you encounter to our [GitHub project](https://github.com/stripe/stripe-terminal-react-native/issues/new/choose). Getting started with the React Native SDK requires four steps: 1. [Install the SDK](https://docs.stripe.com/terminal/payments/setup-integration.md#install) in your app. 1. [Configure](https://docs.stripe.com/terminal/payments/setup-integration.md#configure) your app. 1. [Set up the connection token endpoint](https://docs.stripe.com/terminal/payments/setup-integration.md#connection-token) in your app and backend. 1. [Initialize the SDK](https://docs.stripe.com/terminal/payments/setup-integration.md#initialize) in your app. > If you’re building an **Apps on Devices** integration (running your app on Stripe smart readers such as the S700/S710), you must also complete additional [native Android setup steps](https://docs.stripe.com/terminal/features/apps-on-devices/build.md?terminal-sdk-platform=react-native#setup-app) after following this guide. ## Install the SDK [Client-side] The [React Native SDK](https://github.com/stripe/stripe-terminal-react-native) is open source and fully documented. Internally, it makes use of native iOS and Android SDKs. Install the SDK by running: #### NPM ```bash npm install @stripe/stripe-terminal-react-native ``` #### Yarn ```bash yarn add @stripe/stripe-terminal-react-native ``` #### Expo ```bash npx expo install @stripe/stripe-terminal-react-native ``` ## Configure your app [Client-side] #### React Native CLI #### iOS ### Pods You must run `pod install` in your `ios` directory to install the native dependencies. ### Permissions To prepare your app to work with the Stripe Terminal SDK, make a few changes to your **Info.plist** file in Xcode. 1. Enable location services with the following key-value pair. | Privacy – Location When In Use Usage Description | | ------------------------------------------------ | | **Key** | [NSLocationWhenInUseUsageDescription](https://developer.apple.com/documentation/bundleresources/information_property_list/nslocationwheninuseusagedescription) | | **Value** | **Location access is required to accept payments.** | To reduce fraud risks associated with payments, and to minimize disputes, Stripe must know where payments occur. If the SDK can’t determine the location of the iOS device, payments are disabled until location access is restored. 1. Make sure that your app runs in the background and remains connected to Bluetooth readers. | Required background modes for Bluetooth readers | | ----------------------------------------------- | | **Key** | [UIBackgroundModes](https://developer.apple.com/documentation/bundleresources/information_property_list/uibackgroundmodes) | | **Value** | **bluetooth-central** (Uses Bluetooth LE accessories) | Setting the [bluetooth-central](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html#//apple_ref/doc/uid/TP40013257-CH7-SW6) background mode lets the reader remain in standby mode when your app is running in the background, or when the iOS device is locked. Without this value, standby fails. When your app is running in the background, the reader can turn off automatically to conserve power. 1. Allow your app to display a Bluetooth permission dialog. The app store requires including this, even if your app doesn’t support connecting to Bluetooth readers. | Privacy - Bluetooth Always Usage Description | | -------------------------------------------- | | **Key** | [NSBluetoothAlwaysUsageDescription](https://developer.apple.com/documentation/bundleresources/information_property_list/NSBluetoothAlwaysUsageDescription) | | **Value** | **This app uses Bluetooth to connect to supported card readers.** | iOS 13 introduced more specific permissions concerning an app’s use of Bluetooth peripherals. Apps that link with Core Bluetooth must include this key in their Info.plist file to prevent the app from crashing on its first launch. 1. Pass app validation checks when you submit it to the App Store. As of SDK version 3.4.0, this permission requirement is removed. | Privacy – Bluetooth Peripheral Usage Description | | ------------------------------------------------ | | **Key** | [NSBluetoothPeripheralUsageDescription](https://developer.apple.com/documentation/bundleresources/information_property_list/nsbluetoothperipheralusagedescription) | | **Value** | **Connecting to supported card readers requires Bluetooth access.** | This is an example—you can rephrase the prompt for user permission in your app. 1. Save your app’s **Info.plist**. Now it’s configured correctly and ready for use with the Stripe Terminal SDK. > If you’re using Tap to Pay on iPhone, you must [request and configure](https://developer.apple.com/documentation/proximityreader/setting-up-the-entitlement-for-tap-to-pay-on-iphone) the Tap to Pay on iPhone development entitlement from your Apple Developer account. #### Android ### Permissions The Stripe Terminal SDK requires the following Android permissions to function properly: - `PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT` - `PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN` - `PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION` Use the `requestNeededAndroidPermissions` helper function to automatically request all required permissions before you initialize the Terminal SDK: ```js import { requestNeededAndroidPermissions } from '@stripe/stripe-terminal-react-native'; try { const granted = await requestNeededAndroidPermissions({ accessFineLocation: { title: 'Location Permission', message: 'Stripe Terminal needs access to your location', buttonPositive: 'Accept', }, }); if (granted) { // Initialize the SDK } else { console.error( 'Location and BT services are required to connect to a reader.' ); } } catch (e) { console.error(e); } ``` Alternatively, if you need granular control over permission requests, you can manually request each permission using `PermissionsAndroid.request`: ```js import { PermissionsAndroid } from 'react-native'; // Mobile readers using Bluetooth connection require BLUETOOTH_CONNECT, BLUETOOTH_SCAN, and ACCESS_FINE_LOCATION. // This example shows the pattern for requesting one permission. const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, { title: 'Location Permission', message: 'Stripe Terminal needs access to your location', buttonPositive: 'Accept', }, ); if (granted === PermissionsAndroid.RESULTS.GRANTED) { console.log('Location permission granted'); } else { console.error('Location permission denied'); } ``` ### Manifest To ensure compatibility with Android 12 and later, make sure to add `android:exported="true"` to `AndroidManifest.xml`: ```xml ``` For additional context on changes made in Android 12, see the [Android documentation about safer component exporting](https://developer.android.com/about/versions/12/behavior-changes-12#exported). For devices running on Android 11 or below, you must grant permissions through the manifest as well: ```xml ``` #### Expo > This package can’t be used in the “Expo Go” app because it requires [custom native code](https://docs.expo.io/workflow/customizing/). You must use `npx expo prebuild` to generate native projects and run your app using `npx expo run:ios` or `npx expo run:android`. #### iOS ### Configuring the SDK After [installing](https://docs.stripe.com/terminal/payments/setup-integration.md#installation) the SDK, add the [configuration plugin](https://docs.expo.io/guides/config-plugins/) to the [plugins](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`: Set the following configuration options, depending on your reader type: - `localNetworkUsagePermission` - Required for smart readers using LAN connection - `appDelegate` - Required for Tap to Pay on Android - `tapToPayCheck` - Enables Tap to Pay compatibility checking ```json { "expo": { "plugins": [ [ "@stripe/stripe-terminal-react-native", { "bluetoothBackgroundMode": true, "locationWhenInUsePermission": "Location access is required to accept payments.", "bluetoothPeripheralPermission": "Bluetooth access is required to connect to supported bluetooth card readers.", "bluetoothAlwaysUsagePermission": "This app uses Bluetooth to connect to supported card readers.", "localNetworkUsagePermission": "This app uses the local WiFi network to connect to supported card readers.", "appDelegate": true, "tapToPayCheck": true } ] ] } } ``` ### Build Next, rebuild your app as described in the [Adding custom native code](https://docs.expo.io/workflow/customizing/) guide with: ```bash npx expo prebuild ``` and then: ```bash npx expo run:ios ``` > If you’re using Tap to Pay on iPhone, you must [request and configure](https://developer.apple.com/documentation/proximityreader/setting-up-the-entitlement-for-tap-to-pay-on-iphone) the Tap to Pay on iPhone development entitlement from your Apple Developer account. #### Android ### Permissions The Stripe Terminal SDK requires the following Android permissions to function properly: - `PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT` - `PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN` - `PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION` Use the `requestNeededAndroidPermissions` helper function to automatically request all required permissions before you initialize the Terminal SDK: ```js import { requestNeededAndroidPermissions } from '@stripe/stripe-terminal-react-native'; try { const granted = await requestNeededAndroidPermissions({ accessFineLocation: { title: 'Location Permission', message: 'Stripe Terminal needs access to your location', buttonPositive: 'Accept', }, }); if (granted) { // Initialize the SDK } else { console.error( 'Location and BT services are required to connect to a reader.' ); } } catch (e) { console.error(e); } ``` Alternatively, if you need granular control over permission requests, you can manually request each permission using `PermissionsAndroid.request`: ```js import { PermissionsAndroid } from 'react-native'; // Mobile readers using Bluetooth connection require BLUETOOTH_CONNECT, BLUETOOTH_SCAN, and ACCESS_FINE_LOCATION. // This example shows the pattern for requesting one permission. const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, { title: 'Location Permission', message: 'Stripe Terminal needs access to your location', buttonPositive: 'Accept', }, ); if (granted === PermissionsAndroid.RESULTS.GRANTED) { console.log('Location permission granted'); } else { console.error('Location permission denied'); } ``` ### Configuring the SDK After [installing](https://docs.stripe.com/terminal/payments/setup-integration.md#installation) the SDK, add the [configuration plugin](https://docs.expo.io/guides/config-plugins/) to the [plugins](https://docs.expo.io/versions/latest/config/app/#plugins) array of your `app.json` or `app.config.js`: Set the following configuration options, depending on your reader type: - `localNetworkUsagePermission` - Required for smart readers using LAN connection - `appDelegate` - Required for Tap to Pay on Android - `tapToPayCheck` - Enables Tap to Pay compatibility checking ```json { "expo": { "plugins": [ [ "@stripe/stripe-terminal-react-native", { "bluetoothBackgroundMode": true, "locationWhenInUsePermission": "Location access is required to accept payments.", "bluetoothPeripheralPermission": "Bluetooth access is required to connect to supported bluetooth card readers.", "bluetoothAlwaysUsagePermission": "This app uses Bluetooth to connect to supported card readers.", "localNetworkUsagePermission": "This app uses the local WiFi network to connect to supported card readers.", "appDelegate": true, "tapToPayCheck": true } ] ] } } ``` #### Build Next, rebuild your app as described in the [Adding custom native code](https://docs.expo.io/workflow/customizing/) guide with: ```bash npx expo prebuild ``` and then: ```bash npx expo run:android ``` ## Set up the connection token endpoint [Server-side] [Client-side] ### Server-side To connect to a reader, your backend needs to give the SDK permission to use the reader with your Stripe account, by providing it with the [secret](https://docs.stripe.com/api/terminal/connection_tokens/object.md#terminal_connection_token_object-secret) from a [ConnectionToken](https://docs.stripe.com/api/terminal/connection_tokens.md). Your backend needs to only create connection tokens for clients that it trusts. #### curl ```bash curl https://api.stripe.com/v1/terminal/connection_tokens \ -u <>: \ -X "POST" ``` Obtain the secret from the `ConnectionToken` on your server and pass it to the client side. #### Ruby ```ruby post '/connection_token' do token = # ... Create or retrieve the ConnectionToken {secret: token.secret}.to_json end ``` > The `secret` from the `ConnectionToken` lets you connect to any Stripe Terminal reader and take payments with your Stripe account. Be sure to authenticate the endpoint for creating connection tokens and protect it from cross-site request forgery (CSRF). ### Client-side To give the SDK access to this endpoint, create a token provider single function that requests a `ConnectionToken` from your backend. ```js import { StripeTerminalProvider } from '@stripe/stripe-terminal-react-native'; const fetchTokenProvider = async () => { const response = await fetch(`{YOUR BACKEND URL}/connection_token`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, }); const { secret } = await response.json(); return secret; }; ``` This function is called whenever the SDK needs to authenticate with Stripe or the Reader. It’s also called when a new connection token is needed to connect to a reader (for example, when your app disconnects from a reader). If the SDK can’t retrieve a new connection token from your backend, connecting to a reader fails with the error from your server. > Don’t cache or hardcode the connection token. The SDK manages the connection token’s lifecycle. ## Initialize the SDK [Client-side] To get started, pass in your token provider implemented in [Step 3](https://docs.stripe.com/terminal/payments/setup-integration.md#connection-token) to `StripeTerminalProvider` as a prop. ```js import { StripeTerminalProvider } from '@stripe/stripe-terminal-react-native'; function Root() { const fetchTokenProvider = async () => { const response = await fetch(`${API_URL}/connection_token`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, }); const { secret } = await response.json(); return secret; }; return ( ); } ``` As a last step, call the `initialize` method from `useStripeTerminal` hook. > You must call the `initialize` method from a component nested within `StripeTerminalProvider`, not from the component that contains the `StripeTerminalProvider`. > > After initialization completes, you can use other SDK methods such as `discoverReaders`, `connectReader`, and `processPaymentIntent`. If you attempt to call these methods before initialization, you’ll receive the following error: “First initialize the Stripe Terminal SDK before performing any action.” ```js function App() { const { initialize } = useStripeTerminal(); useEffect(() => { initialize(); }, []); return ; } ``` ## SDK updates Stripe periodically releases updates which can include new functionality, bug fixes, and security updates. Update your SDK as soon as a new version is available. The currently available SDKs are: - [Stripe Terminal Android SDK](https://github.com/stripe/stripe-terminal-android/releases) - [Stripe Terminal iOS SDK](https://github.com/stripe/stripe-terminal-ios/releases) - [Stripe Terminal JavaScript SDK](https://docs.stripe.com/terminal/references/api/js-sdk.md#changelog) - [Stripe Terminal React Native SDK](https://github.com/stripe/stripe-terminal-react-native) ## Next steps - [Connect to a reader](https://docs.stripe.com/terminal/payments/connect-reader.md?terminal-sdk-platform=react-native&reader-type=internet)