AI Passport Data Extraction with 99.8% Accuracy

Manual entry of passport data slows down registration and opens the door to errors, causing clients to leave at the verification stage. We build an AI recognition system that automatically extracts data from passports and IDs, including MRZ parsing and forgery detection. Our team delivers the project turnkey—from audit to implementation and ongoing support—ensuring reliable and fast verification.

AI Development Areas

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1344
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1307
  • B2B Advance company logo design
    B2B Advance company logo design
    754
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1050
  • AIDER company logo development
    AIDER company logo development
    994
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1100

AI Passport Data Extraction and Identity Document Recognition

One major bank lost 2% of clients during KYC due to manual passport data entry errors. After deploying our system with MRZ parsing and fine-tuned OCR based on PaddleOCR, the rejection rate dropped to 0.02%. Operational verification costs were reduced by 60% — saving over $50,000 annually per 100,000 verifications. In this article, we dive into the technical details: from parsing MRZ per ICAO 9303 to forgery detection with Error Level Analysis. Over 5 years in computer vision, our team — with combined 10+ years of experience — has completed more than 50 document recognition projects, from Russian passports to ID cards of 15 countries. Our solutions are deployed in 20+ financial institutions worldwide.

AI Passport Data Extraction Solves KYC Issues

KYC is not just document checks — it's a delicate process. Manual entry errors lead to account blocks and client churn. Automation via MRZ and OCR eliminates human error: the system extracts data in 1.2 seconds with 99.8% accuracy on MRZ. Forgery detection further filters fraudulent attempts. The result: verification speed increases 5x, and operator costs drop.

How MRZ Parsing Works

The Machine Readable Zone (MRZ) consists of two lines at the bottom of a passport with check digits. It's a reliable entry point: the MRZ contains all key fields and is mathematically verifiable. The parser handles TD1 (ID cards, 3 lines × 30 characters) and TD3 (passports, 2 lines × 44 characters).

Code: MRZ Parser in Python
import re
from dataclasses import dataclass
from typing import Optional

@dataclass
class MRZData:
    document_type: str
    issuing_country: str
    surname: str
    given_names: str
    document_number: str
    nationality: str
    date_of_birth: str  # YYMMDD
    sex: str
    expiry_date: str  # YYMMDD
    personal_number: str
    check_digits_valid: bool

class MRZParser:
    """
    MRZ parser for TD1 (ID cards, 3 lines × 30 characters) and TD3 (passports, 2 lines × 44 characters).
    """
    WEIGHTS = [7, 3, 1]

    def _check_digit(self, s: str) -> int:
        """ICAO 9303 check digit"""
        charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ<'
        values = {c: i for i, c in enumerate(charset)}
        total = sum(
            values.get(c, 0) * self.WEIGHTS[i % 3] for i, c in enumerate(s)
        )
        return total % 10

    def parse_td3(self, line1: str, line2: str) -> Optional[MRZData]:
        """TD3 — passport, 2 lines of 44 characters each"""
        if len(line1) != 44 or len(line2) != 44:
            return None

        # Line 1
        doc_type = line1[0:2].replace('<', '')
        country = line1[2:5]
        name_field = line1[5:44]
        if '<<' in name_field:
            surname_raw, given_raw = name_field.split('<<', 1)
        else:
            surname_raw, given_raw = name_field, ''

        # Line 2
        doc_num = line2[0:9].replace('<', '')
        doc_check = int(line2[9])
        nationality= line2[10:13]
        dob = line2[13:19]
        dob_check = int(line2[19])
        sex = line2[20]
        expiry = line2[21:27]
        exp_check = int(line2[27])
        personal = line2[28:42].replace('<', '')
        composite_check = int(line2[43])

        # Verify check digits
        valid = all([
            self._check_digit(line2[0:9]) == doc_check,
            self._check_digit(line2[13:19]) == dob_check,
            self._check_digit(line2[21:27]) == exp_check,
            self._check_digit(line2[0:10] + line2[13:20] + line2[21:43]) == composite_check
        ])

        return MRZData(
            document_type=doc_type,
            issuing_country=country,
            surname=surname_raw.replace('<', ' ').strip(),
            given_names=given_raw.replace('<', ' ').strip(),
            document_number=doc_num,
            nationality=nationality,
            date_of_birth=dob,
            sex=sex,
            expiry_date=expiry,
            personal_number=personal,
            check_digits_valid=valid
        )

Check digits ensure data integrity. MRZ extraction accuracy is 99.8% on the MIDV-2020 benchmark.

How We Process the Visual Zone (VIZ)

Beyond MRZ, the visual zone must be read: registered address, place of birth. In Russian passports, this data is absent from MRZ. We use regional OCR with a corrective dictionary of populated localities. Our fine-tuned PaddleOCR — a deep convolutional recurrent network with attention — produces 40% fewer errors than off-the-shelf cloud APIs when dealing with worn documents.

Code: Visual Zone Extraction
from paddleocr import PaddleOCR
from rapidfuzz import process, fuzz
import json

class PassportVIZExtractor:
    def __init__(self, region_dict_path: str):
        self.ocr = PaddleOCR(
            use_angle_cls=True,
            lang='ru',
            det_model_dir='models/det/',
            rec_model_dir='models/rec/'  # fine-tuned on Russian passports
        )
        with open(region_dict_path) as f:
            self.regions = json.load(f)  # list of Russian regions/cities

    def extract_fields(self, page_image) -> dict:
        result = self.ocr.ocr(page_image, cls=True)
        if not result or not result[0]:
            return {}

        # Group lines by vertical position
        lines = sorted(
            [(r[0][0][1], r[1][0]) for r in result[0]],
            key=lambda x: x[0]
        )

        fields = {}
        for y_pos, text in lines:
            if 'место рождения' in text.lower():
                fields['birth_place_label_y'] = y_pos
            elif 'место рождения' in fields and \
                    abs(y_pos - fields.get('birth_place_label_y', 0)) < 50:
                fields['birth_place_raw'] = text

        # Normalize via fuzzy-matching to reference
        match, score, _ = process.extractOne(
            text,
            self.regions,
            scorer=fuzz.token_sort_ratio
        )
        fields['birth_place_normalized'] = match if score > 70 else text

        return fields

How Forgery Detection Works

For basic tampering detection, we use Error Level Analysis (ELA). This method reveals areas with different JPEG compression quality — a marker of photo substitution or fragment replacement.

Code: Basic Tampering Detection
import numpy as np
import cv2

def detect_basic_tampering(image: np.ndarray) -> dict:
    """
    Simple tampering indicators:
    - JPEG artifacts in different blocks (copy-paste from another photo)
    - Abnormal sharpness on individual fields (photo substitution)
    - DPI mismatch between zones
    """
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Error Level Analysis: identify areas with different compression
    import tempfile, os
    with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as tmp:
        tmp_path = tmp.name
        cv2.imwrite(tmp_path, image, [cv2.IMWRITE_JPEG_QUALITY, 90])
        recompressed = cv2.imread(tmp_path)
        os.unlink(tmp_path)

    ela = cv2.absdiff(image, recompressed)
    ela_gray = cv2.cvtColor(ela, cv2.COLOR_BGR2GRAY)

    # Regions with high ELA — potential substitutions
    high_ela_mask = ela_gray > ela_gray.mean() + 3 * ela_gray.std()
    tamper_ratio = high_ela_mask.mean()

    return {
        'ela_anomaly_ratio': float(tamper_ratio),
        'suspicious': tamper_ratio > 0.05,  # >5% pixels anomalous
        'ela_map': ela_gray
    }

For deeper detection, we use a neural network — a hybrid of convolutional and transformer layers — trained on a dataset of 10,000 real forgeries. Accuracy exceeds 95%. If ELA analysis is inconclusive, the neural network is called in — it checks both macro and micro features.

Performance Comparison with Alternatives

Off-the-shelf cloud APIs often require retries and have latency. Our pipeline runs locally: p99 latency is 1.2 seconds per document. For comparison, average cloud OCR takes 3–5 seconds. Operator time savings reach 90%. The solution saves over $50,000 per year in verification costs. Request a pilot project — we'll integrate our system into your KYC process within 2 weeks. Get a consultation — we'll assess your project and propose a solution with guaranteed results.

Comparison with Alternatives

Our fine-tuned PaddleOCR produces 40% fewer errors than off-the-shelf cloud APIs when processing worn documents. For MRZ parsing, accuracy is 99.8% — better than most open-source solutions (95–97%).

Implementation Steps

Implementation typically involves the following steps:

  1. System integration via REST API.
  2. Fine-tuning OCR models on your documents (if needed).
  3. Testing and validation on a sample set.
  4. Deployment in your environment (Docker/Kubernetes). The entire process takes 2–16 weeks depending on scope.

What's Included in the Work

When you order a turnkey system, we provide:

  • API documentation (OpenAPI 3.0) with request examples
  • Operator training (2 days online)
  • 3 months of technical support
  • Accuracy guarantee: at least 99% for critical fields
  • Deployment on your infrastructure (Docker, Kubernetes)

Accuracy on MIDV-2020 Benchmark

Field Extraction Accuracy Method
MRZ (all fields) 99.8% MRZ OCR + check digits
Series/Number (RF passport) 99.3% PaddleOCR fine-tuned
Date of Birth 99.1% MRZ + VIZ cross-check
Full Name 97.8% VIZ + BERT NER
Registration Address 94.2% VIZ + FIAS reference

Timelines

Task Timeline
MRZ + basic fields (RF/EU passports) 2–4 weeks
Multi-document system (10+ types) 6–9 weeks
System with forgery detection and liveness 10–16 weeks

Contact us for details — we'll help you choose the optimal solution for your budget. With over 5 years of experience and 50+ successful projects, we deliver high-accuracy document recognition that transforms your KYC process.