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

@simprints/simface-sdk

v0.24.1

Published

SimFace facial recognition SDK for web-based KYC workflows

Downloads

1,042

Readme

SimFace SDK

SimFace SDK provides facial recognition for web-based KYC workflows. It exposes one primary JavaScript API for enrollment and verification, plus a lower-level Web Component for advanced UI control.

Works in: all modern browsers, WhatsApp in-app browser, and mobile WebViews.

This repository is the public frontend SDK and demo repo for SimFace. For frontend architecture and contributor setup, see docs/architecture.md and docs/development.md.

For repository policies and contribution guidance, see SECURITY.md, CONTRIBUTING.md, and LICENSE.

The backend API, infrastructure, and TensorFlow Lite runtime live in the separate private backend repository.

The capture flow is planned explicitly as: auto camera -> manual camera -> media picker. The primary API supports two UI modes:

  • popup capture: the SDK opens and manages its own modal capture flow
  • embedded capture: the SDK runs capture inside a host-provided simface-capture element

Face Quality Checks

The SDK automatically performs these checks on captured images before submission:

  1. Face presence - at least one face must be detected.
  2. Single face - only one face should be in the frame.
  3. Face size - face must not be too close or too far.
  4. Centering - face must be approximately centered in the frame.

If a check fails, the user is prompted with specific guidance and asked to retake the photo.

Quick Start

1. Include the SDK

Option A — npm:

npm install @simprints/simface-sdk
import { enroll, verify } from '@simprints/simface-sdk';

Option B — direct script include:

Download the SDK files from the latest GitHub Release and include them directly:

<script type="module" src="simface-sdk.js"></script>

The release contains two builds:

  • simface-sdk.js (ES module)
  • simface-sdk.umd.cjs (UMD/CommonJS build)

2. Configure

const config = {
  projectId: 'your-project-id',
  apiKey: 'your-api-key',
};

Security considerations

  • Treat apiKey as a browser-visible credential. Do not hardcode long-lived secrets into shipped frontend bundles.
  • Prefer issuing short-lived credentials or session-bound tokens from your own backend for each capture session.
  • Keep apiUrl on HTTPS in production and make sure the backend only accepts trusted origins and authorized project IDs.
  • The local demo does not persist project IDs or API keys to localStorage; it only remembers the API URL, presentation mode, and client ID between reloads.

3. Enroll a User

import { enroll } from '@simprints/simface-sdk';

const result = await enroll(config, 'unique-user-id');

if (result.success) {
  console.log('User enrolled successfully!');
} else if (result.alreadyEnrolled) {
  console.log('User is already enrolled - use verify() instead.');
} else {
  console.log('Enrollment failed:', result.message);
}

4. Verify a User

import { verify } from '@simprints/simface-sdk';

const result = await verify(config, 'unique-user-id');

if (result.match) {
  console.log(`Identity verified! (score: ${result.score})`);
} else if (result.notEnrolled) {
  console.log('User not enrolled - use enroll() first.');
} else {
  console.log(`Verification failed (score: ${result.score}, threshold: ${result.threshold})`);
}

5. Choose the capture UI mode

enroll() and verify() are the main SDK entry points. They both use the same capture workflow and backend API. The only UI difference is where the capture UI is rendered.

Both functions accept:

  • workflowOptions: optional capture behavior that applies to both popup and embedded flows
  • captureElement: optional existing simface-capture element; if this argument is present, the SDK uses embedded mode

Popup capture

If you omit captureElement, the SDK opens its popup capture UI:

const workflowOptions = {
  capturePreference: 'auto-preferred',
  allowMediaPickerFallback: true,
};

const enrollResult = await enroll(config, 'unique-user-id', workflowOptions);
const verifyResult = await verify(config, 'unique-user-id', workflowOptions);

Embedded capture

If you want capture inline in your page, create a simface-capture element and pass it as captureElement. The SDK still owns the capture lifecycle; it just renders the UI inline instead of in a popup.

<simface-capture
  embedded
  capture-preference="auto-preferred"
  label="Take a selfie for verification"
  idle-feedback-label="Start verification to see camera guidance here."
  capture-label="Snap photo"
  retake-label="Take another"
  confirm-label="Use this photo"
  retry-label="Start over"
></simface-capture>
const workflowOptions = {
  capturePreference: 'auto-preferred',
  allowMediaPickerFallback: true,
};

const captureElement = document.querySelector('simface-capture');

const enrollResult = await enroll(config, 'unique-user-id', workflowOptions, captureElement);
const verifyResult = await verify(config, 'unique-user-id', workflowOptions, captureElement);

| workflowOptions | Type | Default | Notes | |--------|------|---------|-------| | capturePreference | 'auto-preferred' \| 'manual-only' | 'auto-preferred' | Controls auto vs manual shutter | | allowMediaPickerFallback | boolean | true | Falls back to file picker if camera is unavailable |

API Reference

Primary SDK API

The main integration surface is:

  • enroll(config, clientId, workflowOptions?, captureElement?)
  • verify(config, clientId, workflowOptions?, captureElement?)

These functions:

  • run the camera capture workflow
  • manage popup or embedded capture UI
  • perform face quality validation
  • call the backend API for enrollment or verification

enroll(config, clientId, workflowOptions?, captureElement?): Promise<EnrollResult>

Opens the camera, captures a face image with quality validation, and enrolls the user.

Parameters:

| Parameter | Type | Description | |-----------|------|-------------| | config | SimFaceConfig | SDK configuration (projectId, apiKey, optional apiUrl) | | clientId | string | Unique identifier for the user | | workflowOptions | SimFaceWorkflowOptions | Optional popup/embedded-agnostic capture behavior | | captureElement | SimFaceCaptureElement | Optional embedded simface-capture element |

Returns: EnrollResult

verify(config, clientId, workflowOptions?, captureElement?): Promise<VerifyResult>

Opens the camera, captures a face image, and verifies against the enrolled face.

Parameters:

| Parameter | Type | Description | |-----------|------|-------------| | config | SimFaceConfig | SDK configuration (projectId, apiKey, optional apiUrl) | | clientId | string | Unique identifier for the user | | workflowOptions | SimFaceWorkflowOptions | Optional popup/embedded-agnostic capture behavior | | captureElement | SimFaceCaptureElement | Optional embedded simface-capture element |

Returns: VerifyResult

SimFaceAPIClient and the backend REST interface

SimFaceAPIClient is the lower-level HTTP client used internally by enroll() and verify(). Use it when you want direct control over when capture happens and when backend calls are made.

Typical cases for using SimFaceAPIClient directly:

  • advanced UI flows driven by your own application state
  • direct use of the simface-capture component
  • custom orchestration where capture and backend submission happen in separate steps

At a high level:

  • enroll() and verify() = capture UI + quality checks + backend submission
  • SimFaceAPIClient = backend submission only

SimFaceAPIClient maps directly to the backend REST interface:

  • validateAPIKey() -> POST /api/v1/auth/validate
  • enroll(clientId, imageBlob) -> POST /api/v1/enroll
  • verify(clientId, imageBlob) -> POST /api/v1/verify

Advanced: Direct simface-capture control

Use the simface-capture Web Component directly when you want the host application to manage capture state itself instead of letting enroll() or verify() orchestrate it. In this mode, the component is also the source of truth for embedded UI copy.

<simface-capture
  embedded
  capture-preference="auto-preferred"
  label="Take a selfie for verification"
  idle-feedback-label="Start verification to see camera guidance here."
  capture-label="Snap photo"
  retake-label="Take another"
  confirm-label="Use this photo"
  retry-label="Start over"
></simface-capture>

<script type="module">
  import '@simprints/simface-sdk';
  import { SimFaceAPIClient } from '@simprints/simface-sdk';

  const captureEl = document.querySelector('simface-capture');
  const client = new SimFaceAPIClient({
    projectId: 'your-project-id',
    apiKey: 'your-api-key',
  });

  captureEl.addEventListener('simface-captured', async (e) => {
    const { imageBlob } = e.detail;
    const result = await client.verify('user-123', imageBlob);
    console.log('Verify result:', result);
  });

  captureEl.addEventListener('simface-cancelled', () => {
    console.log('User cancelled capture');
  });

  captureEl.addEventListener('simface-error', (e) => {
    console.error('Capture error:', e.detail.error);
  });

  await captureEl.startCapture();
</script>

In this advanced flow:

  1. the host renders the component
  2. the host starts capture with startCapture() or by setting active = true
  3. the component emits capture events
  4. the host decides what backend call to make with SimFaceAPIClient

This is more flexible, but it also means the host owns more of the workflow.

Component Attributes

| Attribute | Type | Default | Description | |-----------|------|---------|-------------| | label | String | "Capturing Face" | Primary instructional text shown by the component | | idle-feedback-label | String | "Start a capture to see camera guidance here." | Idle guidance text shown in the feedback area before capture begins | | embedded | Boolean | false | Runs the component inline instead of delegating to the popup capture service | | capture-label | String | "Take photo" | Manual capture button label | | retake-label | String | "Retake" | Preview retake button label | | confirm-label | String | "Accept" | Confirm button label used in preview state | | retry-label | String | "Try again" | Error-state retry button label | | capture-preference | "auto-preferred" \| "manual-only" | "auto-preferred" | Whether auto capture should be preferred or disabled | | allow-media-picker-fallback | Boolean | true | Whether the component may fall back to the media picker if camera capture is unavailable |

Events

| Event | Detail | Description | |-------|--------|-------------| | simface-captured | { imageBlob: Blob } | Fires when a quality-checked face image is confirmed | | simface-cancelled | - | Fires when the user cancels the capture flow | | simface-error | { error: string } | Fires on capture/detection errors |

Type Definitions

SimFaceConfig

interface SimFaceConfig {
  projectId: string;
  apiKey: string;
  apiUrl?: string; // Defaults to the hosted SimFace backend
}

SimFaceWorkflowOptions

interface SimFaceWorkflowOptions {
  capturePreference?: 'auto-preferred' | 'manual-only';
  allowMediaPickerFallback?: boolean;
}

EnrollResult

interface EnrollResult {
  success: boolean;
  clientId: string;
  message?: string;
  alreadyEnrolled?: boolean;
}

VerifyResult

interface VerifyResult {
  match: boolean;
  score: number;
  threshold: number;
  message?: string;
  notEnrolled?: boolean;
}

Backend API Endpoints

For clients integrating directly with the REST API:

POST /api/v1/auth/validate

Validate API credentials.

Body: { "projectId": "...", "apiKey": "..." } Response: { "valid": true, "projectId": "...", "name": "..." }

POST /api/v1/enroll

Enroll a new user.

Body: multipart form data with fields projectId, apiKey, clientId, image. Response: { "success": true, "clientId": "..." }

POST /api/v1/verify

Verify a user against their enrollment.

Body: multipart form data with fields projectId, apiKey, clientId, image. Response: { "match": true, "score": 0.85, "threshold": 0.6 }

GET /api/v1/health

Health check endpoint.

Response: { "status": "ok" }

Browser Compatibility

| Browser | Camera Capture | Face Detection | |---------|---------------|----------------| | Chrome (Android/Desktop) | Yes | Yes | | Safari (iOS/Desktop) | Yes | Yes | | WhatsApp in-app browser | Yes (via native camera) | Yes | | Firefox | Yes | Yes | | Samsung Internet | Yes | Yes |

Note: In WhatsApp's in-app browser, the camera opens via the device's native camera app rather than an in-browser preview. Face quality checks run after the photo is taken.

Try the local demo

Build the SDK at the repository root, then run the demo:

npm install
npm run build

cd demo
npm install
npm run dev

The demo runs at http://localhost:4173 and consumes the built SDK artifact from dist/. To enable HTTPS (required for camera access from other devices on the local network), set DEMO_USE_HTTPS=true before starting the demo.

The published demo starts with the hosted demo backend URL by default so GitHub Pages users can try the flow immediately. Override the API URL if you want to point it at a local or alternate backend.