Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.didit.me/llms.txt

Use this file to discover all available pages before exploring further.

A lightweight, server-driven iOS SDK for identity verification with minimal configuration required.

GitHub Repository

View source code and examples on GitHub

Requirements

RequirementMinimum Version
iOS13.0+
Xcode15.0+
Swift5.9+

iOS Version Compatibility

iOS VersionFeatures Available
iOS 13.0 - 14.xAll features except NFC passport reading
iOS 15.0+All features including NFC passport reading

Installation

Add the package to your project using Xcode:
  1. Go to File > Add Package Dependencies
  2. Enter the repository URL:
https://github.com/didit-protocol/sdk-ios
  1. Select the version and click Add Package

CocoaPods

Add the following to your Podfile:
pod 'DiditSDK'
Then run:
pod install
When installing via CocoaPods on apps targeting iOS 13/14, you may see a warning about NFCPassportReader requiring iOS 14+. This warning can be safely ignored — the SDK will work correctly, and NFC functionality is automatically disabled on older iOS versions.

Permissions

The SDK requires the following permissions. Add these to your app’s Info.plist:
PermissionInfo.plist KeyDescriptionRequired
CameraNSCameraUsageDescriptionDocument scanning and face verification✅ Yes
MicrophoneNSMicrophoneUsageDescriptionVideo recording for liveness checks✅ Yes
Photo LibraryNSPhotoLibraryUsageDescriptionUpload documents from device gallery✅ Yes
NFCNFCReaderUsageDescriptionRead NFC chips in passports/ID cards⚠️ If using NFC
LocationNSLocationWhenInUseUsageDescriptionGeolocation for fraud prevention❌ Optional

Example Info.plist Entries

<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>

NFC Configuration

To enable NFC reading for passports and ID cards with chips:
  1. Add NFC Capability in Xcode:
    • Select your target → Signing & Capabilities+ CapabilityNear Field Communication Tag Reading
  2. Add ISO7816 Identifiers to Info.plist:
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
    <string>D23300000045737445494420763335</string>
    <string>A0000002471001</string>
    <string>A0000002472001</string>
    <string>00000000000000</string>
</array>
  1. Add Entitlements (in your .entitlements file):
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
    <string>TAG</string>
</array>
Simulator Limitation: The iOS SDK requires CoreNFC, which is not fully available on simulators. Since Xcode 12, libnfshared.dylib is missing from simulators. Test NFC features on physical devices only.

App Store Review: Even if you disable NFC in your workflow, Apple may request a demo video because NFC code is part of the SDK binary. You can download our NFC demo video to submit to Apple: Download NFC Demo Video


Quick Start

SwiftUI Integration

import SwiftUI
import DiditSDK

struct ContentView: View {
    var body: some View {
        Button("Verify Identity") {
            // Method 1: UniLink — no backend required
            DiditSdk.shared.startVerification(workflowId: "your-workflow-id")
            
            // Method 2: Backend Session — full parameter control
            // DiditSdk.shared.startVerification(token: "your-session-token")
        }
        .diditVerification { result in
            handleResult(result)
        }
    }
    
    private func handleResult(_ result: VerificationResult) {
        switch result {
        case .completed(let session):
            print("Completed: \(session.status)")
        case .cancelled(let session):
            print("Cancelled")
        case .failed(let error, _):
            print("Failed: \(error.localizedDescription)")
        }
    }
}

UIKit Integration

import UIKit
import DiditSDK

class VerificationViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Start verification when ready
        DiditSdk.shared.startVerification(token: "your-session-token")
    }
}

Integration Methods

The SDK supports two integration methods: No backend required. The SDK creates the session directly using your workflow ID from the Didit Console. Limited to vendorData only. (!) For vendor data to work with unlink ensure you have enabled the “Vendor Data” option in the Didit Console.
DiditSdk.shared.startVerification(
    workflowId: "your-workflow-id",
    vendorData: "user-123"
)
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 token
let sessionToken = await yourBackend.createVerificationSession(userId: currentUser.id)

// Pass the token to the SDK
DiditSdk.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

Configuration

Customize the SDK behavior:
let config = DiditSdk.Configuration(
    fontFamily: "Avenir-Medium",    // Custom font (must be registered in your app)
    loggingEnabled: false,          // Enable debug logging
    languageLocale: .english        // Force specific language
)

DiditSdk.shared.startVerification(
    token: "your-session-token",
    configuration: config
)

Configuration Options

PropertyTypeDefaultDescription
fontFamilyString?System fontCustom font family name (must be registered in your app)
loggingEnabledBoolfalseEnable SDK debug logging
languageLocaleSupportedLanguage?Device localeForce specific language
showCloseButtonBooltrueShow close (X) button on verification step screens
showExitConfirmationBooltrueShow confirmation dialog when user attempts to exit
closeOnCompleteBoolfalseAuto-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).

Language Support

The SDK supports 40+ languages. If no language is specified, the SDK uses the device locale with English as fallback.
// Use device locale (default)
let config = DiditSdk.Configuration()

// Force specific language
let config = DiditSdk.Configuration(languageLocale: .french)

// Detect device locale programmatically
let deviceLanguage = SupportedLanguage.fromDeviceLocale()
View All Supported Languages →

Advanced Session Parameters

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.

Handling Results

The VerificationResult enum provides the outcome of the verification:

Result Cases

CaseDescription
.completed(session:)Verification flow completed (check session.status for result)
.cancelled(session:)User cancelled the verification flow
.failed(error:session:)An error occurred during verification

SessionData Properties

PropertyTypeDescription
sessionIdStringUnique session identifier
statusVerificationStatus.approved, .pending, or .declined
countryString?Country code (ISO 3166-1 alpha-3)
documentTypeString?Document type used for verification

Error Types

ErrorDescription
.sessionExpiredThe session has expired
.networkErrorNetwork connectivity issue
.cameraAccessDeniedCamera permission not granted
.unknown(String)Other error with message

Complete Result Handling Example

.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
    }
}

Observing SDK State

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)")
            }
        }
    }
}

Complete SwiftUI Example

import SwiftUI
import DiditSDK

struct HomeView: View {
    @State private var resultMessage: String?
    @State private var isVerified = false
    
    var body: some View {
        VStack(spacing: 24) {
            if isVerified {
                Image(systemName: "checkmark.circle.fill")
                    .font(.system(size: 64))
                    .foregroundColor(.green)
                Text("Identity Verified")
                    .font(.title2)
            } else {
                Button("Verify Identity") {
                    startVerification()
                }
                .font(.headline)
                .padding(.horizontal, 32)
                .padding(.vertical, 16)
                .background(Color.blue)
                .foregroundColor(.white)
                .cornerRadius(12)
            }
            
            if let message = resultMessage {
                Text(message)
                    .foregroundColor(.secondary)
                    .multilineTextAlignment(.center)
                    .padding()
            }
        }
        .diditVerification { result in
            handleResult(result)
        }
    }
    
    private func startVerification() {
        let config = DiditSdk.Configuration(
            languageLocale: .english
        )
        
        // Method 1: UniLink — no backend required
        DiditSdk.shared.startVerification(
            workflowId: "your-workflow-id",
            vendorData: "user-123",
            configuration: config
        )
        
        // Method 2: Backend Session — full parameter control
        // DiditSdk.shared.startVerification(
        //     token: "your-session-token",
        //     configuration: config
        // )
    }
    
    private func handleResult(_ result: VerificationResult) {
        switch result {
        case .completed(let session):
            if session.status == .approved {
                isVerified = true
            }
            resultMessage = """
                Status: \(session.status.rawValue)
                Session: \(session.sessionId)
                Country: \(session.country ?? "N/A")
                Document: \(session.documentType ?? "N/A")
                """
                
        case .cancelled(let session):
            resultMessage = "Cancelled - Session: \(session?.sessionId ?? "unknown")"
            
        case .failed(let error, _):
            resultMessage = "Failed: \(error.localizedDescription)"
        }
    }
}