Native SDK: This is the recommended approach for iOS apps. Native SDKs provide the best user experience, optimized camera handling, and full NFC support.
All features except NFC. No OpenSSL.xcframework, no CoreNFC runtime requirement
iOS 13.0+
Pick Full if your workflow scans the NFC chip on passports/eIDs. Pick Core if you only need document + face + liveness and want to avoid the NFC binary, CoreNFC runtime, and the App Store NFC demo-video review request.
DiditSDK is distributed as a binary podspec hosted in the repo (it is not on the public CocoaPods Trunk), so you must reference the podspec URL.Full SDK (with NFC, iOS 15.0+):
After pod install, open the generated .xcworkspace (not .xcodeproj).
Xcode 15+ rsync errors: If you see Operation not permitted rsync errors during build, set Build Settings → User Script Sandboxing (ENABLE_USER_SCRIPT_SANDBOXING) to No on the project for both Debug and Release.
<key>NSCameraUsageDescription</key><string>Camera access is required to scan your identity documents for verification.</string><key>NSMicrophoneUsageDescription</key><string>Microphone access is required to record video for liveness verification.</string><key>NSPhotoLibraryUsageDescription</key><string>Photo library access is required to upload document images.</string><key>NFCReaderUsageDescription</key><string>NFC access is required to read the chip in your identity document.</string><key>NSLocationWhenInUseUsageDescription</key><string>Location access helps verify your identity and prevent fraud.</string>
Required only when installing the Full SDK. Skip this section if you installed DiditSDK/Core (CocoaPods) or DiditSDKCore (SwiftPM).To enable NFC reading for passports and ID cards with chips:
Add NFC Capability in Xcode:
Select your target → Signing & Capabilities → + Capability → Near Field Communication Tag Reading
Simulator Limitation (Full SDK only): The Full SDK links CoreNFC, and since Xcode 12 libnfshared.dylib is missing from simulators. See this Stack Overflow thread for a workaround. This does not apply when installing the Core SDK (DiditSDK/Core or DiditSDKCore). Test NFC features on physical devices only.
App Store Review (Full SDK only): If you install the Full SDK, Apple may request a demo video during review because NFC-related code is part of the SDK binary — even if your workflow does not use NFC. Download our NFC demo video to submit to Apple: Download NFC Demo Video. This does not apply to the Core SDK.
No backend required. The SDK creates the session directly using your workflow ID from the Didit Console. The UniLink method (startVerification(workflowId:)) only supports vendorData; for any other session parameters use Method 2.
For vendorData to be attached to the session via UniLink, enable the Vendor Data option in the Didit Console.
Method 2: Backend Session (Recommended for Production)
Your backend creates the session via the Create Verification Session API (POST /v3/session/) with full parameter support (contact_details, expected_details, metadata, callback, etc.), then passes the session_token to the SDK.
// Your backend creates a session and returns the tokenlet sessionToken = await yourBackend.createVerificationSession(userId: currentUser.id)// Pass the token to the SDKDiditSdk.shared.startVerification(token: sessionToken)
This approach gives you full control over:
Associating sessions with your users (vendor_data)
Setting contact details and expected details for cross-validation
Setting custom metadata
Configuring callbacks per session
This data (contact details, expected details, metadata, callback) is sent to the Create Verification Session API.
Customize the SDK behavior with DiditSdk.Configuration:
let configuration = DiditSdk.Configuration( languageLocale: .spanish, // Force Spanish language fontFamily: "Avenir", // Custom font (must be registered in your app) loggingEnabled: true, // Enable debug logging showCloseButton: true, // Show close (X) button on step screens showExitConfirmation: true, // Show confirmation dialog when user taps close closeOnComplete: false // Don't auto-dismiss on completion)DiditSdk.shared.startVerification( token: "your-session-token", configuration: configuration)
Custom font family name (must be registered in your app via UIAppFonts in Info.plist)
loggingEnabled
Bool
false
Enable SDK debug logging
showCloseButton
Bool
true
Show close (X) button on verification step screens
showExitConfirmation
Bool
true
Show confirmation dialog when user attempts to exit
closeOnComplete
Bool
false
Auto-dismiss verification UI when complete (Web SDK equivalent: closeModalOnComplete)
Theming & Colors: Colors, backgrounds, and intro screen settings are configured through your White Label settings in the Didit Console, not in the SDK configuration. This ensures consistent branding across all platforms.
Options showCloseButton, showExitConfirmation, and closeOnComplete match the Web SDK’s DiditSdkConfiguration. Mobile-specific options languageLocale and fontFamily exist because the mobile SDK renders the full verification UI natively (unlike the Web SDK which delegates to the hosted frontend inside an iframe).
For advanced session parameters (contact_details, expected_details, metadata, callback), use the Backend Session method. Your backend calls the Create Verification Session API with full parameters, then passes the session_token to the SDK.
.diditVerification { result in switch result { case .completed(let session): switch session.status { case .approved: print("✅ Approved! Session: \(session.sessionId)") // User is verified - grant access case .pending: print("⏳ Under review. Session: \(session.sessionId)") // Show "verification in progress" UI case .declined: print("❌ Declined. Session: \(session.sessionId)") // Handle declined verification } case .cancelled(let session): if let session = session { print("🚫 Cancelled session: \(session.sessionId)") } // User chose to cancel - maybe show retry option case .failed(let error, let session): print("⚠️ Error: \(error.localizedDescription)") // Handle error - show retry or contact support }}
The host app can end an active verification programmatically with DiditSdk.shared.dismiss(). This is the recommended way to tear down the verification when the host needs to take over the screen — for example, when the app moves to the background.
DiditSdk.shared.dismiss()
dismiss() goes through the SDK’s normal completion pipeline: it dismisses the presented UI, resets internal state, and invokes the .diditVerification handler with .cancelled(session:) carrying the current sessionId if a session was created. It is a no-op when no verification is active.
Do not set DiditSdk.shared.isPresented = false to dismiss — the flag only triggers presentation on its rising edge and setting it to false is a no-op. Likewise, calling UIKit’s dismiss(animated:) on the topmost view controller is not supported: it bypasses the SDK’s completion pipeline so your .diditVerification handler is never fired.
You can observe the SDK state for custom loading UI:
struct CustomView: View { @ObservedObject private var sdk = DiditSdk.shared var body: some View { VStack { switch sdk.state { case .idle: Text("Ready to verify") case .creatingSession: ProgressView("Creating session...") case .loading: ProgressView("Loading...") case .ready: Text("Verification in progress") case .error(let message): Text("Error: \(message)") } } }}
End-to-End Example (Backend Session → iOS SDK → Result)
This pattern is the production-ready integration. Your backend creates the session, your iOS app receives the session_token, and the SDK runs the flow.
3. Backend — receive the final decision via webhook
The SDK result is convenient for UI feedback, but the authoritative outcome arrives via webhook. See the Webhooks guide for HMAC verification.
app.post("/api/webhooks/didit", express.raw({ type: "application/json" }), (req, res) => { // 1. Verify the X-Signature header (see Webhooks docs) // 2. Parse the body const event = JSON.parse(req.body.toString()); if (event.webhook_type === "status.updated") { // event.session_id, event.status ("Approved" | "Declined" | "In Review" | ...) // Look up the user by session_id and update their verification state. } res.sendStatus(200);});