SDK reference · iOS SDK / iOS Getting Started

Capture-Only Mode

Capture-Only mode runs the Incode capture experience on-device and returns the resulting photos and videos through the IncdOnboardingDelegate callbacks, without sending data to Incode for processing. Use it when you want Incode's auto-capturing camera UX but do not want the SDK to upload or process the media. You are responsible for whatever you do with the captured media afterward.


How It Works

The capture APIs perform local checks, auto-capture the photo when conditions are met, and return the captured media through a delegate callback.

The diagram below shows the recommended data flow when using Capture-Only mode. The SDK captures locally and hands the media to the host app. The host app sends it to the customer server, which calls the Incode API and decides whether to repeat the capture.

Each module follows the same pattern, but the completion callback, the result type, and the fields it carries change. Read the diagram below once to understand the pattern, then view the diagram for the module you are integrating: ID Capture, Selfie, or Video Selfie. Each module-specific diagram includes the callback signature and the result fields your app receives.

sequenceDiagram
    autonumber
    participant App as Host App
    participant SDK as Incode SDK
    participant Server as Customer Server

    App->>SDK: initIncdOnboarding(...) then sdkMode = .captureOnly
    Note over App,SDK: Keep the shared manager alive so the<br/>SDK is not cleared from memory

    loop For each capture section in the flow
        App->>SDK: startOnboardingSection(flowConfig:sectionTag:delegate:)
        SDK->>SDK: local checks, auto capture
        SDK-->>App: module completion callback with result
        SDK-->>App: onOnboardingSectionCompleted(flowTag)
        Note over App,SDK: Run one section at a time - start the next<br/>only after onOnboardingSectionCompleted
        App->>Server: upload captured media
        Server->>Server: call Incode API, analyze response
        alt capture not acceptable
            Server-->>App: request re-capture
            App->>SDK: startOnboardingSection(...) again
        end
    end

    App->>SDK: deleteLocalUserData()

Starting a second section while one is still running fails with IncdFlowError.sectionAlreadyRunning. Wait for onOnboardingSectionCompleted(_:) before starting the next section.

ID Capture

The diagram below shows the recommended data flow when using Capture-Only mode for the ID Capture module. The result is an in-memory IdScanResult; the image is exposed as a UIImage and a base64 string, not as a file on disk.

sequenceDiagram
    autonumber
    participant App as Host App
    participant SDK as Incode SDK
    participant Server as Customer Server

    App->>SDK: startOnboardingSection (ID scan, front)
    SDK-->>App: onIdFrontCompleted(IdScanResult)
    Note right of App: image (UIImage?)<br/>base64Image (String?)<br/>chosenIdType<br/>metadata (String?)
    SDK-->>App: onOnboardingSectionCompleted(flowTag)
    App->>Server: upload front ID image
    Server-->>App: OK or repeat front scan

    App->>SDK: startOnboardingSection (ID scan, back)
    SDK-->>App: onIdBackCompleted(IdScanResult)
    Note right of App: image (UIImage?)<br/>base64Image (String?)<br/>chosenIdType<br/>metadata (String?)
    SDK-->>App: onOnboardingSectionCompleted(flowTag)
    App->>Server: upload back ID image
    Server-->>App: OK or repeat back scan

Selfie

The diagram below shows the recommended data flow when using Capture-Only mode for the Selfie module.

sequenceDiagram
    autonumber
    participant App as Host App
    participant SDK as Incode SDK
    participant Server as Customer Server

    App->>SDK: startOnboardingSection (selfie scan)
    SDK-->>App: onSelfieScanCompleted(SelfieScanResult)
    Note right of App: image (UIImage?)<br/>selfieBase64 (String?)<br/>selfieEncryptedBase64 (String?)<br/>metadata (String?)<br/>videoFileURL (URL?, video liveness only)
    SDK-->>App: onOnboardingSectionCompleted(flowTag)
    App->>Server: upload selfie
    Server-->>App: OK or repeat selfie scan

Video Selfie

The diagram below shows the recommended data flow when using Capture-Only mode for the Video Selfie module. VideoSelfieResult exposes the captured stills as UIImage and the media as Data.

sequenceDiagram
    autonumber
    participant App as Host App
    participant SDK as Incode SDK
    participant Server as Customer Server

    App->>SDK: startOnboardingSection (video selfie)
    SDK-->>App: onVideoSelfieCompleted(VideoSelfieResult)
    Note right of App: selfie (UIImage?)<br/>idFront / idBack (UIImage?)<br/>document (UIImage?)<br/>videoData (Data?)<br/>audioData (Data?)<br/>voiceConsentSelfie (UIImage?)
    SDK-->>App: onOnboardingSectionCompleted(flowTag)
    App->>Server: upload video selfie assets
    Server-->>App: OK or repeat video selfie

Supported Modules

Capture-Only mode supports the following modules. Each is added to a flow through the matching IncdOnboardingFlowConfiguration.addXxx(...) builder.

Module Builder Description
Intro addIntro(checks:) Displays an introduction screen at the start of a flow.
Full Name addFullName() Collects the user's name and sends it to the server.
Phone addPhone(otpVerification:defaultRegionPrefix:) Collects a user's phone number and can confirm ownership by sending a one-time password (OTP) via SMS.
Email addEmail(otpVerification:) Collects a user's email address and can confirm ownership by sending a one-time password (OTP) to that address.
ID Capture addIdScan(...) Captures the front and back of a government-issued ID, with auto-capture and quality checks, and produces clean images for processing.
NFC addNfcScan(...) Reads the secure NFC chip embedded in ICAO 9303-compliant travel documents (-nfc variant).
Document Capture addDocumentScan(...) Captures a supplementary document, such as a proof of address document, medical document, or bank statement.
Selfie addSelfieScan(...) Captures the user's face with the device camera and runs configurable liveness, face-recognition, and image-quality checks.
Geolocation addGeolocation(isSkippable:) Requests location permission, then captures the precise physical location of the user's device, using its GPS sensor to record coordinates and location fields such as country, state, and city.
Signature addSignature(...) Captures a signature the user hand-draws on screen, optionally presenting documents to sign.
Video Selfie addVideoSelfie(videoSelfieConfiguration:) Records a short video of the user performing a guided series of actions, including capturing their ID and selfie, to confirm physical presence and run liveness and face match checks. It can also capture voice consent.

Set Up Capture-Only Mode

Complete the following steps in order.

Initialize the SDK for Capture-Only

Initialize the SDK with initIncdOnboarding(...), then set sdkMode to .captureOnly on the shared manager before starting a capture section.

IncdOnboardingManager.shared.initIncdOnboarding(
    url: "<YOUR_API_URL>",
    apiKey: "<YOUR_API_KEY>"
) { success, error in
    guard success == true else { return }
    IncdOnboardingManager.shared.sdkMode = .captureOnly
}
  • Capture calls only work after the SDK has been initialized. IncdOnboardingManager.shared is a singleton; keep it alive so the SDK is not cleared from memory.
  • In the Public distribution variant, setting .captureOnly logs a warning and the SDK reverts to .standard.

Perform Capture SDK Calls

Build the module you want to capture into an IncdOnboardingFlowConfiguration, then start an onboarding section. Results arrive on the IncdOnboardingDelegate callbacks. The example below starts an ID scan section; the selfie scan section is started only after onOnboardingSectionCompleted reports the ID section done. Run one section at a time; starting a second section while one is still running fails with IncdFlowError.sectionAlreadyRunning.

// ID scan
IncdOnboardingManager.shared.sdkMode = .captureOnly
IncdOnboardingManager.shared.delegate = self

let idFlow = IncdOnboardingFlowConfiguration()
idFlow.addIdScan(scanStep: .both)

IncdOnboardingManager.shared.startOnboardingSection(
    flowConfig: idFlow,
    sectionTag: "id-scan",
    delegate: self
)
extension MyCaptureController: IncdOnboardingDelegate {
    // ID scan results
    func onIdFrontCompleted(_ result: IdScanResult) {
        // result.image, result.base64Image, result.chosenIdType, result.metadata
    }
    func onIdBackCompleted(_ result: IdScanResult) {
        // result.image, result.base64Image, result.chosenIdType, result.metadata
    }

    // Selfie scan result
    func onSelfieScanCompleted(_ result: SelfieScanResult) {
        // result.image, result.selfieBase64, result.metadata
    }

    // Section lifecycle — start the next section only after this fires
    func onOnboardingSectionCompleted(_ flowTag: String) {
        // Upload the captured media, then start the next section.
        guard flowTag == "id-scan" else { return }

        let selfieFlow = IncdOnboardingFlowConfiguration()
        selfieFlow.addSelfieScan()

        IncdOnboardingManager.shared.startOnboardingSection(
            flowConfig: selfieFlow,
            sectionTag: "selfie-scan",
            delegate: self
        )
    }

    func onSuccess() {}
    func onError(_ error: IncdFlowError) {}
    func userCancelledSession() {}
}

Forward Metadata for Deepsight

If your organization uses Deepsight, forward the metadata field from IdScanResult and SelfieScanResult to the corresponding omni/add/* API request. Deepsight's downstream checks depend on this field. If you omit it, those checks run without the data they need.

Clean Up Local User Data

After the flow exits, call IncdOnboardingManager.shared.deleteLocalUserData() to delete all local user data generated during the flow and clear the current onboarding session data.

Danger

Always call deleteLocalUserData()

Call deleteLocalUserData() to remove the local user data the flow generated. Call it from your success, error, and cancellation callbacks.

Call deleteLocalUserData() from the following delegate callbacks:

func onSuccess() {
    IncdOnboardingManager.shared.deleteLocalUserData()
}

func onError(_ error: IncdFlowError) {
    IncdOnboardingManager.shared.deleteLocalUserData()
}

func userCancelledSession() {
    IncdOnboardingManager.shared.deleteLocalUserData()
}

Supported API Configurations

FlowConfig

IncdOnboardingFlowConfiguration assembles the modules, in order, for the section you start. The builder below lists every module supported in Capture-Only mode. The placeholders stand for the values you supply.

let flow = IncdOnboardingFlowConfiguration()   // or .init(waitForTutorials:)
flow.addIntro(checks: [])
flow.addFullName()
flow.addPhone(otpVerification: true, defaultRegionPrefix: 1)
flow.addEmail(otpVerification: true)
flow.addIdScan(scanStep: .both)
flow.addNfcScan(…)
flow.addDocumentScan(…)
flow.addSelfieScan()
flow.addGeolocation(isSkippable: false)
flow.addSignature(…)
flow.addVideoSelfie(videoSelfieConfiguration: …)

Each builder's full options, result type, and callback are documented on its corresponding module page.

Shared Settings

iOS does not expose a separate shared-configuration object. Settings shared across modules—SDK mode, presentation, delegate, diagnostics, and other flow toggles—are set on IncdOnboardingManager.shared, and theming and localization are configured separately. See Configure Flows Locally and Run End to End for the manager properties and Customization for appearance. The same settings apply in Capture-Only mode.


Customizable Strings

Every user-facing string the SDK shows can be overridden, including in Capture-Only flows. For the complete list of string keys and override methods, see Customization.


For help, see the API Reference or contact Incode support.


Was this page helpful?