Overview
This page documents all non-positive scenarios across the OneSDK, including error events, failed verification states, timeouts, network issues, and recoverable conditions. Understanding these scenarios helps you build robust error handling and provide better user experiences.
For API error codes, see API Error Codes. This page focuses on SDK-level errors and verification outcomes.
Global SDK Errors
Network Events
network_offline
Module: SDK Context (Global)
Description: Emitted when network connection is lost.
Example:
oneSDKInstance.on('network_offline', () => {
showBanner('You are offline. Verification will resume when connection is restored.');
});
Recovery Steps:
- Display offline indicator to user
- Queue pending operations
- Listen for
network_online event to resume
network_online
Module: SDK Context (Global)
Description: Emitted when network connection is restored after being offline.
Example:
oneSDKInstance.on('network_online', () => {
showBanner('Connection restored. Resuming verification...');
resumePendingOperations();
});
Error Event
Event: error
Available On: All modules (SDK context, Individual, IDV, OCR, Biometrics, Device, Form)
Description: Emitted when an error occurs in the SDK or any module.
Error Structure:
{
message: string; // Human-readable error description
name: string; // Error type identifier (empty string if not set)
payload: unknown; // Additional error context
}
Example:
oneSDKInstance.on('error', (error) => {
console.error('SDK Error:', {
message: error.message,
name: error.name,
payload: error.payload
});
showGenericError(error.message);
});
Known error.name Values
Some errors set a specific name value you can check programmatically. Many errors do not set name — for those, inspect error.message instead.
Form Module:
error.name | Description |
|---|
FORM:CONFIGURATION_MISSING | Form recipe is missing a provider name. Check your OneSDK form recipe configuration. |
FORM-LEGACY:CONFIGURATION_MISSING | Legacy form provider is missing the required version field. |
Individual Module:
error.name | Description |
|---|
SUBMIT | A submit retry is in progress. Fires between retry attempts (not on final failure). error.message includes the retry delay. |
IDV / OCR / Biometrics — IDVerse provider:
error.name | Description |
|---|
IDVerseUnableToCreateSession | IDVerse backend could not create a session (backend error code IDVERSE:001). |
IDVerseTransactionClosed | IDVerse session was closed before completion (backend error code IDVERSE:002). |
IDVerseTransactionFailed | IDVerse transaction failed during verification. |
IDVerseScanFailed | IDVerse scan exceeded the maximum retry count. |
IDVerseScanFailedAndDestroyed | IDVerse scan failed and the SDK instance was destroyed. |
IDVerseFatalError | IDVerse reported a fatal internal error. |
IDVerseErrorOnStart | IDVerse OCR or face scan failed to start. |
IDV — Truuth provider:
error.name | Description |
|---|
window is undefined | Truuth SDK requires a browser environment — window is not defined (e.g. SSR context). |
Failed to install TruuthKYCWebSdk | Truuth SDK failed to install. |
Errors Without a name
Most errors emit with an empty name. Use error.message to identify them:
| Module | Scenario | error.message |
|---|
| IDV | Provider offline (PROVIDER_OFFLINE status) | "Provider is offline. Either switch providers and restart or skip IDV temporarily." |
| IDV | Consent not provided (AWAITING_CONSENT status) | "Consent was not provided to the IDV Api. We can't continue." |
| IDV / OCR / Biometrics | Session creation network / HTTP error | The HTTP error message. error.name will be set if the backend returned a known IDVerse error code (see IDVerse named errors above); otherwise empty. error.payload.issues contains any issues from the backend. |
| IDV / OCR / Biometrics / Device | Vendor SDK failed to load | "Vendor sdk '{vendorName}' failed loading" where vendorName is the configured provider. This fires alongside vendor_sdk_failed_loading — prefer handling that event instead. |
| IDV | Sumsub failed to launch | "Failed to launch IDV vendor 'Sumsub'" |
| IDV | Mount failed (async error during mount) | Runtime error message from the caught exception |
| IDV | Mastercard reported an error | error.message is msg from the Mastercard iframe postMessage payload — content is determined by Mastercard |
| OCR | OCR results timed out after two polling attempts | "Two attempts to get OCR results failed with an unresolved 'AWAITING_DOCUMENT_OCR'." |
| OCR | Provider offline | "Provider is offline. Either switch providers and restart or skip OCR temporarily." |
| OCR | Sumsub failed to launch | "Failed to launch OCR vendor 'Sumsub'" |
| Biometrics | Generic vendor error | "Error from vendor SDK '{provider}'" where {provider} is the configured provider name |
| Biometrics | Biometrics submission error | "Error from biometrics submission" |
| Biometrics | Provider offline | "Error initialising biometrics check with '{provider}'. The service doesn't appear to be available." |
| Biometrics | OCR not run before biometrics | "Error initialising biometrics check with '{provider}'. You might need to run the 'ocr' component before running 'biometrics'." |
| Biometrics | Selfie not captured before biometrics | "Error initialising biometrics check with '{provider}'. You might need to capture selfie before running 'biometrics'." |
| Biometrics | Sumsub failed to launch | "Failed to launch Biometrics vendor 'Sumsub'" |
| Individual | Submit failed (final attempt, retries exhausted) | error.response?.data?.message from the API response body, or the raw network error message if no response body |
| Individual | Entity details failed to load (search()) | "Critical error! There was an issue loading the individual's details. Is the entityId ({entityId}) used to create this session valid?" where {entityId} is the actual entity ID |
| IDV — Daon provider | Unexpected error received from the Daon iframe | "DAON_ERROR" |
| IDV — Daon provider | Timeout from the Daon TrustX iframe | "DAON_TIMEOUT" |
Recovery Steps:
- Check
error.name first if set; fall back to parsing error.message
- Use
error.payload for additional context (e.g. HTTP response body, issues array)
- For session creation failures,
session_data_failed_loading fires alongside error and includes the HTTP code and message
- For vendor SDK load failures, handle
vendor_sdk_failed_loading directly — it carries the same information in a structured format
Warning Event
Event: warning
Module: All modules
Description: Emitted for non-critical warnings that don’t prevent operation but should be noted.
Structure:
{
message: string;
payload?: unknown;
}
Example:
oneSDKInstance.on('warning', (warning) => {
console.warn('SDK Warning:', warning.message);
});
Initialization Failures
Scenario: SDK initialization fails with Promise rejection
Causes:
- Invalid or expired session token
- Configuration error
- Network connectivity issues
- CSP policy blocking SDK resources
Example:
try {
const sdk = await OneSdk({
mode: 'production',
session: { token: sessionToken }
});
} catch (error) {
console.error('Initialization failed:', error);
// Generate fresh token and retry
const newToken = await fetchNewTokenFromBackend();
const sdk = await OneSdk({
mode: 'production',
session: { token: newToken }
});
}
Recovery Steps:
- Wrap initialization in try-catch
- Generate fresh token from backend
- Retry initialization with new token
- Check browser console for CSP errors
CSP (Content Security Policy) Errors
Scenario: Browser blocks OneSDK resources due to CSP policy
Symptoms: Browser console shows CSP violations when loading or running the SDK. Blocked resources may originate from FrankieOne’s own domains or from third-party vendor SDKs (Onfido, Sumsub, Sardine, ThreatMetrix, etc.).
Recovery Steps:
Update your CSP headers based on what is being blocked:
| Blocked operation | CSP directive to update |
|---|
| Loading SDK scripts | script-src |
| API connections / XHR / fetch | connect-src |
| Loading images from provider | img-src |
| Loading provider fonts | font-src |
| Vendor iframes (e.g. Sumsub) | frame-src |
Check the browser console for the specific blocked URL, then add the relevant domain to the appropriate directive. Both FrankieOne’s domains and your chosen vendor’s domains may need to be allowlisted.
Content-Security-Policy:
script-src 'self' https://*.frankieone.com [vendor-domains];
connect-src 'self' https://*.frankieone.com [vendor-domains];
img-src 'self' https://*.frankieone.com [vendor-domains] data:;
Replace [vendor-domains] with the actual domains used by your chosen provider. Refer to your provider’s CSP documentation for their full domain list.
Session Management Errors
Session Expiration
Method: getExpirationEpoch() returns timestamp in past
Description: User’s session token has expired before verification completion.
Example:
const expirationEpoch = sdk.session.getExpirationEpoch();
const now = Date.now();
if (expirationEpoch && expirationEpoch * 1000 < now) {
// Session expired — user must start over with a new token from your backend
console.log('Session expired');
showMessage('Your session has expired. Please start over.');
}
Recovery Steps:
- Call
getExpirationEpoch() to check expiration
- Warn users when less than 5 minutes remaining
- If the session expires mid-flow, the user must start over — there is no refresh token mechanism
- Reinitialize SDK with a fresh token obtained from your backend
There is no token refresh mechanism in OneSDK. If a session token expires while the user is mid-verification, you must generate a new token from your backend and reinitialize the SDK. Instruct users to start the verification flow again.
Missing Entity ID
Method: getEntityId() returns null
Description: Session hasn’t been associated with an entity yet.
Example:
const entityId = sdk.session.getEntityId();
if (!entityId) {
console.log('Entity not yet created');
// First-time user - proceed with data collection
} else {
console.log('Existing entity:', entityId);
// Returning user - load existing data
}
Recovery Steps:
- Always check for
null before using entity ID
- Entity will be created after first data submission
Individual Module (KYC) Errors
Verification Status Failures
failed
Property: CheckSummary.status.type
Description: Verification failed automated checks.
Example:
const results = await individual.submit({ verify: true });
if (results.status.type === 'failed') {
console.log('Verification failed');
console.log('Failed checks:', results.checkResults.filter(c => c.result.type === 'failed'));
// Check specific issues
results.checkResults.forEach(check => {
if (check.issues && check.issues.length > 0) {
console.log(`Issues in ${check.type}:`, check.issues);
}
});
}
Recovery Steps:
- Examine
checkResults array for specific failed checks
- Review
issues object for detailed error information
- Check
retryPages for screens that can be retried
- Allow user to correct data and resubmit
fail_manual
Property: CheckSummary.status.type
Description: Manually rejected after review by compliance staff.
Recovery Steps:
- Contact support for rejection reason
- May require completely new verification with different data
- User should be informed this is a final decision
refer
Property: CheckSummary.status.type
Description: Requires manual review; not automatically approved or denied.
Example:
if (results.status.type === 'refer') {
showMessage('Your verification is under review. We\'ll notify you within 24-48 hours.');
}
Recovery Steps:
- Inform user that manual review is in progress
- Provide expected timeline (if known)
- Set up webhook to receive result notification
- Don’t allow resubmission until review complete
wait
Property: CheckSummary.status.type
Description: Waiting for additional information from user.
Example:
if (results.status.type === 'wait') {
// Check what actions are needed
const actions = results.alertList.filter(alert => alert.type === 'action');
actions.forEach(action => {
console.log('Action required:', action.term);
if (action.extra?.action) {
console.log('Specific action:', action.extra.action);
}
});
}
Recovery Steps:
- Check
alertList for specific actions required
- Implement handlers for common action types:
additional_document_required - Upload missing documents
upload_proof_of_address - Provide address verification
document_expired - Upload current document
- Allow user to provide missing information
- Resubmit verification after data provided
unchecked
Property: CheckSummary.status.type
Description: No checks have been run yet.
Recovery Steps:
- Call
submit({ verify: true }) or runChecks() to execute verification
- This is the initial state before any verification
archived
Property: CheckSummary.status.type
Description: Entity has been archived in the system.
Recovery Steps:
- Archiving is irreversible. You cannot unarchive an entity.
- Create a new entity and session to onboard the customer again.
inactive
Property: CheckSummary.status.type
Description: Entity has been deactivated.
Recovery Steps:
- Deactivation is irreversible. You cannot reactivate a deactivated entity.
- Create a new entity and session to onboard the customer again.
Properties: CheckSummary.personalChecks.*
Possible Values:
true - Field validated successfully
false - Field failed validation
null - Field was not checked
Example:
const { personalChecks } = results;
if (personalChecks.name === false) {
showError('Name verification failed. Please check your name matches your ID.');
}
if (personalChecks.dateOfBirth === false) {
showError('Date of birth verification failed.');
}
if (personalChecks.addresses) {
Object.entries(personalChecks.addresses).forEach(([addressId, isValid]) => {
if (isValid === false) {
showError(`Address ${addressId} verification failed.`);
}
});
}
Recovery Steps:
- Identify which specific fields failed (
=== false)
- Prompt user to correct the failed field
- Resubmit verification with corrected data
Risk Assessment Failures
Properties: CheckSummary.risk.class, CheckSummary.risk.level
Risk Classes: low, medium, high, unacceptable, null
Risk Level: Numeric value in the range 0–100. Lower numbers indicate lower risk.
The mapping between risk.level (numeric) and risk.class (categorical) depends on your risk configuration in FrankieOne and is not a fixed universal scale. When risk.class is null, risk.level is typically also absent. Contact your FrankieOne account team to understand your configured thresholds.
Example:
const { risk } = results;
if (risk.class === 'high' || risk.class === 'unacceptable') {
console.log('High risk detected, level:', risk.level);
// Check for blocklist matches
if (results.blocklistPotentialMatches.length > 0) {
console.log('Blocklist matches found:', results.blocklistPotentialMatches);
}
// Check for duplicates
if (results.duplicatePotentialMatches.length > 0) {
console.log('Duplicate entities found:', results.duplicatePotentialMatches);
}
}
Recovery Steps:
high - May require manual review; check blocklistPotentialMatches and duplicatePotentialMatches
unacceptable - Likely verification failure; escalate to compliance team
- Review
alertList for specific risk factors
Check Result Issues
Property: CheckSummary.checkResults[].issues
Each check result may include an issues array with { code, description } entries identifying what failed. See Individual Module — CheckSummary for full structure.
Recovery Steps:
- Parse issues array to identify specific failures
- Display
issue.description to user
- Use
issue.code for programmatic handling
Alert List
Alert Types
All alerts in alertList have a type property that indicates severity:
type | Description |
|---|
alert | High-priority issue requiring attention (fraud indicators, sanctions matches) |
action | User must take a specific action to proceed |
warning | Non-blocking concern that may affect approval |
success | Positive signal from a check |
The term property describes the specific topic of the alert. Known term values include:
term | Description |
|---|
fraud | Fraud risk indicator |
partial | Partial match found |
media | Adverse media match |
watchlist | Watchlist match |
sanction | Sanctions list match |
blacklist | Blocklist match |
duplicate | Potential duplicate entity |
risk | General risk indicator |
The term value depends on the checks configured for your account. Handle unknown term values gracefully.
Action Required
Type: action
Property: CheckSummary.alertList
Common Actions:
additional_document_required - Upload supporting document
upload_proof_of_address - Provide address verification document
document_expired - Upload current/unexpired document
Example:
const actions = results.alertList.filter(alert => alert.type === 'action');
actions.forEach(action => {
console.log('Action required:', action.term);
if (action.extra?.action) {
switch (action.extra.action) {
case 'upload_proof_of_address':
showUploadForm('Please upload proof of address');
break;
case 'additional_document_required':
showUploadForm('Please upload additional document');
break;
case 'document_expired':
showError('Your document has expired. Please upload a current document.');
break;
}
}
});
Recovery Steps:
- Filter
alertList for type === 'action'
- Implement handler for each action type
- Collect required information from user
- Resubmit verification
Warnings
Type: warning
Example:
const warnings = results.alertList.filter(alert => alert.type === 'warning');
warnings.forEach(warning => {
console.warn('Warning:', warning.term);
});
Recovery Steps:
- Display warnings to user
- Assess if warnings prevent verification completion
- Some warnings may not block approval
Duplicate Detection
Duplicate Potential Matches
Property: CheckSummary.duplicatePotentialMatches
Description: Entity may be a duplicate of an existing entity in the system. Each match includes entityId, matchStrength (0–1 confidence), and matched fields. See Individual Module — CheckSummary for full structure.
Recovery Steps:
- Review duplicate matches manually
- Verify if user already has an existing account
- If legitimate duplicate, merge or link entities via backend API
- If false positive, proceed with verification
Duplicate Blocklist Matches
Property: CheckSummary.duplicateBlocklistMatches
Description: Entity matches found across combined duplicate detection and blocklist/sanctions analysis. These represent entities flagged simultaneously in both checks and are high-priority alerts.
Recovery Steps:
- This is a critical alert
- Immediate investigation required
- Likely verification failure
- Escalate to compliance team
Blocklist Matches
Property: CheckSummary.blocklistPotentialMatches
Description: Entity matched against blocklist/sanctions/AML databases.
Example:
if (results.blocklistPotentialMatches.length > 0) {
console.log('BLOCKLIST MATCH DETECTED');
results.blocklistPotentialMatches.forEach(match => {
console.log('Matched entity:', match.entityId);
console.log('Match confidence:', match.matchStrength);
console.log('Matched personal fields:', match.matches.personal);
});
// Halt verification and escalate
escalateToCompliance(results);
}
Recovery Steps:
- Stop verification process immediately
- Escalate to compliance/risk team
- Do NOT proceed with onboarding
- Perform manual investigation
Retry Pages
Property: CheckSummary.retryPages
Description: Recommended pages where the user can retry their submission, so they don’t need to go through the entire flow again. Can be empty if the backend cannot determine which pages should be retried.
Example:
if (results.status.type === 'failed') {
if (results.retryPages.length > 0) {
console.log('Recommended retry pages:', results.retryPages);
// Navigate user to the first recommended retry page
navigateToPage(results.retryPages[0].name);
} else {
// Backend couldn't determine retry pages - restart the full flow
restartVerificationFlow();
}
}
Recovery Steps:
- Navigate user to the recommended retry pages if provided
- User can correct specific data and resubmit
- If
retryPages is empty, the user should restart the full verification flow
checkResults, checkTypes, and checkCounts
For the relationship between checkTypes, checkResults, and checkCounts, see Individual Module — CheckSummary.
Key points:
checkResults depends on which checks are configured. A missing entry for a checkType typically means that check hasn’t run yet.
checkCounts lists data source names that verified each personal info field — not the check results themselves (those are in personalChecks).
Submit Failures
Method: submit() or submit({ verify: true })
Description: Promise rejection on error.
Causes:
- Network error
- Validation error
- Server error
- Timeout
Example:
try {
// retryOptions is NOT enabled by default — pass it explicitly to enable retry behavior
const results = await individual.submit(
{ verify: true },
{
maxRetries: 3,
backoffDelayMs: 1000
}
);
} catch (error) {
console.error('Submit failed:', error);
if (error.message.includes('network')) {
showError('Network error. Please check your connection and try again.');
} else if (error.message.includes('validation')) {
showError('Please check your information and try again.');
} else {
showError('An error occurred. Please try again later.');
}
}
Recovery Steps:
- Pass
retryOptions explicitly to enable automatic retries (not on by default)
- Implement custom error handling in the
catch block
- Show user-friendly error messages
- For persistent errors, contact support
Accessor Usage
Method: individual.access(fieldName)
Description: Returns a reactive Accessor object for reading and writing individual entity fields. Use access() for reading or writing entity data within the module — you don’t have direct access to the full raw entity data object.
Accessor Interface:
{
getValue(): T; // Read current value
setValue(value: T): void; // Write new value
observable: Observable<T>; // Subscribe to reactive changes
}
Use individual.search() to refresh entity data from FrankieOne (fetches latest from backend). Use individual.access() for reading/writing the local entity state.
Example:
// Read
const name = individual.access('name').getValue();
// Write
individual.access('name').setValue({ givenName: 'John', familyName: 'Doe' });
// Subscribe to reactive changes
individual.access('name').observable.subscribe((newName) => {
console.log('Name updated:', newName);
});
See Individual Module - access() for the full list of available fields.
Data Not Persisted
Method: isPersisted() returns false
Description: Changes haven’t been submitted to the server yet.
Example:
if (!individual.isPersisted()) {
showWarning('You have unsaved changes.');
}
// Before navigation
window.addEventListener('beforeunload', (e) => {
if (!individual.isPersisted()) {
e.preventDefault();
e.returnValue = 'You have unsaved changes. Are you sure you want to leave?';
}
});
Recovery Steps:
- Warn user before navigation
- Implement unsaved changes detection
- Prompt to save before leaving page
Common Events: Vendor Modules
The following events are emitted by all vendor-based modules — IDV, OCR, Biometrics, and Device. See the respective module docs for full parameter details.
vendor_sdk_loaded
Emitted when the third-party provider’s SDK has been successfully loaded and is ready.
vendor_sdk_failed_loading
Emitted when the provider’s SDK fails to load. This is the primary signal that the module cannot function.
// Applies to: IDV, OCR, Biometrics, Device
module.on('vendor_sdk_failed_loading', ({ vendor, errorObject }) => {
console.error(`Failed to load ${vendor} SDK:`, errorObject);
});
Recovery Steps:
- Check CSP headers allow the provider’s domains
- Verify credentials (
clientID, environment setting)
- Ensure the provider is configured for your account in FrankieOne
- Fall back to an alternative flow if possible
session_data_generated
Emitted when a provider session has been created. Useful for logging or debugging.
session_data_failed_loading
Emitted when session data fails to load from the provider. Usually indicates a backend configuration issue.
module.on('session_data_failed_loading', ({ code, message }) => {
console.error('Session failed:', message);
showError('Unable to start verification. Please try again.');
});
IDV Module Errors
For vendor_sdk_failed_loading, vendor_sdk_loaded, session_data_generated, and session_data_failed_loading, see Common Events: Vendor Modules.
Status-to-Event Mapping
IDV statuses are delivered through different events depending on their nature:
| Status | Event | Meaning |
|---|
COMPLETE | results | Verification completed successfully |
FAILED | results | Verification failed |
INCOMPLETE | input_required | Verification could not be completed due to incomplete user input |
DOCUMENTS_INVALID | input_required | Document provided was invalid or wrong type |
PROVIDER_OFFLINE | error | The verification provider is unavailable |
AWAITING_CONSENT | input_required | User has not yet provided consent |
WAITING_SELFIE_UPLOAD | input_required | Waiting for selfie capture |
WAITING_DOC_UPLOAD | input_required | Waiting for document upload |
INTERRUPTED | input_required | Verification flow was closed or interrupted |
The results event is only emitted with COMPLETE or FAILED status. All other statuses appear via input_required, error, or processing events. The Biometrics module uses the same IDVStatus enum — all statuses above apply to both IDV and Biometrics.
IDV Status Failures
FAILED
Property: results.checkStatus
Example:
idvFlow.on('results', (results) => {
if (results.checkStatus === 'FAILED') {
console.log('IDV verification failed');
showFailureScreen();
}
});
INCOMPLETE
Description: Verification could not be completed because of missing user input.
Example:
idvFlow.on('input_required', (info, status) => {
if (status === 'INCOMPLETE') {
showMessage('Verification incomplete. Please complete all required steps.');
allowRetry();
}
});
DOCUMENTS_INVALID
Description: Provided documents are invalid or of wrong type.
Example:
idvFlow.on('input_required', (info, status) => {
if (status === 'DOCUMENTS_INVALID') {
showError('Invalid document. Please select a different document type.');
allowRetry();
}
});
PROVIDER_OFFLINE
Description: IDV provider is offline/unavailable. This status surfaces as an error event.
Recovery Steps:
- Show unavailable message to user
- Retry after a delay
- If persistent, contact support
AWAITING_CONSENT
Description: Waiting for user consent to proceed.
Example:
idvFlow.on('input_required', (info, status) => {
if (status === 'AWAITING_CONSENT') {
showMessage('Please provide consent to continue verification.');
allowRetry();
}
});
WAITING_SELFIE_UPLOAD
Description: Waiting for selfie/biometric capture.
Example:
idvFlow.on('input_required', (info, status) => {
if (status === 'WAITING_SELFIE_UPLOAD') {
showMessage('Please capture your selfie to continue.');
allowRetry();
}
});
WAITING_DOC_UPLOAD
Description: Waiting for document upload.
Example:
idvFlow.on('input_required', (info, status) => {
if (status === 'WAITING_DOC_UPLOAD') {
showMessage('Please upload your document to continue.');
allowRetry();
}
});
INTERRUPTED
Description: Verification session was closed or interrupted by the user.
Example:
idvFlow.on('input_required', (info, status) => {
if (status === 'INTERRUPTED') {
// Remount the module to allow the user to resume
showMessage('Verification was interrupted. Click retry to continue.');
showRetryButton(() => idvFlow.mount('#idv-container'));
}
});
Event: input_required
The input_required event is emitted when a check could not be completed due to user input — not because of a system failure. For example:
- The user uploaded the wrong document type
- The user closed the verification session before completing it
- Required captures (selfie, document) have not been provided
Retrying the step will always help resolve input_required — if the user closed the session, remounting the module allows them to continue. Whether to limit the number of retry attempts depends on your business process.
There is no way to differentiate between user abandonment (user deliberately closed the session) and session timeout within the SDK. Both emit input_required with INTERRUPTED status.
Example:
idvFlow.on('input_required', (info, status) => {
console.log('Input required:', status);
// Show retry option — remounting the module resumes the flow
showRetryButton(() => {
idvFlow.unmount();
idvFlow.mount('#idv-container');
});
});
Detection Failed
Event: detection_failed
Example:
idvFlow.on('detection_failed', ({ message, payload }) => {
console.error('Detection failed:', message);
console.error('Details:', payload);
showError(message || 'Document capture failed. Please try again.');
});
Recovery Steps:
- Log error details from
payload
- Show user-friendly error message
- Offer retry option
Session Interrupted
Event: session_interrupted
Provider: Onfido-specific. Other providers do not emit this event — if you listen for it while using a non-Onfido provider, the handler will simply never fire.
Example:
// Only register this listener if using Onfido
idvFlow.on('session_interrupted', () => {
console.log('User closed verification (Onfido)');
saveProgress();
showMessage('You can resume verification later.');
});
OCR Module Errors
For vendor_sdk_failed_loading, vendor_sdk_loaded, session_data_generated, and session_data_failed_loading, see Common Events: Vendor Modules.
isPreloaded() in OCR: The isPreloaded() method is not typically used in standard OCR integrations and can be safely ignored. Use events (detection_complete, results) to track document capture progress instead.
OCR Status Failures
DOCUMENTS_INVALID
Example:
ocrComponent.on('input_required', (info, status) => {
if (status === 'AWAITING_DOCUMENT_UPLOAD_INVALID_TYPE') {
showError('Invalid document type. Please select a different document.');
}
});
DOCUMENTS_UPLOAD_FAILED
Description: Document upload failed during OCR processing.
Recovery Steps:
- Retry upload
- Check file size and format
- Verify network connection
PROVIDER_OFFLINE
Description: OCR provider is offline/unavailable.
Recovery Steps:
- Show provider unavailable message
- Retry after delay
- Fall back to manual data entry if available
FAILED_FILE_SIZE
Description: File size exceeds provider limit.
Recovery Steps:
- Show file size error
- Indicate maximum allowed size
- Ask user to provide smaller file or different format
Description: Incorrect file format provided.
Recovery Steps:
- Show format error
- List accepted formats (JPG, PNG, PDF, etc.)
- Prompt user to select valid file
INTERRUPTED
Description: Capture flow was interrupted.
Recovery Steps:
- Allow user to restart capture\
Biometrics Module Errors
The Biometrics module uses the same IDVStatus enum as the IDV module. All statuses documented in the IDV section (COMPLETE, FAILED, INCOMPLETE, DOCUMENTS_INVALID, etc.) apply equally to Biometrics. There are no Biometrics-specific statuses.
For vendor_sdk_failed_loading, vendor_sdk_loaded, session_data_generated, and session_data_failed_loading, see Common Events: Vendor Modules.
Session Data Failed Loading
Event: session_data_failed_loading
Example:
biometricsComponent.on('session_data_failed_loading', ({ code, message }) => {
console.error('Session failed:', code, message);
showError('Failed to start biometric verification. Please try again.');
});
Event: input_required
Common Scenarios:
- User closed verification session
- Session timeout occurred
- Waiting for selfie capture
- Camera permission denied
Example:
biometricsComponent.on('input_required', (info, status) => {
console.log('Input required:', status);
showMessage('Please complete the biometric capture to continue.');
showRetryButton();
});
Detection Failed
Event: detection_failed
Example:
biometricsComponent.on('detection_failed', ({ message }) => {
console.error('Biometric capture failed:', message);
showError(message || 'Face capture failed. Please try again.');
});
Device Module Errors
For vendor_sdk_failed_loading, vendor_sdk_loaded, and session_data_generated, see Common Events: Vendor Modules. For the Device module specifically, vendor_sdk_failed_loading means device fingerprinting is unavailable — you should fall back to proceeding without device data.
Configuration Validation Errors
Scenario: Missing provider configuration
Error Message: “Your account is missing the environment configuration…”
Recovery Steps:
- Ensure
recipe.deviceCharacteristics.provider is configured
- Verify
clientID and environment are set and correct
- Contact FrankieOne support to verify the provider is enabled for your account
Invalid Activity Type
Scenario: Invalid activity type provided to start()
Error Message: “Activity Type should be one of the following…”
Valid Types: REGISTRATION, LOGIN, CRYPTO_DEPOSIT, CRYPTO_WITHDRAWAL, FIAT_DEPOSIT, FIAT_WITHDRAWAL
Example:
// Incorrect
oneSdkInstance.component('device', { activityType: 'registration' }); // ✗ lowercase
// Correct
oneSdkInstance.component('device', { activityType: 'REGISTRATION' }); // ✓ uppercase
Recovery Steps:
- Use exact activity type string (case-sensitive)
- Verify spelling matches valid types
Device Data Not Appearing in Dashboard
Troubleshooting checklist:
- Check environment — Verify you are checking the correct environment (sandbox vs production) in the dashboard. A mismatch here is the most common cause.
- Check clientID — Ensure the
clientID matches what FrankieOne has configured for your account.
- Provider configured — Confirm with your FrankieOne account team that the device fingerprinting provider is enabled and configured for your account before integrating.
- CSP blockage — There is no direct client-side indicator that device data was blocked (other than the
vendor_sdk_failed_loading event or CSP console errors). Check browser console for blocked requests.
- Success indicator — Listen for the
device_characteristics_extracted event to confirm device data was collected client-side. If this event fires, the data was captured successfully.
- Timeline — How quickly device data appears in the dashboard depends on the vendor. Contact your FrankieOne account team for expected timing.
deviceComponent.on('device_characteristics_extracted', ({ deviceCharacteristics }) => {
console.log('Device data collected — should appear in dashboard');
});
Screen Failed Events
Event Pattern: form:{screen}:failed
Screens: welcome, start, consent, document, personal, review, loading, result, retry, doc_upload, required_document_upload, partial_document_upload, optional_document_upload
Example:
formComponent.on('form:review:failed', (payload) => {
console.error('Review screen failed to load');
showError('Unable to display review. Please refresh the page.');
});
Recovery Steps:
- Log error for investigation
- Show user-friendly error message
- Offer page refresh or retry
- Contact support if persists
form:review:failed, form:review:success, form:review:partial, and form:review:pending are only emitted when customResult: true is set in manual mode. When customResult is false (the default), the form automatically navigates to and displays the configured result screen — no review events are emitted for you to handle.In OCR mode, the only terminal event is ready.
Use customResult: true when you want to intercept the review outcome and handle navigation yourself (e.g., display a custom message or CTA):
Description: Verification did not pass at review stage. Only emitted with customResult: true.
Example:
formComponent.on('form:review:failed', (payload) => {
console.log('Verification failed');
showCustomFailureUI();
});
Description: Partial verification result. Only emitted with customResult: true.
Example:
formComponent.on('form:review:partial', (payload) => {
showCustomPartialUI();
});
Description: Result pending manual review. Only emitted with customResult: true.
Example:
formComponent.on('form:review:pending', (payload) => {
showCustomPendingUI();
});
Result Screen States
Result screen states are display configurations — not error events to handle. They control what message and CTA the built-in result screen shows. Set the state when initializing the RESULT screen to display the appropriate message to the user.
| State | Description |
|---|
SUCCESS | Verification passed |
FAIL | Verification failed |
PENDING | Verification pending manual review |
PARTIAL | Partial verification result |
UPLOAD_FAIL | Document upload failed |
PROVIDER_ERROR | Provider encountered an error |
Example — configure a failure result screen:
const failResult = sdk.component('form', {
name: 'RESULT',
type: 'manual',
state: 'FAIL',
title: { label: 'Verification Failed' },
descriptions: [{ label: 'We were unable to verify your information.' }]
});
failResult.on('form:result:loaded', () => {
console.log('Failure screen displayed');
});
Review Screen — Retry Configuration
When a form submission fails on the Review screen, the SDK has built-in retry behavior controlled by the Review screen’s CTA (cta) configuration. This is not on the Retry screen.
CTA Configuration (Review screen):
{
name: 'REVIEW',
// ...
cta: {
label: 'Submit',
timeoutRetryMiliseconds: 5000, // Auto-retry delay ms — the form retries automatically after this
retryAmount: 3, // Max retry attempts per submission
retryAttemptString: 'Error submitting form. Give it a moment to retry.',
maxRetryAttemptedString: 'Something went wrong, please contact customer service or try again.'
}
}
timeoutRetryMiliseconds — The form automatically retries submission after this delay. No user click needed.
retryAmount — Maximum retry attempts. After exhausting retries, the user sees maxRetryAttemptedString.
- The retry counter is per submission, not persistent across sessions.
- No event is emitted per retry attempt.
Retry Screen
Screen: RETRY
The Retry screen is specific to the eKYC flow — it is shown when verification fails and the user needs to re-enter data. It is not the same as the Review screen’s submission retry.
Example:
const retry = sdk.component('form', {
name: 'RETRY',
type: 'manual'
});
retry.on('form:retry:loaded', (payload) => {
console.log('User can correct data and retry eKYC');
});
Best Practices
1. Always Handle Errors
// ✓ Good
oneSDKInstance.on('error', (error) => {
logError(error);
showUserFriendlyMessage(error);
});
// ✗ Bad - No error handler
oneSDKInstance.on('results', handleResults); // Missing error handler
2. Provide User-Friendly Messages
// ✓ Good
oneSDKInstance.on('error', (error) => {
if (error.name === 'network_error') {
showMessage('Please check your internet connection and try again.');
} else {
showMessage('Something went wrong. Please try again later.');
}
});
// ✗ Bad - Technical jargon
oneSDKInstance.on('error', (error) => {
alert(error.message); // May contain technical details
});
3. Check Status Before Acting
// ✓ Good
const results = await individual.submit({ verify: true });
switch (results.status.type) {
case 'passed':
navigateToSuccess();
break;
case 'failed':
showFailureScreen(results);
break;
case 'refer':
showPendingReview();
break;
case 'wait':
showAdditionalInfoRequired(results.alertList);
break;
default:
handleUnexpectedStatus(results.status.type);
}
// ✗ Bad - Only checking success
if (results.status.type === 'passed') {
navigateToSuccess();
}
// Missing handling for all other states
4. Log Errors for Investigation
// ✓ Good
oneSDKInstance.on('error', (error) => {
// Log to analytics/monitoring
logToSentry({
message: error.message,
name: error.name,
payload: error.payload,
timestamp: Date.now()
});
// Show user-friendly message
showError('An error occurred. Our team has been notified.');
});
5. Handle Network State
// ✓ Good
let isOnline = true;
oneSDKInstance.on('network_offline', () => {
isOnline = false;
showBanner('You are offline. Changes will be saved when connection is restored.');
disableSubmitButton();
});
oneSDKInstance.on('network_online', () => {
if (!isOnline) {
isOnline = true;
hideBanner();
enableSubmitButton();
retryPendingOperations();
}
});
6. Validate Session Before Critical Operations
// ✓ Good
async function performVerification() {
const expirationEpoch = sdk.session.getExpirationEpoch();
const fiveMinutes = 5 * 60 * 1000;
if (expirationEpoch && (expirationEpoch * 1000 - Date.now()) < fiveMinutes) {
console.warn('Session expiring soon — request a new token from your backend');
// There is no token refresh mechanism — must obtain new token from backend
const newToken = await fetchNewTokenFromBackend();
await reinitializeSDK(newToken);
}
// Proceed with verification
const results = await individual.submit({ verify: true });
}
7. Ignore Telemetry Events in Production
Telemetry events (telemetry) are emitted internally by FrankieOne for diagnostic purposes. You do not need to listen to them in your application. Error handling should be done via the error event on each module, not via telemetry.
// ✗ Not needed in production
oneSDKInstance.on('telemetry', (event) => {
console.log('Telemetry:', event); // Only useful for FrankieOne debugging
});
Provider Event Compatibility
Some events are provider-specific and will not fire when using a different provider. If your flow supports multiple providers, check the provider name before registering provider-specific event listeners.
| Event | Onfido | Sumsub | Incode | IDVerse | Daon |
|---|
session_interrupted | ✓ | — | — | — | — |
detection_complete | ✓ | ✓ | ✓ | ✓ | ✓ |
vendor_event | ✓ | ✓ | ✓ | ✓ | ✓ |
vendor_sdk_loaded | ✓ | ✓ | ✓ | ✓ | ✓ |
vendor_sdk_failed_loading | ✓ | ✓ | ✓ | ✓ | ✓ |
If you register a listener for session_interrupted while using Sumsub (or any non-Onfido provider), the handler will simply never fire. This is safe — it won’t cause errors.
Document Selection
The Document Selection screen in the Form module is not deprecated and not tied to legacy flows. It is a standard part of the OCR and manual verification flows.
Recommended patterns for document type selection:
- Use OCR mode — Specify document types in the
documents array when creating the OCR component. The provider’s built-in selector will guide the user.
- Hard code the document type — If your flow requires a specific document type, specify it directly in configuration rather than letting the user choose.
- Use the provider’s built-in selector — Most IDV and OCR providers include their own document type selection UI.
Vendor-Specific Errors
Onfido
These errors are emitted via the error event when using Onfido as the IDV, OCR, or Biometrics provider. OneSDK surfaces these from Onfido’s onError callback.
const idv = oneSdk.flow("idv");
idv.on('error', (error) => {
console.error('Onfido error:', error);
});
| Error Code | Description | Recovery |
|---|
invalid_token | The Onfido IDV token is invalid. | Re-generate the IDV token by remounting the component. |
expired_token | The Onfido IDV token has expired. | Re-generate the IDV token by remounting the component. |
expired_trial | The Onfido trial period has expired. | This is unexpected in production. Contact FrankieOne support if you encounter this error. |
geoblocked_request | The request is not allowed from the user’s location. | The end-user may be in a geoblocked region. Ask them to disable any active VPN, or contact FrankieOne for details. |
permissions_unavailable | Unable to retrieve or access required user permissions. | This may occur when the SDK is loaded within a webview or custom browser that restricts permissions. Try using a standard browser. |
unsupported | A module is not supported in the current environment. | Check the OneSDK documentation for environment requirements, or contact FrankieOne support. |
unsupported_feature | The requested feature is no longer supported. | Check the OneSDK documentation for current feature availability, or contact FrankieOne support. |
invalid_sdk_parameter | The SDK was initialized with invalid parameters. | Review your Onfido provider configuration and correct any invalid parameters. |
unsupported_sdk_version | The workflow is not supported by the current SDK version. | Verify that your configured sdkVersion (e.g., "12" or "14") is compatible with your workflow. |
no_camera | No camera is available and no other capture method exists. | The user has not granted camera access or their device does not have a camera. Prompt the user to enable camera permissions. |
user_consent_denied | The user declined the consent prompt. | The user must provide consent to proceed. Display a message explaining why consent is required and allow them to retry. |