Case study

Card Vault (Card-Snap OCR)

Cross-platform mobile app that scans business cards, extracts contacts via OCR, and syncs them to a backend.

  • TypeScript
  • React Native
  • Node.js
  • Tesseract.js
The core problem

What needed solving

Networking events leave people with stacks of business cards and no fast path into organized contacts. Manual data entry is error-prone and time-consuming, especially after conferences or client meetings.

The solution

What I built

Card Vault removes manual entry entirely: the camera scan triggers an async OCR pipeline on the backend, parses name, title, company, email, and phone number using regex NLP, then returns structured data for review and save.

React Native (Expo) mobile client for business-card scanning built with TypeScript and file-based routing via Expo Router. Captures card images with expo-camera, sends base64 data to a Node.js backend that runs OCR + regex NLP parsing, and returns structured contact fields. Supports manual entry, light/dark mode, and local/backend sync.

Integration

How it fits together

The Expo (React Native) client captures a card with expo-camera and sends it as base64 to a Node.js backend. The backend runs Tesseract OCR, then regex-based parsing that pulls out name, title, company, email, and phone, and returns structured fields for the user to review before saving. The backend URL comes from .env, so one codebase targets local, staging, or production.

Loading diagram…
System architecture

The flow, step by step

  1. Open the app on Android, iOS, or Web via Expo Go, then navigate to the scan screen.
  2. Capture or upload a business card photo. The app encodes the image as base64 and sends it to the Node.js backend API.
  3. Review the extracted fields (name, title, company, email, phone) and correct any low-confidence values before saving.
  4. Browse saved contacts in the Contacts tab or add records manually via the Add screen.
Problems along the way

What got hard, and what I did about it

OCR output is noisy

The problem

Logos, fonts, and layouts make raw OCR text unreliable to save as-is.

What I did

Added a review step: parsed fields are shown for correction before anything is stored.

Keeping the phone app light

The problem

Running OCR on-device would bloat the app and vary wildly by hardware.

What I did

Moved OCR and parsing server-side; the client only captures, sends, and displays.

Takeaways

What I learned

  • When extraction can be wrong, a human-in-the-loop review step beats pretending the model is perfect.
  • Splitting heavy processing to the server keeps a cross-platform client simple.
  • Environment-driven configuration makes the same build usable across local and deployed backends.
Outcome

Where it stands today

Expo Router file-based navigation across Home, Contacts, and Add tabs with a full Stack layout.
Configurable backend URL via .env so the same codebase targets local, staging, or production APIs.
ThemeContext-driven light/dark mode applied globally across all screens.
OCR and NLP parsing handled server-side so the mobile client stays lightweight.

Milestones

  • Camera capture & base64 pipeline

    expo-camera integration sends card images to the backend API for processing.

    Shipped
  • OCR + NLP contact extraction

    Backend parses name, title, company, email, and phone from OCR text using regex NLP.

    Shipped
  • Contact CRUD & manual entry

    Users can review, save, edit, and add contacts manually from the mobile app.

    Shipped
  • Confidence scoring & multilingual support

    Visual confidence indicators and multilingual card parsing are future improvements.

    Planned

Next up

  • Add per-field confidence scores and visual correction hints.
  • Support direct CRM export (HubSpot, Salesforce).
  • Expand regex NLP parsing for multilingual and non-latin card layouts.