@netki/netki-mobilesdk
v13.0.1
Published
Our NetkiSDK lets you create custom KYC onboarding in your app
Readme
Netki OnboardID SDK - React Native
The OnboardID SDK enables you to integrate identity verification directly into your React Native application. Users can capture ID documents and selfies without leaving your app.
Quick Start
To get up and running, complete the Installation and Core Integration sections. Everything else is optional.
Table of Contents
- Requirements
- Installation
- Migrating from 11.x
- Core Integration
- Optional Features
- API Reference
- Error Handling
- Theming
Requirements
- React Native >= 0.71.0
- iOS 17.0 or higher
- Android minimum SDK 24 (Android 7.0), target SDK 34 or higher
- Xcode >= 15
- Gradle >= 8.0
- npm >= 8.0.0
- NFC capability (required for passport reading)
Installation
Step 1: Install the Package
npm install @netki/netki-mobilesdkStep 2: iOS Configuration
Update the iOS deployment target in your ios/Podfile to iOS 17.0 and enable frameworks (required because the RN bridge is written in Swift):
platform :ios, '17.0'
target 'YourApp' do
use_frameworks!
# ... React Native config ...
endNetkiSDK and NFCPassportReader are declared as transitive dependencies of RNNetkisdk, so no extra pod lines are required in your app's Podfile. CocoaPods resolves NetkiSDK directly from trunk.
Force BUILD_LIBRARY_FOR_DISTRIBUTION=YES on NFCPassportReader in a post_install hook to match the Swift ABI stability required by NetkiSDK.xcframework:
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == 'NFCPassportReader'
target.build_configurations.each do |config|
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
end
end
end
endAdd the required keys to your Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera access is required to capture ID documents</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Photo library access is required to store captured images</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Photo library access is required to store captured images</string>
<key>NFCReaderUsageDescription</key>
<string>Used to read NFC chip data from your passport for identity verification.</string>
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>A0000002471001</string>
</array>Enable the Near Field Communication Tag Reading capability in your target's Signing & Capabilities tab. Xcode will add the following to your .entitlements file:
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>TAG</string>
</array>About
A0000002471001: this is the ICAO 9303 ePassport Application Identifier (AID) — a fixed standard value used by all ePassport chips worldwide. Copy it verbatim; it is not application-specific.
Enable NFC on your App ID in Apple Developer Portal
Info.plist keys and entitlements alone are not enough — the App ID itself must have the NFC capability enabled in the Apple Developer Portal, otherwise provisioning strips the entitlement and NFCTagReaderSession.readingAvailable returns false at runtime.
- Sign in at developer.apple.com/account.
- Left nav → Certificates, Identifiers & Profiles → Identifiers.
- Filter to App IDs and open the App ID matching your app's bundle identifier.
- In the Capabilities list, tick NFC Tag Reading and click Save.
- Enabling the capability invalidates existing provisioning profiles. Go to Profiles, filter to that bundle ID, and click Edit → Save on each affected profile so Apple re-issues them with the new entitlement.
- In Xcode: Settings → Accounts → your Apple ID → Download Manual Profiles (or let automatic signing re-fetch on next build).
Repeat for every build configuration whose bundle ID differs (Development / QA / Production typically have three separate App IDs — enable NFC on each).
Install the pods:
cd ios && pod installStep 3: Android Configuration
Update the Kotlin Gradle plugin version in your android/build.gradle to 2.0.21 or higher:
buildscript {
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21")
}
}The SDK is automatically linked and no other configuration is required.
Expo Setup
For Expo managed workflow, add the plugin to your app.json:
{
"plugins": [
"@netki/netki-mobilesdk"
]
}Then run expo prebuild or use EAS Build.
Migrating from 11.x
There are no JavaScript API changes between 11.x and 12.x — only build configuration shifts because netkicv is now bundled into the shipped SDK artifacts.
iOS:
- Remove any explicit
pod 'NetkiSDK', :git => 'https://github.com/netkicorp/onboardid-pod.git', :tag => '...'line from yourPodfile.NetkiSDKis now a transitive dependency ofRNNetkisdkand resolves from CocoaPods trunk. - Remove
pod 'NFCPassportReader'if you had declared it manually — transitive fromNetkiSDK. - Run
pod install --repo-updateso the local CocoaPods trunk cache picks upNetkiSDK 12.0.0.
Android:
- Delete both
art.myverify.ioMaven repository entries fromandroid/build.gradle. The netkicv native library is now embedded inside the publishedcom.netki:netkisdk:12.0.0AAR on Maven Central. - Remove any app-level
implementation "com.netki:netkisdk:11.x.x"override — the bridge already pins the SDK version.
Core Integration
This section covers everything you need to integrate the SDK. Complete these 4 steps for a fully working implementation.
Step 1: Initialize the SDK
Import and initialize the SDK before using any other methods.
import netkiSDK from '@netki/netki-mobilesdk';
const initializeSDK = async () => {
try {
await netkiSDK.initialize();
console.log('SDK initialized');
} catch (error) {
console.error('Initialization failed:', error);
}
};For non-production environments:
await netkiSDK.initializeWithEnv('DEV'); // or 'STAGING'Step 2: Configure with Your API Token
Configure the SDK with the API token provided by Netki.
const configureSDK = async () => {
try {
await netkiSDK.configureWithToken(API_KEY);
console.log('SDK configured');
} catch (error) {
console.error('Configuration failed:', error);
}
};| Parameter | Type | Description |
|-----------|------|-------------|
| token | string | Your API token from Netki |
If your integration uses an access code for the transaction, call the dedicated variant instead:
await netkiSDK.configureWithTokenAndAccessCode(API_KEY, ACCESS_CODE);| Parameter | Type | Description |
|-----------|------|-------------|
| token | string | Your API token from Netki |
| accessCode | string | Access code for the transaction |
Step 3: Start the Identification Flow
Launch the document capture UI and set up event listeners to handle results.
import { DeviceEventEmitter } from 'react-native';
// Set up event listeners (typically in useEffect)
useEffect(() => {
const successListener = DeviceEventEmitter.addListener(
'identificationFlowSuccess',
(data) => {
console.log('Capture successful');
submitIdentification();
}
);
const cancelListener = DeviceEventEmitter.addListener(
'identificationFlowCancel',
() => {
console.log('User cancelled');
}
);
const errorListener = DeviceEventEmitter.addListener(
'identificationFlowError',
(error) => {
console.error('Capture error:', error.errorType, error.message);
}
);
return () => {
successListener.remove();
cancelListener.remove();
errorListener.remove();
};
}, []);
// Start the capture flow
const startCapture = async () => {
const countries = await netkiSDK.getAvailableCountries();
const idTypes = await netkiSDK.getAvailableIdTypes();
netkiSDK.startIdentificationFlow('DRIVERS_LICENSE', 'US');
};ID Types:
| Type | Description |
|------|-------------|
| DRIVERS_LICENSE | Driver's license |
| PASSPORT | Passport |
| GOVERNMENT_ID | National ID card |
Step 4: Submit the Identification
After a successful capture, submit the data to Netki for processing.
const submitIdentification = async () => {
try {
const result = await netkiSDK.submitIdentification();
console.log('Submitted successfully:', result);
// Result may contain extra data like { tracking_did: "..." }
} catch (error) {
console.error('Submission failed:', error);
}
};Once submitted successfully, the identification results will be delivered to your configured backend callback.
Optional Features
The following features extend the core integration. Add them based on your requirements.
Phone Verification
Add phone number verification to your identification flow. This sends an SMS code to the user's phone for verification.
Prerequisites: Complete Steps 1 and 2 from Core Integration first.
Request a Security Code
Send an SMS verification code to the user's phone:
try {
await netkiSDK.requestSecurityCode('+14155551234');
// Code sent - show UI for user to enter the code
} catch (error) {
if (error.code === 'INVALID_PHONE_NUMBER') {
showInvalidPhoneError();
} else {
showGenericError(error.message);
}
}Confirm the Security Code
Verify the code entered by the user:
try {
await netkiSDK.confirmSecurityCode('+14155551234', userEnteredCode);
// Phone verified - proceed with identification
} catch (error) {
if (error.code === 'INVALID_CONFIRMATION_CODE') {
showInvalidCodeError();
} else {
showGenericError(error.message);
}
}Bypass Security Code
For testing or specific business flows:
await netkiSDK.bypassSecurityCode('+14155551234');Biometrics Re-capture
If you need to re-capture biometric data for an existing transaction (e.g., after a failed liveness check), use the biometrics flow.
Prerequisites: Complete Steps 1 and 2 from Core Integration first.
// Start the biometrics capture
netkiSDK.startBiometricsFlow(transactionId);Handle the result using the same event listeners from Step 3, then submit:
const result = await netkiSDK.submitBiometrics();Configuration Options
Business Metadata
Attach custom metadata to the transaction for your internal tracking:
const metadata = JSON.stringify({
internal_user_id: '12345',
signup_source: 'mobile_app'
});
await netkiSDK.setBusinessMetadata(metadata);Important: Call setBusinessMetadata before startIdentificationFlow to ensure the data is included in the submission.
Client GUID
Set a custom identifier to link the transaction to your system:
await netkiSDK.setClientGuid('your-unique-identifier');
// Retrieve the current client GUID
const guid = await netkiSDK.getClientGuid();Geolocation
Capture the user's location with the transaction:
await netkiSDK.setLocation('37.7749', '-122.4194');Liveness Detection
Enable or disable liveness detection for selfie capture:
netkiSDK.enableLivenessDetection(true);Additional Data on Submit
Include additional data fields when submitting:
const additionalData = JSON.stringify({
ssn: '123456789',
tin: 'TIN12345',
alias: 'user alias',
medical_license: '111111111'
});
const result = await netkiSDK.submitIdentificationWithAdditionalData(additionalData);Error Handling
All SDK methods that return promises will reject with an error object on failure:
{
code: string, // Error type (e.g., "INVALID_TOKEN")
message: string // Optional error message with more details
}Example:
try {
await netkiSDK.configureWithToken(token);
} catch (error) {
switch (error.code) {
case 'INVALID_TOKEN':
showInvalidTokenError();
break;
case 'NO_INTERNET':
showNoInternetError();
break;
default:
showGenericError(error.message);
}
}Error Types:
| Error Type | Description |
|------------|-------------|
| NO_INTERNET | No network connection available |
| INVALID_DATA | Invalid data provided to the SDK |
| INVALID_TOKEN | API token is invalid or expired |
| INVALID_ACCESS_CODE | Access code is invalid |
| INVALID_PHONE_NUMBER | Phone number format is invalid |
| INVALID_CONFIRMATION_CODE | SMS confirmation code is incorrect |
| USER_CANCEL_IDENTIFICATION | User cancelled the identification flow |
| UNEXPECTED_ERROR | An unexpected error occurred |
API Reference
Methods
| Method | Returns | Description |
|--------|---------|-------------|
| initialize() | Promise<boolean> | Initialize the SDK. Call once before any other methods. |
| initializeWithEnv(env) | Promise<boolean> | Initialize with specific environment (DEV, STAGING, PROD). |
| isAvailable() | Promise<boolean> | Check if SDK is initialized and ready. |
| configureWithToken(token) | Promise<boolean> | Configure SDK with API token. |
| configureWithTokenAndAccessCode(token, code) | Promise<boolean> | Configure with token and access code. |
| startIdentificationFlow(idType, countryCode) | void | Launch the document capture flow. |
| submitIdentification() | Promise<any> | Submit captured identification data. |
| submitIdentificationWithAdditionalData(data) | Promise<any> | Submit with additional data fields. |
| startBiometricsFlow(transactionId) | void | Launch biometrics re-capture flow. |
| submitBiometrics() | Promise<boolean> | Submit re-captured biometric data. |
| submitBiometricsWithAdditionalData(data) | Promise<boolean> | Submit biometrics with additional data. |
| requestSecurityCode(phoneNumber) | Promise<boolean> | Send SMS verification code. |
| confirmSecurityCode(phoneNumber, code) | Promise<boolean> | Verify SMS code. |
| bypassSecurityCode(phoneNumber) | Promise<boolean> | Bypass phone verification. |
| setBusinessMetadata(metadata) | Promise<boolean> | Attach custom metadata (JSON string). |
| setClientGuid(guid) | Promise<boolean> | Set custom client identifier. |
| getClientGuid() | Promise<string \| null> | Get current client identifier. |
| setLocation(lat, lon) | Promise<boolean> | Set user geolocation. |
| enableLivenessDetection(enabled) | void | Enable/disable liveness detection. |
| getAvailableIdTypes() | Promise<IdType[]> | Get list of supported document types. |
| getAvailableCountries() | Promise<IdCountry[]> | Get list of supported countries. |
Events
| Event Name | Payload | Description |
|------------|---------|-------------|
| identificationFlowSuccess | { pictures?: Picture[] } | Capture completed successfully |
| identificationFlowCancel | none | User cancelled the flow |
| identificationFlowError | { errorType: string, message?: string } | Error occurred during capture |
Types
IdType
type IdType = 'PASSPORT' | 'DRIVERS_LICENSE' | 'GOVERNMENT_ID';PictureType
type PictureType = 'FRONT' | 'BACK' | 'SELFIE' | 'PASSPORT' | 'PASSPORT_SIGNATURE';IdCountry
interface IdCountry {
name: string;
alpha2: string;
alpha3: string;
countryCallingCode: string;
hasBarcodeId: boolean;
flag?: string;
isBanned: boolean;
hasNfcPassport: boolean;
}Picture
interface Picture {
path: string;
type: PictureType;
barcodes?: Barcode[];
passportContent?: PassportContent;
ePassportContent?: EPassportContent;
livenessInformation?: LivenessInformation;
}AdditionalDataField
Fields that can be passed to submitIdentificationWithAdditionalData():
| Field | Key | Description |
|-------|-----|-------------|
| First Name | first_name | User's first name |
| Last Name | last_name | User's last name |
| Alias | alias | Alternative name |
| Client GUID | client_guid | Custom client identifier |
| SSN | ssn | Social Security Number |
| TIN | tin | Tax Identification Number |
| Medical License | medical_license | Medical license number |
| Email | email | Email address |
| Phone Number | phone_number | Phone number |
For complete type definitions, see the TypeScript declaration file (index.d.ts).
Theming
To customize the look and feel of the SDK screens, see the Theme Documentation.
Author
Netki, [email protected]
License
NetkiSDK is available under the MIT license. See the LICENSE file for more info.
