Skip to main content

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.nameDescription
FORM:CONFIGURATION_MISSINGForm recipe is missing a provider name. Check your OneSDK form recipe configuration.
FORM-LEGACY:CONFIGURATION_MISSINGLegacy form provider is missing the required version field.
Individual Module:
error.nameDescription
SUBMITA 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.nameDescription
IDVerseUnableToCreateSessionIDVerse backend could not create a session (backend error code IDVERSE:001).
IDVerseTransactionClosedIDVerse session was closed before completion (backend error code IDVERSE:002).
IDVerseTransactionFailedIDVerse transaction failed during verification.
IDVerseScanFailedIDVerse scan exceeded the maximum retry count.
IDVerseScanFailedAndDestroyedIDVerse scan failed and the SDK instance was destroyed.
IDVerseFatalErrorIDVerse reported a fatal internal error.
IDVerseErrorOnStartIDVerse OCR or face scan failed to start.
IDV — Truuth provider:
error.nameDescription
window is undefinedTruuth SDK requires a browser environment — window is not defined (e.g. SSR context).
Failed to install TruuthKYCWebSdkTruuth SDK failed to install.

Errors Without a name

Most errors emit with an empty name. Use error.message to identify them:
ModuleScenarioerror.message
IDVProvider offline (PROVIDER_OFFLINE status)"Provider is offline. Either switch providers and restart or skip IDV temporarily."
IDVConsent not provided (AWAITING_CONSENT status)"Consent was not provided to the IDV Api. We can't continue."
IDV / OCR / BiometricsSession creation network / HTTP errorThe 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 / DeviceVendor 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.
IDVSumsub failed to launch"Failed to launch IDV vendor 'Sumsub'"
IDVMount failed (async error during mount)Runtime error message from the caught exception
IDVMastercard reported an errorerror.message is msg from the Mastercard iframe postMessage payload — content is determined by Mastercard
OCROCR results timed out after two polling attempts"Two attempts to get OCR results failed with an unresolved 'AWAITING_DOCUMENT_OCR'."
OCRProvider offline"Provider is offline. Either switch providers and restart or skip OCR temporarily."
OCRSumsub failed to launch"Failed to launch OCR vendor 'Sumsub'"
BiometricsGeneric vendor error"Error from vendor SDK '{provider}'" where {provider} is the configured provider name
BiometricsBiometrics submission error"Error from biometrics submission"
BiometricsProvider offline"Error initialising biometrics check with '{provider}'. The service doesn't appear to be available."
BiometricsOCR not run before biometrics"Error initialising biometrics check with '{provider}'. You might need to run the 'ocr' component before running 'biometrics'."
BiometricsSelfie not captured before biometrics"Error initialising biometrics check with '{provider}'. You might need to capture selfie before running 'biometrics'."
BiometricsSumsub failed to launch"Failed to launch Biometrics vendor 'Sumsub'"
IndividualSubmit failed (final attempt, retries exhausted)error.response?.data?.message from the API response body, or the raw network error message if no response body
IndividualEntity 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 providerUnexpected error received from the Daon iframe"DAON_ERROR"
IDV — Daon providerTimeout 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:
  1. Wrap initialization in try-catch
  2. Generate fresh token from backend
  3. Retry initialization with new token
  4. 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 operationCSP directive to update
Loading SDK scriptsscript-src
API connections / XHR / fetchconnect-src
Loading images from providerimg-src
Loading provider fontsfont-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:
  1. Call getExpirationEpoch() to check expiration
  2. Warn users when less than 5 minutes remaining
  3. If the session expires mid-flow, the user must start over — there is no refresh token mechanism
  4. 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:
  1. Examine checkResults array for specific failed checks
  2. Review issues object for detailed error information
  3. Check retryPages for screens that can be retried
  4. 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:
  1. Check alertList for specific actions required
  2. Implement handlers for common action types:
    • additional_document_required - Upload missing documents
    • upload_proof_of_address - Provide address verification
    • document_expired - Upload current document
  3. Allow user to provide missing information
  4. 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.

Personal Information Validation Failures

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:
  1. Identify which specific fields failed (=== false)
  2. Prompt user to correct the failed field
  3. 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:
typeDescription
alertHigh-priority issue requiring attention (fraud indicators, sanctions matches)
actionUser must take a specific action to proceed
warningNon-blocking concern that may affect approval
successPositive signal from a check
The term property describes the specific topic of the alert. Known term values include:
termDescription
fraudFraud risk indicator
partialPartial match found
mediaAdverse media match
watchlistWatchlist match
sanctionSanctions list match
blacklistBlocklist match
duplicatePotential duplicate entity
riskGeneral 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:
  1. Filter alertList for type === 'action'
  2. Implement handler for each action type
  3. Collect required information from user
  4. 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:
  1. Review duplicate matches manually
  2. Verify if user already has an existing account
  3. If legitimate duplicate, merge or link entities via backend API
  4. 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:
  1. Pass retryOptions explicitly to enable automatic retries (not on by default)
  2. Implement custom error handling in the catch block
  3. Show user-friendly error messages
  4. 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:
StatusEventMeaning
COMPLETEresultsVerification completed successfully
FAILEDresultsVerification failed
INCOMPLETEinput_requiredVerification could not be completed due to incomplete user input
DOCUMENTS_INVALIDinput_requiredDocument provided was invalid or wrong type
PROVIDER_OFFLINEerrorThe verification provider is unavailable
AWAITING_CONSENTinput_requiredUser has not yet provided consent
WAITING_SELFIE_UPLOADinput_requiredWaiting for selfie capture
WAITING_DOC_UPLOADinput_requiredWaiting for document upload
INTERRUPTEDinput_requiredVerification 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

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'));
  }
});

input_required — Semantics

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

FAILED_FILE_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.');
});

Input Required

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:
  1. Check environment — Verify you are checking the correct environment (sandbox vs production) in the dashboard. A mismatch here is the most common cause.
  2. Check clientID — Ensure the clientID matches what FrankieOne has configured for your account.
  3. Provider configured — Confirm with your FrankieOne account team that the device fingerprinting provider is enabled and configured for your account before integrating.
  4. 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.
  5. 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.
  6. 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');
});

Form Module Errors

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

Review Events (form:review:*)

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):

form:review:failed

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();
});

form:review:partial

Description: Partial verification result. Only emitted with customResult: true. Example:
formComponent.on('form:review:partial', (payload) => {
  showCustomPartialUI();
});

form:review:pending

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.
StateDescription
SUCCESSVerification passed
FAILVerification failed
PENDINGVerification pending manual review
PARTIALPartial verification result
UPLOAD_FAILDocument upload failed
PROVIDER_ERRORProvider 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.
EventOnfidoSumsubIncodeIDVerseDaon
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:
  1. 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.
  2. Hard code the document type — If your flow requires a specific document type, specify it directly in configuration rather than letting the user choose.
  3. 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 CodeDescriptionRecovery
invalid_tokenThe Onfido IDV token is invalid.Re-generate the IDV token by remounting the component.
expired_tokenThe Onfido IDV token has expired.Re-generate the IDV token by remounting the component.
expired_trialThe Onfido trial period has expired.This is unexpected in production. Contact FrankieOne support if you encounter this error.
geoblocked_requestThe 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_unavailableUnable 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.
unsupportedA module is not supported in the current environment.Check the OneSDK documentation for environment requirements, or contact FrankieOne support.
unsupported_featureThe requested feature is no longer supported.Check the OneSDK documentation for current feature availability, or contact FrankieOne support.
invalid_sdk_parameterThe SDK was initialized with invalid parameters.Review your Onfido provider configuration and correct any invalid parameters.
unsupported_sdk_versionThe 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_cameraNo 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_deniedThe 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.
For Onfido provider configuration and customization options, see Vendor Customizations.