πŸŽ‰ @facesmash/sdk v0.1.0 is now available on npm β€” Read the docs β†’
FaceSmash Docs
JavaScript SDK

SDK Overview

The FaceSmash JavaScript SDK for browser-based facial recognition

The FaceSmash SDK (@facesmash/sdk) provides everything you need to add facial recognition authentication to any web application. It runs entirely in the browser using WebGL-accelerated TensorFlow.js neural networks β€” no server-side ML infrastructure required.

npm install @facesmash/sdk

v0.1.0 β€” The SDK is published on npm and ready for integration. View on npm β†’ View source on GitHub β†’


What the SDK Does

FaceSmash handles the complete biometric authentication pipeline:

  1. Model Loading β€” Downloads and initializes five neural networks (SSD MobileNet v1, TinyFaceDetector, FaceLandmark68, FaceRecognition, FaceExpression) into the browser's WebGL runtime. Models are loaded from a CDN (jsdelivr by default) and cached by the browser.

  2. Face Detection β€” Finds faces in webcam frames using SSD MobileNet v1 as the primary detector. If SSD fails to find a face above the confidence threshold, it automatically falls back to TinyFaceDetector (smaller, faster, less accurate).

  3. Quality Analysis β€” Scores each detected face on multiple dimensions before using it for matching:

    • Detection confidence β€” SSD MobileNet's raw detection score
    • Lighting β€” Measures brightness, contrast, and evenness across the face region
    • Head pose β€” Estimates yaw, pitch, and roll from facial landmarks; rejects non-frontal faces
    • Face size β€” Ensures the face is between 2% and 65% of the frame area
    • Eye aspect ratio β€” Detects if eyes are open (liveness signal)
  4. Descriptor Extraction β€” Extracts a 128-dimensional floating-point vector (face descriptor) from the detected face using the FaceRecognition neural network. This is the mathematical representation of the face.

  5. Matching β€” Compares the extracted descriptor against all registered user profiles and their stored templates using enhanced Euclidean distance matching with adaptive thresholds that adjust based on lighting conditions.

  6. Registration β€” Creates a new user profile in PocketBase, stores the face embedding, creates an initial face template, and records a face scan entry.

  7. Adaptive Learning β€” On each successful login, the SDK updates the user's stored face embedding using a weighted average (learning rate based on quality, lighting, and confidence). High-quality scans are also saved as additional face templates, improving future matching accuracy.


Package Structure

Entry Points

Import PathFormatDescription
@facesmash/sdkESM + CJSCore client, detection utilities, matching utilities, all TypeScript types
@facesmash/sdk/reactESM + CJSReact provider, components (FaceLogin, FaceRegister), and hooks

Both entry points include full TypeScript type declarations (.d.ts).

What's Exported from @facesmash/sdk

// Factory function (recommended)
import { createFaceSmash } from '@facesmash/sdk';

// Class (alternative)
import { FaceSmashClient } from '@facesmash/sdk';

// Low-level detection utilities
import {
  loadModels,
  areModelsLoaded,
  extractDescriptor,
  analyzeFace,
  processImages,
  normalizeDescriptor,
} from '@facesmash/sdk';

// Low-level matching utilities
import {
  calculateSimilarity,
  facesMatch,
  enhancedMatch,
  multiTemplateMatch,
  calculateLearningWeight,
} from '@facesmash/sdk';

// TypeScript types
import type {
  FaceSmashConfig,
  ResolvedConfig,
  FaceAnalysis,
  MatchResult,
  MultiTemplateMatchResult,
  LoginResult,
  RegisterResult,
  UserProfile,
  FaceTemplate,
  HeadPose,
  FaceSizeCheck,
  LightingAnalysis,
  OnProgress,
  FaceSmashEvent,
  FaceSmashEventListener,
} from '@facesmash/sdk';

What's Exported from @facesmash/sdk/react

// Provider (required, wraps your app)
import { FaceSmashProvider } from '@facesmash/sdk/react';

// Drop-in components
import { FaceLogin, FaceRegister } from '@facesmash/sdk/react';

// Hooks
import {
  useFaceSmash,
  useFaceLogin,
  useFaceRegister,
  useFaceAnalysis,
} from '@facesmash/sdk/react';

// All core exports are also re-exported
import { createFaceSmash, FaceSmashClient } from '@facesmash/sdk/react';

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Your Application                           β”‚
β”‚                                                                   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  React Components       β”‚  β”‚  Vanilla JS                     β”‚ β”‚
β”‚  β”‚  <FaceSmashProvider>    β”‚  β”‚  const client = createFaceSmash()β”‚ β”‚
β”‚  β”‚  <FaceLogin>            β”‚  β”‚  client.init()                  β”‚ β”‚
β”‚  β”‚  <FaceRegister>         β”‚  β”‚  client.login(images)           β”‚ β”‚
β”‚  β”‚  useFaceLogin()         β”‚  β”‚  client.register(name, images)  β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚               β”‚                              β”‚                     β”‚
β”‚               β–Ό                              β–Ό                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚              FaceSmashClient (Core)                          β”‚   β”‚
β”‚  β”‚                                                             β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚   β”‚
β”‚  β”‚  β”‚  detection.ts β”‚  β”‚  matching.ts   β”‚  β”‚  types.ts      β”‚  β”‚   β”‚
β”‚  β”‚  β”‚              β”‚  β”‚                β”‚  β”‚                β”‚  β”‚   β”‚
β”‚  β”‚  β”‚  loadModels  β”‚  β”‚  enhanced-     β”‚  β”‚  FaceSmash-    β”‚  β”‚   β”‚
β”‚  β”‚  β”‚  analyzeFace β”‚  β”‚    Match       β”‚  β”‚    Config      β”‚  β”‚   β”‚
β”‚  β”‚  β”‚  extract-    β”‚  β”‚  multi-        β”‚  β”‚  FaceAnalysis  β”‚  β”‚   β”‚
β”‚  β”‚  β”‚    Descriptorβ”‚  β”‚    Template-   β”‚  β”‚  LoginResult   β”‚  β”‚   β”‚
β”‚  β”‚  β”‚  normalize-  β”‚  β”‚    Match       β”‚  β”‚  RegisterResultβ”‚  β”‚   β”‚
β”‚  β”‚  β”‚    Descriptorβ”‚  β”‚  calculate-    β”‚  β”‚  UserProfile   β”‚  β”‚   β”‚
β”‚  β”‚  β”‚  estimate-   β”‚  β”‚    Similarity  β”‚  β”‚  Events        β”‚  β”‚   β”‚
β”‚  β”‚  β”‚    HeadPose  β”‚  β”‚  calculate-    β”‚  β”‚                β”‚  β”‚   β”‚
β”‚  β”‚  β”‚  analyze-    β”‚  β”‚    Learning-   β”‚  β”‚                β”‚  β”‚   β”‚
β”‚  β”‚  β”‚    Lighting  β”‚  β”‚    Weight      β”‚  β”‚                β”‚  β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚               β”‚                              β”‚                     β”‚
β”‚               β–Ό                              β–Ό                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚  @vladmandic/face-apiβ”‚      β”‚  PocketBase REST API        β”‚     β”‚
β”‚  β”‚  TF.js + WebGL      β”‚      β”‚  api.facesmash.app           β”‚     β”‚
β”‚  β”‚  5 Neural Networks  β”‚      β”‚                             β”‚     β”‚
β”‚  β”‚  jsdelivr CDN       β”‚      β”‚  Collections:               β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚  β”œβ”€β”€ user_profiles          β”‚     β”‚
β”‚                               β”‚  β”œβ”€β”€ face_templates         β”‚     β”‚
β”‚                               β”‚  β”œβ”€β”€ face_scans             β”‚     β”‚
β”‚                               β”‚  └── sign_in_logs           β”‚     β”‚
β”‚                               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Data Flow: Login

  1. User faces the camera
  2. SDK captures 3 webcam frames (configurable) at 500ms intervals
  3. Each frame is analyzed: face detection β†’ quality scoring β†’ descriptor extraction
  4. The highest-quality frame's descriptor is selected
  5. SDK fetches all user_profiles from PocketBase
  6. For each profile, it runs enhancedMatch() against the stored face_embedding
  7. If the profile has face_templates, it also runs multiTemplateMatch() and uses the better result
  8. If a match is found (similarity β‰₯ adaptive threshold), the user is authenticated
  9. A sign_in_logs entry and face_scans entry are created
  10. If quality is high enough (>0.5), the stored embedding is updated via weighted averaging
  11. If quality is very high (>0.6), a new template is stored (oldest template is evicted if at max)

Data Flow: Registration

  1. User faces the camera and provides their name
  2. SDK captures 3 webcam frames and selects the best
  3. SDK checks all existing user_profiles for duplicate faces (similarity β‰₯ 0.75)
  4. If no duplicate, creates a user_profiles record with the face embedding
  5. Creates an initial face_templates record labeled registration
  6. Creates a face_scans record of type registration

Neural Networks

The SDK loads five neural networks from @vladmandic/face-api:

ModelSizePurpose
SSD MobileNet v1~5.4 MBPrimary face detector β€” accurate, reliable
TinyFaceDetector~190 KBFallback detector β€” fast, lightweight
FaceLandmark68~350 KB68-point facial landmark detection for head pose estimation
FaceRecognition~6.2 MB128-dimensional face descriptor extraction
FaceExpression~310 KBFacial expression classification (used for liveness signals)

Total download: ~12.5 MB (cached by the browser after first load).

All models are loaded in parallel from the jsdelivr CDN by default. You can host them yourself by setting modelUrl in the configuration.


Browser Requirements

Required APIs

APIPurposeFallback
WebGLTF.js GPU acceleration for neural network inferenceNone β€” required
getUserMediaCamera access for capturing face imagesNone β€” required
Canvas 2DFrame capture and lighting analysisNone β€” required
localStorageUsed by PocketBase client for auth tokensNone β€” required

Supported Browsers

BrowserMin VersionNotes
Chrome80+Best WebGL performance; recommended
Firefox78+Full support
Safari14+Requires user gesture for camera; slower WebGL
Edge80+Chromium-based; same as Chrome
Mobile Chrome80+Works on Android; front camera used by default
Mobile Safari14+Works on iOS; requires HTTPS

HTTPS Required β€” getUserMedia is only available on secure origins (https:// or localhost). The SDK will not work on plain HTTP in production.

Performance

DeviceModel LoadDetection (per frame)Full Login Flow
Modern laptop (M1/i7)2–4 seconds30–80 ms3–5 seconds
Mid-range phone4–8 seconds60–150 ms5–10 seconds
Older laptop (2018)5–10 seconds100–200 ms8–15 seconds

Dependencies

PackageVersionPurpose
@vladmandic/face-api^1.7.15Face detection, landmarks, recognition (wraps TF.js)
pocketbase^0.26.8Client for PocketBase REST API

Peer Dependencies (optional)

PackageVersionWhen Needed
react>=17Only if using @facesmash/sdk/react
react-dom>=17Only if using @facesmash/sdk/react

Quick Example: React

import { FaceSmashProvider, FaceLogin } from '@facesmash/sdk/react';

function App() {
  return (
    <FaceSmashProvider
      config={{
        apiUrl: 'https://api.facesmash.app',
        debug: true,
      }}
      onReady={() => console.log('Models loaded')}
      onError={(err) => console.error('Init failed:', err)}
    >
      <FaceLogin
        onResult={(result) => {
          if (result.success) {
            console.log('Welcome back,', result.user.name);
            console.log('Match similarity:', result.similarity);
          } else {
            console.error('Login failed:', result.error);
          }
        }}
        className="w-full h-80 rounded-xl overflow-hidden"
      />
    </FaceSmashProvider>
  );
}

Quick Example: Vanilla JS

import { createFaceSmash } from '@facesmash/sdk';

const client = createFaceSmash({
  apiUrl: 'https://api.facesmash.app',
  debug: true,
});

// Subscribe to events
const unsubscribe = client.on((event) => {
  if (event.type === 'models-loading') {
    console.log(`Loading: ${event.progress}%`);
  }
});

// Initialize models
await client.init();

// Login with webcam captures (array of base64 data URLs)
const result = await client.login(images);

if (result.success) {
  console.log('Welcome back,', result.user.name);
  console.log('Email:', result.user.email);
  console.log('Similarity:', result.similarity);
} else {
  console.error(result.error);
}

// Cleanup
unsubscribe();

Next Steps

  • React Components β€” <FaceLogin>, <FaceRegister>, provider, and all 4 hooks with full prop tables
  • Vanilla JS β€” createFaceSmash(), client.login(), client.register(), low-level utilities, and complete webcam capture examples
  • Configuration β€” Every config option explained, threshold tuning guide, event system, PocketBase collections, and self-hosting
  • Quickstart β€” Get a working face login in 5 minutes

On this page