Warning
This guide is specific to Web SDK 2.x. For Web SDK 1.x, you can find documentation here.
Do not attempt to upgrade or implement without support. Contact your Incode representative to check if you are a candidate for this upgrade.
The Video Selfie module runs selfie, ID, and optional voice-consent capture as one continuous camera session, recorded on-device and uploaded alongside the captures. The camera switches between front and rear while a single composited recording follows it, so the user sees one uninterrupted experience instead of a sequence of separate capture screens.
This module combines camera-capture and composite / orchestrator traits: it owns several capture steps and drives its own step progression.
Tag
<incode-video-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/video-selfie';
import '@incodetech/web/video-selfie/styles.css';
Properties
| Property | Type | Required | Description |
|---|---|---|---|
config |
VideoSelfieConfig |
❌ | Configuration options |
onFinish |
() => void |
❌ | Called when the session completes |
onError |
(error: string | undefined) => void |
❌ | Called when an error occurs |
Configuration
VideoSelfieConfig mirrors the backend VIDEO_ONBOARDING workflow module, so inside <incode-flow> or <incode-workflow> the orchestrator supplies it from Dashboard. Standalone integrators set it on config directly.
config.steps can explicitly select and order the capture steps. When absent or empty, the SDK derives the order from options such as checkIdScan and checkVoiceConsent.
| Option | Type | Description |
|---|---|---|
steps |
VideoSelfieStep[] |
Optional ordered capture steps. An absent or empty list uses the derived order. |
maxWaitingVideoSelfieFile |
number |
Maximum recording duration in seconds, supplied by Dashboard. It is not an upload timeout. |
useAsSelfie |
boolean |
Treat the captured selfie as the session's selfie, so a separate Selfie step is unnecessary. |
showTutorials |
boolean |
Show the tutorial screen before capture. When false, the module starts at the permission step. |
companyName |
string |
Company name shown in the consent copy. |
checkLiveness |
boolean |
Run liveness checks on the selfie step. |
checkIdScan |
boolean |
Add the front and back ID capture steps. |
checkDocumentScan |
boolean |
Add the proof-of-address document step. |
compareIdEnabled |
boolean |
Compare the captured face against the ID portrait. |
compareOcrEnabled |
boolean |
Compare OCR data from the front of the ID. |
compareBackIdEnabled |
boolean |
Compare against the back of the ID. |
compareBackOcrEnabled |
boolean |
Compare OCR data from the back of the ID. |
checkVoiceConsent |
boolean |
Add the spoken-consent step. |
voiceConsentQuestions |
number |
How many consent questions to ask. |
numberOfTries |
number |
Validation attempts per capture and voice step. Default 3; -1 means unlimited. |
speechToTextCheck |
boolean |
Validate the consent audio server-side. Default true. |
selfieQualityAffectsScore |
boolean |
Let selfie quality contribute to the session score. |
validateClosedEyes |
boolean |
Reject frames where the eyes are closed. |
validateFaceMask |
boolean |
Reject frames where a face mask is present. |
validateHeadCover |
boolean |
Reject frames where a head covering obscures the face. |
validateLenses |
boolean |
Reject frames where glasses or lenses interfere. |
Pass Dashboard-provided quality-check settings through unmodified. The recording duration limit applies to the active recording, including capture steps.
Steps
VideoSelfieStep is the set of capture steps a session can run, in flow order:
| Step | Camera | Description |
|---|---|---|
selfie |
Front | Face capture with liveness and quality checks. |
frontId |
Rear | Front of the ID document. |
backId |
Rear | Back of the ID document. |
poa |
Rear | Proof-of-address document. |
questions |
Front | On-screen consent questions. |
speech |
Front | Spoken consent, recorded for verification. |
For example, steps: ['selfie', 'frontId', 'backId'] keeps that order. A nonempty top-level steps option on createVideoSelfieRecordingManager takes precedence over config.steps. If both are absent or empty, the derived order is ID sides, optional proof of address, Selfie, then configured questions and speech.
State machine
VideoSelfieRecordingState carries a status plus live step and detection detail:
| Status | Description |
|---|---|
idle |
Initial state, waiting for start(). |
starting |
Acquiring the first camera and opening the upload. |
recording |
Capturing the active step. |
validationFeedback |
A validation check failed; the module dwells to show the reason before retrying. |
flippingId |
Prompting the user to turn the ID over between the front and back steps. |
switchingCamera |
Moving between front and rear cameras for the next step. |
finalizing |
Finishing the upload after the last step. |
success |
Upload accepted. Carries recordingId. |
finished |
Terminal. |
error |
Failed. Carries error and errorKind. |
aborted |
The session was abandoned without finalizing. |
State properties:
| Property | Type | Description |
|---|---|---|
step |
VideoSelfieStep? |
The active capture step. |
stepIndex |
number |
Zero-based index of the active step. |
isLastStep |
boolean |
Whether advancing finalizes the session. |
stream |
MediaStream? |
The raw camera for the active step. Render this as the preview. |
composite |
MediaStream? |
The composited recording output that follows camera switches. Not for preview. |
detectionStatus |
string? |
Live capture feedback for the active step — show it as guidance. |
orientation |
DetectionOrientation? |
Document orientation when the detector reports one, so an ID mask can follow a rotated document. undefined keeps the fixed frame. |
validationFailure |
object? |
Why the current attempt failed, during a validationFeedback dwell. |
attemptsRemaining |
number |
Attempts left on the active step. -1 means unlimited. |
recordingId |
string | null |
The completed upload id, available during success and finished. |
error |
string? |
Failure detail when status === 'error'. |
errorKind |
'connection' | 'technical' | 'maxVideoLengthReached' | 'validationAttemptsExhausted' |
Failure category; the duration-limit and exhausted-validation kinds cannot retry. |
API methods
| Method | Purpose | Callable when |
|---|---|---|
start() |
Acquire the camera, open the upload, and begin recording. | idle |
nextStep() |
Advance to the next step, switching cameras when needed. Finalizes on the last. | recording |
retry() |
Retry the active step after a validation failure or error. | validationFeedback; error only for recoverable connection or technical failures |
abort() |
Abandon the session without finalizing the upload. | Any active status |
Plus the universal lifecycle: subscribe, getState, stop.
Terminal errors
maxVideoLengthReached means the configured recording duration has elapsed. Do not offer retry. The SDK completes the recorded upload, briefly displays the limit message, then reaches finished so Flow can advance.
validationAttemptsExhausted means the allowed validation attempts have ended. Do not retry or restart that attempt in place. A standalone component reports it through onError with moduleErrorCode: 'VIDEO_SELFIE_VALIDATION_ATTEMPTS_EXHAUSTED'. Flow handles that terminal module outcome by advancing the configured journey; it is not a successful verification result.
Headless hosts should branch on errorKind, preserve session-result handling, and stop the manager when leaving the surface.
Headless usage
import { setup } from '@incodetech/core';
import { createVideoSelfieRecordingManager } from '@incodetech/core/video-selfie';
await setup({ apiURL, token });
const manager = createVideoSelfieRecordingManager({ config });
manager.subscribe((state) => {
if (state.status === 'recording') {
renderPreview(state.stream, {
step: state.step,
guidance: state.detectionStatus,
attemptsLeft: state.attemptsRemaining,
});
}
if (state.status === 'finished') {
onDone(state.recordingId);
}
});
manager.start();
Render state.stream as the preview, not state.composite — the composite exists to keep one continuous recording across camera switches.
Creating the manager starts its required WASM warmup. manager.start() waits for that warmup before it acquires the camera, and reports a retryable technical error if warmup fails.
@incodetech/core/video-selfie also exports helpers for building your own capture screen: resolveVideoSelfieSteps (which steps a config runs), facingModeForStep, createVideoSelfieCameraWarmer (warm the camera before the user reaches the step), getVideoSelfieQuestions and getVoiceConsentPhrase (consent copy), and createConsentRecorder.
App background recovery
When the browser moves to the background, the module pauses recording and capture validation. The open upload and completed video chunks remain unchanged.
When the browser returns, the module waits for a new camera frame before it resumes recording. The module acquires the video camera again if necessary.
If the audio track or recorder cannot recover, the module reports a technical error. The user can retry with a new recording.
The module does not complete a recording with a frozen background interval.
WASM requirement
The resolved steps determine pipelines: selfie needs videoSelfie; frontId or backId needs videoSelfieId. This also applies to explicit step lists. The Core recording manager automatically loads exactly what its config needs. You can still call warmupVideoSelfieWasm(config, steps) earlier for explicit preloading, or derive the list with videoSelfieWasmPipelines(config, steps) and pass it to setup({ wasm: { pipelines } }).
See also
- Module Patterns → camera-capture
- WASM Configuration
- Module: Selfie: the single-step selfie capture module
- Individual Modules