Document Verification Implementation in Mobile Applications
Document verification via mobile camera is standard for fintech and KYC processes. User photographs passport, driver's license or travel document, app recognizes data and checks authenticity. Implementation is more complex than it looks: capture quality, forgery detection and OCR accuracy create a chain of failure points.
Document Detection and Quality Before OCR
First stage — ensure document is in frame correctly, without glare and blur. Showing user "too dark" or "tilt phone" is more important than good OCR — garbage input gives garbage output.
On iOS for real-time document rectangle detection — Vision.VNDetectRectanglesRequest:
let request = VNDetectRectanglesRequest { request, error in
guard let observations = request.results as? [VNRectangleObservation],
let doc = observations.first else { return }
// Check confidence and aspect ratio for passport
if doc.confidence > 0.9 && isValidDocumentAspectRatio(doc) {
// Capture frame
captureDocument(rect: doc)
}
}
request.minimumConfidence = 0.8
request.minimumAspectRatio = 0.5
For glare checking — analyze brightness via CIFilter.glassDistortion or custom Metal shader. Specular highlights (white spots on laminated passport surface) — typical OCR failure cause in ~15% cases.
On Android — CameraX + MLKit DocumentScanner API (2024+) or OpenCV for rectangle detection via Imgproc.findContours.
OCR: Platform vs Specialized SDKs
Apple Vision (VNRecognizeTextRequest) — good quality for Latin and Cyrillic, works on-device:
let textRequest = VNRecognizeTextRequest { request, _ in
let observations = request.results as? [VNRecognizedTextObservation] ?? []
let lines = observations.compactMap { $0.topCandidates(1).first?.string }
parseDocumentFields(from: lines)
}
textRequest.recognitionLevel = .accurate
textRequest.recognitionLanguages = ["ru-RU", "en-US"]
textRequest.usesLanguageCorrection = true
Google ML Kit Text Recognition v2 — on Android, supports Latin, Cyrillic, Devanagari and more scripts. Works on-device.
Specialized SDKs: Regula Document Reader, ABBYY Mobile Capture, Scandit. Cost money but better accuracy on MRZ (Machine Readable Zone) passports and understand specific document structures. Regula knows formats of 240+ countries.
MRZ: Most Valuable
Machine Readable Zone — two lines with OCR-optimized OCR-B font at bottom of passport or ID card. From here extract: name, document number, date of birth, expiry, nationality.
Parse MRZ per ICAO 9303 standard (implementation — open libraries NFCPassportReader on iOS or MRZParser on Android):
// MRZ line: P<RUSLASTNAME<<FIRSTNAME<<<<<<<<<<<<<<<
// Line 2: PA1234567<8RUS9001011M2512310<<<<<<<<<6
struct MRZData {
let documentNumber: String
let lastName: String
let firstName: String
let nationality: String
let dateOfBirth: Date
let expiryDate: Date
let gender: Character
var isChecksumValid: Bool {
// Check control digits per ICAO 9303
validateMRZCheckDigits(line2: rawLine2)
}
}
Check digits in MRZ — simple way to verify data wasn't corrupted by OCR. If checksum fails — reread document, don't send to server.
NFC Verification of Biometric Passports
New passports (ICAO LDS1) contain NFC chip with biometric data and digital signature from issuing country. Chip reading — more reliable verification than OCR.
On iOS (CoreNFC, NFCTagReaderSession):
// Basic Access Control: key formed from MRZ
let bacKey = BACKey(documentNumber: mrz.documentNumber,
dateOfBirth: mrz.dateOfBirth,
dateOfExpiry: mrz.expiryDate)
let nfcReader = NFCPassportReader()
nfcReader.readPassport(mrzKey: bacKey.key,
tags: [.DG1, .DG2, .SOD]) { result in
switch result {
case .success(let passport):
let photo = passport.passportImage // UIImage from DG2
let isValid = passport.documentSigned // verify CSCA certificate
case .failure(let error):
handleNFCError(error)
}
}
NFC available only on physical devices, iPhone 7+. On Android — NfcAdapter with PACE/BAC.
Server-Side Validation
OCR data from client — always untrusted. Final verification happens on server: compare document photo with user selfie via face matching API (Amazon Rekognition, Azure Face, or ГАРАНТ/Passport-service for Russian documents).
Implementation Process
Define document types and countries. Choose SDK (Vision/ML Kit vs specialized). Implement capture flow: detection, quality check, capture. OCR + parse fields. NFC verification (if needed). Server validation with face matching. Test on collection of real documents with various quality.
Timeline Guidelines
Basic passport OCR (MRZ + main fields) — 1–2 weeks. Full KYC flow with NFC, face matching, multiple document types — 6–10 weeks.







