React Native quick start
This guide gets a working biometric capture on screen with the Mobai-provided user interface. The example uses V3 constraints, shows production feedback, and returns a video with three sampled frames by default.
The React Native package @mobaibio/mobai-biometric wraps the native iOS and Android SDKs. Version 2.3.3 is distributed from Mobai's private Cloudsmith repository. To get a read-only access token, contact support at support@mobai.bio.
Requirements
| Requirement | Version |
|---|---|
| React Native | 0.61 to 0.86 |
| React | Up to 19.2.3 |
| iOS deployment target | 15.0 or later |
| JDK for Android builds | 17 |
- Physical iOS and Android devices for production-quality camera testing
Version 2.3.3 has been tested on devices with React Native 0.81 and builds with React Native 0.86. React Native 0.87 and later are not supported yet: npm install stops with an ERESOLVE peer dependency error. Create new projects with a supported version, for example:
npx @react-native-community/cli init MyApp --version 0.86.3
1. Install the package
Map the @mobaibio scope to the Mobai Cloudsmith npm registry. Add the following to .npmrc in your project root and export your token as MOBAI_ACCESS_TOKEN:
@mobaibio:registry=https://npm.cloudsmith.io/mobai/sdks/
//npm.cloudsmith.io/mobai/sdks/:_authToken=${MOBAI_ACCESS_TOKEN}
Then add the package:
npm install @mobaibio/mobai-biometric@2.3.3
For Yarn 2 and later, see Install for React Native.
2. Configure iOS
The native MobaiBiometric pod is served from Mobai's Cloudsmith CocoaPods repository. Add your token to ~/.netrc as described in Install on iOS with CocoaPods, then update ios/Podfile. The following is the React Native template Podfile with the required Mobai additions, which are marked with comments:
# Mobai: the Cloudsmith spec source, followed by the public CDN.
source 'https://dl.cloudsmith.io/basic/mobai/sdks/cocoapods/index.git'
source 'https://cdn.cocoapods.org/'
# Resolve react_native_pods.rb with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p',
'require.resolve(
"react-native/scripts/react_native_pods.rb",
{paths: [process.argv[1]]},
)', __dir__]).strip
platform :ios, min_ios_version_supported
prepare_react_native_project!
target 'MyApp' do
# Mobai: build pods as static frameworks.
use_frameworks! :linkage => :static
config = use_native_modules!
# Mobai: SwiftProtobuf must be a dynamic framework.
pre_install do |installer|
installer.pod_targets.each do |pod|
if ['SwiftProtobuf'].include?(pod.name)
def pod.dynamic_framework?;
true
end
def pod.build_type;
Pod::BuildType.dynamic_framework
end
end
end
end
use_react_native!(
:path => config[:reactNativePath],
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
post_install do |installer|
react_native_post_install(
installer,
config[:reactNativePath],
:mac_catalyst_enabled => false,
)
# Mobai: module stability for the SDK and its dependency.
installer.pods_project.targets.each do |target|
if ['MobaiBiometric', 'SwiftProtobuf'].include? target.name
target.build_configurations.each do |config|
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
end
end
end
# Mobai: Xcode 26 and later reject pod targets below iOS 15.0,
# and the SwiftProtobuf resource bundle declares 11.0.
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
if config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f < 15.0
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0'
end
end
end
end
end
All three Mobai additions are required. A Podfile can contain only one pre_install and one post_install block, so merge these loops into any blocks that your Podfile already has. Then install the pods:
cd ios && pod install --repo-update
While MobaiBiometric 2.3.3 is also listed in the public CocoaPods trunk, pod install prints Found multiple specifications for MobaiBiometric (2.3.3). The Mobai source is listed first, so CocoaPods uses it, and the warning can be ignored.
iOS 27: adopt the UIScene lifecycle
Apps built with the iOS 27 SDK must use the UIScene lifecycle; otherwise iOS stops the app at launch. The React Native template does not do this yet. If your app does not already use a scene delegate, create the window in a SceneDelegate, and also assign it to AppDelegate.window, because launch() presents the Mobai capture screen from the app delegate's window:
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var reactNativeDelegate: ReactNativeDelegate?
var reactNativeFactory: RCTReactNativeFactory?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
let delegate = ReactNativeDelegate()
let factory = RCTReactNativeFactory(delegate: delegate)
delegate.dependencyProvider = RCTAppDependencyProvider()
reactNativeDelegate = delegate
reactNativeFactory = factory
// The window is created in SceneDelegate.
return true
}
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let windowScene = scene as? UIWindowScene,
let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let window = UIWindow(windowScene: windowScene)
self.window = window
// Required by launch(): the capture screen is presented from AppDelegate.window.
appDelegate.window = window
appDelegate.reactNativeFactory?.startReactNative(
withModuleName: "MyApp",
in: window,
launchOptions: nil
)
}
}
Register the scene delegate in Info.plist:
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
Replace MyApp with your module name.
3. Configure Android
The React Native package uses the native bio.mobai:biometric:2.3.3 package from Mobai's private Cloudsmith Maven repository. Store your Mobai access token in ~/.gradle/gradle.properties as mobaiCloudsmithToken (or supply MOBAI_ACCESS_TOKEN as a CI secret). Then add the repository to android/build.gradle. The React Native template has no allprojects block, so add this block at the end of the file; if your file already has one, add the maven entry to its repositories:
allprojects {
repositories {
maven {
url "https://dl.cloudsmith.io/basic/mobai/sdks/maven/"
credentials {
username = "token"
password = project.providers.gradleProperty("mobaiCloudsmithToken")
.orElse(project.providers.environmentVariable("MOBAI_ACCESS_TOKEN"))
.getOrElse("")
}
content {
includeGroup("bio.mobai")
}
}
}
}
Build Android with JDK 17. Newer JDKs, such as the JDK 25 bundled with current Android Studio versions, fail with Error resolving plugin [id: 'com.facebook.react.settings']. Set JAVA_HOME to a JDK 17 installation, or select JDK 17 in Android Studio under Settings → Build, Execution, Deployment → Build Tools → Gradle → Gradle JDK.
4. Add camera permission
On iOS, add NSCameraUsageDescription to the application's Info.plist:
<key>NSCameraUsageDescription</key>
<string>We use the camera to capture your face for identity verification.</string>
On Android, the SDK declares the CAMERA permission. The predefined UI requests it at runtime; for the custom UI, request it yourself before showing the capture view.
5. Start a capture
import { useEffect } from "react";
import { Button, NativeEventEmitter } from "react-native";
import {
launch,
MobaiBiometric,
EVENT_SUCCESS,
EVENT_FAILURE,
MBCaptureConstraints,
MBImageQualityLevel,
type MBCaptureSessionResult,
type ErrorResult,
} from "@mobaibio/mobai-biometric";
export function IdentityScreen() {
useEffect(() => {
const emitter = new NativeEventEmitter(MobaiBiometric);
const success = emitter.addListener(EVENT_SUCCESS, (result: MBCaptureSessionResult) => {
// result.videoData, result.padData and result.image are Base64 strings.
// Continue with your upload or verification flow.
});
const failure = emitter.addListener(EVENT_FAILURE, (error: ErrorResult) => {
// Show error.errorDescription and let the user retry.
});
return () => {
success.remove();
failure.remove();
};
}, []);
const startBiometricCapture = () =>
launch({
captureConstrains: MBCaptureConstraints.V3,
imageQualityLevel: MBImageQualityLevel.LEVEL_2,
videoCaptureDuration: 2000,
showProgressBar: true,
showFaceStatusLabel: true,
showCountdownLabel: true,
cameraPermissionAlert: {
title: "Camera access required",
message: "Enable camera access in Settings to continue.",
settingText: "Open Settings",
cancelText: "Cancel",
},
});
return <Button title="Start capture" onPress={startBiometricCapture} />;
}
isDebugging can remain false. showProgressBar and showFaceStatusLabel make progress and live V3 guidance visible in production.
6. Test the capture
Run the application on a physical iPhone and Android device, grant camera access, and keep one face inside the overlay. V3 requires valid face distance, position, pose, and lighting before capture starts.