@finclusionaibuild/liveness-sdk
v1.0.7
Published
AWS Face Liveness SDK for React applications.
Maintainers
Readme
@finclusionaibuild/liveness-sdk
A comprehensive Face Liveness Detection SDK for React applications. This SDK provides biometric face verification capabilities with a mobile-responsive UI.
Features
- ✅ Face Liveness Detection - Real-time face verification.
- ✅ Mobile Responsive - Optimized for mobile, tablet, and desktop devices
- ✅ Multiple Components -
LivenessDetector,ExternalLiveness,PaymentLiveness - ✅ TypeScript Support - Full TypeScript definitions included
- ✅ Error Handling - Comprehensive error handling and retry mechanisms
- ✅ Customizable - Custom logos, instruction text, and styling
- ✅ React Native Ready - Works with React Native via WebView
Installation
npm install @finclusionaibuild/liveness-sdkPeer Dependencies
The SDK requires these peer dependencies to be installed in your project:
npm install react@^18.0.0 react-dom@^18.0.0 @tanstack/react-query@^5.39.0Prerequisites
- React Query Setup: You must wrap your application (or the component using the SDK) with
QueryClientProvider:
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
{/* Your app */}
</QueryClientProvider>
);
}- CSS Import: You must import the SDK's stylesheet:
import "@finclusionaibuild/liveness-sdk/styles.css";Quick Start (Web)
Basic Example
import React from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { LivenessDetector } from "@finclusionaibuild/liveness-sdk";
import "@finclusionaibuild/liveness-sdk/styles.css";
const queryClient = new QueryClient();
function App() {
const config = {
apiBaseUrl: "https://api.example.com",
getAuthToken: () => localStorage.getItem("authToken"),
endpoints: {
createSession: "/api/liveliness",
verify: "/api/liveliness/{sessionId}",
},
};
const handleComplete = () => {
console.log("Liveness check completed!");
// Navigate to next step
};
return (
<QueryClientProvider client={queryClient}>
<LivenessDetector
config={config}
token={localStorage.getItem("authToken")}
gotoNext={handleComplete}
/>
</QueryClientProvider>
);
}Advanced Example with Customization
import React, { useState } from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import {
LivenessDetector,
type LivenessConfig,
} from "@finclusionaibuild/liveness-sdk";
import "@finclusionaibuild/liveness-sdk/styles.css";
const queryClient = new QueryClient();
function AdvancedLivenessExample() {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const config: LivenessConfig = {
apiBaseUrl: process.env.REACT_APP_API_BASE_URL || "https://api.example.com",
getAuthToken: () => {
// Get token from your auth system
return localStorage.getItem("authToken");
},
endpoints: {
createSession: "/api/v1/liveliness/create",
verify: "/api/v1/liveliness/{sessionId}/verify",
},
};
const handleComplete = async () => {
setIsLoading(true);
try {
// Handle successful liveness check
console.log("Liveness verification successful!");
// Proceed to next step in your flow
window.location.href = "/next-step";
} catch (err) {
setError("Failed to process liveness result");
console.error(err);
} finally {
setIsLoading(false);
}
};
return (
<QueryClientProvider client={queryClient}>
<div className="container mx-auto p-4">
{error && (
<div className="mb-4 p-4 bg-red-100 border border-red-400 text-red-700 rounded">
{error}
</div>
)}
<LivenessDetector
config={config}
token={localStorage.getItem("authToken")}
gotoNext={handleComplete}
logoUrl="/custom-logo.svg" // Optional: Custom logo
instructionText="Please position your face in the center of the frame and follow the instructions."
/>
</div>
</QueryClientProvider>
);
}Error Handling Example
import React, { useState } from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { LivenessDetector, type LivenessError } from "@finclusionaibuild/liveness-sdk";
import "@finclusionaibuild/liveness-sdk/styles.css";
const queryClient = new QueryClient();
function ErrorHandlingExample() {
const [error, setError] = useState<LivenessError | null>(null);
const [retryCount, setRetryCount] = useState(0);
const config = {
apiBaseUrl: "https://api.example.com",
getAuthToken: () => localStorage.getItem("authToken"),
endpoints: {
createSession: "/api/liveliness",
verify: "/api/liveliness/{sessionId}",
},
};
const handleComplete = () => {
console.log("Success!");
setError(null);
setRetryCount(0);
};
const handleError = (err: LivenessError) => {
setError(err);
console.error("Liveness error:", err);
// Handle specific error types
if (err.response?.status === 403) {
// Handle unauthorized
alert("Session expired. Please login again.");
} else if (err.response?.status === 400) {
// Handle bad request
if (retryCount < 3) {
setRetryCount((prev) => prev + 1);
// Component will retry automatically
} else {
alert("Maximum retry attempts reached. Please contact support.");
}
}
};
return (
<QueryClientProvider client={queryClient}>
<div>
{error && (
<div className="mb-4 p-4 bg-yellow-100 border border-yellow-400 rounded">
<p className="font-semibold">Error occurred:</p>
<p>{error.message || "Unknown error"}</p>
<p className="text-sm mt-2">Retry count: {retryCount}/3</p>
</div>
)}
<LivenessDetector
config={config}
token={localStorage.getItem("authToken")}
gotoNext={handleComplete}
/>
</div>
</QueryClientProvider>
);
}Component API
LivenessDetector
Main liveness detection component with full verification flow.
Props:
interface LivenessDetectorProps {
config: LivenessConfig; // Required: Configuration object
token?: string | null; // Optional: Authentication token
gotoNext: () => void; // Required: Callback on success
logoUrl?: string; // Optional: Custom logo URL (defaults to iDCERTIFY logo)
instructionText?: string; // Optional: Custom instruction text
}Example:
<LivenessDetector
config={config}
token={authToken}
gotoNext={() => console.log("Complete!")}
logoUrl="/my-logo.svg"
instructionText="Custom instructions here"
/>ExternalLiveness
Standalone liveness component for external pages or separate flows.
Props:
interface ExternalLivenessProps {
config: LivenessConfig;
token?: string | null;
gotoNext: () => void;
region?: string; // Optional:
logoUrl?: string;
instructionText?: string;
}Example:
<ExternalLiveness
config={config}
token={authToken}
gotoNext={handleComplete}
region="us-west-2"
/>PaymentLiveness
Payment verification variant that compares face with user profile.
Props:
interface PaymentLivenessProps {
config: LivenessConfig;
token?: string | null;
gotoNext: () => void;
handleClose?: () => void; // Optional: Close handler
logoUrl?: string;
instructionText?: string;
onSendOtp?: () => Promise<void>; // Optional: OTP sending callback
}Example:
<PaymentLiveness
config={config}
token={authToken}
gotoNext={handleComplete}
handleClose={() => setShowModal(false)}
onSendOtp={async () => {
await sendOtpToUser();
}}
/>Configuration
LivenessConfig
interface LivenessConfig {
apiBaseUrl: string; // Base URL for your API
getAuthToken: () => string | null; // Function to get auth token
includeLivenessGuide?: boolean; // Optional: Show guide modal
endpoints?: {
createSession?: string; // Optional: Custom endpoint (default: '/api/liveliness')
verify?: string; // Optional: Custom verify endpoint
compareWithUser?: string; // Optional: Custom compare endpoint (PaymentLiveness)
};
}Example:
const config: LivenessConfig = {
apiBaseUrl: "https://api.example.com",
getAuthToken: () => {
// Your token retrieval logic
return localStorage.getItem("token");
},
includeLivenessGuide: true, // Show pre-liveness guide modal
endpoints: {
createSession: "/custom/liveliness/create",
verify: "/custom/liveliness/{sessionId}/verify",
},
};React Native Usage (WebView)
To use this SDK in React Native applications, you'll need to embed it in a WebView component. The SDK provides a UMD build specifically for WebView compatibility. Here's a complete example:
Installation
npm install react-native-webview
# For iOS, you may also need:
cd ios && pod installComplete React Native Example
import React, { useRef, useState } from "react";
import { View, StyleSheet, Alert, Platform } from "react-native";
import { WebView } from "react-native-webview";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
// HTML template with SDK embedded
const getHTML = (token: string, apiBaseUrl: string) => `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Liveness Check</title>
<style>
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
overflow: hidden;
}
#root {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<div id="root"></div>
<!-- React and ReactDOM -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<!-- React Query -->
<script src="https://unpkg.com/@tanstack/react-query@5/build/umd/index.production.min.js"></script>
<!-- SDK CSS -->
<link rel="stylesheet" href="https://unpkg.com/@finclusionaibuild/[email protected]/dist/styles.css">
<!-- SDK Bundle (UMD) -->
<script src="https://unpkg.com/@finclusionaibuild/[email protected]/dist/index.umd.js"></script>
<script>
// Access SDK from global window object (UMD build exposes FinclusionLivenessSDK)
const { QueryClient, QueryClientProvider } = TanStackReactQuery;
const { LivenessDetector } = window.FinclusionLivenessSDK;
const { createRoot } = ReactDOM;
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 2,
refetchOnWindowFocus: false,
},
},
});
const config = {
apiBaseUrl: '${apiBaseUrl}',
getAuthToken: () => '${token}',
endpoints: {
createSession: '/api/liveliness',
verify: '/api/liveliness/{sessionId}',
},
};
const handleComplete = () => {
// Send message to React Native
window.ReactNativeWebView.postMessage(JSON.stringify({
type: 'LIVENESS_COMPLETE',
success: true,
}));
};
const App = () => {
return React.createElement(QueryClientProvider, { client: queryClient },
React.createElement(LivenessDetector, {
config: config,
token: '${token}',
gotoNext: handleComplete,
})
);
};
const root = createRoot(document.getElementById('root'));
root.render(React.createElement(App));
</script>
</body>
</html>
`;
function LivenessScreen() {
const webViewRef = useRef<WebView>(null);
const [loading, setLoading] = useState(true);
const authToken = "your-auth-token-here"; // Get from your auth system
const apiBaseUrl = "https://api.example.com";
const handleMessage = (event: any) => {
try {
const data = JSON.parse(event.nativeEvent.data);
switch (data.type) {
case "LIVENESS_COMPLETE":
Alert.alert("Success", "Liveness check completed!", [
{
text: "OK",
onPress: () => {
// Navigate to next screen
navigation.navigate("NextScreen");
},
},
]);
break;
case "LIVENESS_ERROR":
Alert.alert("Error", data.message || "Liveness check failed");
break;
default:
console.log("WebView message:", data);
}
} catch (error) {
console.error("Error parsing WebView message:", error);
}
};
return (
<View style={styles.container}>
<WebView
ref={webViewRef}
source={{ html: getHTML(authToken, apiBaseUrl) }}
onMessage={handleMessage}
onLoadEnd={() => setLoading(false)}
style={styles.webview}
javaScriptEnabled={true}
domStorageEnabled={true}
mediaPlaybackRequiresUserAction={false}
allowsInlineMediaPlayback={true}
// Camera permissions
permissions={["camera", "microphone"]}
// iOS specific
allowsBackForwardNavigationGestures={false}
// Android specific
mixedContentMode="always"
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
webview: {
flex: 1,
},
});
export default LivenessScreen;React Native with Local Bundle (Recommended)
For better performance and offline support, bundle the SDK locally:
import React, { useRef } from "react";
import { View, StyleSheet } from "react-native";
import { WebView } from "react-native-webview";
import { Asset } from "expo-asset"; // or react-native-fs for bare React Native
function LivenessScreen() {
const webViewRef = useRef<WebView>(null);
// Load SDK bundle from local assets
const [sdkHtml, setSdkHtml] = useState("");
useEffect(() => {
// Load your bundled HTML file
// This should include React, React Query, and the SDK bundle
loadSDKHTML().then(setSdkHtml);
}, []);
return (
<View style={styles.container}>
<WebView
ref={webViewRef}
source={{ html: sdkHtml }}
onMessage={handleMessage}
style={styles.webview}
javaScriptEnabled={true}
domStorageEnabled={true}
mediaPlaybackRequiresUserAction={false}
allowsInlineMediaPlayback={true}
/>
</View>
);
}React Native Permissions Setup
iOS (Info.plist)
Add camera and microphone permissions:
<key>NSCameraUsageDescription</key>
<string>We need access to your camera for face verification</string>
<key>NSMicrophoneUsageDescription</key>
<string>We need access to your microphone for face verification</string>Android (AndroidManifest.xml)
Add camera and internet permissions:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.camera.front" android:required="true" />React Native Error Handling
const handleMessage = (event: any) => {
try {
const data = JSON.parse(event.nativeEvent.data);
if (data.type === "LIVENESS_ERROR") {
const error = data.error;
if (error.response?.status === 403) {
// Handle unauthorized - redirect to login
navigation.navigate("Login");
} else if (error.response?.status === 400) {
// Handle bad request
Alert.alert("Verification Failed", "Please try again");
} else {
// Generic error
Alert.alert("Error", error.message || "Something went wrong");
}
}
} catch (error) {
console.error("Error handling message:", error);
}
};
// Handle WebView errors
const handleError = (syntheticEvent: any) => {
const { nativeEvent } = syntheticEvent;
console.error("WebView error: ", nativeEvent);
Alert.alert("Error", "Failed to load liveness check");
};TypeScript Types
The SDK exports comprehensive TypeScript types:
import type {
LivenessConfig,
LivenessSession,
LivenessVerificationResponse,
FaceMatchResponse,
LivenessError,
} from "@finclusionaibuild/liveness-sdk";
// Example usage
const config: LivenessConfig = {
apiBaseUrl: "https://api.example.com",
getAuthToken: () => localStorage.getItem("token"),
};
const handleResponse = (response: LivenessVerificationResponse) => {
if (response.confidence > 60) {
console.log("Verification successful!", response.confidence);
}
};API Endpoints
The SDK expects your backend to provide these endpoints:
Create Session
Endpoint: GET /api/liveliness (or custom via config.endpoints.createSession)
Response:
{
"sessionId": "string",
"AccessKeyId": "string",
"SecretAccessKey": "string",
"SessionToken": "string",
"Region": "string"
}Verify Session
Endpoint: GET /api/liveliness/{sessionId} (or custom via config.endpoints.verify)
Response:
{
"confidence": 85.5,
"image": "base64-encoded-image",
"success": true,
"message": "Verification successful"
}Compare with User (PaymentLiveness)
Endpoint: GET /api/liveliness/{sessionId}/compare-with-user (or custom via config.endpoints.compareWithUser)
Response:
{
"isMatch": true,
"confidence": 92.3,
"details": "Face matches user profile"
}Styling
The SDK includes all necessary styles bundled. Simply import:
import "@finclusionaibuild/liveness-sdk/styles.css";The stylesheet includes:
- Tailwind CSS utilities (responsive, mobile-optimized)
- Finclusion UI styles (processed and rebranded)
- Component-specific styling
Note: The SDK is mobile-responsive by default. No additional CSS configuration needed.
Troubleshooting
Camera Not Working
Web:
- Ensure HTTPS (required for camera access)
- Check browser permissions
- Verify
getUserMediaAPI is available
React Native:
- Check camera permissions in
Info.plist(iOS) andAndroidManifest.xml(Android) - Ensure WebView has
allowsInlineMediaPlayback={true}(iOS) - Verify
mediaPlaybackRequiresUserAction={false}
Styles Not Applying
- Ensure you've imported the CSS:
import '@finclusionaibuild/liveness-sdk/styles.css'; - Check that the CSS file is being loaded (inspect network tab)
- Verify no CSS conflicts with your app's styles
React Query Errors
- Ensure
QueryClientProviderwraps your component - Verify React Query version matches peer dependency (
^5.39.0) - Check that
QueryClientis created outside component render
API Errors
- Verify
apiBaseUrlis correct - Check authentication token is valid
- Ensure endpoints match your backend API
- Check CORS settings if using cross-origin requests
Build Errors
- Ensure all peer dependencies are installed
- Verify Node.js version (recommended: 18+)
- Check TypeScript version compatibility
Examples
Modal Integration
import React, { useState } from "react";
import { LivenessDetector } from "@finclusionaibuild/liveness-sdk";
function LivenessModal() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button onClick={() => setIsOpen(true)}>Start Verification</button>
{isOpen && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg max-w-2xl w-full max-h-[90vh] overflow-auto p-4">
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-bold">Face Verification</h2>
<button onClick={() => setIsOpen(false)}>✕</button>
</div>
<LivenessDetector
config={config}
token={token}
gotoNext={() => {
setIsOpen(false);
// Handle success
}}
/>
</div>
</div>
)}
</>
);
}With Loading States
import React, { useState } from "react";
import { LivenessDetector } from "@finclusionaibuild/liveness-sdk";
function LivenessWithLoading() {
const [isVerifying, setIsVerifying] = useState(false);
return (
<div>
{isVerifying && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white p-6 rounded-lg">
<p>Processing verification...</p>
</div>
</div>
)}
<LivenessDetector
config={config}
token={token}
gotoNext={async () => {
setIsVerifying(true);
try {
// Process result
await processVerification();
} finally {
setIsVerifying(false);
}
}}
/>
</div>
);
}License
MIT
Support
For issues, questions, or contributions, please visit our GitHub repository.
Version
Current version: 1.0.3
