React Native Implementation
React Native Project Requirements
Before React Native SDK integration, ensure your environment meets these requirements:
- Node.js: v18+
- npm: v9+ (or yarn v1.22+)
- React: v17+
- React Native: v0.72+
- TypeScript (optional, but recommended): v5+
- Android: 7.1+ (API level 25+)
- iOS: 12.0+
React Native Installation
For React Native Users:
The code snippet below installs the SDK alongside its compulsory peer dependencies required to work seamlessly:
Install the SDK
npm install kora-identity-react-native-sdkor
yarn add kora-identity-react-native-sdkFor iOS, install pods
cd ios && pod install && cd ..Rebuild your App:
npx react-native run-android
npx react-native run-iosFor Expo Users:
The code snippet below installs the SDK:
npm install kora-identity-react-native-sdkor
yarn add kora-identity-react-native-sdkThese peer dependencies must be installed for the SDK to function properly. The code snippet below automatically selects the versions compatible with your Expo SDK version:
npx expo install react-native-webviewRebuild your App
For Android:
npx expo prebuild --cleannpx expo run:androidFor iOS:
npx expo prebuild --cleannpx expo run:iosNOTE: We recommend always fetching the latest stable version from npm.
React Native Permissions
Android
Add camera permission to your Android manifest:
<uses-permission android:name="android.permission.CAMERA" />If your app flow requires audio support, you may also need microphone permission depending on your setup.
iOS
Add camera usage description to your Info.plist:
<key>NSCameraUsageDescription</key>
<string>This app needs camera access for liveness verification.</string>If your app flow requires microphone access, add the appropriate microphone usage description as well.
React Native Import and Setup
import { koraLivenessService } from 'kora-identity-react-native-sdk';
import type {
LivenessConfig,
LivenessResult,
} from 'kora-identity-react-native-sdk';You can also use the component wrapper:
import { LivenessCheck } from 'kora-identity-react-native-sdk';React Native Configuration Example
const verificationConfig = {
publicKey: 'your_public_key_here',
user: {
firstName: 'John',
lastName: 'Doe',
email: '[email protected]',
},
branding: {
color: '#2376F3',
name: 'Your Company',
logo: 'https://your-domain.com/logo.png',
},
presentation: 'modal',
allowAudio: false,
};React Native Start Verification
Auto or Platform-Determined Flow
const startVerification = async () => {
try {
const component = await koraLivenessService.checkLiveness({
...verificationConfig,
onSuccess: (result: LivenessResult) => {
console.log('Verification successful:', result);
},
onFailure: (result: LivenessResult) => {
console.log('Verification failed:', result);
},
onClose: () => {
console.log('User closed verification');
},
});
setLivenessComponent(component);
} catch (error) {
console.error('Failed to start verification:', error);
}
};Explicit Passive Liveness
const startPassiveVerification = async () => {
const component = await koraLivenessService.checkLiveness({
...verificationConfig,
type: 'passive',
onSuccess: (result: LivenessResult) => {
console.log('Passive verification successful:', result);
},
onFailure: (result: LivenessResult) => {
console.log('Passive verification failed:', result);
},
onClose: () => {
console.log('Verification closed');
},
});
setLivenessComponent(component);
};Explicit Active Liveness
const startActiveVerification = async () => {
const component = await koraLivenessService.checkLiveness({
...verificationConfig,
type: 'active',
tasks: [
{
id: 'complete_the_circle',
difficulty: 'medium',
timeout: 30000,
},
{
id: 'blink',
difficulty: 'easy',
maxBlinks: 3,
timeout: 15000,
},
],
onSuccess: (result: LivenessResult) => {
console.log('Active verification successful:', result);
},
onFailure: (result: LivenessResult) => {
console.log('Active verification failed:', result);
},
onClose: () => {
console.log('Verification closed');
},
});
setLivenessComponent(component);
};React Native Render Example
import React, { useState } from 'react';
import { View, Button } from 'react-native';
import { koraLivenessService } from 'kora-identity-react-native-sdk';
import type { LivenessResult } from 'kora-identity-react-native-sdk';
const App = () => {
const [livenessComponent, setLivenessComponent] =
useState<React.ReactElement | null>(null);
const [result, setResult] = useState<LivenessResult | null>(null);
const handleVerification = async () => {
try {
const component = await koraLivenessService.checkLiveness({
publicKey: 'your_public_key',
user: {
firstName: 'John',
lastName: 'Doe',
email: '[email protected]',
},
onSuccess: (response) => {
setResult(response);
setLivenessComponent(null);
},
onFailure: (response) => {
setResult(response);
setLivenessComponent(null);
},
onClose: () => {
setLivenessComponent(null);
},
});
setLivenessComponent(component);
} catch (error) {
console.error('Verification error:', error);
}
};
if (livenessComponent) {
return <View style={{ flex: 1 }}>{livenessComponent}</View>;
}
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Button title="Start Verification" onPress={handleVerification} />
</View>
);
};
export default App;React Native Alternative Component Wrapper
import React, { useState } from 'react';
import { View, Button } from 'react-native';
import { LivenessCheck } from 'kora-identity-react-native-sdk';
const App = () => {
const [showLiveness, setShowLiveness] = useState(false);
if (showLiveness) {
return (
<View style={{ flex: 1 }}>
<LivenessCheck
publicKey="your-kora-public-key"
config={{
user: {
firstName: 'John',
lastName: 'Doe',
email: '[email protected]',
},
branding: {
color: '#2376F3',
},
}}
onSuccess={(result) => {
console.log('Success:', result);
setShowLiveness(false);
}}
onFailure={(result) => {
console.log('Failed:', result);
setShowLiveness(false);
}}
onClose={() => setShowLiveness(false)}
/>
</View>
);
}
return (
<View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
<Button
title="Start Liveness Check"
onPress={() => setShowLiveness(true)}
/>
</View>
);
};
export default App;React Native Active Liveness Task Example
const customTasks = [
{
id: 'yes_or_no',
difficulty: 'medium',
questions: [
{
question: 'Are you ready to proceed?',
answer: true,
errorMessage: 'Please respond as instructed on screen',
},
],
},
{
id: 'motions',
difficulty: 'hard',
maxNods: 3,
maxBlinks: 2,
timeout: 45000,
},
];Universal Configuration Schema
The liveness verification service across all platforms uses a consistent configuration object schema:
The following schema represents the universal configuration format. Platform-specific implementations may have slight variations in method names or import paths, but the core configuration structure remains consistent across React Native, Web, and Flutter.
{
publicKey: string; // Your merchant API public key
type?: 'active' | 'passive'; // Liveness type (optional for auto-detection)
debugMode?: boolean; // Enable debug logging
sandboxEnvironment?: boolean; // Use sandbox environment for react native and flutter. Web gets it from the key.
user: { // User information (required)
firstName: string;
lastName?: string;
email?: string;
};
branding?: { // UI customization (optional)
color?: string; // Primary brand color (hex)
logo?: string; // Logo URL
logoAlt?: string;
};
presentation?: 'modal' | 'page'; // Presentation mode
allowAudio?: boolean; // Allow audio instructions
tasks?: Array<{ // Custom tasks for active liveness
id: string; // Task identifier
difficulty?: 'easy' | 'medium' | 'hard';
timeout?: number; // Task timeout in milliseconds
maxBlinks?: number; // For blink tasks
maxNods?: number; // For motion tasks
questions?: Array<{ // For yes/no tasks
question: string;
answer: boolean;
errorMessage?: string;
}>;
}>;
idLookup?: { // Optional ID lookup and facial match
idType: string;
fields: Record<string, unknown>;
verificationConsent: boolean;
validation?: {
firstName?: string;
lastName?: string;
dateOfBirth?: string;
};
};
// Callback functions
onSuccess?: (result: LivenessResult) => void;
onFailure?: (result: LivenessResult) => void;
onClose?: () => void;
onStart?: () => void; // available for RN and Flutter only
}Parameter Definitions
publicKey: (Required) Your merchant account's API public keytype: (Optional) Specify 'active' or 'passive' liveness check:- Active Liveness: User performs prompted actions (blink, turn head, say phrases). Best for higher-assurance checks where interaction is acceptable
- Passive Liveness: System detects signs of life from natural video/image streams. Best for frictionless, low-to-medium risk flows.
If omitted, the backend will auto-determine the best type based on risk assessment
user: (Required) Customer information including first name (required), last name, and emailbranding: (Optional) Customize the user interface (UI) by configuring your brand color and logo. Note that the "Powered by Kora" footer remains fixed and cannot be modified or hidden.presentation:(Optional) Choose between 'modal' (overlay) or 'page' (full screen) presentationtasks: (Optional) For active liveness, specify custom tasks like blink, motion detection, or yes/no questionsidLookup: (Optional) Run an ID lookup and facial match alongside the liveness check. Requires explicit customer consent. See "ID lookup" belowonIdLookupResult: (Optional) Callback function executed when the ID lookup result is ready. Always fires after onSuccess, never beforeallowAudio: (Optional) Enable audio instructions during verificationonSuccess: (Optional) Callback function executed when verification succeedsonFailure: (Optional) Callback function executed when verification failsonClose:(Optional) Callback function executed when the user closes the verification
The result object
onSuccess and onFailure both receive a LivenessResult:
{
success: boolean;
data?: any;
error?: string;
metadata?: Record<string, any>;
}On a successful check, data carries the session reference and status:
{
success: true,
data: { reference: 'LC-...', status: 'passed' },
metadata: { type: 'active' }
}ID Lookup and Facial Match
A liveness check can carry an ID lookup. The customer's ID details are sent with the session, and the backend matches the captured face against the photo held for that ID. The liveness check runs exactly as it otherwise would — the customer sees no extra screens, and there is no ID entry UI in the SDK. You pass the details you already hold.
ID lookup is optional. Omit idLookup and the check behaves exactly as before.
Requesting a lookup
await koraLivenessService.checkLiveness({
...verificationConfig,
idLookup: {
idType: 'ng_bvn',
fields: { id: '12345678901' },
verificationConsent: true,
validation: {
firstName: 'Ada',
lastName: 'Lovelace',
dateOfBirth: '1990-12-10',
},
},
onSuccess: (result) => {
// Liveness passed. The ID lookup result is not ready yet.
},
onIdLookupResult: (result) => {
if (result.verified) {
// Face matched the ID on record.
}
},
});idLookup fields
| Field | Required | Description |
|---|---|---|
idType | Yes | The ID type to look up, for example ng_bvn, ng_nin, ng_passport |
fields | Yes | The ID values themselves, flat. { id: '12345678901' } for most types; extra keys where the type needs them. Must not be empty |
verificationConsent | Yes | Must be true. Collect explicit customer consent before starting a lookup — the SDK rejects the call otherwise |
validation | No | Optional cross-checks: firstName, lastName, dateOfBirth (YYYY-MM-DD) |
Fields must not contain the keys
id_type,verification_consentorvalidationThey are reserved keys and the SDK will reject them.
Receiving the result
The ID lookup finishes after the liveness check does, so the two results arrive separately. onSuccess fires as soon as liveness passes; onIdLookupResult fires once the lookup completes. The order is guaranteed: the ID result never arrives before onSuccess.
| Field | Description |
|---|---|
reference | The liveness session reference |
status | The liveness status for the session |
workflowStatus | Whether the full workflow completed |
verified | true only when liveness passed, the workflow completed, and the verification result was valid |
verification | The verification detail, when present |
timedOut | true if the result was still pending when polling gave up |
error | The reason the lookup could not be completed |
Treat verified as the single answer. A failed liveness check can never report as verified, even where the ID itself was found.
Handling Result Timeouts
The SDK polls for the ID lookup result for approximately 90 seconds. If the result does not arrive within this window, the following behavior occurs:
Event Trigger: The onIdLookupResult callback fires with timedOut: true and no verification data.
Liveness Status: The liveness check is unaffected and operates independently onSuccess has already fired).
Fallback Resolution: Query the session reference server-side to retrieve the final outcome.
Updated 23 days ago