Skip to main content

Overview

The OCR (Optical Character Recognition) module handles document capture and extraction of identity information from government-issued documents. It integrates with third-party OCR providers to capture document images and extract data such as name, date of birth, document number, and expiry date.

Accessing the Module

The OCR module is accessed through the SDK’s component factory:
const sdk = await OneSdk({
  mode: 'production',
  session: { token: 'your-token' }
});

// Create OCR component instance
const ocrComponent = sdk.component('ocr', options);

Supported Providers

The OCR module supports multiple document capture providers:
ProviderValueLearn More
Onfido'onfido'onfido.com
Sumsub'sumsub'sumsub.com
Incode'incode'incode.com
IDVerse'idverse'idverse.com
Daon'daon'daon.com
Each provider has different capabilities, supported document types, and geographic coverage. Visit the provider’s website to understand their specific features and limitations.

Configuration Options

Basic Configuration

const ocrComponent = sdk.component('ocr', {
  provider: {
    name: 'onfido'
  }
});

Common Options

OptionTypeDescription
maxDocumentCountnumberMaximum number of documents to capture
documentsarrayArray of document configurations specifying types and countries
skipInitProcessbooleanSkip initialization process (advanced use)
Documents Array Structure:
documents: [
  {
    type: 'DRIVERS_LICENCE',     // Document type
    countries: ['AUS', 'NZL']    // ISO country codes (optional)
  }
]

Provider-Specific Options

Onfido Provider

const ocrComponent = sdk.component('ocr', {
  provider: {
    name: 'onfido',
    sdkVersion: '13.0.0',           // Onfido SDK version
    theme: 'light',                  // 'light' or 'dark'
    showExitButton: true,            // Show exit button in UI
    crossDevicePolicy: 'disable',    // Cross-device flow: 'force' or 'disable'
    onUserExit: () => {              // Callback when user exits
      console.log('User exited');
    },
    customUI: {                      // Custom UI configuration
      // See Onfido documentation for customUI options
    }
  },
  documents: [
    { type: 'PASSPORT', countries: ['AUS'] }
  ]
});
Onfido Options:
OptionTypeDescription
sdkVersionstringVersion of the Onfido SDK to use. Default: '12'. Refer to the Onfido documentation for available versions.
theme'light' | 'dark'UI theme
showExitButtonbooleanDisplay exit button in the UI
crossDevicePolicy'force' | 'disable'Enable/disable cross-device flow
onUserExit() => voidCallback function when user exits
customUIobjectCustom UI styling configuration (see Custom UI section below)
_crossDeviceLinkMethodsArray<'qr_code' | 'copy_link' | 'sms'>Cross-device sharing methods (internal)
Onfido Custom UI Properties: The customUI object allows extensive styling customization:
customUI: {
  // Typography
  fontWeightBody: 400,
  fontSizeBody: '16px',
  fontSizeSubtitle: '18px',
  fontSizeTitle: '24px',

  // Colors - Background
  colorBackgroundSurfaceModal: '#FFFFFF',
  colorBackgroundIcon: '#353FF4',
  colorBackgroundInput: '#FFFFFF',

  // Colors - Content/Text
  colorContentBody: '#475467',
  colorContentTitle: '#101828',
  colorContentSubtitle: '#344054',
  colorContentInput: '#101828',

  // Colors - Buttons (Primary)
  colorContentButtonPrimaryText: '#FFFFFF',
  colorBackgroundButtonPrimary: '#353FF4',
  colorBackgroundButtonPrimaryHover: '#2835E5',
  colorBackgroundButtonPrimaryActive: '#1F2AD1',

  // Colors - Buttons (Secondary)
  colorContentButtonSecondaryText: '#344054',
  colorBackgroundButtonSecondary: '#FFFFFF',
  colorBackgroundButtonSecondaryHover: '#F9FAFB',
  colorBackgroundButtonSecondaryActive: '#F2F4F7',

  // Colors - Buttons (Tertiary)
  colorContentButtonTertiaryText: '#344054',

  // Borders
  borderRadiusButton: '8px',
  borderStyleSurfaceModal: '1px solid #E4E7EC',
  colorBorderInput: '#D0D5DD',
  colorInputOutline: '#353FF4',

  // Additional UI elements
  colorIcon: '#667085',
  colorBackgroundInfoPill: '#F2F4F7',
  colorContentInfoPill: '#344054',
  // ... see Onfido documentation for full list
}

Incode Provider

const ocrComponent = sdk.component('ocr', {
  provider: {
    name: 'incode',
    sdkVersion: '1.0.0',         // SDK version
    numberOfTries: 3,            // Max capture attempts
    consentId: 'consent_123',    // Consent identifier
    renderCamera: {
      showDocSelector: true,     // Show document selector
      showTutorial: true         // Show tutorial screens
    }
  },
  documents: [
    { type: 'DRIVERS_LICENCE' }
  ]
});
Incode Options:
OptionTypeDescription
sdkVersionstringVersion of the Incode SDK to use. Default: '1.75.2'. Refer to the Incode documentation for available versions.
numberOfTriesnumberMaximum number of capture attempts
consentIdstring | nullConsent identifier for the session
renderCameraobjectCamera rendering options (see below)
renderCamera Options:
OptionTypeDescription
showDocSelectorbooleanDisplay document type selector
showTutorialbooleanDisplay tutorial/instructions

Sumsub Provider

const ocrComponent = sdk.component('ocr', {
  provider: {
    name: 'sumsub',
    config: {
      theme: 'light',              // 'light' or 'dark'
      lang: 'en',                  // Language code
      email: 'user@example.com',   // Pre-fill email
      phone: '+1234567890'         // Pre-fill phone
    },
    options: {
      addViewportTag: true,        // Add viewport meta tag
      adaptIframeHeight: true      // Auto-adjust iframe height
    }
  }
});
Sumsub Options:
OptionTypeDescription
configobjectSumsub configuration (theme, lang, email, phone). See IDV Module - Sumsub for details.
optionsobjectSumsub SDK options (addViewportTag, adaptIframeHeight). See IDV Module - Sumsub for details.

IDVerse Provider

const ocrComponent = sdk.component('ocr', {
  provider: {
    name: 'idverse',
    translations: {              // Custom translations (optional)
      // Language-specific strings
    },
    retryCount: 3,              // Max retry attempts
    skipLoad: false,            // Skip loading vendor SDK
    workerPathString: '/path',  // Worker script path
    assetPathString: '/assets'  // Asset files path
  }
});
IDVerse Options:
OptionTypeDescription
translationsobjectCustom translation strings
retryCountnumberMaximum retry attempts
skipLoadbooleanSkip loading vendor SDK (advanced)
workerPathStringstringPath to worker script files
assetPathStringstringPath to asset files

Daon Provider

const ocrComponent = sdk.component('ocr', {
  provider: {
    name: 'daon',
    products: ['IdentityX', 'VeriFLY'],  // Daon products to use
    processInstanceParameters: [
      {
        name: 'param1',
        mandatory: true,
        minimumLength: 1,
        maximumLength: 50,
        default: 'value'
      }
    ]
  }
});
Daon Options:
OptionTypeDescription
productsstring[]Array of Daon product names to use
processInstanceParametersarrayProcess instance parameters (see structure below)
Process Instance Parameters:
PropertyTypeDescription
namestringParameter name
mandatorybooleanWhether parameter is required
minimumLengthnumberMinimum value length (optional)
maximumLengthnumberMaximum value length (optional)
defaultstring | numberDefault value

Methods

mount()

Mounts the OCR component to a DOM element. Signature:
mount(domElementOrSelector: string | HTMLElement): void
Parameters:
ParameterTypeRequiredDescription
domElementOrSelectorstring | HTMLElementYesCSS selector string (e.g., '#ocr-container') or HTMLElement object where the component will be mounted
Description: Mounts the OCR component to the specified DOM element. After mounting, call start() to begin the document capture process. Example:
// Mount to element by ID - capture begins automatically
ocrComponent.mount('#ocr-container');

// Mount to element reference
const container = document.getElementById('ocr-container');
ocrComponent.mount(container);

start()

Legacy Method: This method is for headless OCR integration and is not recommended for standard use. Modern provider integrations handle the capture flow automatically after mounting. Avoid using this method unless you have a specific headless integration requirement.
Starts the document capture process in headless mode. Signature:
start(): void
Description: Initiates the document capture flow for headless OCR implementations. For standard provider integrations, the capture flow begins automatically when mounting.

unmount()

Unmounts the OCR component from the DOM. Signature:
unmount(): void
Description: Removes the OCR component from the DOM and cleans up resources. Call this when the user navigates away or document capture is complete. Example:
ocrComponent.unmount();

isPreloaded()

Not typically used: isPreloaded() is not used in standard OCR integrations and can be safely ignored. Use events (detection_complete, results) to track document capture progress instead. This method was designed for legacy headless OCR flows.
Checks if OCR data has been previously captured for this entity. Signature:
isPreloaded(): boolean | null
Returns: boolean | null - true if OCR data exists for this entity, false if not, null if unable to determine Description: Returns true if the entity has existing OCR/document data in local state. This method was designed for headless integrations where you need to check local state before rendering capture UI. For standard provider integrations, document capture status should be determined by:
  • Using the results event to receive capture completion status
  • Querying your backend API for document verification results
  • Checking entity status through the FrankieOne API
Example:
// ✅ Use events to track capture progress
ocrComponent.on('results', ({ document }) => {
  console.log('Document captured:', document);
  proceedToNextStep();
});

ocrComponent.mount('#ocr-container');
// Capture begins automatically
This method only checks for the presence of document data in local state, not the actual verification result. Always verify document status through your backend API before proceeding with verification workflows.

access()

Legacy Method: This method is for headless OCR integration and is not recommended for standard use. For standard provider integrations, use events to track document capture progress instead of polling status. Avoid using this method unless you have a specific headless integration requirement.
Accesses reactive data accessors for the OCR component state. Signature:
access(fieldName: 'status'): Accessor
Description: Provides access to internal OCR status for headless implementations. For standard provider integrations, listen to events (detection_complete, results, etc.) instead of polling status.

statuses

Object containing all possible OCR status constants. Type: Readonly<typeof OCRStatus> Description: Provides access to OCR status enum values for comparison in event handlers and status checks. Available Statuses:
Provider-Specific: Not all statuses are used by all providers. The specific statuses emitted depend on your chosen provider’s workflow and capabilities.
StatusValueDescription
WAITING_OCR_RUN'AWAITING_DOCUMENT_OCR'Waiting for OCR processing to run
WAITING_BACK'AWAITING_DOCUMENT_UPLOAD_BACK'Waiting for back side of document
WAITING_FRONT'AWAITING_DOCUMENT_UPLOAD_FRONT'Waiting for front side of document
COMPLETE'COMPLETE_OCR'OCR capture and processing complete
DOCUMENTS_INVALID'AWAITING_DOCUMENT_UPLOAD_INVALID_TYPE'Invalid document type provided
DOCUMENTS_UPLOAD_FAILED'AWAITING_DOCUMENT_UPLOAD_FAILED_OCR'Document upload failed
PROVIDER_OFFLINE'AWAITING_OCR_RESULTS_PROVIDER_OFFLINE'OCR provider is offline/unavailable
FAILED_FILE_SIZE'DOCUMENT_INVALID_EXCEEDED_SIZE_LIMIT'File size exceeds limit
FAILED_FILE_FORMAT'DOCUMENT_INVALID_INCORRECT_FILE_FORMAT'Incorrect file format
INTERRUPTED'INTERRUPTED'Capture flow was interrupted (provider-specific)
Example:
const ocrComponent = sdk.component('ocr', { provider: { name: 'onfido' } });

ocrComponent.on('input_required', (info, status) => {
  if (status === ocrComponent.statuses.WAITING_FRONT) {
    console.log('Please capture front of document');
  } else if (status === ocrComponent.statuses.WAITING_BACK) {
    console.log('Please capture back of document');
  }
});

ocrComponent.on('results', ({ document }) => {
  const status = ocrComponent.access('status').getValue();

  if (status === ocrComponent.statuses.COMPLETE) {
    console.log('OCR completed successfully');
    console.log('Extracted data:', document);
  }
});

Events

The OCR module emits events throughout the document capture lifecycle.
Provider-Specific Behavior: Events and statuses vary by provider. Not all providers emit all events, and some events are provider-specific. Always test with your chosen provider to understand which events are emitted and when.

session_data_generated

Emitted when session data for the vendor is generated. Arguments:
{
  session: {
    entityId: string;
    vendorParameters: unknown;
  }
}
Example:
ocrComponent.on('session_data_generated', ({ session }) => {
  console.log('OCR session created for entity:', session.entityId);
});

ready

Emitted when the OCR component is ready and mounted. Arguments:
{
  domElement: HTMLElement;
}
Example:
ocrComponent.on('ready', ({ domElement }) => {
  console.log('OCR component ready in element:', domElement);
});

detection_complete

Emitted when document capture is complete. Arguments:
{
  provider: string;
} | []
Example:
ocrComponent.on('detection_complete', (data) => {
  if (data && data.provider) {
    console.log(`Document captured with ${data.provider}`);
  } else {
    console.log('Document capture complete');
  }
  showProcessingMessage();
});

detection_failed

Emitted when document capture fails. Arguments:
{
  message?: string;
}
Example:
ocrComponent.on('detection_failed', ({ message }) => {
  console.error('Capture failed:', message);
  showErrorMessage(message || 'Failed to capture document. Please try again.');
});

input_required

Emitted when a non-positive flow has occurred but is likely recoverable by retrying. Arguments:
(
  info: {
    documentType: string | null;
    side: 'front' | 'back' | null;
  },
  status: OCRStatus,
  provideFile: (blob: File) => void
)
Description: This event indicates that document capture cannot proceed in its current state, but the issue is typically recoverable. Common scenarios include:
  • Waiting for front or back side of document
  • User needs to retry capture
  • Document type mismatch
Legacy Parameter: The provideFile callback is for headless OCR integration and is not recommended for standard use. For standard provider integrations, the provider handles file capture automatically. Avoid using this parameter unless you have a specific headless integration requirement.
Example:
ocrComponent.on('input_required', (info, status) => {
  console.log('Input required:', {
    documentType: info.documentType,
    side: info.side,
    status: status
  });

  if (status === ocrComponent.statuses.WAITING_FRONT) {
    showMessage('Please capture the front of your document');
  } else if (status === ocrComponent.statuses.WAITING_BACK) {
    showMessage('Please capture the back of your document');
  }
});

results

Emitted when OCR processing is complete and document data is available. Arguments:
{
  document: Document | null;
  entityId: string | null;
}
Description: Contains the extracted document information including ID number, expiry date, date of birth, and other fields depending on document type. The document structure matches the Document Structure used in the Individual module. Example:
ocrComponent.on('results', ({ document, entityId }) => {
  if (document) {
    console.log('Document extracted:', {
      type: document.idType,
      number: document.idNumber,
      expiry: document.idExpiry,
      dateOfBirth: document.dateOfBirth,
      country: document.country
    });

    // Document is automatically added to Individual module
    navigateToNextStep();
  } else {
    console.log('No document data extracted');
    showRetryOption();
  }
});

file_uploaded

Emitted when a file is successfully uploaded.
Legacy Headless OCR: This event is primarily used in legacy headless OCR implementations. For standard provider integrations, use the results event instead.
Arguments:
{
  fileName: string | null;
  mimeType: string | null;
  scanId: string | null;
  statusAfterUpload: OCRStatus;
  statusBeforeUpload: OCRStatus | null;
}
Example:
ocrComponent.on('file_uploaded', (meta) => {
  console.log('File uploaded:', meta.fileName);
  console.log('Status changed:', meta.statusBeforeUpload, '→', meta.statusAfterUpload);
});

session_closed

Emitted when the OCR session is closed. Arguments: None Example:
ocrComponent.on('session_closed', () => {
  console.log('OCR session closed');
  ocrComponent.unmount();
});

session_interrupted

Emitted when the user interrupts the capture session. Arguments:
{
  eventName: string;
  reason: string;
  module: 'OCR' | 'BIOMETRICS';
}
Provider-Specific:
  • Onfido: Emits this when the verification modal is closed.
Example:
ocrComponent.on('session_interrupted', ({ reason, eventName }) => {
  console.log(`Session interrupted: ${reason}`);
  console.log('Event:', eventName);
  saveProgress();
});

session_data_failed_loading

Emitted when session data fails to load. Arguments:
{
  code?: unknown;
  message: string;
}
Example:
ocrComponent.on('session_data_failed_loading', ({ message, code }) => {
  console.error('Failed to load session:', message);
  console.error('Error code:', code);
  showError('Unable to start document capture. Please try again.');
});

vendor_event

Emitted for provider-specific events. Arguments:
Record<string, unknown>  // Provider-specific event data
Example:
ocrComponent.on('vendor_event', (event) => {
  console.log('Provider event:', event);
  // Handle provider-specific events
});

Common Events

The OCR module also emits common events inherited from the event system:
  • error - When an error occurs
  • warning - For non-critical warnings
  • info - Informational messages
  • loading - Loading state changes
See Event System Reference for details.

Complete Example

import OneSdk from '@frankieone/one-sdk';

async function captureDocument() {
  try {
    // Initialize SDK
    const sdk = await OneSdk({
      mode: 'production',
      session: { token: await getSessionToken() }
    });

    // Create OCR component with Onfido provider
    const ocrComponent = sdk.component('ocr', {
      provider: {
        name: 'onfido',
        theme: 'light',
        showExitButton: true
      },
      documents: [
        { type: 'DRIVERS_LICENCE', countries: ['AUS'] },
        { type: 'PASSPORT' }
      ]
    });

    // Set up event listeners before mounting
    ocrComponent.on('session_data_generated', ({ session }) => {
      console.log('OCR session started for:', session.entityId);
    });

    ocrComponent.on('ready', () => {
      console.log('OCR component ready');
      // Capture begins automatically - no need to call start()
    });

    ocrComponent.on('detection_complete', () => {
      console.log('Document captured, processing...');
      showMessage('Processing your document...');
    });

    ocrComponent.on('detection_failed', ({ message }) => {
      console.error('Capture failed:', message);
      showError(message);
      enableRetry();
    });

    ocrComponent.on('input_required', (info, status) => {
      console.log('Input required:', info.documentType, info.side);

      if (status === ocrComponent.statuses.WAITING_FRONT) {
        showInstruction('Please capture the front of your document');
      } else if (status === ocrComponent.statuses.WAITING_BACK) {
        showInstruction('Please capture the back of your document');
      }
    });

    ocrComponent.on('file_uploaded', (meta) => {
      console.log('File uploaded:', meta.fileName);
      updateProgress();
    });

    ocrComponent.on('results', ({ document, entityId }) => {
      console.log('OCR complete for entity:', entityId);

      if (document) {
        console.log('Extracted document data:', {
          type: document.idType,
          number: document.idNumber,
          expiry: document.idExpiry,
          dateOfBirth: document.dateOfBirth
        });

        // Document automatically added to Individual module
        ocrComponent.unmount();
        navigateToNextStep();
      } else {
        console.log('No document data extracted');
        showRetryOption();
      }
    });

    ocrComponent.on('session_closed', () => {
      console.log('User closed OCR session');
      ocrComponent.unmount();
    });

    ocrComponent.on('error', (error) => {
      console.error('OCR error:', error);
      showError('Document capture error. Please try again.');
    });

    // Mount the component - capture begins automatically
    ocrComponent.mount('#ocr-container');

  } catch (error) {
    console.error('OCR initialization failed:', error);
    throw error;
  }
}

Best Practices

  1. Handle all events, not just results - Also listen to input_required (for recoverable states like WAITING_FRONT, WAITING_BACK, DOCUMENTS_INVALID), detection_failed (for capture failures), and error (for system failures).
  2. Set up event listeners before mounting - Register all event handlers before calling mount() to avoid missing events.
  3. Unmount on navigation - Always call unmount() when the user leaves the page to clean up resources.
  4. Provider-specific configuration - Review each provider’s documentation for optimal configuration.
  5. Error handling - Always listen to the error event and provide user-friendly error messages.

Common Issues

Component not displaying

Ensure the mount element exists in the DOM and has sufficient size:
#ocr-container {
  width: 100%;
  min-height: 600px;
}

Session data failed to load

This usually means the backend session setup failed. Ensure your backend is correctly generating IDV tokens.

Provider-specific errors

Check the vendor_event emissions for provider-specific error details and consult the provider’s documentation.