AI-powered identity document verification for notarial compliance.
π Winner Β· VillageHacks 2026 (Notary Track) Β· Arizona State University
Upload a government-issued ID and get an instant authenticity verdict, extracted data fields with per-field confidence scores, and compliance flags against RULONA, NIST IAL2, and MISMO standards. Cross-reference a second document or verify a live selfie against the ID photo, with biometric matching running entirely in-browser.
Full Video: link
App Live Link: link
Hybrid AI + deterministic architecture. The LLM extracts signals. Code computes the verdict. Five weighted signals are aggregated in TypeScript with hard caps for expired IDs, invalid state-specific ID number formats, and per-level failures. The model cannot hallucinate a passing score.
Two-step Gemini pipeline. Step 1 classifies the document (type, issuing state, side, under-21 flag, REAL ID star). That classification is injected into the Step 2 prompt, enabling state-specific field format rules and reducing hallucinations on ambiguous documents.
Privacy enforced architecturally. Face comparison runs entirely client-side via face-api.js. The 128-dim descriptor matching happens in the browser; the selfie never reaches the server.
Compliance-ready output. Results cite specific regulatory standards (RULONA Β§ 2(14), NIST SP 800-63-3 IAL2, MISMO) with expiration checks and out-of-state flags, directly usable in notarial documentation.
Browser Server
ββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββ
Upload ID image
βββ (optional) 2nd document
βββ (optional) Live selfie
β
βββ Promise.all([
β
βββ POST /api/verify βββββββββββΊ Route Handler
β β
β βββ Gemini Step 1: Classify
β β (type, state, side, orientation)
β β
β βββ Gemini Step 2: Analyze
β β (forensics, extraction, compliance)
β β
β βββ computeVerdict()
β deterministic scoring
β βββββββββ JSON result βββββββββ in TypeScript
β
βββ runFaceComparison()
face-api.js (client-side)
TinyFaceDetector
FaceRecognitionNet
128-dim descriptor matching
])
β
βββ Render verification dashboard
The LLM extracts signals. Code computes the score.
| Signal | Weight |
|---|---|
| Template conformance | 25% |
| Data field validity | 25% |
| Data consistency | 20% |
| Image integrity | 15% |
| Security feature presence | 15% |
Hard caps override the weighted score: invalid state-specific ID number format caps confidence at 40%, expired documents at 70%, any per-level failure at 77%.
Verdict thresholds: β₯ 78% AUTHENTIC, β₯ 50% SUSPICIOUS, < 50% FAKE.
| Technology | Purpose |
|---|---|
| Next.js 16 (App Router) | Full-stack framework with API Route Handlers |
| React 19 + TypeScript 5 | UI with state machine-driven flow |
| Tailwind CSS 4 | Styling |
| Gemini 2.5 Flash | Two-step document classification and forensic analysis |
| face-api.js | Client-side face detection and 128-dim descriptor matching |
Hackathon prototype. Verification logic works end to end; surrounding infrastructure is not production-grade.
Not implemented: authentication, rate limiting, persistent storage, structured logging, MIME type verification against image bytes, cache eviction, test suite.
Production roadmap: auth and per-tenant API keys, audit log persistence, edge rate limiting, integration tests for the scoring engine, structured logging with per-step latency metrics, bounded LRU cache.
git clone https://github.com/yourusername/VerifyID.git
cd VerifyID
npm install
cp .env.example .env.local
# add GEMINI_API_KEY to .env.local
npm run devGet a Gemini API key at aistudio.google.com/apikey. Optional GEMINI_API_KEY_FALLBACK is used on rate-limit errors.
src/
βββ app/
β βββ page.tsx # Client state machine, selfie capture, face comparison
β βββ api/verify/route.ts # API route, validates input, calls Gemini pipeline
β βββ layout.tsx # App shell, font loading
βββ lib/
β βββ gemini.ts # Two-step Gemini pipeline, scoring engine, cache
β βββ types.ts # TypeScript interfaces for all verification levels
βββ components/
βββ VerificationResult.tsx # Results dashboard (verdict, fields, compliance)
βββ UploadZone.tsx # Drag-and-drop file upload
βββ ScanAnimation.tsx # Loading state
public/
βββ models/ # face-api.js model weights