Skip to content

How to build an MRZ Scanner for iOS in Swift

Kevin May 5, 2025 8 mins read
iOS Data Capture SDK

In this tutorial, we’ll use Xcode, Swift, and the Scanbot MRZ Scanner SDK to create an app for extracting data from machine-readable zones on ID cards and similar documents.

Scanning the machine-readable zone on an ID card with our iOS MRZ Scanner

We’ll achieve this in just three easy steps:

  1. Preparing the project
  2. Setting up the main screen
  3. Implementing the MRZ scanning feature

All you need is a Mac with the latest version of Xcode and a test device, since we’ll need to use the camera.

Want to see the final code right away? Click here.

ViewController.swift:

import UIKit
import ScanbotSDK

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func scanMRZButtonTapped(_ sender: Any) {
        let configuration = SBSDKUI2MRZScannerScreenConfiguration()
        SBSDKUI2MRZScannerViewController.present(on: self,
                                                 configuration: configuration) { result in
            if let result {
                if let model = result.mrzDocument?.wrap() as? SBSDKDocumentsModelMRZ {
                    var message = ""

                    // Retrieve the values, e.g.:
                    if let givenName = model.givenNames?.value {
                        message += "Given name: \(givenName.text)\n"
                    }
                    if let birthDate = model.birthDate?.value {
                        message += "Birth date: \(birthDate.text)\n"
                    }
                    if let expiryDate = model.expiryDate?.value {
                        message += "Expiry date: \(expiryDate.text)\n"
                    }
                    // Add more values as needed.

                    let alert = UIAlertController(title: "Result",
                                                  message: message,
                                                  preferredStyle: .alert)
                    let action = UIAlertAction(title: "OK",
                                               style: .cancel)
                    alert.addAction(action)
                    self.present(alert, animated: true)
                }

            } else {
                let alert = UIAlertController(
                    title: "No Result",
                    message: "No MRZ data was captured. Please try again.",
                    preferredStyle: .alert
                )
                let action = UIAlertAction(title: "OK", style: .cancel)
                alert.addAction(action)
                self.present(alert, animated: true)
            }
        }
    }
}

Step 1: Prepare the project

Open Xcode and create a new iOS App project. Name the project (e.g., “iOS MRZ Scanner”), choose Storyboard as the interface, and Swift as the language.

After opening your project, go to File > Add Package Dependencies… and add the Scanbot SDK package for the Swift Package Manager.

Open your Main App Target’s Info tab and add a Privacy – Camera Usage Description key with a value such as “Grant camera access to scan an MRZ”.

In AppDelegate.swift, add a line for setting the license key to the application(_:didFinishLaunchingWithOptions:) method. We don’t need one for this tutorial, but if you have a license key you’d like to use, uncomment the code below and replace <YOUR_LICENSE_KEY> with your actual key.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Uncomment the following line and replace <YOUR_LICENSE_KEY> with your actual key
    // Scanbot.setLicense("<YOUR_LICENSE_KEY>")

    return true
}

Without a license key, the SDK will run in trial mode for 60 seconds per session. If you need more than that, you can generate a free trial license.

Step 2: Set up the main screen

We’ll now create a simple UI for starting our MRZ scanner.

First, open Main.storyboard and add a UIButton with a meaningful label (e.g., “Scan MRZ”) to the main view.

After that, create an IBAction for the button in ViewController.swift and implement the button action to present the scanner view controller.

@IBAction func scanMRZButtonTapped(_ sender: UIButton) {
    // Code to present the scanner view controller will go here
}

We’ll also need to add the following import to ViewController.swift:

import ScanbotSDK

Step 3: Implement the MRZ scanning feature

This step involves presenting the MRZ Scanner view controller. The Scanbot SDK provides a pre-built UI for the scanning process. You’ll need to instantiate the scanner, present it modally, and cast the resulting generic document to the MRZ model using the wrap method.

To do that, add the following code inside scanMRZButtonTapped() in ViewController.swift:

let configuration = SBSDKUI2MRZScannerScreenConfiguration()
SBSDKUI2MRZScannerViewController.present(on: self,
                                         configuration: configuration) { result in
    if let result {
        if let model = result.mrzDocument?.wrap() as? SBSDKDocumentsModelMRZ {
            var message = ""
            
            // Retrieve the desired values, e.g.:
            if let givenName = model.givenNames?.value {
                message += "Given name: \(givenName.text)\n"
            }
            if let birthDate = model.birthDate?.value {
                message += "Birth date: \(birthDate.text)\n"
            }
            if let expiryDate = model.expiryDate?.value {
                message += "Expiry date: \(expiryDate.text)\n"
            }
            // Add more values as needed.
            
            let alert = UIAlertController(title: "Result",
                                          message: message,
                                          preferredStyle: .alert)
            let action = UIAlertAction(title: "OK",
                                       style: .cancel)
            alert.addAction(action)
            self.present(alert, animated: true)
        }
        
    } else {
        // Indicates that the cancel button was tapped.
    }
}

In this example, we look for the given name, birth date, and expiry date and add the values to a message string, which we then display in an alert dialog. You can also handle the user canceling the scanning process like this:

} else {
    let alert = UIAlertController(
        title: "No Result",
        message: "No MRZ data was captured. Please try again.",
        preferredStyle: .alert
    )
    let action = UIAlertAction(title: "OK", style: .cancel)
    alert.addAction(action)
    self.present(alert, animated: true)
}

Your final ViewController.swift will then look like this:

import UIKit
import ScanbotSDK

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func scanMRZButtonTapped(_ sender: Any) {
        let configuration = SBSDKUI2MRZScannerScreenConfiguration()
        SBSDKUI2MRZScannerViewController.present(on: self,
                                                 configuration: configuration) { result in
            if let result {
                if let model = result.mrzDocument?.wrap() as? SBSDKDocumentsModelMRZ {
                    var message = ""

                    // Retrieve the values, e.g.:
                    if let givenName = model.givenNames?.value {
                        message += "Given name: \(givenName.text)\n"
                    }
                    if let birthDate = model.birthDate?.value {
                        message += "Birth date: \(birthDate.text)\n"
                    }
                    if let expiryDate = model.expiryDate?.value {
                        message += "Expiry date: \(expiryDate.text)\n"
                    }
                    // Add more values as needed.

                    let alert = UIAlertController(title: "Result",
                                                  message: message,
                                                  preferredStyle: .alert)
                    let action = UIAlertAction(title: "OK",
                                               style: .cancel)
                    alert.addAction(action)
                    self.present(alert, animated: true)
                }

            } else {
                let alert = UIAlertController(
                    title: "No Result",
                    message: "No MRZ data was captured. Please try again.",
                    preferredStyle: .alert
                )
                let action = UIAlertAction(title: "OK", style: .cancel)
                alert.addAction(action)
                self.present(alert, animated: true)
            }
        }
    }
}

Our MRZ Scanner iOS app is now ready. Build and run it on your test device to read an MRZ code …

Example of an MRZ on an ID card

… and test your scanner!

Scanning the machine-readable zone on an ID card with our iOS MRZ Scanner

Conclusion

This completes the basic implementation of an MRZ Scanner for iOS using Swift and the Scanbot SDK. We used the SDK’s Ready-to-Use UI Components with their default values for this tutorial, but you can further customize the MRZ scanning screen to fit your needs. You can also use the SDK to scan MRZ codes from image files instead of a live camera stream.

In this tutorial, we only extracted three of the many values a machine-readable zone can encode. For a complete list of all extractable values, please refer to the SBSDKDocumentsModelMRZ entry in the SDK’s API references.

Not every MRZ code contains all possible values. This also depends on the format of the ID document on which the machine-readable zone is located. There are five standard document formats, each with a different type of MRZ:

  • TD1: This format is used for credit card-sized documents, like ID cards. Its convenient size has the downside that the MRZ is on the back, which means both sides of the document must be scanned. The MRZ consists of three lines of 30 characters each, including check digits. If the encoded data in a line does not fill it entirely, filler characters (<) are used to complete it.
  • TD2: The TD2 document format is slowly being replaced by the TD1 standard, but is still being used for ID cards in some countries. Since the format is bigger, the MRZ fits on the same side as the human-readable information. It also occupies just two lines of 36 characters each. The encoded data is the same as for TD1, but in a different order. Notably, the holder’s name is on the first line rather than the last.
  • TD3: This format is used for most international passports, specifically the identification card at the beginning of the booklet. Just like TD2, it has two MRZ lines on the front of the document, but with 44 characters each. The first line begins with a “P” (for “passport”) and the second ends with an additional check digit for optional data.
  • MRV-A: MRV stands for “machine-readable visa”. This document type is indicated by a “V” at the beginning of the first MRZ line. The order and types of information encoded in the MRZ of an MRV-A document are similar to those of TD2 and TD3, but with no check digit for the second line. Each line is 44 characters long.
  • MRV-B: MRV-B documents are slightly smaller than MRV-A ones, thus the two MRZ lines are just 36 characters long. The information encoded is the same, however.

For more information on how to configure the MZR Scanner, head over to the documentation.

Should you have questions or run into any issues, we’re happy to help! Just shoot us an email via tutorial-support@scanbot.io.

Happy scanning! 🤳

Related blog posts