Overview
The split flow uses the OCR and Biometrics components separately instead of the combined IDV flow. This gives you full control over the journey between document capture and facial verification — you can customize loading states, handle OCR results before proceeding to biometrics, and optionally insert a review screen between the two.
Modules used: ocr , biometrics , form (WELCOME, CONSENT, DOCUMENT, LOADING screens)
Daon provider: Document selection and the documents parameter are not required when using the Daon provider — Daon provides its own document type selection screen. To use custom document selection instead of Daon’s built-in screen, contact your FrankieOne account team.
Flow Diagram
Welcome Screen
Initial greeting and introduction to the verification process.
Consent Screen
Capture user consent for data processing.
Document Selection
User selects the type of document to capture.
OCR Capture
Camera-based document capture and data extraction.
Biometrics Capture
Facial verification via selfie capture.
Result
Verification outcome displayed.
Full Implementation
<! DOCTYPE html >
< html lang = "en" >
< head >
< meta charset = "UTF-8" />
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" />
< title > OneSDK Split Flow </ title >
< script src = "https://assets.frankiefinancial.io/one-sdk/v1/oneSdk.umd.js" ></ script >
< style >
body { margin : 0 ; font-family : sans-serif ; background : #fff ; }
#onesdk-wrapper { position : relative ; width : 100 % ; height : 100 vh ; }
#onesdk-container { width : 100 % ; height : 100 % ; }
#loading-overlay {
position : absolute ; top : 0 ; left : 0 ; width : 100 % ; height : 100 % ;
z-index : 10 ; background : #fff ;
}
</ style >
</ head >
< body >
< div id = "onesdk-wrapper" >
< div id = "onesdk-container" ></ div >
< div id = "loading-overlay" ></ div >
</ div >
< script >
async function startOneSDK () {
try {
// 1. Generate session token (move to your backend in production)
const tokenResponse = await fetch (
"https://backend.kycaml.uat.frankiefinancial.io/auth/v2/machine-session" ,
{
method: "POST" ,
headers: {
authorization: "machine " + btoa ( "<CUSTOMER_ID>:<CUSTOMER_CHILD_ID>:<API_KEY>" ),
"Content-Type" : "application/json" ,
},
body: JSON . stringify ({
permissions: {
preset: "one-sdk" ,
reference: "split-" + Date . now (),
},
}),
}
);
const session = await tokenResponse . json ();
// 2. Initialize OneSDK
const oneSdk = await OneSDK ({
session: session ,
mode: "development" ,
recipe: {
ocr: {
maxDocumentCount: 3 ,
},
form: {
provider: { name: "react" },
},
},
});
const appContainer = "#onesdk-container" ;
// 3. Create form components
const welcome = oneSdk . component ( "form" , {
name: "WELCOME" ,
type: "ocr" ,
});
const consent = oneSdk . component ( "form" , { name: "CONSENT" });
const documentForm = oneSdk . component ( "form" , {
name: "DOCUMENT" ,
showPreps: true ,
});
const loading = oneSdk . component ( "form" , {
name: "LOADING" ,
title: { label: "Loading..." },
descriptions: [{ label: "" }],
});
const biometrics = oneSdk . component ( "biometrics" );
// 4. Wire up form navigation
welcome . mount ( appContainer );
welcome . on ( "form:welcome:ready" , () => {
consent . mount ( appContainer );
});
consent . on ( "form:consent:ready" , () => {
documentForm . mount ( appContainer );
});
// 5. Handle document selection → OCR capture
documentForm . on ( "form:document:ready" , ({ inputInfo }) => {
loading . mount ( "#loading-overlay" );
const docType = inputInfo . documentType ;
const ocr = oneSdk . component ( "ocr" , {
documents: [{ type: docType , countries: [ "AUS" ] }],
});
ocr . mount ( appContainer );
ocr . on ( "loading" , ( isLoading ) => {
if ( ! isLoading ) {
loading . unmount ();
}
});
ocr . on ( "error" , ( err ) => {
console . error ( "OCR error:" , err );
});
// 6. Handle OCR results → Biometrics
ocr . on ( "results" , ({ document }) => {
if ( document ) {
loading . mount ( "#loading-overlay" );
biometrics . mount ( appContainer );
}
});
});
// 7. Handle biometrics
let biometricsError = false ;
biometrics . on ( "detection_failed" , () => {
biometricsError = true ;
});
biometrics . on ( "session_closed" , () => {
if ( biometricsError ) {
biometrics . mount ( appContainer );
biometricsError = false ;
}
});
biometrics . on ( "loading" , ( isLoading ) => {
if ( ! isLoading ) {
loading . unmount ();
}
});
biometrics . on ( "results" , ( result ) => {
document . getElementById ( "onesdk-container" ). innerHTML =
"<h2>Verification complete</h2>" ;
});
biometrics . on ( "error" , ( err ) => {
console . error ( "Biometrics error:" , err );
});
} catch ( error ) {
console . error ( "OneSDK initialization failed:" , error );
}
}
startOneSDK ();
</ script >
</ body >
</ html >
import { useEffect , useRef } from "react" ;
import OneSdk from "@frankieone/one-sdk" ;
export default function SplitFlow ({ session }) {
const initRef = useRef ( false );
useEffect (() => {
if ( ! session || initRef . current ) return ;
initRef . current = true ;
( async () => {
try {
const oneSdk = await OneSdk ({
session ,
mode: "development" ,
recipe: {
ocr: { maxDocumentCount: 3 },
form: {
provider: { name: "react" },
},
},
});
const appContainer = "#onesdk-container" ;
const welcome = oneSdk . component ( "form" , { name: "WELCOME" , type: "ocr" });
const consent = oneSdk . component ( "form" , { name: "CONSENT" });
const documentForm = oneSdk . component ( "form" , { name: "DOCUMENT" , showPreps: true });
const loading = oneSdk . component ( "form" , {
name: "LOADING" , title: { label: "Loading..." }, descriptions: [{ label: "" }],
});
const biometrics = oneSdk . component ( "biometrics" );
welcome . mount ( appContainer );
welcome . on ( "form:welcome:ready" , () => consent . mount ( appContainer ));
consent . on ( "form:consent:ready" , () => documentForm . mount ( appContainer ));
documentForm . on ( "form:document:ready" , ({ inputInfo }) => {
loading . mount ( "#loading-overlay" );
const ocr = oneSdk . component ( "ocr" , {
documents: [{ type: inputInfo . documentType , countries: [ "AUS" ] }],
});
ocr . mount ( appContainer );
ocr . on ( "loading" , ( isLoading ) => {
if ( ! isLoading ) loading . unmount ();
});
ocr . on ( "error" , ( err ) => console . error ( "OCR error:" , err ));
ocr . on ( "results" , ({ document }) => {
if ( document ) {
loading . mount ( "#loading-overlay" );
biometrics . mount ( appContainer );
}
});
});
let biometricsError = false ;
biometrics . on ( "detection_failed" , () => { biometricsError = true ; });
biometrics . on ( "session_closed" , () => {
if ( biometricsError ) {
biometrics . mount ( appContainer );
biometricsError = false ;
}
});
biometrics . on ( "loading" , ( isLoading ) => {
if ( ! isLoading ) loading . unmount ();
});
biometrics . on ( "results" , () => {
document . getElementById ( "onesdk-container" ). innerHTML =
"<h2>Verification complete</h2>" ;
});
biometrics . on ( "error" , ( err ) => console . error ( "Biometrics error:" , err ));
} catch ( error ) {
console . error ( "OneSDK initialization failed:" , error );
}
})();
}, [ session ]);
return (
< div id = "onesdk-wrapper" style = { { position: "relative" , width: "100%" , height: "100vh" } } >
< div id = "onesdk-container" style = { { width: "100%" , height: "100%" } } />
< div
id = "loading-overlay"
style = { { position: "absolute" , top: 0 , left: 0 , width: "100%" , height: "100%" , zIndex: 10 , background: "#fff" } }
/>
</ div >
);
}
Step-by-Step Breakdown
1. Initialize the SDK
Pass the session object to OneSDK() . Include the ocr and form.provider recipe configuration.
Create form components for Welcome, Consent, Document selection, and a shared Loading screen. Create the ocr and biometrics components separately.
3. Wire Up Events
Use .on(event) listeners to navigate between screens and transition from OCR to biometrics. A single loading screen is reused for both OCR and biometrics initialization — mounted to the overlay before each component, and unmounted when the component is ready.
Unmount clears the container. Calling .unmount() on a component removes all content from the element it was mounted to — not just the component itself. Loading screens in this flow are mounted to a separate overlay element (#loading-overlay) so that unmounting them does not destroy the OCR or biometrics component underneath. See the IDV with Review flow for a detailed explanation.
4. Handle Results
Listen for results on both the OCR and biometrics components. See Error Scenarios for details on handling failures.
OCR Results Handling
When the OCR component completes, it returns the extracted document data and the flow proceeds to biometrics:
ocr . on ( "results" , ({ document }) => {
if ( document ) {
// Access extracted fields if needed
const dob = document . ocrResult . dateOfBirth ;
const name = document . ocrResult . fullName ;
// Proceed to biometrics
loading . mount ( "#loading-overlay" );
biometrics . mount ( appContainer );
}
});
See OCR Module for all available result fields.
Biometrics Error Recovery
The biometrics component may fail due to camera issues or detection problems. Implement automatic retry:
let biometricsError = false ;
biometrics . on ( "detection_failed" , () => {
biometricsError = true ;
});
biometrics . on ( "session_closed" , () => {
if ( biometricsError ) {
biometrics . mount ( appContainer );
biometricsError = false ;
}
});
See Biometrics Module for all events and configuration options.
Adding a Review Screen
To let users confirm extracted data before proceeding to biometrics, insert a review screen between OCR and biometrics:
const review = oneSdk . component ( "form" , {
name: "REVIEW" ,
type: "ocr" ,
});
ocr . on ( "results" , ({ document }) => {
if ( document ) {
review . mount ( appContainer );
}
});
review . on ( "form:review:ready" , () => {
loading . mount ( "#loading-overlay" );
biometrics . mount ( appContainer );
});
Customization Reference
Aspect Reference SDK initialization options SDK Initialization OCR component configuration OCR Module Biometrics configuration Biometrics Module Form screen configuration Form Module Screen names and types Form Screens Event names and payloads Events Error handling patterns Error Scenarios