NAV Navbar
  • Verifai iOS SDK (v 4.1.0)
  • Quick start guide
  • General info
  • Advanced
  • Verifai iOS SDK (v 4.1.0)

    Welcome to the Verifai App implementation documentation. If you have any questions that are unanswered you can always contact our support.

    This documentation will continue to expand as we add extra services.

    Older versions

    If you're looking for documentation for previous versions of Verifai then check below:

    Version Link
    4.0.x Documentation
    3.4.x Documentation

    Quick start guide

    Modules

    Verifai is modular with the following modules:

    iOS has split up the package into these modules, plus another VerifaiCommons module. This module contains shared models and functionality that the different modules require. From an implementation standpoint, though, there are the following relevant portions:

    Setting a shared licence

    Verifai requires a licence to be used in all modules. In order to make this easier and less error-prone we have moved all licencing calls to the VerifaiCommons module, such that all other modules (i.e. Verifai, VerifaiNFC etc.) can request the licence from this shared module.

    Attaching to the Verifai logger

    NOTE: this is for debugging purposes only. You can attach a VerifaiLogger to the VerifaiCommons module to read the log output from all the different Verifai modules. This includes four levels of severity, listed in increasing severity:

    Required keys in Info.plist

    In order to use Verifai there are multiple required keys in Info.plist:

    key Verifai VerifaiNFC VerifaiLiveness VerifaiManualDataCrosscheck VerifaiManualSecurityFeatureCheck
    NSCameraUsageDescription Yes - Yes - -
    NSMicrophoneUsageDescription - - Yes - -
    NSSpeechRecognitionUsageDescription - - Yes - -
    NFCReaderUsageDescription - Yes - - -
    com.apple.developer.nfc.readersession.iso7816.select-identifiers - Yes - - -
    1. Import the right module for your project and set the licence in the shared VerifaiCommons module to allow every module to use this licence without having to individually set any licences.
    2. [Optional] Set a configuration for the flow of Verifai to lead the user through a more specific flow suitable for your use-case.
    3. Start the desired module.
    4. Receive the result from this flow and utilize it further in your own application.

    These four steps are further described in the following sections.

    1. Import and setting the licence

    Check out the table below for a reference of which modules you need depending on the functionality you need.

    Feature 4.x import
    Document scanning (Automatic & manual scanning) Verifai and VerifaiCommons
    Document scanning + NFC scanning Verifai and VerifaiCommons + VerifaiNFC
    Document scanning + Liveness check Verifai and VerifaiCommons + VerifaiLiveness
    Document scanning + NFC scanning + Liveness check Verifai and VerifaiCommons + VerifaiNFC + VerifaiLiveness
    Document scanning + VIZ check Verifai and VerifaiCommons + VerifaiManualDataCrosscheck
    Document scanning + Security checks Verifai and VerifaiCommons + VerifaiManualSecurityFeatureCheck
    // Top of file
    import VerifaiCommons
    
    // Further on, i.e. application:didFinishLaunchingWithOptions:
    let licenceString = "=== Verifai Licence file V2 ===[...]"
    
    switch VerifaiCommons.setLicence(licenceString) {
        case .success(_): 
            print("Successfully configured Verifai")
        case .failure(let error): 
            print("🚫 Licence error: \(error)")
    }
    

    Setting the licence is as easy as supplying a raw String to the VerifaiCommons module. Please note that the === Verifai Licence file V2 === licence header should always be included in the licence.

    2. Configuration

    We think that every company is unique and requires changes to accommodate the use-case in the SDKs. You can change quite a lot, ranging from the colors to the internal workings by making your own validators and enabling of disabling certain features.

    Check out our configuration options to see how you can configure the flow in the SDK.

    For iOS specific configuration check out the Advanced configuration section.

    3. Start Verifai

    Starting Verifai

    do {
        try Verifai.start(over: self) { result in
            switch result {
            case .failure(let err): 
                print("Error or cancellation: \(err)")
                // Or look for a specific error
                if case VerifaiFlowCancelError.flowCancelled = error {
                    handleVerifaiCancellation()
                }
            case .success(let result):
                // Continue with the result
                let frontImage = result.frontImage
                // etc....
            }
        }
    } catch {
        print("🚫 Unhandled error: \(error)")
    }
    

    You can start Verifai by calling the start(over:) method. This start Verifai and presents itself over the viewController: UIViewController that was supplied. This starts the entire flow which, when finished, automatically dismisses the presented view controller and calls the resultBlock block.

    This has multiple implications:

    1. It is no longer possible to include the Verifai flow in a horizontal (navigation stack only) navigation flow. There are plans to include this in subsequent releases.
    2. If you want the user to be able to cancel Verifai you have to supply the possibility to do so yourself. All the calls to start modally return a UINavigationController, which you can then use to supply a cancel button.

    This general pattern is also applicable for the other Verifai modules:

    Start VerifaiNFC

    Starting Verifai NFC

    // Use result obtained earlier with `Verifai.start`
    let result: VerifaiResult
    do {
        try VerifaiNFC.start(over: self, documentData: result, retrieveImage: true) { nfcResult in
            switch nfcResult {
            case .failure(_): 
                print("Error or cancellation")
                // Or look for a specific error
                if case VerifaiNFCError.nfcNotAvailable = error {
                    handleVerifaiError()
                }
            case .success(let nfcResult):
                // Continue with result
                let photo = nfcResult.photo
                // etc....
            }
        }
    } catch {
        print("🚫 Unhandled error: \(error)")
    }
    

    Consult the code example on the right side for an example of how to start and handle results from VerifaiNFC. Also make sure you have added the required values to your Info.plist file. For more in check out the Project setup for NFC section.

    Start VerifaiLiveness

    Starting Verifai Liveness

    do {
        try VerifaiLiveness.start(over: self) { result in
            switch result {
            case .failure(_): 
            print("Error or cancellation")
            case .success(let livenessResult):
                // Continue with result
                let checksPassed = livenessResult.automaticChecksPassed
                // etc....
            }
        }
    } catch {
        print("🚫 Unhandled  error: \(error)")
    }
    

    Consult the code example on the right side to for an example of how to start and handle results from VerifaiLiveness

    Start VerifaiManualDataCrosscheck

    Starting Verifai Manual Data Crosscheck

    // Use result obtained earlier with `Verifai.start`
    let result: VerifaiResult
    // Optional, adds an extra check if the photo area is unblocked
    let nfcResult: VerifaiNFCResult? 
    do {
        try VerifaiManualDataCrosscheck.start(over: self,
                                              documentData: result,
                                              nfcImage: nfcResult?.photo) { mdcsResult in
                                                // Handle result
                                                switch mdcsResult {
                                                case .success(let checkResult):
                                                    // Continue with result
                                                    let allChecksPassed = checkResult.passedAll
                                                    // etc....
                                                case .failure(let error):
                                                    print("Error or cancellation: \(error)")
                                                }
        }
    } catch {
        print("🚫 Unhandled error: \(error)")
    }
    

    Consult the code example on the right side to for an example of how to start and handle results from VerifaiManualDataCrosscheck

    Start VerifaiManualSecurityFeatureCheck

    Starting Verifai Manual Security Feature check

    // Use result obtained earlier with `Verifai.start`
    let result: VerifaiResult
    do {
        try VerifaiManualSecurityFeatureCheck.start(over: self, documentData: result) { result in
            switch result {
            case .failure(let error):
                print("Error or cancellation: \(error)")
            case .success(let checkResult):
                // Continue with result
                let checksPassed = checkResult.passed
                // etc....
            }
        }
    } catch {
        print("🚫 Unhandled error: \(error)")
    }
    

    Consult the code example on the right side to for an example of how to start and handle results from VerifaiManualSecurityFeatureCheck

    4. Process the result

    Check out our result processing guide for more info on the results you can get from Verifai.

    General info

    Prerequisites

    Example project

    All the concepts documented so far have also been included in the example app that you can download to see a working example of Verifai.

    Example app on Github

    Supported orientations

    We've built the SDK to be as flexible as possible on many types of screens. Keeping this in mind we don't force any orientation programmatically. Currently the SDK is tested and is supported to run in portrait mode for phone sized devices. For tablet sized devices we support both portrait and landscape orientations.

    Installation

    There are multiple ways to install the Verifai SDK in your app. You can install automatically through CocoaPods or Carthage (recommended), or manually.

    CocoaPods

    CocoaPods is a dependency manager for iOS projects.

    Verifai is modular with the following modules:

    Plus the shared module VerifaiCommons

    To add the full SDK through Cocoapods add the following lines to your Podfile:
    pod 'Verifai', '~> 4.1.0'

    Additionally you can add the NFC or Liveness check modules if you so require.

    pod 'VerifaiNFC', '~> 4.1.0'
    pod 'VerifaiLiveness', '~> 4.1.0'
    pod 'VerifaiManualDataCrosscheck', '~>4.1.0'
    pod 'VerifaiManualSecurityFeatureCheck', '~> 4.1.0'

    Carthage

    Carthage is a simple, decentralized dependency manager.

    If you're using Carthage you'll have to update your Cartfile to load the new versions of the framework. Because each module is now separate they all have to be loaded separately. Place the following lines in your Cartfile

    binary "https://dashboard.verifai.com/downloads/sdk/nfc/carthage.json"
    binary "https://dashboard.verifai.com/downloads/sdk/liveness-check/carthage.json"
    binary "https://dashboard.verifai.com/downloads/sdk/manual-data-crosscheck/carthage.json"
    binary "https://dashboard.verifai.com/downloads/sdk/manual-security-features-check/carthage.json"

    Manually

    Finally, it is also possible to manually install the framework.

    1. Download the Verifai modules along with the required support frameworks provided by the download from the Verifai Dashboard
    2. Add the frameworks you downloaded from our backend into you project:
      • In Xcode right click on the folder where you want the framework files and choose Add files to "Folder_Name"
      • Select the frameworks (i.e. Verifai.framework) you want to add and press on Add
      • Alternatively you can drag the .framework files into the right folder in Xcode
    3. Make sure that the framework folder is included in Project -> Build Settings -> Search Paths -> Framework Search Paths. For example: if the frameworks reside in the Project Root/Frameworks folder, add the entry $(PROJECT_DIR)/Frameworks to the Framework Search Paths.
    4. One final note on manually adding frameworks: when publishing your app to the App Store Apple will only accept an archive which contains iOS device binaries (so no simulator binaries). Since universal binaries are delivered (both simulator and device) the frameworks contain both architectures. As such, you may need to strip the provided framework binaries to get rid of the simulator architectures (x86 and i386). Dependency managers like CocoaPods and Carthage do this automatically for you. When debugging on your device Xcode also automatically does this for you, but it doesn't when Archiving. There are a multitude of tools and automatic scripts to find which fix this for you, but it is also possible to use the provided script from Carthage (/usr/local/bin/carthage copy-frameworks). Make sure to provide the proper paths to the framework binaries (e.g. $(PROJECT_DIR)/Frameworks) to the input files, resulting in e.g. $(PROJECT_DIR)/Frameworks/Verifai.framework. Also make sure to put in the right output files to e.g. $(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Verifai.framework.
      More info here

    Advanced

    Set a configuration for Verifai

    Setting up the configuration

    let config = VerifaiConfiguration(enableAutomatic: false,
                                      requireDocumentCopy: true,
                                      requireCroppedImage: true,
                                      requireNFCWhenAvailable: true)
    
    // Extra configuration
    config.showInstructionScreens = true
    config.scanDuration = 2.0
    do {
        try Verifai.configure(with: config)
    } catch VerifaiConfigurationError.invalidConfiguration(let description) {
        print("🚫 Invalid configuration: " + description)
    } catch {
        print("🚫 An error occurred while setting the configuration: \(error)")
    }
    

    In order to set a custom configuration for Verifai you have to supply a VerifaiConfiguration. This configuration can then be set using Verifai.configure(with:), during which the configuration will be checked for errors.

    Extra configuration options:

    Configuration option Description Default value
    validators Array of validators that will be run after the automatic or manual scans empty VerifaiValidator array
    documentFilters Array of document filters that determine which documents a user can select in the manual flow empty VerifaiDocumentFilter array
    documentFiltersAutoCreateValidators Whether setting document filters automatically creates validators for the automatic scan views true
    countryCode Alpha 2 country code, used to customize the ai network scan, determined by your phone's region code (currently only "NL" is available) none
    customDismissButtonTitle Dismiss button string value nil
    scanDuration Scan length in seconds 3.0
    showInstructionScreens Whether we should show the instruction screens before key events in the flow true
    scanHelpConfiguration How the scan help throughout the flow should be configured Default VerifaiScanHelpConfiguration settings.

    Note on the Dismiss button

    On iOS it's also possible to configure the dismiss bar button item title for the modally presented Verifai view. To do this set the value of customDismissButtonTitle inside the VerifaiConfiguration. It is your responsibility to provide the string with the right translation. If no string is provided then Verifai will default to using Cancel. In this case Verifai will also take care of translating this string.

    Note on Instruction screens

    There are 5 Instruction screens provided by the SDK that will get displayed before the following key events:

    When What does it explain
    Before an AI scan How to take an image of a document
    Before an OCR scan Asks the user if the document has an MRZ and explains how it looks like, then explains how to scan that MRZ

    More information about flow configurations for Verifai can be found here: Enabling and disabling features

    Set the scan help configuration with VerifaiScanHelpConfiguration

        let configuration = VerifaiConfiguration()
        configuration.enableAutomatic = false
        configuration.enableManual = true
        configuration.showInstructionScreens = true
        configuration.requireCroppedImage = true
        configuration.scanHelpConfiguration =
            VerifaiScanHelpConfiguration(isScanHelpEnabled: true,
                                         customScanHelpScreenInstructions:
                NSAttributedString(string: "Our own custom instruction"),
                                         customScanHelpScreenMp4FileName: "OurInstructionVideo")
    
        do {
            try Verifai.configure(with: configuration)
        } catch {
            fatalError("🚫 Unable to setup configuration: \(error)")
        }
    

    Verifai provides scan help instructions and videos trough some flows to ensure the user can get a successful scan. This starts with simple instructions when a scan goes wrong or help on how to hold the document when performing an NFC scan.

    The scan help even allows for a final fallback that will simply let the user take an image of the document (without OCR or document recognition) to ensure that a result is provided. We call this doing a Basic scan and users will see the option in several help screens, popups and error catching screens.

    When scanning the OCR of a document, if the MRZ isn't found after 15 seconds or if we see that it is found but immediately lost several times a popup will appear. In this popup we give some simple help or allow the user to go to a main scan help screen.

    This help screen has a video and some helpful text, it also allows the user to retry and continue the scanning process. There's a second button in the help screen that allows the user to so a basic scan and just take an image of the document.

    Keep in mind that if scan help is enabled and the user takes an image via Verifai's basic scan mechanism then an image will be supplied in the result but no document position as we don't know where the document is.

    Also note that if the requireMRZContents is enabled and isScanHelpEnabled is enabled we will allow the user to take an image and the result will not have MRZ data. So keep this in mind when processing the result.

    When the user uses the basic scan option as ultimate fallback the isBasicScan object will be true in the VerifaiResultFlowInformation returned in the VerifaiResult.

    Scan help popup on iOS

    Here's a description of the VerifaiScanHelpConfiguration object:

    Configuration option Description Default value
    isScanHelpEnabled Whether the scan help popup and scan help screen are enabled true
    customScanHelpScreenInstructions An NSAttributedString that allows you to set your own instructions in the scan help screen. The default instructions Verifai provides
    customScanHelpScreenMp4FileName Allows you to provide the filename of an mp4 in your main bundle that allows you to show your own scan help instruction video. The default scan instruction video Verifai provides

    Custom scan help instruction video

    With the VerifaiScanHelpConfiguration you can setup your own scan instruction video. You do this by providing the filename of the video file in the customScanHelpScreenMp4FileName value. To set a video it has to meet the following requirements:

    If any of these checks fail a VerifaiConfigurationError shall be returned when setting the VerifaiScanHelpConfiguration object in the configuration.

    Verifai Document Filters

    Example document filter setup, in this example only Dutch passports and drivers licences options are shown to the user when he needs to manually select a document

    let configuration = VerifaiConfiguration()
    configuration.documentFilters = [
        VerifaiDocumentTypeWhiteListFilter(validDocumentTypes: [.passport, .driversLicence]),
        VerifaiDocumentWhiteListFilter(countryCodes: ["NL"])
    ]
    

    Document filters on iOS

    Document filters allow you to control the documents and countries shown to the user in the document selection screen (shown above). There are currently 3 types of document filters:

    Filter Description
    VerifaiDocumentTypeWhiteListFilter Only document types provided in this filter will be shown. If no filter is set, all document types are shown.
    VerifaiDocumentWhiteListFilter Only countries provided to this filter's Alpha 2 country list will be shown to the user in the country selection step.
    VerifaiDocumentBlackListFilter Countries provided to this filter's Alpha 2 country list will be removed from the complete list in the country selection step.

    You can set these filters in the documentFilters property of the VerifaiConfiguration object. On the right you can see an example and how these filter can be set.

    Document filters and validators

    Document filters and validators work differently from each other. A document filter acts on the selection steps of the Verifai flow. While the validators check if what was selected or scanned (in the automatic flow) is allowed.

    We understand that these two items often have a relationship with each other. For example if you add a document filter to only show Dutch documents ("NL") then you probably also want a validator that checks that the document that was scanned is a Dutch document.

    To facilitate this behaviour we added the documentFiltersAutoCreateValidators flag to the VerifaiConfiguration object. Its default is true and it will automatically create and add validators that match the document filters set.

    Of course you are always free to set this flag to false and set your own validators and or filters. In this way you can for example create a flow where you only show passports and id cards in the document selection but also allows drivers licences to be valid scan results.

    If your business needs require you to change the document filters on a per scan basis please keep in mind that having the documentFiltersAutoCreateValidators flag set to true will keep adding validators to your validators list. In this case you might want to manually clear the validators array in the VerifaiConfiguration object before adding or removing document filters.

    VerifaiResult

    As briefly described in Result processing iOS also provide a VerifaiResultFlowInformation object in the VerifaiResult object. This object provides info about the flow the user followed when trying to scan a document and ending up in the full manual flow. This allows you to get some possible clues of what the user was trying to scan. If a user successfully followed the automatic flow or OCR assisted flow the value of the VerifaiResultFlowInformation object wil be nil. A description of the object can be found below.

    Value Description Type
    selectedCountryCode The country a user selected in the country selection screen String?
    selectedDocumentType The document type a user selected in the document type selector screen VerifaiDocumentType?
    selectedCountryCode The document size a user elected when starting the manual flow. VerifaiDocumentDisplaySize?

    And some info on the VerifaiDocumentDisplaySize object:

    Value Description
    passport The document has the size format of a passport
    creditcard The document has the size format of a credit card

    Document positions

        // Transform to CGImage to use iOS's powerful cropping mechanism
        guard let cgImage = fullImage.cgImage,
              let croppedCGImage = cgImage.cropping(to: frontDocumentPosition) else {
            return UIImage()
        }
        return UIImage(cgImage: croppedCGImage)
    

    The iOS VerifaiResult object also returns the document positions of the images that were returned. Consequently if no images are returned (because of the settings) then both document position values will be nil. If only the front image is returned (for example in passports) then only the front document position object will be returned.

    The frontDocumentPosition and backDocumentPosition are both of type CGRect?. And are made in the coordinate system of the image they belong to. So you could for example crop the document out of the full image using these values. A demo of this can be seen on the right side code example.

    If cropping is enabled then the document position rectangle will just be of the full image as they are then the same.

    Because images can be full images now the document position values are required to be able to perform the Manual Datacrosscheck and the Manual security features check. If the values are not provided (because of settings) then a noDocumentPositionAvailable error will be thrown.

    Keep in mind that if scan help is enabled and the user takes an image via Verifai's basic scan mechanism then an image will be supplied in the result but no document position as we don't know where the document is.

    VerifaiNFC

    Starting Verifai NFC

    // Use result obtained earlier with `Verifai.start`
    let result: VerifaiResult
    do {
        try VerifaiNFC.start(over: self, documentData: result, retrieveImage: true) { nfcResult in
            switch nfcResult {
            case .failure(_): 
                print("Error or cancellation")
            case .success(let nfcResult):
                // Continue with result
                let photo = nfcResult.photo
                // etc....
            }
        }
    } catch {
        print("🚫 Unhandled error: \(error)")
    }
    

    Starting the NFC module is very similar to starting the other modules by calling VerifaiNFC.start(over:[...]). There are multiple required parameters:

    There are also some additional optional parameters:

    The NFC instruction screen

    If the NFC instruction screen setting is true then an instructional screen with a video will be shown to the user before scanning an NFC document. This screen explains what the user can expect and how to hold the device to the document to correctly scan the NFC.

    Project setup for NFC

    Before being able to use the NFC module you need to add the plist keys on the right to your Info.plist file.

    <key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
    <array>
        <string>A0000002471001</string>
        <string>A00000045645444C2D3031</string>
    </array>
    

    You also need to add a string with a message that tells the user why the app is requesting access to the device’s NFC hardware. Add it to your project's Info.plist file (NFCReaderUsageDescription key on the right).

    <key>NFCReaderUsageDescription</key>
    <string>NFC permission here!</string>
    

    Lastly you need to add the NFC capability to your app. Select your project in Xcode and go to the Signing and Capabilities tab (Next to General). Press the + button on the top left and a window will pop up where you can search for capabilities.

    Search for Near Field Communication Tag Reading and add it to your project. More info here.

    NFC Availability

    Check NFC Availability

    guard VerifaiNFC.nfcAvailable() else {
        print("NFC not available")
        return
    }
    

    On device NFC scanning of documents is available starting on iOS 13. Not all supported iOS 13 devices have the right NFC hardware to perform an NFC scan. If you try starting a scan on a device that doesn't support NFC scanning a VerifaiNFCError.nfcNotAvailable error will be thrown when calling VerifaiNFC.start.

    Before starting the NFC module you should check if you're device supports it. We've added a function to check this. You can find an example on the right.

    VerifaiLiveness

    Starting Verifai Liveness

    do {
        try VerifaiLiveness.start(over: self) { (result) in
            switch result {
            case .failure(_): 
            print("Error or cancellation")
            case .success(let livenessResult):
                // Continue with result
                let checksPassed = livenessResult.automaticChecksPassed
                // etc....
            }
        }
    } catch {
        print("🚫 Unhandled error: \(error)")
    }
    

    The most basic way to start the liveness checks is to just call VerifaiLiveness.start(over:). This only offers a small amount of functionality, so in order to take full advantage of the provided checks you have to supply VerifaiLiveness with more parameters. The full signature can be viewed on the right side.

    Full signature

    public static func start(over viewController: UIViewController,
                             requirements: [VerifaiLivenessCheck]? = nil,
                             videoLocation: URL? = nil,
                             showDismissButton: Bool = true,
                             customDismissButtonTitle: String? = nil,
                             resultBlock: @escaping VerifaiResultBlock<VerifaiLivenessCheckResults>) throws -> UINavigationController
    

    Example of using some custom checks

        static func performLivenessCheck(presenter: UIViewController) {
            // Setup where the checks will be saved (like in the documents folder)
            guard let documentsPathURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
                print("Unable to find documents folder")
                return
            }
            // Setup the checks
            let selfieCheck = VerifaiSelfieLivenessCheck(instruction: "Your custom instruction message for the 
                                                                        check or nil if you want to use the default one")
            guard let headTiltCheck = VerifaiTiltLivenessCheck(faceAngle: 20.0,
                                                               instruction: "Your custom instruction message for the check or 
                                                                                nil if you want to use the default one") else {
                print("Invalid check setup, we validate some tests before accepting them")
                return
            }
    
            // Define requirements
            let checkRequirements = [
                selfieCheck,
                headTiltCheck
            ]
            do {
                try VerifaiLiveness.start(over: presenter,
                                          requirements: checkRequirements,
                                          videoLocation: documentsPathURL,
                                          showDismissButton: true,
                                          customDismissButtonTitle: nil,
                                          resultBlock: { checkResult in
                    switch checkResult {
                    case .failure:
                        print("Error or cancellation")
                    case .success(let livenessResult):
                        // Continue with result
                        let checksPassed = livenessResult.automaticChecksPassed
                        dump(checksPassed) // If all checks passed
                        // You'll see 2 result objects after the next dump,
                        // in the recordingUrl for one you'll find an mp4 for one check and a jpg for the other
                        dump(livenessResult.resultList)
                    }
                })
            } catch {
                print("🚫 Unhandled error: \(error)")
            }
        }
    

    You can also set the Liveness check to use a more custom set of checks that you can setup yourself. On the example on the right we run the liveness check only with a selfie check and a head tilt check. You can also use custom initializers that we provided to use the default instruction. These initializers can be found further below at the Requirements part of this document.

    Video location

    If desired the recordings can be saved to a location on the device. Set the videoLocation URL to indicate where the recordings will be saved. The exact url for each result gets returned in the result object. If you leave this empty then the checks will still be performed but nothing will be recorded. In that case all the result url's in the result object will be nil.

    Dismiss button

    The following parameters can be set while starting the liveness check to configure if and how the dismiss button is shown:

    Requirements

    The liveness check consists of a series of checks that the user has to proceed through. A default list of five checks is already provided by the VerifaiLiveness.defaultRequirements() function, which are also used as a default in the start method. These requirements are all available requirements, but randomly shuffled.

    If you want to have control over which checks are displayed and in what order you can supply your own list of requirements. The following requirements are available:

    Requirement How to create
    Speech VerifaiSpeechLivenessCheck(speechRequirement:locale:)
    Left tilt VerifaiTiltLivenessCheck.leftTiltLivenessCheck(faceAngle:)
    Right tilt VerifaiTiltLivenessCheck.leftTiltLivenessCheck(faceAngle:)
    Close eyes VerifaiEyesLivenessCheck(duration:)
    Selfie VerifaiSelfieLivenessCheck()

    These are the only requirements allowed. Subclassing VerifaiLivenessCheck is not supported and will result in a failure with error VerifaiLCError.undefinedLivenessCheck.

    All these requirements provide a default localized instruction for the user, but you can also supply your own custom instruction string. An example of this can be seen on the right at the start of this segment.

    Example:

    let closeEyesCheck = VerifaiEyesLivenessCheck(duration: 2)
    let tiltLeft = VerifaiTiltLivenessCheck.leftTiltLivenessCheck()
    let tiltRight = VerifaiTiltLivenessCheck.rightTiltLivenessCheck()
    let speech = VerifaiSpeechLivenessCheck(speechRequirement: "apple banana pizza",
                                            locale: Locale(identifier: "en-US"))
    let selfie = VerifaiSelfieLivenessCheck()
    let requirements: [VerifaiLivenessCheck?] = [selfie,
                                                 tiltLeft,
                                                 speech,
                                                 closeEyesCheck,
                                                 tiltRight]
    // Shuffle and filter out nil requirements
    let filteredRequirements = requirements.shuffled().compactMap { $0 }
    

    Check results

    In order to see the actual results of the Liveness checks you have to supply a location where Verifai can save media of recordings or photos of the checks. This location videoLocation: URL? is nil by default, indicating no recordings will be saved at all. Links to the final recordings are provided in VerifaiLivenessCheckResult.recordingUrl: URL?.

    VerifaiManualDataCrosscheck

    Starting Verifai Manual Data Crosscheck

    // Use result obtained earlier with `Verifai.start`
    let result: VerifaiResult
    // Optional, adds an extra check if the photo area is unblocked
    let nfcResult: VerifaiNFCResult? 
    do {
        try VerifaiManualDataCrosscheck.start(over: self,
                                              documentData: result,
                                              nfcImage: nfcResult?.photo) { mdcsResult in
                                                // Handle result
                                                switch mdcsResult {
                                                case .success(let checkResult):
                                                    // Continue with result
                                                    let allChecksPassed = checkResult.passedAll
                                                    // etc....
                                                case .failure(let error):
                                                    print("Error or cancellation: \(error)")
                                                }
        }
    } catch {
        print("🚫 Unhandled error: \(error)")
    }
    

    Starting the Manual Data Crosscheck module is very similar to starting the other modules by calling VerifaiManualDataCrosscheck.start(over:[...]). There are multiple required parameters:

    There are also some additional optional parameters:

    VerifaiManualSecurityFeatureCheck

    Starting Verifai Manual Security Feature check

    // Use result obtained earlier with `Verifai.start`
    let result: VerifaiResult
    do {
        try VerifaiManualSecurityFeatureCheck.start(over: self, documentData: result) { result in
            switch result {
            case .failure(let error):
                print("Error or cancellation: \(error)")
            case .success(let checkResult):
                // Continue with result
                let checksPassed = checkResult.passed
                // etc....
            }
        }
    } catch {
        print("🚫 Unhandled error: \(error)")
    }
    

    Starting the Manual Data Crosscheck module is very similar to starting the other modules by calling VerifaiManualDataCrosscheck.start(over:[...]). There are multiple required parameters:

    There are also some additional optional parameters:

    Errors

    What follows is an overview of the errors Verifai can return with a description of what causes them.

    Verifai

    Error Type Description Possible solutions
    flowCancelled VerifaiFlowCancelError The user cancelled out of the flow Show an error condition or ask the user to retry
    neuralNetworkLoadingFailed VerifaiFlowCancelError Something went wrong loading the neural network Make sure an internet connection is active and retry
    invalidConfiguration(_ description: String) VerifaiConfigurationError The configuration provided in Verifai.configure(with: is invalid. Check the description in the error, fix your configuration and retry.
    permissionDenied VerifaiCameraError The user denied the camera permission request Request your user to go to your app's setting and enable the camera permission
    slowNetwork(_ timeout: TimeInterval) VerifaiNetworkError A timeout on the network has been detected Check your internet connection and retry
    invalidRequest(_ underlyingError: Error?) VerifaiNetworkError And invalid request was triggered by the OS Check the underlying iOS error for more info
    downloadFailed(_ underlyingError: Error?) VerifaiNetworkError A download operation failed Check the underlying iOS error for more info

    VerifaiNFC

    Error Type Description Possible solutions
    nfcReadError VerifaiNFCError Reading the NFC chip failed (you can retry) Ask your user to hold the document firmly and retry
    nfcCancelled VerifaiNFCError The user cancelled the NFC reading operation Show an error condition or ask the user to retry
    nfcNotAvailable VerifaiNFCError The current device does not support NFC scanning Show an error condition
    nfcReadTimedOut VerifaiNFCError The NFC operation timed out Show an error condition
    invalidMRZData VerifaiNFCError The provided MRZ data is nil or invalid You provided a VerifaiResult object that does not contain valid MRZ data or valid NFC document key

    VerifaiLiveness

    Error Type Description Possible solutions
    undefinedLivenessCheck VerifaiLCError Undefined liveness check submitted Ensure you're using one of the provided liveness check types as subclassing is not allowed
    lowSpaceForOperation VerifaiLCError Low space detected on the device to save the liveness check data Ask your user to free up space on the device and retry
    internalAVError VerifaiLCError An internal AV error occurred An internal error occurred during recording, please try again
    cancelledLivenessChecks VerifaiLCError The user cancelled the liveness check operation Show an error condition or ask the user to retry

    VerifaiManualDataCrosscheck

    Error Type Description Possible solutions
    dataInvalid VerifaiManualDataCrosscheckError The manual data cross check could not be performed because the structure of the data appears to be invalid Ensure the scanning data from Verifai has an idModel object to perform the check
    insufficientData VerifaiManualDataCrosscheckError The manual data cross check could not be performed because there aren't enough unblocked zones available Either lower the amount of required checks or reassess your blocked zones on the Verifai Dashboard
    manualDataCrosscheckCancelled VerifaiManualDataCrosscheckError The manual data cross check was cancelled Show an error condition or ask the user to retry
    noDocumentPositionAvailable VerifaiManualDataCrosscheckError No document position provided Check your code or settings, no document position was available, the document position is required to perform this check.

    VerifaiManualSecurityFeatureCheck

    Error Type Description Possible solutions
    manualSecurityFeaturesDownloadFailed VerifaiManualSecurityFeatureError Downloading the document's security features failed Ensure there's an active internet connection
    noSecurityFeaturesFound VerifaiManualSecurityFeatureError No security features found for this document Please contact us and we'll look together at a solution for this
    manualSecurityfeatureCheckCancelled VerifaiManualSecurityFeatureError The manual security feature check was cancelled Show an error condition or ask the user to retry
    noDocumentPositionAvailable VerifaiManualDataCrosscheckError No document position provided Check your code or settings, no document position was available, the document position is required to perform this check.

    Theming and colors

    Setting custom colors for Verifai components

    ## NavBarBackgroundColor
    UIColor.Verifai.navBarBackgroundColor = UIColor.red
    
    ## ScanHighlightTextColor
    UIColor.Verifai.scanHighlightTextColor = UIColor.blue
    
    ## BottomBoxTitleTextColor
    UIColor.Verifai.bottomBoxTitleTextColor = UIColor.green
    

    As described in our theming and styling section Verifai allows you to customize certain colors throughout the framework. All the colors described in the styling and theming section can be found under Verifai's UIColor extension. On the right there are a few examples of how to change certain colors.

    A note on iOS 10

    Ensure iOS 11 or later is running before running Verifai

    if #available(iOS 11.0, *) {
        do {
        try Verifai.start(over: self) { result in
            switch result {
            case .failure(let err): 
                print("Error or cancellation: \(err)")
            case .success(let result):
                // Continue with the result
                let frontImage = result.frontImage
                // etc....
            }
        }
        } catch {
            print("🚫 Unhandled error: \(error)")
        }
    } else {
        print("🚫 Verifai requires iOS 11 or later")
    }
    

    We understand that many developers want to support as many devices as possible to give their customers the best possible user experience. This might mean supporting older iOS versions like iOS 10.

    Verifai uses technologies that require iOS 11 or later. We still want you to be able to give the best possible user experience to your users, so starting in Verifai 3.2 we have added to ability to compile on iOS 10. This means you won't be required to update your deployment target to (at least) iOS 11 to compile your app with Verifai.

    Sadly the SDK cannot run on iOS 10 and you'll notice this if you still support iOS 10 because the Verifai.start method will throw an error indicating this. It's up to you to ensure the user is running iOS 11 or later before using Verifai (code example of this on the right). Furthermore this allows you to implement your own screen or flow informing the user that their iOS version is too low to run this feature.

    The same is true for other Verifai components: