NAV Navbar
swift kotlin java javascript python
  • General introduction of SDK
  • General overview of our approach
  • Components
  • Customization
  • Implementation docs
  • Result processing
  • General introduction of SDK

    Welcome to Verifai's technical documentation. Verifai provides software that verifies all types of ID documents from all countries. Our aim is to create a solution for every use case. What sets Verifai apart is our "privacy first" approach, which means that you are compliant straight out of the box. We won't dictate the process, but instead find ways to suit your needs. We do, however, also aim to offer the very best default settings. That way, you won't need to configure a lot to get started.

    General overview of our approach

    We think that a modular approach is the best way to do this. For instance, you might not need NFC. In that case, there is no reason to request dependencies and permissions from your users. For every feature that is not strictly related to the other, we have a "component". These components can be used independently and are supported by the "Core", an essential core component that contains the basics that are needed to communicate with our backend services, and is able to validate your licenses.


    For example, you are running an electric scooter rental business (like Bird), and someone wants to sign up for your service. You want to check their driver's license, and verify the authenticity of that document using NFC.

    The components used in this example are linked together in the following way:

    Components used in example



    The Core is the main component of Verifai. Everything that is needed to scan documents and communicate with our backend services is available. It does everything that the other components can't and provides the foundation for all the other components to build upon.

    The user flow is changed by setting certain requirements.

    Let's say you need a copy of someone's ID and would like to use the MRZ contents to fast fill their name in a form. By default, this is all taken care of by the SDKs. However, if you do not require a copy of the ID, you can change the configuration so the user will take a different route through the SDKs and will not be confronted with unnecessary tasks and screens.

    Example (high level) user flow:

    Core flow

    Obviously, there is a lot more to it. To find out more, see the section about customization.

    Copy ID

    Using the camera, it can take a picture of the ID, and store that data. The data can be accessed after the scanning process has been completed. We always store the largest resolution available (on any platform). If the document has been classified, either manually or automatically, masking will also be applied.

    In the example below (taken with an iPhone), you can see that the pictures have been blocked by the masking template.

    Photo's blocked by masking template

    Read the MRZ (Machine Readable Zone)

    MRZ of dutch specimen document

    There are several standardized types of MRZs. Travel documents are standardized by ICAO. Verifai supports all documents that implement this standard.

    Standards that we support are:

    We also use the MRZ to see if we can find meta data about the document and to check whether the classification is correct.

    In the Result processing section, you will find extensive documentation about the MRZ, the standards, and how to access the processed data.

    Document chooser

    There are situations where we're not certain which document exactly the user is scanning. For example they can look very similar or the documents have no difference in the MRZ.

    We do our best to keep the process as short an easy for users. Experience has taught us that giving the user too many choices with a new process can be confusing and overwhelming. So if it's possible we will make a decision on which document it is by choosing the most popular one. We have identified many popular documents that most of the current population use compared to others that look similar.

    A great example of this is the Dutch passport, the ordinary passport and diplomatic passport look 99% the same. So when given the choice we will automatically choose the most popular one.

    Our team identifies and keeps track of popular countries in many countries. If a country has 2 or more documents that are very populair (or equal in popularity) then the document chooser will still show up to allow the user to choose from the possible documents.

    document chooser

    This begs the question, what if the document chosen should always be chosen from a list of all possible documents. In this case users should be directed to the manual document chooser. There all documents will always be available to be chosen.


    Since the introduction of biometric passports many countries have integrated an NFC chip in their document. That chip can be read by the NFC component.

    The chip is secured with a password (access key). That password can be found in the MRZ of the document.

    NFC access key

    Therefore, you can't access the NFC chip without reading the MRZ first. That is why you need a VerifaiResult to start the NFC component. See the high level diagram below:

    NFC example flow

    The chips also contain digital signatures over the data. All countries sign their documents using "Signing Certificates". We have an extensive database of certificates that allow us to verify the signatures. If the signatures are proven to be correct, you can safely assume the chip is authentic. The process is called Public Key Infrastructure (PKI) and is used all over the world to check data integrity.

    We regularly update the certificates with publicly provided MasterLists.

    In the Result processing section, you will find extensive documentation about NFC and how to check the results.

    Liveness check

    The liveness checks allow you to check whether the person whose document you're scanning actually is the one using the app at the moment. By using the Liveness check component, you can set up a few simple tasks that the user can perform to confirm that they are alive. We also built in 4 default checks that allow you to simply start the liveness check.

    Available checks:

    Liveness example flow

    In the Result processing section, you will find extensive information about the way the results of this check are processed.

    Manual Data Crosscheck

    The Manual Data Crosscheck is compatible with Verifai 3.1 and newer. This check guides the user to manually check the data that has been read from the machine readable zone (MRZ) with the data Visual Inspection Zones (VIZ). It can also let the user compare the picture from inside the NFC chip with the picture on the document.

    Manual Security Features Check

    Verifai's Manual Data Security Features Check lets the user check visible and invisible security features of a scanned document. It helps the user to distinguish counterfeit documents from real documents. Improving the security and reliability of manual document checks. Combined with the NFC validity check from the NFC module and the visual check from the Manual Data Crosscheck it will give perfect results.

    The Manual Security Features Check will present checks of the following types:

    Hold against the light

    The "Hold against the light"-check asks the user to hold the document against a light. Some documents allow you to see through them (through tiny holes). Certain security features or color changes then become visible.

    Tilt the document

    Some security features change color, reflections or an image when the document is tilted. This type of security feature check asks the user to tilt the document and shows what should change.

    Feel this area

    Lets the user feel a particular, in the screen highlighted, area to feel e.g. a pattern or "bold" text. Counterfeit documents mostly do not contain these tactile parts since these are difficult to fake.

    Check this

    Lets the user check a certain part of the document. The question will be stated on the screen.

    Enlarge this area

    Enlarges a part of the document to let the user check if a small security features, like a micro size printed text, are on the document and valid.


    The Verifai document database contains many security features. Each security features consists of a score between 0 and 1 (e.g. 0.35). It is possible to set a threshold, where the default is 1.0 when no threshold has been set, to prevent the user from checking for a long time. The checks are finished when the threshold has been met.

    All checks are always presented in a random order, to keep the focus of the person that checks the document. Checks might differ every time, when there are more checks available than the threshold allows.

    In the result processing section, you will find extensive information about the way the results of this security features check are processed.


    We believe that every company is unique and therefore requires tailor-made 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 or disabling certain features.


    Every use case is different and our product has to fit around your process. That is why we have a validation system in place with which you can limit the amount of acceptable documents, and check the user input instantly. This sets Verifai apart from other solutions, which only let you check once the whole process has been completed.

    We believe that this is the most user-friendly way, as it is very interactive.

    The validators run immediately after taking a picture of the document, and just before the cropping screen.

    When the document is scanned, an idModel metadata object (as included in the result) is fetched from our backend so it can determine whether certain data, like the type and country, is allowed. When an MRZ has been read, an mrzData object is create (also like the result), so it can verify the checksums and/or the NFC key.

    Here's what the process looks like:

    Validators flow

    Name Arguments Looks at Description Default enabled
    CountryWhitelist takes list of countries idModel Checks if the document is on the whitelist No
    CountryBlacklist takes list of countries idModel Checks if the document is on the blacklist No
    HasMrz - idModel Checks if the IdModel has MRZ No
    Types takes list of types idModel Checks for type based on IdModel No
    MrzAvailable - mrzData Sees if there is a MRZ result No
    NfcKeyWhenAvailable - Both Checks for an MRZ result if there is an NFC chip in the document No

    Build a custom validator

    Custom validator examples

    // Some iOS example on how you can make custom validators to perform an array of validity checks
    class ValidityExampleValidator: VerifaiMrzValidator {
        var mrzData: VerifaiMRZModel?
        var document: VerifaiDocumentResult?
        var side: String?
        var invalidMessage: String = "Document is expired"
        func validate() -> Bool {
            // get the data we need to check the expiration date
            if let mrz = mrzData,
                let expirationDate = mrz.parsedDateOfExpiry {
                // Return whether the expiration date is in the future compared to now
                return expirationDate > Date()
            // The data available to fulfil this validation is not available or validation failed
            return mrzData == nil
    class ValiditySevenMonthsExampleValidator: VerifaiMrzValidator {
        var mrzData: VerifaiMRZModel?
        var document: VerifaiDocumentResult?
        var side: String?
        var invalidMessage: String = "Document has to be valid for at least 7 months"
        func validate() -> Bool {
            // get the data we need to check the expiration date
            if let mrz = mrzData,
                let expirationDate = mrz.parsedDateOfExpiry {
                // Return whether the expiration date is 7 months in the future compared to now
                if let futureDate = .month, value: 7, to: Date()) {
                    return expirationDate > futureDate
            // The data available to fulfil this validation is not available or validation failed
            return mrzData == nil
    class ValidityMustHaveMRZExampleValidator: VerifaiMrzValidator {
        var mrzData: VerifaiMRZModel?
        var document: VerifaiDocumentResult?
        var side: String?
        var invalidMessage: String = "Document has to have an MRZ"
        func validate() -> Bool {
            if let hasMRZ = document?.hasMrz {
                return hasMRZ
            return false
    class ValidityDocumentSpecificExampleValidator: VerifaiMrzValidator {
        var mrzData: VerifaiMRZModel?
        var document: VerifaiDocumentResult?
        var side: String?
        var invalidMessage: String = "A passport has to be at least valid for 7 months, Id card have to be valid from now"
        func validate() -> Bool {
            // Make sure we have all the data needed to proceed
            if let documentTypePrefix = document?.type,
                let mrz = mrzData,
                let expirationDate = mrz.parsedDateOfExpiry {
                let documentType = VerifaiDocumentType(mrzType: documentTypePrefix)
                switch documentType {
                case .passport:
                    // Return whether the expiration date is 7 months in the future compared to now
                    if let futureDate = .month, value: 7, to: Date()) {
                        return expirationDate > futureDate
                case .idCard:
                    return expirationDate > Date()
                    return true
           // The data available to fulfil this validation is not available or validation failed
           return mrzData == nil

    If you would like to build your own validator, you can! A validator has a generic interface that you can implement.

    What we provide:

    By using these two objects you can build your own validator. It doesn't matter what it all does, as long as these two are implemented:

    Document filters

    Document filters allow you to control which document types or which document countries are shown to the user in the document and country selection screens.

    Document filters on iOS

    This allows you to control the documents and countries that a user can select if we don't find the document automatically. There are 3 types of filters:

    Filter type Description Filtered by
    Country white list Only countries in the white list are shown in the country selection screen Alpha 2 country list
    Country black list Countries in the blacklist are removed from the country selection screen Alpha 2 country list
    Document type Only document types provided are shown in the document type selection screen Document type

    For example implementation examples on iOS and Android please consult the implementation documents.

    The relationship between document filters and validators

    Document filters are different than validators. Document filters are used to determine what gets shown to the user as an acceptable document or country. While validators actually control what gets accepted after a scan. This means that you can setup which document / countries you would prefer for example but allow more documents in the scanning phase.

    An example:
    You can setup filters to only show passports and id's because you prefer them (Document filters). But also allow drivers licences because they can also be valid (Validators).

    We understand that in most cases the logical thing to do is to sync up the document filters and validators to show and accept the same documents / countries.
    To facilitate this we added the documentFiltersAutoCreateValidators boolean to the configuration. This value defaults to True and will automatically create the correct validators if you set document filters. More info on this subject is available in the iOS and Android implementation docs.

    Enabling and disabling features

    By default, we route the user through all features we think are necessary to reach the goal of getting a idModel and mrzData for you in the end.

    However, there are some routes the user can take through the system that prevent this from happening. For example, the user could reach the "Take photo manually" screen and draw over it by hand. That way, you will receive the images but no metadata for the document or the MRZ (if applicable).

    For this reason, you get access to configuration options that let you limit the freedom of the user, and force them through a route.

    Configration flow example

    The settings you can change are:

    Setting Description Adds validator Default
    enable_automatic Controls the automatic document recognition (Blue line) - True
    enable_post_cropping Controls the cropping interaction (Yellow line) - True
    enable_manual Controls if you can manually draw masking (Red line) - True
    require_document_copy If False, you won't go to automatic mode and correction screens - True
    require_cropped_image If False, you will receive a full image taken and not only the document (iOS only) - True
    require_mrz_contents If True, it adds a validator and disables all docs without MRZ HasMrz False
    require_nfc_when_available Adds an NFC key validator if the document has an NFC chip NfcKeyWhenAvailable False
    read_mrz_contents Lets you disable the MRZ OCR, which is useful if you only require a copy - True
    enable_auto_update If we check for Neural Network updates every time - True

    We have several recommended settings to achieve a certain goal. The enable_auto_update setting is left out because it does not influence functionality or the path the user takes.

    Full functionality

    If you don't adjust anything, this will be the standard configuration (default settings).

    Setting Value
    enable_automatic True
    enable_post_cropping True
    enable_manual True
    require_document_copy True
    require_mrz_contents False
    require_nfc_when_available False
    read_mrz_contents True

    Quickly read the MRZ

    Setting Value
    enable_automatic False
    enable_post_cropping False
    enable_manual False
    require_document_copy False
    require_mrz_contents True

    * please note that defaults are not displayed in the table, only the settings you need to change or set

    Quickly read the NFC chip

    Setting Value
    enable_automatic False
    enable_post_cropping False
    enable_manual False
    require_document_copy False
    require_mrz_contents True
    require_nfc_when_available True

    * please note that defaults are not displayed in the table, only the settings you need to change or set

    Afterwards, you should add the HasNfc validator to make sure a document with NFC is scanned.

    You can then use that data to run the NFC component.

    Only photograph the ID

    Setting Value
    read_mrz_contents False

    Disabling manual masking

    Setting Value
    enable_manual False

    Styling and theming

    Because every company has it's own style, you can set specific colors for almost every element in the SDK.

    Visual indication of variables

    All colors used

    Full overview, with names, colors and default values. By default, the "non-Main" colors inherit from another (Main) color.

    Where Name of color Main color Default Inherits from Filter
    Main PrimaryColor Yes #FF576D
    Main SecondaryColor Yes #FFFFFF
    Main PositiveColor Yes #5FB501
    Main NegativeColor Yes #FF576D
    Main NavBarBackgroundColor No PrimaryColor
    Main NavBarTextColor Yes #FFFFFF
    Viewfinder CameraOverlayColor Yes #FFFFFF
    Viewfinder DocumentScanHighlightColor Yes #FF576D
    Viewfinder DocumentCropHighlightColor Yes #F5E216
    Viewfinder ScanHighlightTextColor Yes #FFFFFF
    Viewfinder HintBoxBackgroundColor Yes #409ECA
    Viewfinder HintBoxTextColor No NavBarTextColor
    Viewfinder CameraHintBoxTextColor No CameraOverlayColor
    Viewfinder CameraHintBoxBackgroundColor Yes #000000 opacity 0.5
    Viewfinder BlockedFieldColor Yes #000000 opacity 0.5
    Viewfinder MrzBoxHintBorder No DocumentScanHighlightColor
    Viewfinder MrzBoxHintBackgroundColor No MrzBoxHintBorder opacity 0.5
    Viewfinder MrzBoxDetectedBorder No PositiveColor
    Viewfinder MrzBoxDetectedBackgroundColor No MrzBoxDetectedBorder opacity 0.5
    Viewfinder CroppingOverlayColor No CameraHintBoxBackgroundColor
    Bottom BottomBoxBackgroundColor Yes #212121
    Bottom BottomBoxTitleTextColor Yes #FFFFFF
    Bottom BottomBoxImageTintColor No BottomBoxTitleTextColor
    Bottom BottomBoxTextAreaBackgroundColor No BottomBoxTitleTextColor opacity 0.15
    Bottom BottomBoxTextAreaTextColor No BottomBoxTitleTextColor
    Bottom BottomBoxImageLowlightTintColor No BottomBoxImageTintColor opacity 0.5
    Bottom BottomBoxImageHighlightTintColor No PrimaryColor
    Bottom PaginationCircleColor No TopBoxImageTintColor
    Top TopBoxBackgroundColor Yes #E6E6E6
    Top TopBoxImageTintColor No BottomBoxBackgroundColor opacity 0.5
    Top TopBoxTextColor No TopBoxImageTintColor
    Buttons AffirmativeButtonBackgroundColor No PositiveColor
    Buttons AffirmativeButtonTextColor No SecondaryColor
    Buttons PrimaryButtonBackgroundColor No PrimaryColor
    Buttons PrimaryButtonTextColor No SecondaryColor
    Buttons PrimaryButtonImageTintColor No PrimaryButtonTextColor
    Buttons InvertedButtonBackgroundColor No SecondaryColor opacity 0.15
    Buttons InvertedButtonTextColor No SecondaryColor
    Buttons InvertedButtonBorderColor No SecondaryColor
    Buttons InvertedButtonImageTintColor No InvertedButtonTextColor
    Buttons AlternativeInvertedButtonBackgroundColor No PrimaryColor opacity 0
    Buttons AlternativeButtonBorderColor No PrimaryColor
    Buttons AlternativeInvertedButtonTextColor No PrimaryColor
    Buttons CameraButtonColor No SecondaryColor
    ListView SearchBoxBackgroundColor No BackgroundColor darken 0.15
    ListView BackgroundColor Yes #FFFFFF
    ListView TextColor Yes #000000

    Implementation docs

    iOS SDK

    All documentation needed to integrate the Verifai iOS SDK can be found here:

    Upgrade guides providing details on how to upgrade from previous iOS SDK versions can be found here:

    Android SDK

    All documentation needed to integrate the Verifai Android SDK can be found here:

    Upgrade guides providing details on how to upgrade from previous Android SDK versions can be found here:

    Result processing



    When Verifai has completed its process, it will provide access to a VerifaiResult object. The object is a boiled-down version of all information we have extracted from the document.

    In general, there are a few major components to the result:

    1. frontImage: Picture of the front (bitmap or UIImage)
    2. frontDocumentPosition: The position of the document in the coordinate system of the front image (iOS only). More info on this object available in the iOS Implementation docs
    3. backImage: Picture of the back (bitmap or UIImage)
    4. backDocumentPosition: The position of the document in the coordinate system of the back image (iOS only). More info on this object available in the iOS Implementation docs
    5. mrzData : The MRZ Data object, instance of VerifaiMrzDataResult (or VerifaiMRZModel on iOS)
    6. idModel: The ID Model for further processing, instance of VerifaiDocumentResult
    7. resultFlowInformation: Info about the choices made by the user in the flow (iOS only). More info on this object available in the iOS Implementation docs

    There are some functions in the VerifaiResult as well, so you can access crops of certain parts of the document, including the holder's picture.

    If there is no need for a picture of the document, both of these

      frontImage: UIImage?
      backImage: UIImage?
      mrzModel: VerifaiMRZModel?
      idModel: VerifaiDocumentResult?
      resultFlowInformation: VerifaiResultFlowInformation?
    Code example
      frontImage: Bitmap
      backImage: Bitmap
      mrzData: VerifaiMrzDataResult
      idModel: VerifaiDocumentResult

    Processing the pictures

    The pictures are stored in the platform's main image format type. You can access them with frontImage or backImage. Please note that the privacy sensitive data is already removed from that image (if enabled).

    If there is no need for a picture of the document, both of these fields might be 'null'.

    The picture is taken in the maximum size that the device supports. If you need a scaled version, you will need to take care of that yourself. The image is uncompressed, so you can work with the highest quality possible.

    MRZ Data (VerifaiMrzDataResult)

    Utopia Passport (ICAO 9303_p3)

    While a lot of data is stored in the MRZ, it does not include everything. We try to get as much out of the MRZ as we can, and provide you with the easiest way to interface with that data.

    Below, you will find an example of a MRZ from a passport. It is 44 chars long and has two rows. As you can see, not all data on the card had a place in the MRZ.

    Doc (2) Country (3) Surname << Given names (39)
    P < U T O E R I K S S O N < < A N N A < M A R I A < < < < < < < < < < < < < < < < < < <
    Document Number (9) Check (1) Nationality (3) Birthday (6) Check (1) Sex (1) Expiry Date (6) Check (1) Optional Data (14) Check (1) Check (1)
    L 8 9 8 9 0 2 C 3 6 U T O 7 4 0 8 1 2 2 F 1 2 0 4 1 5 9 Z E 1 8 4 2 2 6 B < < < < < 1 0

    The supported formats are:

    Format Size Description
    TD1 3x30 Typically an ID card
    TD2 2x36 Intermediate format ID card
    TD3 2x44 The Passport format. The example above is TD3
    MRV-A 2x44 VISA - Almost like TD3 format
    MRV-B 2x36 VISA - Almost like TD1 format
    EDL-NLD 1x30 Format of dutch driver's licenses
    ID-FRA 2x36 Alternative implementation of TD2

    Not all fields are available for all types of MRZs. The format codes above are referenced in the overview of fields in the mrzData object.

    Getting the MRZ data

    See and example of how we access the MRZ data after a successful scan on the right. Note that you will only receive MRZ data if your configuration is setup to return it.

    Accessing the MRZ data after a successful scan

    do {
        try Verifai.start(over: self) { result in
            switch result {
            case .failure(let err): 
                print("Error or cancellation: \(err)")
            case .success(let successResult):
                // Continue with the result
                let mrzData = successResult.mrzData
                // Print the given names
                print("Given names: \(mrzData?.givenNames)")
    } catch {
        print("🚫 Unhandled error: \(error)")

    Data fields for all ICAO compatible documents

    Property Type Description Formats
    mrzString str Entire MRZ as read by OCR engine All
    format str Format of the MRZ read All
    documentType str Type of document, first char of MRZ All
    documentSubType str Second char of document type part All
    countryCode str 3 digit country code All
    surname str Surname of holder TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA
    givenNames str Given names of holder TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA
    documentNumber str Unique doc number All
    documentNumberCheckDigit str Check digit documentNumber TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA
    nationality str Nationality of holder TD1, TD2, TD3, MRV-A, MRV-B
    dateOfBirth str Date of birth of holder TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA
    dateOfBirthCheckDigit str Check digit dateOfBirth TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA
    sex str Sex of holder TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA
    dateOfExpiry str Expiration date of doc TD1, TD2, TD3, MRV-A, MRV-B
    dateOfExpiryCheckDigit str Check digit dateOfExpiry TD1, TD2, TD3, MRV-A, MRV-B
    optionalData str Optional data (first one if there are two) TD1, TD2, TD3, MRV-A, MRV-B
    optionalDataCheckDigit str Check digit optionalData TD3
    optionalDataTwo str Additional Optional data TD1
    compositeCheckDigit str Check digit of all fields TD1, TD2, TD3, ID-FRA, EDL-NLD
    documentSpecificData obj Key value list of extra available fields ID-FRA, EDL-NLD
    firstName str Alias of givenNames -
    lastName str Alias of surname -

    Composed data

    Not actual fields but convenient to access.

    Property Type Description Formats
    nfcKey str Key to access the NFC chip (might also be available on documents without a chip) TD1, TD2, TD3, MRV-A, MRV-B

    Validation and read errors

    Property Type Description Formats
    validityScore float All checks passed will return a float 1.0 All
    isNfcKeyValid bool? nfcKey fields read correctly TD1, TD2, TD3, MRV-A, MRV-B, EDL-NLD
    isDocumentCodeValid bool? Document code (P, I, D) is valid for the MRZ All
    isDocumentNumberValid bool? documentNumber correct TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA
    isDateOfBirthValid bool? dateOfBirth correct TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA
    isDateOfExpiryValid bool? dateOfExpiry correct TD1, TD2, TD3, MRV-A, MRV-B
    isCompositeValid bool? All fields correct TD1, TD2, TD3, ID-FRA, EDL-NLD
    isOptionalDataValid bool? optionalData correct (only TD3!) TD3
    isDateOfIssueValid bool? If the date of issue fields are correct ID-FRA
    isLine1LengthValid bool? First line length correct All
    isLine2LengthValid bool? Second line length correct TD1, TD2, TD3, MRV-A, MRV-B, ID-FRA
    isLine3LengthValid bool? Third line length correct TD1

    "bool?" means a nullable boolean

    French ID specific (documentSpecificData)

    Property Type Description Formats
    departmentOfIssuance str Issuing department doc ID-FRA
    officeOfIssuance str Issuing office doc ID-FRA
    dateOfIssue str Year and month of issue ID-FRA

    Dutch driver's license specific (documentSpecificData)

    Property Type Description Formats
    driversLicenceVersion str Version of driver's license EDL-NLD
    driversLicenceRandomItem str Random data EDL-NLD
    driversLicenceChip str Driver's license chip version (char 6) EDL-NLD

    Document model (VerifaiDocumentResult)

    VerifaiDocumentResult object in JSON format

        "uuid": "7dd168c5-4125-499c-b6a3-bba103ebab5f",
        "type": "P",
        "model": "NLD-AO-04002p",
        "country": "NL",
        "width_mm": 125.0,
        "height_mm": 88.0,
        "sample_front": "https://[...].jpg",
        "has_mrz": true,
        "mrz_type": "td3",
        "mrz_start": "P<NLD",
        "nfc_type": "emrtd",
        "zones": [
                "side": "FRONT",
                "x": 0.32,
                "y": 0.12,
                "width": 0.04,
                "height": 0.03,
                "block": false,
                "title": "DOCUMENT_TYPE"
                "side": "FRONT",
                "x": 0.36,
                "y": 0.12,
                "width": 0.06,
                "height": 0.04,
                "block": false,
                "title": "COUNTRY_CODE"

    We keep a record of (most) of the Passports, ID cards and Driver's Licenses in our database. For a current overview, please look at our website. Even if we are not familiar with the actual model, we are still able to return MRZ and NFC data objects.

    The model contains some data that is not very relevant for most use cases. However, we have chosen to expose as much data as we can, as you might just be the one who does need it.

    We have split the information up into three parts:

    Field Type Example Description
    uuid str 72bf03...265cdb6 Unique identifier in our database
    type str "P" Internal ID Model type see list below
    model str "NLD-AO-04002p" Name of document according to the naming schema
    country str "NL" ISO 3166-1 alpha-2 country code
    widthMm float 125.0 document width in millimetres
    heightMm float 88.0 document height in millimetres
    sampleFront str "https://....jpg" URL to preview image
    mrzType str "td3" Type of MRZ on the document, see list below for types
    mrzStart str "P<NLD" Document MRZ should start with this
    nfcType str "emrtd" Protocol type in chip, see list below for types
    zones list See example code List of zones, see Zones section
    hasMrz bool true Convenience function to check for a MRZ type zone

    Document Model VerifaiDocumentResult.type list options

    Value Description
    P Passport
    I ID Card
    D Driver's License
    R Refugee travel doc
    IT Residence Permit

    The VerifaiDocumentResult.model naming schema

    Every document in our database has a name that is partly generated.

    If we take a document name (model in the Document model), for example NLD-AO-04002p (Dutch Passport), we can split it up in its individual parts.

    Example Position Length Description
    NLD 0-2 3 Country code
    - 3 1 Divider
    A 4 1 Category (see possible options below)
    O 5 1 Kind (see possible options below)
    - 6 1 Divider
    04 7-8 2 Series
    002 9-11 3 Version
    p 12 1 Internal

    Possible options for "Category":

    Value Description
    A Passport
    B Identity card
    C Visa
    D Stamp
    E Entry paper
    F Driver's license
    G Vehicle license/log book
    H Residence-related document
    I Seafarers\' identity document
    J Travel document issued to non-nationals
    K Train driver's license
    L Crew member certificate / pilot\'s license
    M Certificate for operators of pleasure crafts / captain\'s license
    P Civil status/other official document
    S Special authorisation card
    T Travel document
    V Authorisation to represent a company
    W Work permit
    X Other document

    Possible options for "Kind":

    Value Description
    B Birth
    D Diplomatic
    E Entry stamp
    F Military
    I Social security card/tax card
    M Marriage
    N Nationality/citizenship
    O Ordinary document
    P Temporary/Provisional/Emergency
    R Divorce
    S Service/official
    T Death certificate
    X Exit stamp
    Y Related/associated document

    Document Model VerifaiDocumentResult.mrzType options

    Value Description
    td1 TD1 (ICAO), 3x30 chars
    td2 TD2 (ICAO), 2x36 chars
    td3 TD3 (ICAO), 2x44 chars
    id_fr French ID, 2x36 chars
    edl_nl Dutch Electronic Driver's license (NL), 1x30 chars

    Document Model VerifaiDocumentResult.nfcType types

    Value Description
    emrtd ICAO compliant NFC chip
    edl_nl Dutch Electronic Driver's license
    unsupported Has chip, but we don't support the protocol

    Document Model VerifaiDocumentResult.zones items

    All documents have zones. Those zones contain a few fields so you know the contents, and the location. Please note that is is a list of objects.

    Field Type Description
    title str Value from the list of zones below
    side str Side of document, either FRONT or BACK
    x float Start position of zone on x-axis (left)
    y float Start position of zone on y-axis (top)
    width float Width in ratio with the entire width of document
    height float Height in ratio with the entire height of document
    block bool If we blocked the zone in processing

    List of zone types (title in the zone object):

    Value Group Description
    BLOOD_TYPE Biometric Blood type
    COLOR_EYES Biometric Color of eyes
    COLOR_HAIR Biometric Color of hair
    FINGERPRINT Biometric Fingerprint
    SEX Biometric Sex
    HEIGHT Biometric Height
    PHOTO Biometric Photo
    FACIAL_FEATURES Biometric Facial features
    VIS_DIST_MARKS Biometric Visible distinguishing marks
    GLASSES Biometric Glasses
    WEIGHT Biometric Weight
    DOCUMENT_NUMBER Document Details Document number
    PREV_DOCUMENT_NUMBER Document Details Previous document number
    CATEGORY Document Details Category
    COUNTRY_CODE Document Details Country code (Alpha-3)
    ISSUING_AUTH Document Details Issuing authority
    ISSUING_COUNTRY Document Details Issuing country
    MODIFICATIONS Document Details Modifications
    NUMBER_ENTRIES Document Details Number of entries
    NUMBER_REGISTRATION Document Details No. of registration
    OBSERVATIONS_PAGE Document Details Observations page
    PLACE_ISSUE Document Details Place of issue
    REMARKS Document Details Remarks / Notes
    STATUS Document Details Status
    DOCUMENT_TYPE Document Details Type of document
    DRIVERS_LICENSE_TYPE Document Details Type of driver's license
    PERMIT_TYPE Document Details Type of permit
    VISA_TYPE Document Details Visa Type
    COSTS Document Details Fee / Costs
    COPY Document Details Copy
    RENEWAL_COUNT Document Details No. of renewals
    REPLACEMENT_COUNT Document Details No. of replacement
    TRAN_CODE Document Details Tran. code
    ISSUE_NO Document Details Issue No.
    CHILDREN Family Children
    FATHER_NAME Family Father's name
    MAIDEN_NAME Family Maiden name
    MARITAL_STATUS Family Marital status
    MOTHER_NAME Family Mother's name
    SPOUSE_NAME Family Name of spouse (Husband/Wife')
    BARCODE Machine Readable Barcode
    CHIP Machine Readable Microchip
    QR-CODE Machine Readable QR-Code
    MRZ Machine Readable MRZ
    CC Payment Credit Card number
    CVC Payment CVC
    CONTINUE_SURNAME Name Continue surname
    FULL_NAME Name Full Name
    GIVEN_NAME Name Given name
    NAME_IN_NAT_LANGUAGE Name Name in National Language
    SURNAME Name Surname
    ALIAS Name Alias (also known as)
    DATE_OF_BIRTH Personal Date of birth
    DOMESTIC_DATE Personal Date of domestication
    PERSONAL_IDENTITY_NO Personal Personal/Identity number
    NATIONALITY Personal Nationality
    RACE Personal Race
    QUALITY/FUNCTION Personal Quality/Function
    PLACE_OF_BIRTH Personal Place of birth
    STATE_BIRTH Personal State of birth
    BEARER_SIGNATURE Personal Bearer's signature
    TITLE Personal Title
    PHONE Personal Telephone number
    INSURANCE_NUMBER Personal Insurance number
    DONOR Personal Donor State
    HOST_ORG Personal Host Organization
    ALLERGIES Personal Allergies
    ICE_CONTACT Personal ICE / Emergency Contact
    PERM_MEDS Personal Permanent medication
    STREET Residential Living address
    MUNICIPALITY Residential Municipality
    PLACE_LANDING Residential Place of landing
    RESIDENCE Residential Residence
    RESIDENT_SINCE Residential Resident since
    STATE Residential State
    DESTINATION Travel Destination
    ENDORSEMENT Travel Endorsement
    TRANSPORTATION Travel Mode of transportation
    DATE_OF_DEPARTURE Travel Date of departure
    ENTRY_PURPOSE Travel Purpose of Entry
    DATE_OF_EXPIRY Validity Date of expiry
    DATE_OF_ISSUE Validity Issuing date
    DATE_OF_RENEWAL Validity Renewal date
    DATE_OF_TEST Validity Date of test
    DURATION_STAY Validity Duration of stay
    DURATION_LICENSE Validity Duration of license
    UNSPECIFIED Residential Unspecified

    NFC Result

    Once the process of NFC scanning is complete, you will receive the VerifaiNfcResult. It contains all the details from the chip in the document. Which data is available depends on the configuration that you set up for the component. For example, downloading the picture from the chip takes a long time. If you skip this step, you can check the authenticity in a split second.

    Validation and checks

    When you use the NFC chip to check the authenticity of the document, you only have to call three functions If they are all True, you can assume the chip is valid and signed by the issuer.

    Checking the validity of a document after an NFC scan

    // Use result obtained earlier with `Verifai.start`
            var 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):
                        // Check the document validity
                        if nfcResult.originality && nfcResult.authenticity && nfcResult.confidentiality {
                            print("Document is valid")
                        } else {
                            print("Document is not valid or validity uncertain")
            } catch {
                print("🚫 Unhandled error: \(error)")
    if nfc_result.originality() && nfc_result.authenticity() && nfc_result.confidentiality():

    Originality, Authenticity and Confidentiality

    In this more detailed section we provide you with more information about the chip and the process of validation.

    Security Triangle

    To make sure the document and data is valid, you can use this triangle. The first concerns the secure communication layer (confidentiality()), the second concerns gaining access to the chip data according to protocols (originality()) and the last concerns the integrity of the data itself (authenticity()). If you miss one of these checks, you cannot be sure the data that has been read is not falsified.

    Field Type Description
    originality() bool Did Chip Authentication and/or Active Authentication pass their checks
    authenticity() bool Did the document signing, certificate, root certificate and passive authentication hashes checks all pass
    confidentiality() bool Were the BAC and optionally the Chip Authentication successful

    Advanced Validation and checks

    Field Type Description
    mrzMatch bool Does the MRZ from the OCR match the MRZ from the card
    comSodMatch bool Does the EF.COM from the OCR match the data groups in EF.SOd
    bacSuccess bool Chip was accessed successfully, see bacStatus
    activeAuthenticationSuccess bool Active authentication was performed successfully, see activeAuthenticationStatus
    chipAuthenticationSuccess bool Chip authentication was performed successfully, see chipAuthenticationStatus
    documentSignatureCorrect bool Is the document data signed by the certificate from the EF.SOd
    documentCertificateValid bool Is the certificate valid (so not expired or revoked for example)
    signingCertificateMatchesWithParent enum MATCH The signing certificate match with the parent or root in Verifai's database
    NO_MATCH Signing does not match with parent or root
    REVOKED Matches, but certificate has been revoked by the issuer
    NOT_FOUND There was no matching parent or root certificate found in Verifai's database
    NOT_CHECKED Check did not take place yet, or has been skipped
    scanCompleted bool If the process of scanning completed.

    More details about the status of Basic Authentication, Active Authentication and Chip Authentication

    Field Type Description
    bacStatus enum SUCCESS Chip was accessed successfully
    FAILED Failed to gain access to chip
    NOT_CHECKED Process has not been performed yet
    RANDOM_FAILED The chip did not return a challenge
    activeAuthenticationStatus enum SUCCESS Active authentication was performed successfully
    SIGNATURE_FAILED Unable to verify the public key on the chip
    FAILED Active authentication failed
    NOT_PRESENT Active authentication not present on the chip
    NOT_CHECKED Active authentication process hasn't been performed
    chipAuthenticationStatus enum SUCCESS Chip authentication was performed successfully
    FAILED Chip authentication failed
    NOT_PRESENT Chip authentication not present on the chip
    NOT_CHECKED Chip authentication process hasn't been performed

    Data in the chip

    The ICAO has standardized the protocol, the data structure, and security mechanisms of eMRTD's in the Doc 9303 part 9, 10, 11 and 12. You can view those documents here: ICAO Doc 9303

    Data fields in the chip

    Not all data in the chip is readable for everyone. Examples include fingerprints. General available data includes the chip always contains a digital copy of the holder's passport photo and a digital version of the MRZ.

    Field Type Description
    photo Bitmap (or UIImage on iOS) Photo of the document holder
    mrzData VerifaiMrzDataResult Parsed MRZ data from the MRZ copy in the chip

    Advanced data fields in the chip

    If your use case requires even more data from the chip, we can expose all of it using the fields below.

    Field Type Description
    dataGroups list list of LDS data objects
    documentCertificate str DER formatted X.509 certificate from the document
    edlNlData object See Dutch Driver's License section
    type enum MRTD Standard ICAO compliant document
    EDL_NLD Dutch driver's license

    Detailed raw information:

    Field Type Description
    sodHashes list list of bytes of hashes
    sodData bytes raw SOD data
    featurePoints int Number of feature points in the photo (DG5)
    mimeBytes bytes MIME type of image (DG5)
    aaDigestAlgorithm str Active Authentication digest algorithm type
    chipAuthenticationOid str raw OID (like 2.16.840., see for reference
    chipAuthenticationAgreementAlgorithm enum Chip Authentication digest algorithm type
    chipAuthenticationPublicKeyAlgorithm enum Chip Authentication Public key algorithm type

    Additional data from Verifai backend (so not actually in the chip):

    Field Type Description
    signingCertificate str DER formatted X.509 certificate from the Verifai backend

    LDS (Logical Data Groups)

    Data in passports is stored in Logical Data Groups. For example, the photo is stored in DG2, and the MRZ in DG1. See ICAO Doc 9303p10 page 4 for more information.

    Field Type Description
    data bytes The data read from the datagroup
    hash bytes Digest of the data in the datagroup
    readStatus enum SUCCESS The file has been read successfully
    FAILED Reading the file failed
    NO_ACCESS The file is protected, Verifai did not gain access
    FILE_NOT_FOUND The file has not been found on the MRTD

    Dutch driver's license specific (EdlNlData)

    The Dutch driver's license also contains a chip. However, in addition to the eMRTD standard fields, it contains more available fields. Below is a list of fields that are available:

    Field Type Description
    issuingMemberState str The state issuing the driver's license
    surname str The last name(s) of the document holder
    givenNames str The first name(s) of the document holder
    dateOfBirth str The date of birth of the document holder
    placeOfBirth str The place of birth of the document holder
    dateOfIssue str Date when the document was issued
    dateOfExpiry str Date when the document expires
    issuingAuthority str The authority that issued the document
    documentNumber str The document's document number
    bsn str The document holder personal number
    nationality str The nationality of the document holder
    sex str The document holder's gender
    surnameIcao str The surname of the document holder in ICAO notation
    firstnameIcao str The first name of the document holder in ICAO notation
    surnameGba str The surname of the document holder in GBA notation
    firstnameGba str The first name of the document holder in GBA notation
    placeOfBirthGba str The place of birth of the document holder in GBA notation
    countryOfBirthGba str The country of birth of the document holder in GBA notation
    firstNames str Alias of givenNames
    lastName str Alias of surname

    Liveness Check

    Once the checks are completed, Verifai will return a VerifaiLivenessCheckResults object, which contains a list of all the VerifaiLivenessCheckResult (no s) objects. However, the checks now include 3 extra variables with the results:

    Liveness check result object (VerifaiLivenessCheckResult)

    Field Type Description
    automaticChecksPassed bool If all checks have SUCCESS or UNDETERMINED status
    successRatio float number of checks divided by number of SUCCESS status results
    resultList list list of VerifaiLivenessCheckResult objects for further processing

    Liveness check result list items (VerifaiLivenessCheckResult)

    Every check produces such a result. It is composed of the original check with additional result fields.

    Field Type Description
    check VerifaiLivenessCheck Reference to the actual check provided at the start
    videoFile File (Android only) DEPRECATED > Replaced by recording
    recording File (Android only) The location of the video H.264 file including the audio or the image
    recordingUrl URL? (iOS only) The location of the result recording or image
    status enum SUCCESS Check is successfully passed
    UNDETERMINED Check couldn't be validated automatically
    SKIPPED Check was skipped by the user

    Manual Data Crosscheck

    The Manual Data Crosscheck will return all the field names that have been checked, and a boolean value that will indicated if check was passed or not.

    Field Type Description
    checks MutableMap<String,Boolean> (Android), [String: Bool] (iOS) A map with the name of every check and a boolean if the check has passed (or not)
    passedAll boolean True when all checks are passed. False if one or more check(s) failed

    Manual Security Features Check

    The result object of the Manual Security Features check is quite simple. The class where the object is an instance of is called VerifaiManualSecurityFeaturesCheckResult. It contains three floats.

    Field Type Description
    maxScore float The summed score of all available security feature checks
    score float The score of the performed security feature checks
    threshold float The threshold that has been set
    passed bool (iOS only) Shorthand for score >= threshold