Selfie Module
Selfie Module Guide
This guide is specific to Web SDK 2.0. If you are still using 1.x, you can find documentation here. Contact your Incode Representative for upgrade information and check if you are a candidate for this upgrade.
The Selfie module captures a user's face with ML-powered liveness detection to prevent spoofing.
Follows the camera-capture pattern. See that page for the shared manager lifecycle, capture sub-states, and skeleton; the rest of this page covers Selfie-specific config, detection statuses, and methods.
Tag
<incode-selfie> is a standard Web Component. Importing the UI subpath registers the custom element; importing the CSS applies the module's styles.
import '@incodetech/web/selfie';
import '@incodetech/web/selfie/styles.css';
Properties
Set these as JavaScript properties on the element (not as HTML attributes):
| Property | Type | Required | Description |
|---|---|---|---|
config |
SelfieConfig |
❌ | Configuration options (validation flags, modes) |
onFinish |
() => void |
❌ | Called when capture completes successfully |
onError |
(error: string) => void |
❌ | Called when an error occurs |
WASM Requirements
The Selfie module uses WebAssembly for face detection and liveness analysis. Pre-warm WASM during setup() so models are ready before the user reaches the camera step:
await setup({
apiURL: 'https://demo-api.incodesmile.com',
token: 'your-session-token',
wasm: { pipelines: ['selfie'] },
});
See WASM Configuration for self-hosted paths and the lower-level warmupWasm() API.
Usage
Vanilla HTML / TypeScript
<incode-selfie></incode-selfie>
<script type="module">
import { setup } from '@incodetech/core';
import '@incodetech/web/selfie';
import '@incodetech/web/selfie/styles.css';
await setup({
apiURL: 'https://demo-api.incodesmile.com',
token: 'your-session-token',
wasm: { pipelines: ['selfie'] },
});
const selfie = document.querySelector('incode-selfie');
selfie.onFinish = () => console.log('Selfie captured!');
selfie.onError = (err) => console.error('Selfie error:', err);
</script>
React
import { useEffect, useRef } from 'react';
import { setup } from '@incodetech/core';
import type { SelfieConfig } from '@incodetech/core/selfie';
import '@incodetech/web/selfie';
import '@incodetech/web/selfie/styles.css';
type SelfieElement = HTMLElement & {
config?: SelfieConfig;
onFinish: () => void;
onError: (error: string) => void;
};
await setup({
apiURL: 'https://demo-api.incodesmile.com',
token: 'your-session-token',
wasm: { pipelines: ['selfie'] },
});
export function SelfieCapture() {
const ref = useRef<SelfieElement>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
el.onFinish = () => console.log('Selfie captured!');
el.onError = (err) => console.error('Selfie error:', err);
}, []);
return <incode-selfie ref={ref} />;
}
Headless Mode
For complete UI control, use the createSelfieManager from @incodetech/core/selfie.
Quick Start
import { setup } from '@incodetech/core';
import { createSelfieManager } from '@incodetech/core/selfie';
import { warmupWasm } from '@incodetech/core/wasm';
await setup({
apiURL: 'https://demo-api.incodesmile.com',
token: 'your-session-token',
});
await warmupWasm({
wasmPath: '/wasm/webLib.wasm',
glueCodePath: '/wasm/webLib.js',
modelsBasePath: '/wasm/models',
pipelines: ['selfie'],
});
const manager = createSelfieManager({
config: {
showTutorial: true,
autoCaptureTimeout: 10,
validateLenses: true,
validateFaceMask: true,
},
});
manager.subscribe((state) => {
console.log('Status:', state.status);
if (state.status === 'capture') {
console.log('Detection:', state.detectionStatus);
console.log('Stream ready:', !!state.stream);
}
if (state.status === 'finished') {
console.log('Selfie captured!', state.processResponse);
manager.stop();
}
});
manager.load();
State Machine Flow
load
nextStep
granted
upload done
success
idle
tutorial
permissions
capture
processing
finished
States Reference
| Status | Description | Key Properties |
|---|---|---|
idle |
Initial state, waiting for load() |
– |
loading |
Checking permissions (when no tutorial) | – |
tutorial |
Showing tutorial. Entered when showTutorial is true orageAssurance is true |
ageAssurance (boolean; mirrors config.ageAssurance) |
permissions |
Camera permission handling | permissionStatus |
capture |
Camera active, detecting face | stream, captureStatus, detectionStatus, attemptsRemaining |
processing |
Server-side processing of the captured selfie | – |
finished |
Capture complete | processResponse? |
closed |
User closed the flow | – |
error |
Fatal error occurred | error |
Capture State Properties
| Property | Type | Description |
|---|---|---|
stream |
CameraStream |
Camera stream for <video> element |
captureStatus |
string |
Current status of the capture |
detectionStatus |
DetectionStatus |
Face detection feedback |
attemptsRemaining |
number |
Remaining capture attempts |
uploadError |
string? |
Error message if upload failed |
assistedOnboarding |
boolean |
Whether assisted onboarding mode is active |
debugFrame |
ImageData? |
Latest processed frame (for debugging) |
Detection Status Values
| Status | User Instruction |
|---|---|
idle |
"Preparing camera..." |
detecting |
"Detecting face..." |
noFace |
"Position your face in the frame" |
tooManyFaces |
"Only one face should be visible" |
tooClose |
"Move back" |
tooFar |
"Move closer" |
blur |
"Hold still, image is blurry" |
dark |
"Improve lighting conditions" |
faceAngle |
"Face your camera directly" |
headWear |
"Remove head coverings" |
lenses |
"Remove glasses or lenses" |
eyesClosed |
"Open your eyes" |
faceMask |
"Remove face mask" |
centerFace |
"Center your face" |
getReady |
"Get ready..." |
getReadyFinished |
"Hold still..." |
capturing |
"Capturing photo..." |
manualCapture |
"Tap to capture" |
offline |
"No network connection" |
API Methods
| Method | Description | When to Use |
|---|---|---|
load() |
Starts the selfie flow | Always call first |
nextStep() |
Advances from tutorial to permissions | When tutorial |
requestPermission() |
Requests camera access | When permissions.idle or permissions.learnMore |
capture() |
Manual capture trigger | When detectionStatus === 'manualCapture' |
close() |
Close the flow | Anytime |
stop() |
Cleanup resources | When unmounting |
getState() |
Returns current state | Anytime |
subscribe(callback) |
Subscribe to state changes | Returns unsubscribe function |
Capture-only flow
createSelfieCaptureOnlyManager exposes the same state machine and API surface as createSelfieManager, but bypasses Incode's /omni/add/face upload. Instead of submitting the captured frame and waiting on server-side processing, the manager invokes a customer-supplied onCapture(response) callback with the raw face image.
The config is SelfieConfig plus a required onCapture callback — enforced at compile time:
import { setup } from '@incodetech/core';
import { initializeSession } from '@incodetech/core/session';
import { createSelfieCaptureOnlyManager, type SelfieCaptureOnlyConfig, type FaceCaptureOnlyResponse } from '@incodetech/core/selfie';
const config: SelfieCaptureOnlyConfig = {
showTutorial: true,
showPreview: false,
captureAttempts: 3,
validateLenses: true,
onCapture: async (response: FaceCaptureOnlyResponse) => {
const { image } = response;
await uploadToMyBackend(image.blob);
},
};
const manager = createSelfieCaptureOnlyManager({ config });
manager.load();
Configuration Options
SelfieConfig is FlowModuleConfig['SELFIE'] & BaseFaceCaptureConfig. Here are some options you can configure:
| Option | Type | Required | Description |
|---|---|---|---|
showTutorial |
boolean |
✅ | Show tutorial before capture |
showPreview |
boolean |
✅ | Show preview after capture |
enableFaceRecording |
boolean |
✅ | Enable video recording of the capture |
autoCaptureTimeout |
number |
✅ | Seconds before auto-capture triggers |
captureAttempts |
number |
✅ | Maximum capture attempts |
validateLenses |
boolean |
✅ | Reject captures with glasses/lenses |
validateFaceMask |
boolean |
✅ | Reject captures with face mask |
validateBrightness |
boolean |
✅ | Reject captures with poor lighting |
deepsightLiveness |
`'SINGLE_FRAME' | 'MULTIMODAL' | 'VIDEOLIVENESS'` |
Troubleshooting
Face Not Detected
- Ensure good lighting (avoid backlighting)
- Remove glasses or hats if possible
- Position face within the outline
Camera Issues
- Ensure HTTPS (camera requires secure context)
- Check browser permissions