---
title: Getting Started with the PingOne Recognize Mobile SDK
description: A step-by-step guide to integrating the PingOne Recognize Mobile SDK.
component: recognize
page_id: recognize:mobile-sdk:mobile-sdk-getting-started
canonical_url: https://docs.pingidentity.com/recognize/mobile-sdk/mobile-sdk-getting-started.html
llms_txt: https://docs.pingidentity.com/recognize/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
revdate: April 20, 2026
section_ids:
  prerequisites: Before you begin
  pingone-recognize-sdk-requirements: PingOne Recognize SDK requirements.
  installation: Installation
  essential-configuration: Essential Configuration
  additional-configuration: Additional Configuration
  shared-circuits: Shared Circuits
  networking-module: Networking Module
---

# Getting Started with the PingOne Recognize Mobile SDK

Learn how to integrate the PingOne Recognize SDK in your Android or iOS mobile application, and enroll and authenticate users through the PingOne Recognize platform.

Before jumping into your code editor, make sure that you are familiar with the various [components](mobile-sdk-components.html) of the authentication system and common biometric [integration flows](mobile-sdk-integration-flows.html).

## Before you begin

Make sure you have both required API keys and the list of production hosts from your PingOne Recognize contact:

* `YOUR_CLOUDSMITH_TOKEN` to download the SDK from Cloudsmith repository

* `KEYLESS_API_KEY` to configure the mobile SDK

* `KEYLESS_HOSTS` a list of node URLs. URLs in `KEYLESS_HOSTS` must not contain trailing slashes (`/`).

## PingOne Recognize SDK requirements.

* Android

* iOS

* Flutter

* React Native

The PingOne Recognize SDK uses:

* [Android 6.0](https://developer.android.com/about/versions/marshmallow) (API level 23) and above

* [Kotlin 1.9.25](https://github.com/JetBrains/kotlin/releases/tag/v1.9.25)

* [Gradle 8.7](https://docs.gradle.org/8.7/release-notes.html)

* [Android Gradle Plugin 8.3.0](https://developer.android.com/build/releases/past-releases/agp-8-3-0-release-notes)

* [AndroidX](https://developer.android.com/jetpack/androidx/)

The PingOne Recognize SDK uses:

* [iOS 13](https://developer.apple.com/documentation/ios-ipados-release-notes/ios-13-release-notes)

* [Swift 5.1](https://www.swift.org/swift-evolution/#?version=5.1)

* [Cocoapods 1.15.2](https://github.com/CocoaPods/CocoaPods/releases/tag/1.15.2)

Set up a physical iOS device for running your app and enable the following permissions:

* Enable camera permissions: add the `Privacy - Camera Usage Description` key in your project `Info.plist` (in Xcode under Project > Info):

  ```xml
  <key>NSCameraUsageDescription</key>
  <string>{p1recognize} needs access to your camera to enroll and authenticate you. {p1recognize} cannot be used without your camera. Please allow camera permissions.</string>
  ```

* Enable background processing to synchronize PingOne Recognize data. You can find a comprehensive guide in [Apple documentation](https://developer.apple.com/documentation/UIKit/using-background-tasks-to-update-your-app). In short, enable the `Background processing` mode under `Signing & Capabilities/Background Modes`. Then add the following in your `Info.plist` under `Permitted background task scheduler identifiers`:

  ```xml
  <key>NSCameraUsageDescription</key>
  <key>BGTaskSchedulerPermittedIdentifiers</key>
  <array>
      <string>YOUR APP IDENTIFIER</string>
  </array>
  ```

The PingOne Recognize SDK uses:

* [Flutter 3.0](https://docs.flutter.dev/release/release-notes/release-notes-3.0.0) or higher

* [Dart 3.0](https://dart.dev/guides/whats-new#dart-3) or higher

* All requirements from both Android and iOS platforms

Set up required permissions as described in the Android and iOS sections.

The PingOne Recognize RN SDK requires:

* React 18.2.0 or higher

* React Native 0.71.0 or higher

Additionally, ensure you meet the native requirements for each platform:

* **Android**: Minimum SDK 23 (Android 6.0), Kotlin `2.2.0` or higher.

* **iOS**: Target version `13.0` or higher

## Installation

|   |                                                                                                                                                                                              |
| - | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | **PingOne Recognize Anti-Inject variant for enhanced frame injection prevention** If you are using the anti-inject SDK variant with runtime application self protection (RASP), you need to: |

1. Set the package repository `partners-rasp-*` communicated to you by the Delivery team.

2. Add into your app assets the `license` file provided by the Delivery team.

* Android - Gradle

* iOS - SPM

* iOS - CocoaPods

* Flutter

* React Native

1. To allow PingOne Recognize to handle the result of [registerForActivityResult](https://developer.android.com/training/basics/intents/result#register), you must call PingOne Recognize from an Activity implementing [ActivityResultCaller](https://developer.android.com/reference/androidx/activity/result/ActivityResultCaller).

   Extend any AndroidX activity that implements this interface, for example [ComponentActivity](https://developer.android.com/reference/androidx/activity/ComponentActivity) or [AppCompatActivity](https://developer.android.com/reference/androidx/appcompat/app/AppCompatActivity).

2. If you use Proguard, add the following rules to your Proguard configuration file:

   ```none
   # {p1recognize} Proguard
   -keep class io.keyless.sdk.** {*;}
   -keepclassmembers class io.keyless.sdk.** {*;}
   ```

3. In the `repositories` section of the `settings.gradle` file of your Android app, add the snippet below, replacing `YOUR_CLOUDSMITH_TOKEN` with the CloudSmith token provided to you by PingOne Recognize.

   ```groovy
   dependencyResolutionManagement {
       repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
       repositories {
           google()
           mavenCentral()
           maven {
               url "https://dl.cloudsmith.io/YOUR_CLOUDSMITH_TOKEN/keyless/partners/maven/"
           }
       }
   }
   ```

4. In the `dependencies` block of your project `build.gradle` file, typically `app/build.gradle`, add:

   ```groovy
   dependencies {
   // ...

   implementation 'io.keyless:keyless-mobile-sdk:+'
   }
   ```

5. In the `android` block of your project `build.gradle` file, make sure you have:

   ```groovy
   android {
       // ...

       compileOptions {
           sourceCompatibility JavaVersion.VERSION_1_8
           targetCompatibility JavaVersion.VERSION_1_8
       }

       // Add only if you're using Kotlin
       kotlinOptions {
           jvmTarget = "1.8"
       }
   }
   ```

Cloudsmith distributes artifacts and works as a Swift Package Registry. To use packages from a registry, set up the environment for that registry and log in.

When working with Swift projects, registries can be configured locally to the project. Xcode does not support local registry configuration, so configure globally for the editor to detect packages.

|   |                                                                             |
| - | --------------------------------------------------------------------------- |
|   | It is best to run the following commands from a terminal with Xcode closed. |

1. To configure the PingOne Recognize Cloudsmith Package Registry, run:

   ```bash
   swift package-registry set --global --scope keyless https://swift.cloudsmith.io/keyless/partners/
   swift package-registry login https://swift.cloudsmith.io/keyless/partners/ --token <your-api-token>
   ```

2. Use the token provided to you in place of `<your-api-token>`.

3. Because this registry is global, provide the scope `keyless` for the PingOne Recognize Package Registry.

   These commands add the following to `~/.swiftpm/configuration/registries.json`:

   ```json
   {
     "authentication" : {
       "swift.cloudsmith.io" : {
         "loginAPIPath" : "/keyless/<repo>",
         "type" : "token"
       }
     },
     "registries" : {
       "keyless" : {
         "supportsAvailability" : false,
         "url" : "https://swift.cloudsmith.io/keyless/<repo>/"
       }
     },
     "version" : 1
   }
   ```

4. After setup, open Xcode, go to **File > Add Package Dependencies**, and search for package `keyless.mobile-sdk`.

**Optional: Test Release Candidates**

Release candidates are available in a separate repo. Because Xcode does not handle semantic versioning with build numbers well, use this approach:

1. Download the package manually from Cloudsmith with your token.

2. Extract the archive to a folder named `KeylessSDKPackage`.

3. Drag and drop the extracted folder inside your Xcode project, under the project root.

If a PingOne Recognize SDK package is already configured, it is seamlessly replaced by the local one. Otherwise, add `KeylessSDK` library to your target from project settings.

|   |                                                                                         |
| - | --------------------------------------------------------------------------------------- |
|   | Because CocoaPods is in maintenance mode, this method will be discontinued. Prefer SPM. |

1. Create a Podfile if you do not already have one:

   ```bash
   cd your-project-directory
   pod init
   ```

2. Add the `keyless-mobile-sdk` pod to your `Podfile`:

   ```ruby
   # This is the {p1recognize} repository for partners
   source 'https://dl.cloudsmith.io/YOUR_CLOUDSMITH_TOKEN/keyless/partners/cocoapods/index.git'

   target 'MyApp' do
       use_frameworks!

       # Add the {p1recognize} pod
       pod 'keyless-mobile-sdk'
   end
   ```

3. Add the following at the bottom of your `Podfile`:

   ```ruby
   post_install do |installer|
   installer.pods_project.targets.each do |target|
       target.build_configurations.each do |config|
       config.build_settings['ENABLE_BITCODE'] = 'NO'
       end
   end
   end
   ```

4. Install pods:

   ```bash
   pod install

   Analyzing dependencies
   Cloning spec repo `cloudsmith-YOUR_CLOUDSMITH_TOKEN-keyless-partners-cocoapods-index` from `https://dl.cloudsmith.io/YOUR_CLOUDSMITH_TOKEN/keyless/partners/cocoapods/index.git`
   ```

1) Add the PingOne Recognize SDK repository:

   ```bash
   echo '${CLOUDSMITH_TOKEN}' | dart pub token add https://dart.cloudsmith.io/keyless/flutter/
   ```

2) Add the PingOne Recognize SDK dependency to `pubspec.yaml`:

   ```bash
   dart pub add keyless_flutter_sdk:PACKAGE_VERSION --hosted-url https://dart.cloudsmith.io/keyless/flutter/
   ```

3) Follow installation steps in both Android and iOS sections to set up native SDKs.

4) Run `flutter pub get` to download dependencies:

   ```bash
   flutter pub get
   ```

You also need to bridge native SDKs used by the Flutter SDK in the `android` and `ios` sections of your Flutter project.

**Android**

1. Add the following line in root `build.gradle`:

   ```groovy
   allprojects {
       repositories {
           google()
           mavenCentral()
           maven {
               setUrl("https://dl.cloudsmith.io/YOUR_CUSTOM_TOKEN/keyless/partners/maven/")
           }
       }
   }
   ```

2. Replace `YOUR_CUSTOM_TOKEN` with the Cloudsmith token provided by the PingOne Recognize integration support team.

3. Then open your `Android.manifest` and add the following inside the `<application>` tag:

   ```xml
   <provider
       android:name="androidx.startup.InitializationProvider"
       android:authorities="${applicationId}.androidx-startup"
       android:exported="false"
       tools:node="merge">

       <meta-data
           android:name="io.keyless.fluttersdk.KeylessInitializer"
           android:value="androidx.startup" />
   </provider>
   ```

**iOS**

1. Target at least iOS 13 in your project.

2. Open your `PodFile` and add:

   ```bash
   source 'https://dl.cloudsmith.io/YOUR_CUSTOM_TOKEN/keyless/partners/cocoapods/index.git'
   ```

3. Add the following permissions in `Info.plist`:

   ```xml
   <key>NSCameraUsageDescription</key>
   <string>{p1recognize} needs access to your camera to enroll and authenticate you. {p1recognize} cannot be used without your camera. Please allow camera permissions.</string>
   <key>NSMicrophoneUsageDescription</key>
   <string>{p1recognize} needs access to your camera to enroll and authenticate you. {p1recognize} cannot be used without your camera. Please allow camera permissions.</string>
   ```

1) Configure access to the private registry by creating a `.npmrc` file in your project root:

   ```bash
   @react-native-keyless:registry=https://npm.cloudsmith.io/keyless/partners-rc/
   //npm.cloudsmith.io/keyless/partners/:_authToken=YOUR_CLOUDSMITH_TOKEN
   ```

   Replace `YOUR_CLOUDSMITH_TOKEN` with the token provided to you.

2) Add the PingOne Recognize SDK dependency:

   ```bash
   # Using npm
   npm install @react-native-keyless/sdk

   # Using yarn
   yarn add @react-native-keyless/sdk
   ```

**Android Setup**

1. Add the PingOne Recognize Maven repository to root `build.gradle`:

   ```groovy
   allprojects {
       repositories {
           google()
           mavenCentral()
           maven {
               url "https://dl.cloudsmith.io/YOUR_CLOUDSMITH_TOKEN/keyless/partners/maven/"
           }
       }
   }
   ```

2. Verify Kotlin version is `2.2.0` or higher in your Android plugin configuration.

**iOS Setup**

1. Ensure `platform :ios, '13.0'` or higher in `ios/Podfile`.

2. Add private spec repo at top of Podfile:

   ```ruby
   source 'https://dl.cloudsmith.io/YOUR_CLOUDSMITH_TOKEN/keyless/partners/cocoapods/index.git'
   source 'https://cdn.cocoapods.org/'
   ```

3. Add camera permissions in `ios/Info.plist`:

   ```xml
   <key>NSCameraUsageDescription</key>
   <string>This app uses the camera to scan face.</string>
   ```

4. Install native dependencies:

   ```bash
   cd ios && pod install
   ```

## Essential Configuration

There is some essential configuration required before you can use the PingOne Recognize SDK.

* Android

* iOS

* Android v4.6

* iOS v4.6

* Flutter

* React Native

1. Initialize PingOne Recognize SDK in your `Application` class:

   ```kotlin
   // MainApplication
   override fun onCreate() {
       super.onCreate()
       // Initialize {p1recognize}
       Keyless.initialize(this)
   }
   ```

   |   |                                                                                                                                                                                                                                                                         |
   | - | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   |   | If your app crashes with `java.lang.IllegalStateException: Attempting to launch an unregistered ActivityResultLauncher` (or React Native bridges do not receive enrollment completion), this may be due to a mismatch between `applicationId` and Activity `namespace`. |

   In this case, pass your Activities namespace as a second parameter:

   ```kotlin
   // MainApplication
   override fun onCreate() {
       super.onCreate()
       // Initialize {p1recognize}
       Keyless.initialize(this, "my.app.test")
   }
   ```

2. Add your application class to `AndroidManifest.xml`:

   ```xml
   <application
       android:allowBackup="true"
       android:name=".MainApplication"
       android:label="@string/app_name"
       android:supportsRtl="true">
   </application>
   ```

3. Configure PingOne Recognize SDK from `MainActivity`, `ViewModel`, or your PingOne Recognize integration class. `configure` is asynchronous, so wait for completion before calling other APIs:

   ```kotlin
   val setupConfig = SetupConfig(
           apiKey = "KEYLESS_API_KEY",
           hosts = listOf("KEYLESS_HOSTS")
       )

    Keyless.configure(setupConfig) { result ->
       when (result) {
           is Keyless.KeylessResult.Success -> {
               Log.d("KeylessSDK", "configure success")
               // {p1recognize} is ready
           }
           is Keyless.KeylessResult.Failure -> {
               Log.d("KeylessSDK", "configure error")
           }
        }
    }
   ```

1) Create `SetupConfig` and pass it to `Keyless.configure` (typically in `application(:didFinishLaunchingWithOptions:)`):

   ```swift
   let setupConfig = SetupConfig(
           apiKey: "KEYLESS_API_KEY",
           hosts: ["KEYLESS_HOSTS"]
       )

   if let error = Keyless.configure(configuration: setupConfig) {
       print("{p1recognize}.Configure failed with error: \(error)")
   }
   ```

1. Initialize PingOne Recognize SDK:

   ```kotlin
   // MainApplication
   override fun onCreate() {
       super.onCreate()
       Keyless.initialize(this)
   }
   ```

2. Add your application class to the manifest.

3. Configure using `SetupConfiguration`:

   ```kotlin
   val setupConfiguration = SetupConfiguration.builder
       .withApiKey("KEYLESS_API_KEY")
       .withHosts(listOf("KEYLESS_HOSTS"))
       .build()

   Keyless.configure(setupConfiguration) { result ->
       when (result) {
           is Keyless.KeylessResult.Success -> {
               Log.d("KeylessSDK", "configure success")
           }
           is Keyless.KeylessResult.Failure -> {
               Log.d("KeylessSDK", "configure error")
           }
       }
   }
   ```

1) Create `Keyless.SetupConfiguration` and pass it to `Keyless.configure`:

   ```swift
   let setupConfiguration = Keyless.SetupConfiguration.builder
       .withApiKey("KEYLESS_API_KEY")
       .withHosts(["KEYLESS_HOSTS"])
       .build()

   if let error = Keyless.configure(configuration: setupConfiguration) {
       print("Keyless.Configure failed with error: \(error)")
   }
   ```

1. Import required packages:

   ```dart
   import 'package:keyless_flutter_sdk/keyless.dart';
   import 'package:keyless_flutter_sdk/models/configurations/setup_configuration.dart';
   ```

2. Configure SDK during app initialization:

   ```dart
   final setupConfiguration = SetupConfiguration(
       apiKey: "KEYLESS_API_KEY",
       hosts: ["KEYLESS_HOSTS"],
   );

   try {
       await Keyless.instance.configure(setupConfiguration);
       print("Keyless SDK configured successfully");
   } catch (error) {
       print("Failed to configure Keyless SDK: $error");
   }
   ```

1) Initialize native SDK for Android in `MainApplication.kt`:

   ```kotlin
   import io.reactnative.keyless.sdk.KeylessSDKModule

   override fun onCreate() {
       super.onCreate()
       KeylessSDKModule.initialize(application = this)
   }
   ```

2) Configure SDK once app starts:

   ```javascript
   import Keyless, { SetupConfig } from '@react-native-keyless/sdk';

   const config = new SetupConfig({
     apiKey: 'KEYLESS_API_KEY',
     hosts: ['KEYLESS_HOSTS'],
   });

   const result = await Keyless.configure(config);

   result.fold({
     onSuccess: data => {
       console.log('Keyless SDK configured successfully:', data);
     },
     onFailure: error => {
       console.error('Failed to configure Keyless SDK:', error);
     },
   });
   ```

## Additional Configuration

In addition to essential configuration parameters, you can also specify optional parameters detailed throughout Mobile SDK docs (for example, Logging, Liveness Settings).

### Shared Circuits

This is the target desired number of circuits kept on the server. Use `numberOfSharedCircuits` to set this value.

### Networking Module

If you need to perform network requests on behalf of the Keyless SDK, implement the `KLNetworkingModule` interface and set `networkingModule` with your implementation.

* Android

* iOS

```kotlin
public interface KLNetworkingModule {
    public fun sendHTTPRequest(
        baseUrl: String,
        path: String,
        method: String,
        headers: Map<String, String>,
        body: String
    ): KLHTTPResponse

    public data class KLHTTPResponse(
        val errorCode: Int,
        val httpCode: Int,
        val responseBody: String
    )
}
```

```swift
public protocol KLNetworkingModule {
    func sendHTTPRequest(
        host: String,
        url: String,
        method: String,
        headers: [String: String],
        body: String
    ) -> KLHTTPResponse
}

public struct KLHTTPResponse {
    var errorCode: Int
    var httpCode: Int
    var responseBody: String
    public init(errorCode: Int, httpCode: Int, responseBody: String) {
        self.errorCode = errorCode
        self.httpCode = httpCode
        self.responseBody = responseBody
    }
}
```
