Skip to content

How to build a JavaScript MRZ Scanner web app for reading IDs and passports

Kevin July 3, 2025 6 mins read
Web Data Capture SDK

In this tutorial, we’ll create a browser-based app for extracting data from machine-readable zones on ID documents. The result will be a single stand-alone HTML file you can run on your server.

To implement the scanning functionalities and app UI, we’ll use the Scanbot Web MRZ Scanner SDK.

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

To accomplish this, we only need to follow three simple steps:

  1. Setting up the HTML page and including the Web SDK
  2. Implementing the MRZ Scanner
  3. Mapping the data and displaying the results

Let’s get started!

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

index.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
    <title>Web MRZ Scanner</title>
</head>

<body style="margin: 0">
    <button id="scan-mrz">Scan MRZ</button>
    <p id="mapped"></p>
    <script type="module">
        import "https://cdn.jsdelivr.net/npm/scanbot-web-sdk@7.2.0/bundle/ScanbotSDK.ui2.min.js";
        const sdk = await ScanbotSDK.initialize({
            enginePath:
                "https://cdn.jsdelivr.net/npm/scanbot-web-sdk@7.2.0/bundle/bin/complete/"
        });
        document
            .getElementById("scan-mrz")
            .addEventListener("click", async () => {
                const config = new ScanbotSDK.UI.Config.MrzScannerScreenConfiguration();
                const result = await ScanbotSDK.UI.createMrzScanner(config);

                const mappedParagraph = document.getElementById("mapped");
                mappedParagraph.innerText = "";

                if (!result) {
                    mappedParagraph.innerText = "No result. Please try again.";
                    return;
                }

                if (!result?.mrzDocument) {
                    mappedParagraph.innerText = "No MRZ document found. Please try again.";
                    return;
                }

                const mapped = result?.mrzDocument.fields.map(field => {
                    return `${field.type.name}:  ${field.value?.text}`
                });

                mappedParagraph.innerHTML = mapped.join('<br>');
            })
    </script>
</body>

</html>

Requirements

The Scanbot Web SDK is optimized for mobile devices. Although you can test the app’s basic functionality using your laptop camera or a webcam, we recommend you run it on a smartphone.

You can use a service like ngrok, which creates a tunnel to one of their SSL-certified domains. Their Quick Start guide will help you get up and running quickly.

Step 1: Set up the HTML page and include the Web SDK

First, create an index.html with the following code:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
    <title>Web MZR Scanner</title>
</head>

<body style="margin: 0">
    <button id="scan-mrz">Scan MRZ</button>
    <p id="mapped"></p>
    <script type="module">
        import "https://cdn.jsdelivr.net/npm/scanbot-web-sdk@7.2.0/bundle/ScanbotSDK.ui2.min.js";
        const sdk = await ScanbotSDK.initialize({
            enginePath:
                "https://cdn.jsdelivr.net/npm/scanbot-web-sdk@7.2.0/bundle/bin/complete/"
        });
    </script>
</body>

</html>

This sets up an HTML5 document with a viewport and a button that we’ll use to start the MRZ Scanner in the next step. The code also loads the Scanbot Web SDK from a CDN (content delivery network) and initializes it.

Please note that using a CDN is only recommended for prototyping. In your production environment, please download the Web SDK directly (or install it via npm) and include its files in your project.

💡 Without a license key, our SDK only runs for 60 seconds per session. This is more than enough for the purposes of our tutorial, but if you like, you can generate a license key on our website.

Step 2: Implement the MRZ Scanner

Next, we need to attach an event listener to the button. When the button is clicked, a new instance of the SDK’s configuration object will be created and the createMrzScanner method will launch the document scanner.

We’ll store the result of the scanning process in a result object and ensure that if no pages are scanned (e.g., when the user cancels the operation), the function exits early.

The result will look like this:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
    <title>Web MRZ Scanner</title>
</head>

<body style="margin: 0">
    <button id="scan-mrz">Scan MRZ</button>
    <p id="mapped"></p>
    <script type="module">
        import "https://cdn.jsdelivr.net/npm/scanbot-web-sdk@7.2.0/bundle/ScanbotSDK.ui2.min.js";
        const sdk = await ScanbotSDK.initialize({
            enginePath:
                "https://cdn.jsdelivr.net/npm/scanbot-web-sdk@7.2.0/bundle/bin/complete/"
        });
        document
            .getElementById("scan-mrz")
            .addEventListener("click", async () => {
                const config = new ScanbotSDK.UI.Config.MrzScannerScreenConfiguration();
                const result = await ScanbotSDK.UI.createMrzScanner(config);

                const mappedParagraph = document.getElementById("mapped");
                mappedParagraph.innerText = "";

                if (!result) {
                    mappedParagraph.innerText = "No result. Please try again.";
                    return;
                }

                if (!result?.mrzDocument) {
                    mappedParagraph.innerText = "No MRZ document found. Please try again.";
                    return;
                }
            })
    </script>
</body>

</html>

Step 3: Mapping the data and displaying the results

Now we only need to extract the data fields from the MRZ, map them to a new array of strings, and display the result in our mapped paragraph.

const mapped = result?.mrzDocument.fields.map(field => {
    return `${field.type.name}:  ${field.value?.text}`
});

mappedParagraph.innerHTML = mapped.join('<br>');
})

Your final index.html will look like this:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
    <title>Web MRZ Scanner</title>
</head>

<body style="margin: 0">
    <button id="scan-mrz">Scan MRZ</button>
    <p id="mapped"></p>
    <script type="module">
        import "https://cdn.jsdelivr.net/npm/scanbot-web-sdk@7.2.0/bundle/ScanbotSDK.ui2.min.js";
        const sdk = await ScanbotSDK.initialize({
            enginePath:
                "https://cdn.jsdelivr.net/npm/scanbot-web-sdk@7.2.0/bundle/bin/complete/"
        });
        document
            .getElementById("scan-mrz")
            .addEventListener("click", async () => {
                const config = new ScanbotSDK.UI.Config.MrzScannerScreenConfiguration();
                const result = await ScanbotSDK.UI.createMrzScanner(config);

                const mappedParagraph = document.getElementById("mapped");
                mappedParagraph.innerText = "";

                if (!result) {
                    mappedParagraph.innerText = "No result. Please try again.";
                    return;
                }

                if (!result?.mrzDocument) {
                    mappedParagraph.innerText = "No MRZ document found. Please try again.";
                    return;
                }

                const mapped = result?.mrzDocument.fields.map(field => {
                    return `${field.type.name}:  ${field.value?.text}`
                });

                mappedParagraph.innerHTML = mapped.join('<br>');
            })
    </script>
</body>

</html>

Now run the app and read an MRZ code …

Example of an MRZ on an ID card

… to test your scanner!

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

Conclusion

🎉 Congratulations! You can now extract data from machine-readable zones from your browser!

If this tutorial has piqued your interest in integrating scanning functionalities into your web app or website, make sure to take a look at the SDK’s other neat features in the documentation – or run our example project for a more hands-on experience.

Should you have questions about this tutorial 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