npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@healthcloudai/hc-document-capture-ui

v0.4.0

Published

React Native UI for document capture — ID, insurance, and selfie scanning with Veryfi Lens / OpenCV.js

Readme

@healthcloudai/hc-document-capture-ui

React Native UI package for document capture — ID scanning, insurance card scanning, and selfie capture — across iOS, Android, and Web.

Provides hooks, services, and optional web components. All backend communication goes through the injected HCSettingsClient from @healthcloudai/hc-settings-connector — no credentials or URLs are hardcoded inside this package.


How it works

App creates DocumentCaptureConfig { settingsClient, registrationTypes?, veryfiCredentials?, theme?, ... }
        │
        ▼
<DocumentCaptureProvider config={...}>   ← wrap navigator or screen
        │
        ▼
useDocumentCapture()                     ← reads config from context
        │
        ├─ Native (iOS/Android): Veryfi Lens SDK → captures image → file URI
        │
        ├─ Web: JScanifyWebCapture (OpenCV.js) or VeryfiLensWebCapture (WASM)
        │        → captures image → data URL
        │
        └─ processCapture(fileUri, type)
                │
                ├─ type listed in registrationTypes? → NO (auth path)
                │         │
                │    1. GET canned URL
                │         ├─ identification  → getDrivingLicenseCannedUrl
                │         ├─ healthinsurance → getInsuranceCannedUrl
                │         └─ userphoto       → getUserImageCannedUrl
                │    2. PUT file → fetch(ImageURL, { method: "PUT" })
                │    3. OCR submit
                │         ├─ identification  → captureDrivingLicense
                │         ├─ healthinsurance → captureInsurance
                │         └─ userphoto       → captureUserPhoto
                │
                ├─ type listed in registrationTypes? → YES (no-auth path)
                │         │
                │    1. GET canned URL → getRegistrationDocumentCannedUrl(type, ext)
                │    2. PUT file       → fetch(ImageURL, { method: "PUT" })
                │    3. OCR submit     → captureRegistrationDocument(fileId, type)
                │
                └─ 4. Return OCR data → DriversLicenseData | InsuranceCardData

Installation

npm install @healthcloudai/hc-document-capture-ui

Peer dependencies

| Package | Required | Notes | |---|---|---| | react >=18 <20 | ✅ | | | react-native >=0.72.0 | ✅ | | | @healthcloudai/hc-settings-connector | ✅ | Provides HCSettingsClient | | expo-file-system | ✅ | Native file read/write for upload | | @expo/vector-icons | Optional | Icons used by the capture UI components | | @veryfi/react-native-veryfi-lens | Optional | Native iOS/Android capture | | veryfi-lens-wasm | Optional | Web WASM capture | | expo-camera | Optional | Native fallback camera used by CardCameraCapture | | expo-image-manipulator | Optional | Crops fallback camera captures to the scan frame | | expo-image-picker | Optional | Gallery selection | | heic2any | Optional | Converts HEIC/HEIF uploads to JPEG on web | | react-native-reanimated >=3.0.0 | Optional | Animations |


Platform setup

iOS

1. Install Veryfi Lens pod

In your Podfile (or via Expo config plugin — see below):

pod 'VeryfiLens', :podspec => 'https://lens.veryfi.com/podspec/veryfi-lens-id-only-framework.podspec'

2. Camera permission in Info.plist:

<key>NSCameraUsageDescription</key>
<string>Used to scan ID and insurance documents</string>

3. Expo config plugin (recommended):

// app.config.js
export default {
  plugins: [
    ["@healthcloudai/hc-document-capture-ui/plugin"]
  ]
};

The plugin handles pod and permission setup automatically via expo prebuild.


Android

1. Add Veryfi Maven repository

The Expo config plugin does this automatically. Manual alternative in android/build.gradle:

allprojects {
  repositories {
    maven { url "https://dl.cloudsmith.io/public/veryfi/veryfi-lens/maven/" }
  }
}

2. Camera permission in AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" />

3. Minimum SDK

Set minSdkVersion = 26 in android/build.gradle (Veryfi Lens requirement).


Web

No native setup needed. The package uses:

  • JScanifyWebCapture — OpenCV.js loaded from CDN (https://docs.opencv.org/4.x/opencv.js), no installation needed
  • VeryfiLensWebCapture — requires veryfi-lens-wasm peer dep
npm install veryfi-lens-wasm

Ensure your Metro / bundler config allows WASM if using VeryfiLensWebCapture.


Configuration

All app-specific concerns are injected via DocumentCaptureConfig. The package never reads environment variables or hardcodes any values.

import { HCSettingsClient } from "@healthcloudai/hc-settings-connector";
import { DocumentCaptureConfig } from "@healthcloudai/hc-document-capture-ui";

// settingsClient is your existing connector instance — same one used by the rest of the app
const settingsClient = new HCSettingsClient(httpClient, loginClient);

const config: DocumentCaptureConfig = {
  // Required — owns all canned URL, capture, and save APIs
  settingsClient,

  // Optional — document types that use the unauthenticated registration path.
  // Omit this field (or leave it empty) to use the authenticated path for all types.
  // See "Pre-signin vs post-signin capture" below for details.
  registrationTypes: ["identification"],

  // Optional — Veryfi Lens native/web credentials
  veryfiCredentials: {
    url: "https://api.veryfi.com/",
    clientId: "YOUR_VERYFI_CLIENT_ID",
    userName: "YOUR_VERYFI_USERNAME",
    apiKey: "YOUR_VERYFI_API_KEY",
  },

  // Optional — UI color overrides (merged with defaults)
  theme: {
    primary: "#4caf90",    // confirm button, document outline
    background: "#000000", // camera backdrop
    text: "#FFFFFF",       // labels
    error: "#F2A0A0",      // error messages
    overlay: "rgba(0,0,0,0.5)", // close button scrim
  },

  // Optional — navigation callback
  onNavigate: (route, params) => navigation.navigate(route, params),

  // Optional — location where the app serves this package's HTML assets
  assetBasePath: "/document-capture",

  // Optional — self-hosted OpenCV.js URL for JScanifyWebCapture
  opencvScriptUrl: "/vendor/opencv.js",

  // Optional — structured logger (default: silent)
  logger: (level, message, metadata) => {
    console.log(`[hc-capture][${level}] ${message}`, metadata ?? "");
  },
};

DocumentCaptureTheme defaults

| Property | Default | Used for | |---|---|---| | background | #000000 | Camera/scanner backdrop | | text | #FFFFFF | Titles, button labels, loading text | | primary | #4caf90 | Confirm button, document outline stroke | | error | #F2A0A0 | Error message text | | overlay | rgba(0,0,0,0.5) | Close button background scrim | | surface | #1a1a1a | Dialog and popup surfaces | | border | #333333 | Dividers, borders, and subtle backgrounds |


DocumentCaptureProvider

Wrap your navigator or screen with the provider before using any hooks from this package.

import { DocumentCaptureProvider } from "@healthcloudai/hc-document-capture-ui";

function App() {
  const config: DocumentCaptureConfig = {
    settingsClient,        // HCSettingsClient instance from hc-settings-connector
    veryfiCredentials: {   // from app env variables
      url: process.env.VERYFI_URL!,
      clientId: process.env.VERYFI_CLIENT_ID!,
      userName: process.env.VERYFI_USERNAME!,
      apiKey: process.env.VERYFI_API_KEY!,
    },
    theme: { primary: "#4caf90" },
    logger: (level, msg, meta) => console[level](msg, meta),
    onNavigate: (route, params) => navigation.navigate(route, params),
  };

  return (
    <DocumentCaptureProvider config={config}>
      <YourNavigator />
    </DocumentCaptureProvider>
  );
}

Pre-signin vs post-signin capture

Some apps need to scan documents before the user logs in (e.g. during registration), while others scan them after login (e.g. in account settings). Some apps need both — for example, ID scan during registration but insurance scan after login.

The registrationTypes config field controls which document types use the unauthenticated backend path. Everything else uses the authenticated path automatically.

Authenticated path (default)

When registrationTypes is omitted or does not include a given capture type, the hook calls endpoints that require a valid auth token:

| Capture type | Canned URL | OCR submit | |---|---|---| | "identification" | getDrivingLicenseCannedUrl | captureDrivingLicense | | "healthinsurance" / "insurance" | getInsuranceCannedUrl | captureInsurance | | "userphoto" | getUserImageCannedUrl | captureUserPhoto |

Unauthenticated registration path

When a capture type is listed in registrationTypes, the hook calls:

| Canned URL | OCR submit | |---|---| | getRegistrationDocumentCannedUrl(type, ext) | captureRegistrationDocument(fileId, type) |

No auth token is sent. The settingsClient must still be configured with loginClient.configure(tenantId, environment), but the user does not need to be logged in.

Note: putIdDetails and putInsuranceDetails always require authentication. They are not available in the registration flow. If you need to persist the scanned document, do it after the user logs in.


Example: all capture after login (default)

No registrationTypes needed. The user is authenticated before reaching the capture screens.

// App.tsx
function App() {
  return (
    <DocumentCaptureProvider config={{ settingsClient }}>
      <AppNavigator />
    </DocumentCaptureProvider>
  );
}

// Inside AppNavigator — user is already logged in
function IDSettingsScreen() {
  const { processCapture, captureDriversLicense, putIdDetails, isProcessing, result } =
    useDocumentCapture();

  // After the user confirms the OCR data, save it to the EHR
  if (result?.ocrData) {
    return (
      <ConfirmScreen
        data={result.ocrData as DriversLicenseData}
        onConfirm={() => putIdDetails({ Image: result.fileId })}
      />
    );
  }

  // Native: use Veryfi Lens (returns null on web)
  if (Platform.OS !== "web") {
    return <Button title="Scan ID" onPress={captureDriversLicense} loading={isProcessing} />;
  }

  // Web: use OpenCV.js scanner
  return (
    <JScanifyWebCapture
      documentType="id"
      onCaptured={(dataUrl) => processCapture(dataUrl, "identification")}
      onClose={() => navigation.goBack()}
    />
  );
}

Example: ID scan before login, insurance after login

Use registrationTypes: ["identification"] so the ID step works without a token. Insurance is not listed, so it uses the authenticated path automatically. Both screens can live under the same DocumentCaptureProvider.

// App.tsx
function App() {
  return (
    <DocumentCaptureProvider
      config={{
        settingsClient,
        registrationTypes: ["identification"], // ID → no-auth, insurance → auth
      }}
    >
      <AppNavigator />
    </DocumentCaptureProvider>
  );
}

// Registration flow — user is NOT logged in yet
function RegistrationIDScreen() {
  const { processCapture, captureDriversLicense, isProcessing, result } = useDocumentCapture();

  // Hook automatically uses getRegistrationDocumentCannedUrl + captureRegistrationDocument
  // No auth token is required.
  // Note: putIdDetails is NOT available here — save after login if needed.

  if (Platform.OS !== "web") {
    return <Button title="Scan ID" onPress={captureDriversLicense} loading={isProcessing} />;
  }

  return (
    <JScanifyWebCapture
      documentType="id"
      onCaptured={(dataUrl) => processCapture(dataUrl, "identification")}
      onClose={() => navigation.goBack()}
    />
  );
}

// Settings flow — user IS logged in
function InsuranceSettingsScreen() {
  const { processCapture, captureInsuranceCard, putInsuranceDetails, isProcessing, result } =
    useDocumentCapture();

  // Hook uses getInsuranceCannedUrl + captureInsurance (authenticated).
  // putInsuranceDetails is available here.

  if (result?.ocrData) {
    const ocr = result.ocrData as InsuranceCardData;
    return (
      <ConfirmScreen
        data={ocr}
        onConfirm={(details) => putInsuranceDetails(details)}
      />
    );
  }

  if (Platform.OS !== "web") {
    return <Button title="Scan Insurance" onPress={captureInsuranceCard} loading={isProcessing} />;
  }

  return (
    <JScanifyWebCapture
      documentType="insurance"
      onCaptured={(dataUrl) => processCapture(dataUrl, "healthinsurance")}
      onClose={() => navigation.goBack()}
    />
  );
}

Example: both ID and insurance before login

<DocumentCaptureProvider
  config={{
    settingsClient,
    registrationTypes: ["identification", "healthinsurance"],
  }}
>
  <RegistrationNavigator />
</DocumentCaptureProvider>

Both capture types now use the unauthenticated registration path. The OCR response shape is the same — result.ocrData is still DriversLicenseData or InsuranceCardData.


useDocumentCapture hook

Main hook — handles the full capture → upload → OCR flow. Must be used inside <DocumentCaptureProvider>.

const capture = useDocumentCapture();

Return values

| Property | Type | Description | |---|---|---| | isProcessing | boolean | Upload + OCR in progress | | isVeryfiProcessingUi | boolean | Veryfi SDK is processing after shutter (show loading overlay) | | isVeryfiAvailable | boolean | Veryfi native SDK is linked and ready | | result | DocumentCaptureResult \| null | Last successful capture result | | error | Error \| null | Last error | | captureDriversLicense() | () => Promise<DocumentCaptureResult> | Native Veryfi ID capture (iOS/Android) | | captureInsuranceCard() | () => Promise<DocumentCaptureResult> | Native Veryfi insurance capture (iOS/Android) | | captureSelfie(fileUri) | (uri: string) => Promise<DocumentCaptureResult> | Upload + submit a selfie URI | | processCapture(uri, type) | (uri, type) => Promise<DocumentCaptureResult> | Upload + OCR for any capture type (used after web capture) | | uploadCapture(uri, type) | (uri, type) => Promise<UploadResult> | Request a presigned URL and upload the image without starting OCR | | processUploadedCapture(upload, type) | (upload, type) => Promise<DocumentCaptureResult> | Start OCR for a result returned by uploadCapture | | putInsuranceDetails(details) | (details: InsuranceDetails) => Promise<void> | Save confirmed insurance OCR data to EHR (authenticated only — not available in registration flow) | | putIdDetails(details) | (details: IdDetails) => Promise<void> | Save confirmed ID OCR data to EHR (authenticated only — not available in registration flow) | | reset() | () => void | Clear result, error, and processing state |

DocumentCaptureResult

interface DocumentCaptureResult {
  fileId: string;              // S3 file key / FileName from canned URL response
  url: string;                 // S3 ImageURL where file was uploaded
  key: string;                 // Same as fileId
  captureType: DocumentCaptureType;
  ocrData?: DriversLicenseData | InsuranceCardData; // Populated after OCR submit
}

Usage example

import { useDocumentCapture, JScanifyWebCapture } from "@healthcloudai/hc-document-capture-ui";
import { Platform } from "react-native";

// IdScanScreen must be rendered inside <DocumentCaptureProvider>
function IdScanScreen() {
  const { captureDriversLicense, processCapture, putIdDetails, isProcessing, result, error } =
    useDocumentCapture();

  // --- Native (iOS / Android) ---
  const handleNativeCapture = async () => {
    try {
      const result = await captureDriversLicense();
      console.log("OCR data:", result.ocrData);
      // result.ocrData is DriversLicenseData
    } catch (e) {
      console.error(e);
    }
  };

  // --- Web ---
  if (Platform.OS === "web") {
    return (
      <JScanifyWebCapture
        documentType="id"
        onCaptured={async (dataUrl) => {
          const result = await processCapture(dataUrl, "identification");
          console.log("OCR data:", result.ocrData);
        }}
        onClose={() => navigation.goBack()}
      />
    );
  }

  // ... native UI
}

useVeryfiLens hook

Lower-level hook for screens that need direct Veryfi Lens control (e.g. when you want to handle the image yourself before OCR).

const veryfi = useVeryfiLens({
  credentials: config.veryfiCredentials,
  onCaptureSuccess: (result) => console.log(result.imageUri),
  onCaptureCancel: () => navigation.goBack(),
  onCaptureError: (err) => console.error(err),
});

Return values

| Property | Type | Description | |---|---|---| | isAvailable | boolean | Veryfi native SDK linked | | isInitializing | boolean | SDK initializing | | isCapturing | boolean | Camera open | | isVeryfiLensProcessingUi | boolean | Post-shutter processing | | shouldUseFallback | boolean | true on web or when SDK unavailable — show web fallback | | result | VeryfiLensResult \| null | Raw SDK result | | error | Error \| null | | | captureDriversLicense() | () => Promise<VeryfiLensResult> | | | captureInsuranceCard() | () => Promise<VeryfiLensResult> | | | captureDocument(type) | (type: VeryfiDocumentType) => Promise<VeryfiLensResult> | | | reset() | () => void | |

VeryfiLensResult

interface VeryfiLensResult {
  success: boolean;
  imageUri?: string;   // file:// URI (native) or data URL (web)
  imagePath?: string;  // absolute file path (native)
  documentType?: VeryfiDocumentType;
  data?: DriversLicenseData | InsuranceCardData; // SDK-extracted OCR (if available)
  error?: string;
  rawResponse?: unknown;
}

Web capture components

Both components are web-only — they return null on iOS/Android.

JScanifyWebCapture

OpenCV.js document scanner. Auto-captures when document is stable and in frame. No external SDK, no licensing.

import { JScanifyWebCapture } from "@healthcloudai/hc-document-capture-ui";

<JScanifyWebCapture
  documentType="id"           // "id" | "insurance"
  theme={config.theme}        // optional
  logger={config.logger}      // optional
  opencvScriptUrl="/vendor/opencv.js" // optional; also read from provider config
  onCaptured={(dataUrl) => processCapture(dataUrl, "identification")}
  onClose={() => navigation.goBack()}
  onError={(err) => console.error(err)}
/>

How it works: loads opencv.js from CDN → accesses device camera → draws video frames to canvas → runs Canny edge detection and contour analysis → when a stable 4-corner document quad is detected, performs perspective warp and CLAHE enhancement → calls onCaptured with a JPEG data URL.


VeryfiLensWebCapture

Veryfi Lens WASM web capture. Requires veryfi-lens-wasm installed.

import { VeryfiLensWebCapture } from "@healthcloudai/hc-document-capture-ui";

<VeryfiLensWebCapture
  documentType="insurance"    // "id" | "insurance"
  clientId={config.veryfiCredentials.clientId}
  theme={config.theme}        // optional
  onCaptured={(dataUrl) => processCapture(dataUrl, "healthinsurance")}
  onClose={() => navigation.goBack()}
  onError={(err) => console.error(err)}
/>

Native fallback camera

CardCameraCapture provides an expo-camera fallback when the Veryfi native SDK is unavailable or when the consuming app wants to own the capture screen. It renders an ID/insurance card guide, supports timed auto-capture and a manual shutter, and crops the returned photo to the visible guide frame when expo-image-manipulator is installed.

import { CardCameraCapture } from "@healthcloudai/hc-document-capture-ui";

<CardCameraCapture
  documentType="id"
  topInset={safeAreaInsets.top}
  bottomInset={safeAreaInsets.bottom}
  onCaptured={(fileUri) => processCapture(fileUri, "identification")}
  onClose={() => navigation.goBack()}
  onError={(error) => console.error(error)}
/>

expo-camera and expo-image-manipulator are optional peers. If expo-camera is not installed, the component renders an unavailable state and calls onError. If expo-image-manipulator is missing, the original uncropped photo URI is returned.

Capture UI building blocks

  • CardScanGuide renders a reusable ID/insurance card guide.
  • CaptureOcrNoticeModal renders a themed web notice for capture/OCR failures.
  • WebFileUploadDialog provides web selfie capture and single/multiple image selection. It reads assetBasePath from its prop or the provider config.
  • VeryfiHelpView provides a themed help screen for the native Veryfi camera.
  • getCaptureErrorMessage normalizes empty and generic capture errors.
  • cropToScanFrame exposes the fallback camera crop helper for custom capture screens.

Full flow with all platforms

// DocumentCaptureScreen must be rendered inside <DocumentCaptureProvider>
function DocumentCaptureScreen({ documentType }: { documentType: "id" | "insurance" }) {
  const {
    captureDriversLicense,
    captureInsuranceCard,
    processCapture,
    putIdDetails,
    putInsuranceDetails,
    isVeryfiAvailable,
    isProcessing,
    result,
  } = useDocumentCapture();

  const captureType = documentType === "id" ? "identification" : "healthinsurance";

  // Web — show OpenCV scanner
  if (Platform.OS === "web") {
    return (
      <JScanifyWebCapture
        documentType={documentType}
        onCaptured={(dataUrl) => processCapture(dataUrl, captureType)}
        onClose={() => navigation.goBack()}
      />
    );
  }

  // Native — use Veryfi Lens
  const handleCapture = () => {
    if (documentType === "id") return captureDriversLicense();
    return captureInsuranceCard();
  };

  // After OCR result, let user confirm then save
  if (result?.ocrData) {
    return (
      <ConfirmScreen
        ocrData={result.ocrData}
        onConfirm={async (details) => {
          if (documentType === "id") await putIdDetails({ Image: result.fileId });
          else await putInsuranceDetails(details as InsuranceDetails);
        }}
      />
    );
  }

  return <CaptureButton onPress={handleCapture} loading={isProcessing} />;
}

API response examples

Canned URL response (from settingsClient.getDrivingLicenseCannedUrl)

{
  "Data": {
    "ImageURL": "https://hc-dev-storage-cv-sources.s3.us-east-1.amazonaws.com/1234567890123.jpg?X-Amz-Signature=...",
    "FileName": "1234567890123.jpg",
    "Extension": null
  },
  "IsOK": true,
  "ErrorMessage": null
}

ID capture OCR response (from settingsClient.captureDrivingLicense)

{
  "Data": {
    "IsCaptured": true,
    "InsurancePackages": null,
    "CapturedData": {
      "FirstName": "John",
      "LastName": "Doe",
      "StreetAddress": "123 Main St",
      "City": "Austin",
      "ZipCode": "78701",
      "State": "TX",
      "IssuedDate": "2019-03-15",
      "ExpiresDate": "2027-03-15",
      "Dob": "1990-06-01",
      "IDNumber": "12345678"
    }
  },
  "IsOK": true,
  "ErrorMessage": null
}

Mapped to DriversLicenseData:

{
  firstName: "John",
  lastName: "Doe",
  address: "123 Main St",
  city: "Austin",
  zipCode: "78701",
  state: "TX",
  issueDate: "2019-03-15",
  expirationDate: "2027-03-15",
  dateOfBirth: "1990-06-01",
  licenseNumber: "12345678",
  rawData: { /* original backend fields */ }
}

Insurance capture OCR response (from settingsClient.captureInsurance)

{
  "Data": {
    "IsCaptured": true,
    "InsurancePackages": [
      { "Id": 42, "Name": "BlueCross PPO Gold" }
    ],
    "CapturedData": {
      "FirstName": "Jane",
      "LastName": "Doe",
      "MemberId": "XYZ987654",
      "GroupNumber": "GRP001",
      "EffectiveDate": "2024-01-01",
      "RxBIN": "004336",
      "RxPCN": "ADV",
      "RxGRP": "RXGRP01",
      "Carrier": "BlueCross BlueShield"
    }
  },
  "IsOK": true,
  "ErrorMessage": null
}

Mapped to InsuranceCardData:

{
  memberName: "Jane Doe",
  memberId: "XYZ987654",
  groupNumber: "GRP001",
  effectiveDate: "2024-01-01",
  rxBin: "004336",
  rxPcn: "ADV",
  rxGrp: "RXGRP01",
  insurerName: "BlueCross BlueShield",
  rawData: { /* original backend fields */ }
}

Save insurance details payload (putInsuranceDetails)

await putInsuranceDetails({
  InsurancePackageId: "42",     // from InsurancePackages[0].Id
  MemberId: "XYZ987654",
  FirstName: "Jane",
  LastName: "Doe",
  Sex: "F",
  Image: result.fileId,         // fileName from upload (e.g. "1234567890123.jpg")
});

Save ID details payload (putIdDetails)

await putIdDetails({
  Image: result.fileId,  // fileName from upload
});

HEIC utilities

Helper functions for detecting and normalizing HEIC/HEIF images (common on iOS).

import {
  isHeicMimeType,
  isHeicFileName,
  isHeicUri,
  isHeicAsset,
  getExtensionForMimeType,
  getMimeTypeForExtension,
  toJpegFileName,
  convertHeicBlobToJpeg,
  normalizeWebUploadBlob,
  normalizeWebImageFile,
  normalizeWebImageAsset,
} from "@healthcloudai/hc-document-capture-ui";

isHeicMimeType("image/heic")          // true
isHeicFileName("photo.HEIF")          // true
isHeicUri("file:///tmp/scan.heic")    // true
getExtensionForMimeType("image/png")  // "png"
getMimeTypeForExtension("jpg")        // "image/jpeg"
toJpegFileName("scan.heic")          // "scan.jpg"

The normalizeWeb* helpers are web-only. They load the optional heic2any peer lazily when a HEIC/HEIF file needs conversion, so native bundles do not load that dependency.


Advanced: direct upload service

For custom upload flows outside of useDocumentCapture:

import { uploadFile, writeDataUrlToFile } from "@healthcloudai/hc-document-capture-ui";

// Write a web data URL to a native file (no-op on web — returns data URL as-is)
const { fileUri, contentType } = await writeDataUrlToFile(dataUrl, "capture.jpg");

// Upload to canned URL — works on both web and native
const result = await uploadFile(
  fileUri,
  (extension) =>
    settingsClient.getDrivingLicenseCannedUrl(extension).then((r) => ({
      ImageURL: r.Data?.ImageURL ?? null,
      FileName: r.Data?.FileName ?? null,
    })),
);
// result: { fileId: "1234567890123.jpg", url: "https://...", key: "1234567890123.jpg" }

Expo config plugin

The plugin configures native projects for Veryfi Lens. Add it to app.config.js:

export default {
  plugins: [
    ["@healthcloudai/hc-document-capture-ui/plugin"]
  ]
};

Then run:

npx expo prebuild

Android: Adds the Veryfi Maven repository to android/build.gradle.
iOS: Removes any legacy manual VeryfiLens pod entries (autolinking handles it from RN 0.72+).


Platform behavior summary

| Feature | iOS | Android | Web | |---|---|---|---| | Document capture | Veryfi Lens SDK or CardCameraCapture fallback | Veryfi Lens SDK or CardCameraCapture fallback | JScanifyWebCapture (OpenCV.js) or VeryfiLensWebCapture (WASM) | | Upload | expo-file-system uploadAsync → PUT canned URL | Same | Canvas compress → fetch PUT canned URL | | Image compression | None (Veryfi handles it) | None | Auto-compressed to ≤1MB JPEG via Canvas API | | HEIC normalization | Detected by MIME/extension | Same | Converted to JPEG with optional heic2any | | isVeryfiAvailable | true if pod linked | true if VeryfiLensAndroid native module present | Always false |


Types reference

type DocumentCaptureType = "userphoto" | "healthinsurance" | "identification" | "insurance";

interface DocumentCaptureConfig {
  settingsClient: HCSettingsClient;

  /**
   * Document types that use the unauthenticated registration path.
   * Types not listed here use the authenticated path.
   * Omit entirely to use the authenticated path for all types.
   */
  registrationTypes?: DocumentCaptureType[];

  veryfiCredentials?: VeryfiLensCredentials;
  theme?: Partial<DocumentCaptureTheme>;
  onNavigate?: (route: string, params?: Record<string, unknown>) => void;
  assetBasePath?: string;
  opencvScriptUrl?: string;
  logger?: (level: "debug" | "info" | "warn" | "error", message: string, metadata?: Record<string, unknown>) => void;
}

interface InsuranceDetails { InsurancePackageId: string; MemberId: string; FirstName: string; LastName: string; Sex: string; Image: string; // fileName from upload result }

interface IdDetails { Image: string; // fileName from upload result }

interface DriversLicenseData { firstName?: string; lastName?: string; dateOfBirth?: string; expirationDate?: string; issueDate?: string; licenseNumber?: string; state?: string; address?: string; city?: string; zipCode?: string; gender?: string; rawData?: Record<string, unknown>; // ... full list in types.ts }

interface InsuranceCardData { memberName?: string; memberId?: string; groupNumber?: string; effectiveDate?: string; rxBin?: string; rxPcn?: string; rxGrp?: string; insurerName?: string; rawData?: Record<string, unknown>; // ... full list in types.ts }