Circadify

Configuration

Configure the Circadify Web SDK with all available options.

The SDK accepts a configuration object when you create a new CircadifySDK instance. Only apiKey is required.

Basic Configuration

import { CircadifySDK } from '@circadify/web-sdk';
 
const sdk = new CircadifySDK({
  apiKey: 'ck_live_your_key_here',
});
typescript

Full Configuration

const sdk = new CircadifySDK({
  apiKey: 'ck_live_your_key_here',
  baseUrl: 'https://api.circadify.com',
  measurementDuration: 30, // accepted but currently a no-op — see the table below
  debug: false,
  onDeviceOnly: true,
  allowFallbackVitals: false, // default — keep off; see "Fallback Vitals" below
 
  // Per-frame callbacks for rendering custom UI:
  onProgress:        (e) => { /* phase + percent */ },
  onQualityState:    (q) => { /* full per-frame quality */ },
  onQualityWarning:  (w) => { /* transient warnings */ },
  onLandmarks:       (lm) => { /* normalized face landmarks */ },
  onCameraReady:     ({ stream, video }) => { /* mirror stream */ },
});
typescript

Configuration Reference

OptionTypeDefaultDescription
apiKeystringRequired. Your API key (ck_test_* or ck_live_*).
baseUrlstring'https://api.circadify.com'Custom API base URL.
measurementDurationnumber30Currently a no-op. Accepted for backward compatibility, but the 4.x capture pipeline does not consume it — capture length is fixed by the frame budget (720 frames, ≈24 s at 30 fps). Setting a different value does not change scan duration.
debugbooleanfalseEnable debug logging to the browser console.
onDeviceOnlybooleantrueRequests the standard local capture and measurement payload preparation path. This does not mean results are computed fully on-device.
allowFallbackVitalsbooleanfalseOpt-in; keep off in health-adjacent products. When true, transient infrastructure failures resolve with synthetic placeholder vitals (isFallback: true, confidence: 0) instead of throwing. See Fallback Vitals.
onProgress(e: ProgressEvent) => voidPhase + percent updates throughout measurement.
onQualityState(q: QualityState) => voidFull per-frame quality state (lighting, motion, pose, readiness). Use for live quality meters.
onQualityWarning(w: QualityWarning) => voidFires on transient warnings (lighting, motion, face_position — occlusion is declared in the type but never emitted).
onLandmarks(lm: Landmark[]) => voidNormalized face landmarks. Use to render your own face overlay.
onCameraReady({ stream, video }) => voidFires once after the camera is acquired. Useful for mirroring the SDK-owned video into custom UI.
wasmConfigWasmConfigOverride CDN URLs for approved self-hosted runtime assets.

CircadifyConfig Interface

interface CircadifyConfig {
  apiKey: string;
  baseUrl?: string;
  measurementDuration?: number;
  debug?: boolean;
  onDeviceOnly?: boolean;
  allowFallbackVitals?: boolean;
  onProgress?: (event: ProgressEvent) => void;
  onQualityState?: (state: QualityState) => void;
  onQualityWarning?: (warning: QualityWarning) => void;
  onLandmarks?: (landmarks: Landmark[]) => void;
  onCameraReady?: (info: { stream: MediaStream; video: HTMLVideoElement }) => void;
  wasmConfig?: WasmConfig;
}
typescript

Progress Callback

The onProgress callback fires throughout measurement with a ProgressEvent object:

interface ProgressEvent {
  percent: number;    // 0-100
  phase: 'initializing' | 'readiness' | 'capturing' | 'uploading' | 'processing';
  elapsed: number;    // Seconds since measurement started
  remaining?: number; // Estimated seconds remaining (when available)
  captureProgress?: number; // 0–1 frame-buffer fill; only while phase === 'capturing'
}
typescript
PhaseProgressWhat's happening
initializing0–5%Creating session and preparing the SDK runtime
readiness5–10%Opening camera, waiting for quality checks to pass
capturing10–60%Capturing the measurement
uploading60–80%Uploading the measurement payload
processing80–100%Waiting for cloud processing

Quality State Callback

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

Frames where no face is detected are skipped — the callback does not fire on them, so meters driven by this event freeze at their last values rather than degrade when the user leaves the frame. Watch onLandmarks (which fires with empty landmarks) to detect face loss.

interface QualityState {
  lighting: { brightness: number; stability: number; isTooDark: boolean; isTooBright: boolean; isUnstable: boolean; isOk: boolean };
  motion:   { motionMagnitude: number; isStill: boolean };
  pose:     { yaw: number; pitch: number; isFacingForward: boolean };
  isReady:  boolean;
  messages: string[];
}
typescript

Quality Warning Callback

The onQualityWarning callback fires on transient quality drops:

interface QualityWarning {
  type: 'lighting' | 'motion' | 'face_position' | 'occlusion';
  message: string;
  severity: 'low' | 'medium' | 'high';
}
typescript

Use this for short-lived toasts ("Hold still", "Move to better lighting"). For sustained UI state, prefer onQualityState. Note that occlusion and severity 'low' exist in the type union but are never emitted by 4.x.

Landmarks Callback

The onLandmarks callback emits normalized face landmarks during measurement. Use it to render your own face overlay.

interface Landmark {
  x: number; // 0-1 normalized, NOT mirrored
  y: number; // 0-1 normalized, NOT mirrored
  z: number; // depth (relative)
}
typescript
Want a face / heat-glow overlay?

You usually shouldn't build one from this callback. Drop in CircadifyScanView from the Web SDK's React bindings for a ready-made glow overlay. If you need a custom one, prefer a 2D <canvas> in immediate mode — see Custom UI → Face overlay. Avoid a hand-rolled three.js / @react-three/fiber overlay (a known freeze bug from creating BufferGeometry in useMemo); if you must, follow Advanced: a 3D (r3f) overlay.

Camera Ready Callback

When you don't pass a videoElement to measureVitals(), the SDK creates an off-DOM <video> and reads from it directly. onCameraReady fires once with the live stream so you can mirror it into your own UI:

const sdk = new CircadifySDK({
  apiKey: 'ck_live_your_key_here',
  onCameraReady: ({ stream, video }) => {
    myPreviewVideo.srcObject = stream;
  },
});
typescript

Fallback Vitals (allowFallbackVitals)

Default: false — and we recommend leaving it off. By default, every failed measurement throws a CircadifyError; the SDK never substitutes values for a failed scan.

When you opt in with allowFallbackVitals: true, exactly three transient infrastructure failures — UPLOAD_FAILED, NETWORK_ERROR, and TIMEOUT — stop throwing when they occur during the upload/processing phase. Instead, measureVitals() resolves with a synthetic placeholder result:

  • isFallback: true — the marker that this is not a measurement
  • confidence: 0 — always, so a fallback can never score as trustworthy
  • Vitals values that are randomized, not measured: when the session supplied a server fallback configuration (the usual case), the result carries a full set of vitals — heart rate, HRV, respiratory rate, SpO₂, and blood pressure — each drawn at random within server-supplied ranges. Only when no fallback configuration is available does the result reduce to a fixed heartRate: 72 with the other fields absent.

All other errors — quota, authentication, session, capture quality, processing failures, cancellation — always throw, regardless of this setting. So do the same three codes when they arise outside the upload/processing phase: a TIMEOUT from the 60-second capture watchdog (the scan gathered too few frames) and a NETWORK_ERROR from session start always throw.

Fallback values are NOT measurements

Fallback vitals are fabricated placeholders. They are not derived from the user's face, camera, or any physiological signal. Because a fallback result usually carries a full, plausible-looking set of vitals — randomized within nominal ranges, not an obviously-degenerate placeholder — branching on isFallback is the only way to tell it apart from a real measurement. If you enable this option, your integration must check isFallback on every result and clearly present fallback results to end users as unavailable/placeholder data — never as a measured vital. Rendering a fallback heartRate as if it were real misleads the person being scanned.

When (not) to use it. This option exists for non-clinical demo surfaces where an unbroken UI flow matters more than the reading (e.g. a trade-show kiosk that must not dead-end on venue Wi-Fi). Do not enable it in any health, wellness, or care-adjacent context: Circadify provides general-wellness measurements, is not a medical device, and is not FDA-cleared — surfacing fabricated values as readings is precisely the failure mode to avoid. For development and UI testing, prefer a ck_test_ sandbox key instead, which returns deterministic simulated vitals through the real API flow.

Note: the React bindings' <CircadifyProvider> does not expose this option — fallback vitals are only reachable when you construct CircadifySDK directly. The mobile SDKs (iOS, Android) have no equivalent; they always throw on failure.

Self-Hosting Runtime Assets

For air-gapped or regulated environments, host required SDK runtime assets on your own infrastructure:

interface WasmConfig {
  visionWasmUrl?: string;
  visionModelUrl?: string;
  geometryEngineUrl?: string;
}
typescript
const sdk = new CircadifySDK({
  apiKey: 'ck_live_your_key_here',
  wasmConfig: {
    visionWasmUrl: 'https://your-cdn.example.com/runtime/',
    visionModelUrl: 'https://your-cdn.example.com/runtime/',
    geometryEngineUrl: 'https://your-cdn.example.com/runtime/geometry.js',
  },
});
typescript

Contact support@circadify.com for approved self-hosting instructions.

Tip

Runtime assets are lazy-loaded on first measurement and cached by the browser. Subsequent measurements skip the download when the cache is valid.

Next Steps