The KYC Documents Capture SDK gives your organization full control over the document and selfie capture experience. You own the UI, branding, and flow; Trulioo provides the underlying image capture and verification technology.
Build capture experiences that align with your brand guidelines, with custom overlays, animations, and messaging, while relying on Trulioo's built-in verification intelligence for accuracy and security.
Looking for a ready-made solution? Use the KYC Documents SDK instead. It provides the same capture and verification technology with a complete Trulioo-designed UI and minimal setup.
Use this guide when integrating host-owned document or selfie camera capture into an iOS app.
This guide covers the public Swift package, Capture runtime initialization, camera controller embedding, image verification and acceptance, transaction submission, and support evidence. Use the KYC Documents iOS guide when the hosted KYC Documents UI owns the full document verification flow.
The Trulioo KYC Documents Capture iOS SDK provides document and selfie capture capabilities that can be embedded in an iOS host screen.
Customer applications can expect the SDK to:
- initialize the active capture transaction from a shortcode
- create a document or selfie camera for the active transaction
- return a camera
UIViewControllerfor UIKit embedding or SwiftUI bridging - return capture feedback or manual capture results
- verify and accept captured images before submission
- submit accepted images and return iOS-native success or error callbacks
A standard iOS Capture integration looks like this:
- add the
TruliooKYCDocumentsCaptureSwift package - initialize the runtime with a shortcode
- create a camera for document or selfie capture
- render the camera and embed the returned
UIViewController - use
startFeedback(...)for auto capture orcaptureLatestFrame(...)for manual capture - use
verifyImage()andacceptImage()on the returned image result - call
submit(...)when all required images have been accepted - call
reset()when the host app is done with the transaction or needs a fresh session
- GitHub repository:
https://github.com/Trulioo/kyc-documents-capture.git - package name:
TruliooKYCDocumentsCapture - main runtime wrapper:
TruliooCaptureRuntimeLive - minimum iOS version:
15.0
The public SwiftPM package includes:
- the binary
TruliooKYCDocumentsCapturetarget - the
TruliooKYCDocumentsCaptureRuntimeSwift bridge - the upstream
Trulioodependency pinned by the package release metadata
Host applications must:
- embed the SDK-owned camera
UIViewControllerinto the host UI - handle iOS camera permission flow
- provide a valid Capture shortcode
- decide whether a verified image should be accepted
- decide when the session should be submitted or reset
Add the package:
dependencies: [
.package(url: "https://github.com/Trulioo/kyc-documents-capture.git", from: "X.Y.Z")
]Import the modules you use:
import TruliooKYCDocumentsCapture
import TruliooKYCDocumentsCaptureRuntimeImport Trulioo only when the host application also uses the base Trulioo SDK directly.
Before starting a Capture flow, make sure the host application:
- has a valid shortcode generated through the Trulioo customer handoff flow using the Customer API 3.0 handoff operation
- uses a shortcode configured for the document or selfie capture journey
- has a presentation path for the SDK camera view controller
- handles iOS camera permission
In your view controller or capture coordinator:
import TruliooKYCDocumentsCapture
import TruliooKYCDocumentsCaptureRuntime
import UIKit
final class CaptureCoordinator {
private let capture = TruliooCaptureRuntimeLive()
func startCapture(
shortcode: String,
presentCamera: @escaping (UIViewController) -> Void
) {
capture.initialize(shortcode: shortcode) { [weak self] error, transactionId in
guard let self else { return }
if let error {
print("Initialize failed:", error)
return
}
print("Initialized transaction:", transactionId ?? "missing")
let camera = self.capture.createCamera(
config: ContractTruliooCameraConfig(
detectionType: .document
)
)
let controller = camera.render(cameraProps: nil)
presentCamera(controller)
camera.startFeedback { error, response in
if let error {
print("Auto capture failed:", error)
return
}
guard let response else {
print("Auto capture did not return an image")
return
}
Task {
do {
let verify = try await response.verifyImage()
let accepted = verify.verifyResponses.contains { value in
value == "SUCCESS" || value == "SUCCESS_REQUIRES_BACK"
}
if accepted {
try await response.acceptImage()
}
self.capture.submit { submitError in
if let submitError {
print("Submit failed:", submitError)
return
}
camera.remove()
self.capture.reset()
}
} catch {
print("Verify or accept failed:", error)
}
}
}
}
}
}Embed or present the returned camera UIViewController using the host application's normal UIKit or SwiftUI container pattern.
When removing an embedded UIKit child controller, use the normal child-controller teardown sequence:
controller.willMove(toParent: nil)
controller.view.removeFromSuperview()
controller.removeFromParent()Pair host UI teardown with camera.remove() when the camera instance is no longer needed.
initialize(...) configures the Capture bridge, authorizes the active transaction, fetches Capture configuration, and returns the transaction id through its completion handler. It must complete before the application creates a camera.
The completion handler provides the active transaction id. Retain it for host diagnostics and support correlation; the Capture runtime retains the active session until reset() is called.
Main runtime entry points:
TruliooCaptureRuntimeLive.initialize(shortcode:locale:completion:)Start or resume the active Capture transaction with default runtime options.TruliooCaptureRuntimeLive.initialize(shortcode:options:locale:completion:)Start or resume the active Capture transaction.TruliooCaptureRuntimeLive.createCamera(config:)Create a document or selfie camera instance for the active transaction.TruliooCaptureRuntimeLive.submit(completion:)Finalize the active transaction after the required images have been accepted.TruliooCaptureRuntimeLive.reset()Clear the active Capture state and prepare for a new initialization.
Main camera entry points:
render(cameraProps:)Return an SDK-ownedUIViewControllerthat hosts the camera UI. Embed that controller in UIKit or bridge it into SwiftUI withUIViewControllerRepresentable.startFeedback(...)Run auto capture until the SDK accepts a candidate frame.startFeedback(filter:result:)Run auto capture with a caller-provided acceptance predicate.captureLatestFrame(...)Perform a manual capture from the latest available frame.stopFeedback()Stop an active auto-capture session.onFeedbackState()Observe SDK feedback labels through the bridged flow.onCaptureRegion()Observe the active capture region through the bridged flow.getResolution(...)Read the active camera stream resolution.resume()Resume preview after interruption or review.remove()Tear down the rendered camera and release resources.
Capture result entry points:
verifyImage()Request post-capture verification feedback. Call this on theTruliooCaptureResponseorTruliooManualCaptureResponsereturned bystartFeedback(...)orcaptureLatestFrame(...).acceptImage()Accept the image into the active transaction. Call this on theTruliooCaptureResponseorTruliooManualCaptureResponsereturned bystartFeedback(...)orcaptureLatestFrame(...).
If a newer initialize call supersedes an older one, the older completion may receive TruliooCaptureInitializationSupersededError.
The normal Capture flow is:
- call
initialize(...) - create a camera with
ContractTruliooCameraConfig - call
render(cameraProps:) - embed the returned
UIViewController - call
startFeedback(...)orcaptureLatestFrame(...) - inspect the result using
verifyImage() - call
acceptImage()if the host application wants to keep that image - repeat for additional required images
- call
submit(...) - call
reset() - remove the embedded camera
UIViewControllerfrom the parent hierarchy using the cleanup pattern above
submit(...) finalizes the active transaction. reset() clears local Capture state and should be called before reusing the runtime for a new transaction.
The Device Intelligence send and debug wait paths do not apply to the Capture SDK. Capture submission is finalized through submit(...) after the required accepted images are associated with the active transaction.
The host application owns:
- the shortcode
- the UIKit container and surrounding controls
- permission prompts and user guidance outside the camera component
- whether the current step is document or selfie
- whether to use auto capture or manual capture
- whether to accept the verified image
- when to submit or reset
The SDK owns:
- camera session setup and teardown
- frame analysis and auto-capture selection
- post-capture verification requests
- transaction-scoped image ids and feedback payloads
- accepted-image association with the active transaction
The public iOS Capture contract does not require host configuration for upload pacing or frame timing.
Important defaults:
- document is the default detection type
startFeedback(...)uses the SDK default acceptance behaviorsubmit(...)does not clear local state by itself
startFeedback(...) returns TruliooCaptureResponse.
Important fields:
imageIddetectionTypeimageFeedbacks
verifyImage() returns ITruliooVerifyFeedback.
Important fields:
isVerifyAttemptAvailableverifyResponses
Recommended host-side acceptance rule:
- treat
SUCCESSandSUCCESS_REQUIRES_BACKas accepted verify outcomes unless your product has a stricter policy
- always initialize with a shortcode created for the active transaction
- do not reuse a stale shortcode after
reset() - after calling
reset(), a newinitialize(...)call is required before reuse
- Initialization, capture, verification, acceptance, and submission report errors through their documented completion handlers or thrown async errors; handle them before continuing the flow.
- Do not use cameras or image results after
reset(); initialize a new Capture session first. - Call
stopFeedback()to end an active auto-capture attempt, then update the host UI from the resulting callback or error.
- Initialization fails: Confirm the shortcode is valid and the host app is using the expected environment.
- Camera view stays blank:
Confirm the returned camera
UIViewControlleris retained, embedded in the active view hierarchy, and camera permission is granted. - Auto capture never resolves:
Inspect
onFeedbackState()to see whether the SDK is repeatedly asking for a retake condition. - Submit fails after capture: Confirm the expected images were accepted before submission.