Skip to content

Events

The SDK is headless — all UI state flows through callbacks set on the constructor. This page covers the lifecycle and per-frame events; see Configuration for the full callback reference.

Register callbacks when creating the SDK instance. They remain active for all measureVitals() calls on that instance.

import { CircadifySDK } from '@circadify/web-sdk';
const sdk = new CircadifySDK({
apiKey: 'ck_live_your_key_here',
onProgress: (e) => console.log(`${e.phase}: ${e.percent}%`),
onQualityState: (q) => updateQualityMeters(q),
onQualityWarning: (w) => showToast(w.message),
onLandmarks: (lm) => renderFaceMesh(lm),
onCameraReady: ({ stream }) => mirrorStream(stream),
});

To stop receiving events, call sdk.destroy(). There is no per-callback unsubscribe mechanism — callbacks are tied to the SDK instance lifecycle.

The onProgress callback fires as the measurement moves through each phase. Use it to update progress bars, status text, or step indicators.

interface ProgressEvent {
phase: 'initializing' | 'readiness' | 'capturing' | 'uploading' | 'processing';
percent: number; // 0–100
elapsed: number;
remaining?: number;
}
PhaseDescriptionTypical Duration
initializingLoading WASM modules and initializing the Vision Engine2–5 s (first load), under 100 ms (cached)
readinessWaiting for face detection and quality checks to passUser-dependent
capturingRecording and preprocessing video frames~24 s
uploadingSending preprocessed data to the server5-30 s (network dependent)
processingServer-side inference and signal processing60-90 s

The onQualityState callback fires every frame during readiness and capture with the full quality picture. Use it to drive live quality meters or pills.

interface QualityState {
lighting: { brightness: number; stability: number; isOk: boolean; /* … */ };
motion: { motionMagnitude: number; isStill: boolean };
pose: { yaw: number; pitch: number; isFacingForward: boolean };
isReady: boolean;
messages: string[];
}
const sdk = new CircadifySDK({
apiKey: 'ck_live_your_key_here',
onQualityState: (q) => {
setLightingPill(q.lighting.isOk ? 'good' : 'warn');
setMotionPill(q.motion.isStill ? 'good' : 'warn');
setPosePill(q.pose.isFacingForward ? 'good' : 'warn');
setReady(q.isReady);
},
});

The onQualityWarning callback fires on transient quality drops. Use it for short-lived toasts; use onQualityState for sustained UI state.

interface QualityWarning {
type: 'lighting' | 'motion' | 'face_position' | 'occlusion';
severity: 'low' | 'medium' | 'high';
message: string;
}
Warning TypeTriggerExample Message
lightingScene is too dark, too bright, or has flickering light”Improve lighting conditions for a better scan”
motionExcessive head or body movement detected”Hold still during the scan”
face_positionHead is turned, tilted, or too far from camera”Center your face in the frame”
occlusionPart of the face is blocked (hand, mask, etc.)”Make sure your face is fully visible”
SeverityMeaning
lowMinor degradation; measurement can still proceed
mediumNoticeable impact on accuracy; user should correct
highMeasurement quality is severely compromised; prompt the user immediately

The onLandmarks callback emits the full 468-point face mesh from MediaPipe every frame. Use it to render a custom face overlay, thermal glow, or any geometry-driven UI:

const sdk = new CircadifySDK({
apiKey: 'ck_live_your_key_here',
onLandmarks: (landmarks) => {
canvasRenderer.drawMesh(landmarks);
},
});

Errors during measureVitals() are thrown as CircadifyError exceptions, not delivered via callbacks. Wrap your measurement call in a try/catch block to handle failures.

import { CircadifySDK, CircadifyError, CircadifyErrorCode } from '@circadify/web-sdk';
try {
const result = await sdk.measureVitals({ videoElement: myVideoEl });
} catch (error) {
if (error instanceof CircadifyError) {
if (error.isRetryable) {
showRetryPrompt(error.message);
} else {
showError(error.message);
}
}
}

See Error Codes for the full list of error codes and recovery strategies.