Methods
Complete reference for all Circadify Web SDK methods.
Reference for all public methods on the CircadifySDK instance.
measureVitals(options?)
Runs the full measurement flow: camera access, scan capture, upload, and result delivery. Returns a promise that resolves with the vital signs result.
The SDK is headless — you render the <video> element and any overlays. The SDK drives the camera, measurement preparation, and upload, and emits per-frame events via the callbacks set on the constructor.
const result = await sdk.measureVitals({
videoElement: document.getElementById('preview') as HTMLVideoElement,
demographics: { age: 35, sex: 'M', fitzpatrick: 3 },
signal: abortController.signal,
});typescriptParameters (MeasurementOptions):
| Name | Type | Required | Description |
|---|---|---|---|
videoElement | HTMLVideoElement | No | Caller-owned <video>. The SDK binds the camera stream to it. If omitted, the SDK creates an off-DOM video. Either way, onCameraReady fires with the stream and video element once the camera is acquired — on every measureVitals() call. |
demographics | Demographics | No | User demographics to improve accuracy. |
signal | AbortSignal | No | Cancel the measurement mid-scan via AbortController. |
constraints | MediaTrackConstraints | No | Extra video-track constraints for camera acquisition, deep-merged over the SDK defaults (facingMode: 'user', width: { ideal: 640 }, height: { ideal: 480 }, frameRate: { max: 30 }). Per-constraint objects merge key-by-key ({ width: { min: 320 } } → width: { ideal: 640, min: 320 }); scalar values replace the default outright ({ facingMode: 'environment' } selects the rear camera). Audio is never requested regardless of what you pass. |
Demographics:
interface Demographics {
age?: number;
sex?: 'M' | 'F';
fitzpatrick?: 1 | 2 | 3 | 4 | 5 | 6;
}typescriptReturns: Promise<VitalSignsResult>
interface VitalSignsResult {
heartRate: number; // BPM (always present)
hrv?: number; // Heart rate variability (ms)
respiratoryRate?: number; // Breaths per minute
spo2?: number; // Blood oxygen saturation (%)
systolicBp?: number; // Systolic blood pressure (mmHg)
diastolicBp?: number; // Diastolic blood pressure (mmHg)
confidence: number; // 0-1 measurement reliability
sessionId: string; // Unique session identifier
timestamp: number; // Unix timestamp (ms)
isFallback?: boolean; // true ONLY for synthetic placeholder results
// (requires opt-in allowFallbackVitals; absent on real measurements)
}typescriptA confidence above 0.7 indicates a reliable measurement. Below 0.4 suggests quality issues and should usually prompt a retry.
If isFallback is true, the result contains synthetic placeholder values, not measurements — it always carries confidence: 0 and only occurs when you explicitly enabled allowFallbackVitals (default off). Never display a fallback result as a measured vital. When the option is off (the default), failed measurements throw instead, and isFallback is always absent.
Errors thrown:
| Error Code | When |
|---|---|
MISSING_API_KEY | No API key was provided — thrown synchronously by the constructor, not by measureVitals() |
CAMERA_PERMISSION_DENIED | User denied camera access |
CAMERA_NOT_AVAILABLE | No camera found on the device |
CAMERA_IN_USE | Camera is already in use by another application |
FACE_NOT_DETECTED | Declared but not currently thrown by 4.x — face absence surfaces as FACE_DETECTION_TIMEOUT instead |
FACE_DETECTION_TIMEOUT | The readiness gate (face detection + lighting + stillness + pose) did not pass within 30 seconds — a detected face in poor lighting for 30 seconds also triggers it |
QUALITY_TOO_LOW | Declared but not currently thrown by 4.x — quality problems surface as quality warnings mid-scan or as PROCESSING_FAILED after upload |
WASM_LOAD_FAILED | Required SDK runtime assets failed to load |
BROWSER_NOT_SUPPORTED | Browser lacks navigator.mediaDevices.getUserMedia — the only API this check tests; a missing WebAssembly runtime surfaces as WASM_LOAD_FAILED instead |
RATE_LIMITED | Sandbox (ck_test_) request rate limit exceeded (retryable — back off first) |
QUOTA_EXCEEDED | Monthly scan quota exhausted on a live key (not retryable — do not build retry loops on it) |
CANCELLED | The AbortController signal was triggered |
NETWORK_ERROR | Network request failed (retryable) |
UPLOAD_FAILED | Secure upload failed (retryable) |
TIMEOUT | Capture missed its 60-second frame deadline, or polling for results timed out (retryable) |
This is the common subset — see Error Codes for the complete list (including session, processing, and API errors) and per-code retry guidance.
Building UI from per-frame callbacks
Render quality meters, face overlays, and progress UI from the callbacks set on the SDK constructor. See Configuration for the full list. The most common are onProgress, onQualityState, and onLandmarks.
const sdk = new CircadifySDK({
apiKey: 'ck_live_your_key_here',
onProgress: (e) => updateProgressBar(e.phase, e.percent),
onQualityState: (q) => updateQualityMeters(q),
onLandmarks: (lm) => renderFaceOverlay(lm), // 2D canvas; or use CircadifyScanView for a ready-made glow overlay
});
const result = await sdk.measureVitals({ videoElement: myVideoEl });typescriptFor the face/heat-glow visual, mount CircadifyScanView from the Web SDK's React bindings rather than building it from onLandmarks. If you need a custom overlay, prefer a 2D <canvas> — see Custom UI → Face overlay. Avoid a hand-rolled three.js / @react-three/fiber overlay (Advanced: a 3D (r3f) overlay has the rules and the known freeze bug).
checkCameraAccess()
Checks whether the device has a usable camera by briefly acquiring (and immediately releasing) a video stream. Because it calls getUserMedia, it will trigger the browser's camera-permission prompt if the user has not already granted or denied access for your site. Call it at a moment where a permission prompt is acceptable — not silently on page load.
const hasCamera = await sdk.checkCameraAccess();
if (!hasCamera) {
showMessage('Camera not available on this device.');
}typescriptReturns: Promise<boolean>
getDeviceCapabilities()
Returns a coarse, synchronous check of the browser's camera API support. It does not enumerate devices or probe hardware.
const capabilities = sdk.getDeviceCapabilities();
console.log(capabilities.hasCamera); // true if mediaDevices.getUserMedia exists
console.log(capabilities.hasFrontCamera); // the same API-presence check — NOT a hardware probe
console.log(capabilities.isSecureContext); // true (HTTPS)typescriptReturns: DeviceCapabilities
interface DeviceCapabilities {
hasCamera: boolean; // navigator.mediaDevices.getUserMedia exists
hasFrontCamera: boolean; // identical check — true does NOT guarantee a front camera
isSecureContext: boolean; // window.isSecureContext
mediaDevicesSupported: boolean;
maxResolution?: { width: number; height: number }; // reserved — never populated in 4.x
}typescripthasCamera, hasFrontCamera, and mediaDevicesSupported are all the same API-presence check (navigator.mediaDevices.getUserMedia exists) — no device enumeration is performed. hasFrontCamera can be true on a device with no front camera at all, and maxResolution is never populated. Don't gate UX on hasFrontCamera. To find out whether a usable camera actually exists, call checkCameraAccess() (which triggers a permission prompt) or handle CAMERA_NOT_AVAILABLE from measureVitals().
cancel()
Tears down the scanner mid-measurement. It is not equivalent to aborting an AbortSignal — its reach depends on the phase:
- Readiness / capture: reliable. The scanner is destroyed, the camera is released, and the
measureVitals()promise rejects withCANCELLED. - Uploading / processing:
cancel()does not abort the in-flight upload request or result polling — those honor only theAbortSignalyou passed tomeasureVitals(). The measurement keeps running and can still resolve or reject normally.
sdk.cancel();typescriptFor full-lifecycle cancellation, pass an AbortSignal to measureVitals() and abort it — that cancels every phase, including upload and polling:
const controller = new AbortController();
const promise = sdk.measureVitals({ videoElement, signal: controller.signal });
// later, from any phase:
controller.abort(); // promise rejects with code CANCELLEDtypescriptdestroy()
Releases all resources, including active camera streams and SDK runtime resources.
sdk.destroy();typescriptCall destroy() when the SDK is no longer needed — for example, on component unmount.
After destroy(), the instance cannot be reused. Create a new CircadifySDK instance for another measurement.
React cleanup example
useEffect(() => {
const sdk = new CircadifySDK({ apiKey: 'ck_live_your_key_here' });
// ...use sdk
return () => sdk.destroy();
}, []);typescriptThe Web SDK's React bindings' <CircadifyProvider> does this automatically when it unmounts.
Next Steps
- Configuration — All SDK options and per-frame callbacks
- Events — Progress and quality events
- Error Codes — Full error reference