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. |
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.sharedis a singleton; keep it alive so the SDK is not cleared from memory. - In the Public distribution variant, setting
.captureOnlylogs 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.