A standalone React Native and Web SDK for face verification and Zero-Knowledge (ZK) proofs.
- Face Matching: High-accuracy face embedding comparison.
- Liveness Detection: Interactive liveness checks with antispoofing protection.
- Demographic Analysis: Optional age and gender estimations alongside captures.
- ZK Proofs: Generate and verify cryptographic proofs of identity without revealing facial biometric data.
- Platform Agnostic: Works on iOS, Android (via Expo), and Web.
To keep documentation clean, each major module has its own dedicated documentation:
core/: Headless business logic, types, and matching algorithms.react-native/: UI components, platform adapters, and hooks for React Native/Expo.config/: Configuration guides, environments, and CDN settings.storage/: Built-in storage adapters for persisting enrolled references and proofs.assets/: ONNX models and WebView-based liveness/ZK scripts.example/: A complete Expo app demonstrating how to integrate the SDK.
- Node.js: >= 20
- Expo SDK: 54 or compatible React Native
- Git LFS: Required for downloading ONNX models and WASM binaries.
-
Install dependencies in the root:
npm install
-
Install dependencies in your host app:
npm install @jupitermetalabs/face-zk-sdk
The global runtime configuration for the SDK instance.
| Field | Type | Description |
|---|---|---|
liveness |
Object |
Optional. Controls anti-spoofing. |
liveness.enabled |
boolean |
If true, requires liveness check to pass for overall success. |
zk |
Object |
Optional. Controls ZK proof generation. |
zk.enabled |
boolean |
Enables the ZK proof subsystem. |
zk.engine |
ZkProofEngine |
The engine implementation (e.g., Plonky3 WebView bridge). |
zk.requiredForSuccess |
boolean |
If true, verification fails if ZK proof generation fails. |
storage |
StorageAdapter |
Optional. Provider for saving reference images/embeddings. |
onLog |
Function |
Optional. Local logging callback for telemetry. |
Note: Match pass/fail is determined by the ZK engine (which owns the threshold internally). The SDK exposes the raw L2² distance and match percentage in
VerificationOutcome.matchfor informational use.
Pass to verifyOnly / verifyWithProof (5th argument) to supply per-call providers and override global config. Extends VerificationOptions.
| Field | Type | Description |
|---|---|---|
livenessProvider |
LivenessProvider |
Optional. Liveness provider for this call. |
imageDataProvider |
ImageDataProvider |
Optional. Image-data provider (base64, size, quality). |
liveness |
Partial |
Override enabled for this check. |
zk |
Partial |
Override requiredForSuccess for this session. |
includeImageData |
Object |
Request extra data in the verified event payload. |
*.base64 |
boolean |
Include the captured live frame as a base64 string. |
*.sizeKb |
boolean |
Include the approximate size of the image. |
*.qualityScore |
number |
Include an image quality score (0–1, higher = better). |
Pass these to ReferenceEnrollmentFlow or createReferenceFromImage.
| Field | Type | Description |
|---|---|---|
metadata |
Object |
Key-value pairs stored alongside the reference (e.g., userId). |
persist |
boolean |
If true, automatically saves the template via the storage adapter. |
Git LFS is required to clone ONNX model files and WASM binaries (stored via LFS):
git lfs install
git lfs pullPeer dependencies — install in your host app:
npx expo install react-native-webview expo-camera expo-file-system expo-assetMetro config — add asset extensions so Metro bundles .onnx, .wasm, and .html files.
In your metro.config.js:
const { getDefaultConfig } = require('expo/metro-config');
const config = getDefaultConfig(__dirname);
config.resolver.assetExts.push('onnx', 'wasm', 'html', 'data');
module.exports = config;Camera permissions — add to your app config:
- iOS (
app.jsonorInfo.plist):NSCameraUsageDescription - Android (
app.jsonorAndroidManifest.xml):android.permission.CAMERA
Call once at app startup:
import { initializeSdk } from '@jupitermetalabs/face-zk-sdk/react-native';
await initializeSdk({
models: {
detection: { module: require('./assets/models/det_500m.onnx') },
recognition: { module: require('./assets/models/w600k_mbf.onnx') },
antispoof: { module: require('./assets/models/antispoof.onnx') },
ageGender: { module: require('./assets/models/genderage.onnx') },
wasm: { module: require('./assets/wasm/zk_face_wasm_bg.wasm') },
zkWorkerHtml: { module: require('./assets/zk-worker.html') },
},
});Pass this to the UI components or headless core functions to control liveness, ZK, storage, and logging:
import type { FaceZkRuntimeConfig } from '@jupitermetalabs/face-zk-sdk/react-native';
const sdkConfig: FaceZkRuntimeConfig = {
liveness: { enabled: true },
zk: { enabled: true, engine: myZkProofEngine, requiredForSuccess: false },
storage: myStorageAdapter,
};The SDK ships with a built-in WebView liveness provider. Use the unified factory:
import { createLivenessProvider } from '@jupitermetalabs/face-zk-sdk/react-native';
// Default — uses the SDK's built-in WebView anti-spoof result
const provider = createLivenessProvider({ spoofScore: metadata.spoofScore });
// Custom — plug in your own host-side liveness service
const provider = createLivenessProvider({ service: myLivenessService, minScore: 0.8 });FaceZkVerificationFlow uses the built-in WebView provider automatically; you only need createLivenessProvider when implementing a headless flow or substituting your own liveness service.
Capture a reference face and save it to storage.
<ReferenceEnrollmentFlow
sdkConfig={sdkConfig}
onComplete={(template) => console.log("Enrolled!", template)}
/>Verify a live user against a saved reference.
<FaceZkVerificationFlow
sdkConfig={sdkConfig}
reference={savedReference}
mode="verify-with-proof"
onComplete={(outcome) => console.log("Verified!", outcome)}
/>Enable by passing the ageGender model in initializeSdk. Results are returned automatically alongside every verification and enrollment.
Enable the model:
await initializeSdk({
models: {
detection: { module: require('./assets/models/det_500m.onnx') },
recognition: { module: require('./assets/models/w600k_mbf.onnx') },
antispoof: { module: require('./assets/models/antispoof.onnx') },
ageGender: { module: require('./assets/models/genderage.onnx') }, // add this
},
});Read results from verification:
<FaceZkVerificationFlow
onComplete={(outcome) => {
// outcome.liveCapture is populated after a successful live capture
console.log(outcome.liveCapture?.gender); // "Male" | "Female" | "Unknown"
console.log(outcome.liveCapture?.age); // e.g. 28
}}
/>Read results from enrollment:
<ReferenceEnrollmentFlow
onComplete={(template) => {
// gender/age stored in template metadata under sdkResponse
console.log(template.metadata?.sdkResponse?.gender);
console.log(template.metadata?.sdkResponse?.age);
}}
/>If ageGender is not configured, gender will be undefined and age will be undefined — the rest of the SDK functions normally.
Please see the individual README.md files in each subdirectory for more technical details on the architecture.