Skip to content

Migrating v2 → v3

@circadify/web-sdk@3.0.0 removes the built-in DOM scanning UI and ships the headless API that v2.1/v2.2 had partially documented but not fully wired up. This guide covers what changed and how to update your code.

v2.xv3.0
Built-in DOM UIYes (src/ui/)Removed
MeasurementOptions.containerMounts SDK UIRemoved
MeasurementOptions.ui (ScanningUIOptions)Customize SDK UIRemoved
MeasurementOptions.videoElementDocumented but not wiredNow binds the camera stream to your video
onLandmarks, onQualityState, onCameraReadyDocumented but not emittedNow actually emitted every frame / on event
onDeviceOnly flagDocumentedNow sends X-Circadify-On-Device: true header
Session, ProgressEvent typesDocumentedNow exported as primary names (SessionState, MeasurementProgress retained as aliases)
Bundle size~75 KB minified~30 KB minified

The vision pipeline (face detection, ROI cropping, perspective warp, quality checks, frame buffer, tensor encoding) is unchanged. v3 is a packaging change, not an algorithm change.

React apps → install @circadify/react@1.0+

Section titled “React apps → install @circadify/react@1.0+”

If you were using v2’s built-in container UI, switch to @circadify/react and use <CircadifyScan> — it’s a drop-in replacement with a styled three-stage flow (Readiness → Scan → Results) and the same camera + extraction pipeline underneath.

import { CircadifySDK } from '@circadify/web-sdk';
const sdk = new CircadifySDK({ apiKey });
await sdk.measureVitals({
container: document.getElementById('scan'),
});
import { CircadifyProvider, CircadifyScan } from '@circadify/react';
import '@circadify/react/styles.css';
<CircadifyProvider apiKey={apiKey}>
<CircadifyScan autoStart onResult={(r) => …} />
</CircadifyProvider>

See the React guide for hooks, custom flows, and composable subcomponents.

Vanilla JS → bring your own video element

Section titled “Vanilla JS → bring your own video element”

Replace container with your own <video>. The SDK now binds the camera stream to it.

<video id="preview" autoplay playsinline muted></video>
<div id="scan-container"></div>
const result = await sdk.measureVitals({
container: document.getElementById('scan-container'),
});
const videoEl = document.getElementById('preview');
const result = await sdk.measureVitals({ videoElement: videoEl });

If you want the visual polish v2 gave you for free (face guide oval, status banner, progress bar, thermal glow), build it with the per-frame callbacks documented in Custom UI — or install @circadify/react for a drop-in.

If you were already in “headless mode” (no container passed), v2 measureVitals() ran your scan but couldn’t actually emit per-frame landmarks or quality state — those callbacks were declared but never fired. v3 wires them up:

const sdk = new CircadifySDK({
apiKey,
onProgress: (e) => …, // unchanged
onQualityWarning: (w) => …, // unchanged
onQualityState: (q) => …, // now actually fires every frame
onLandmarks: (lm) => …, // now actually fires every frame
onCameraReady: (i) => …, // now actually fires once after camera start
});

If you previously simulated these by patching the SDK, polling internal state, or maintaining your own face mesh — you can delete that workaround.

Session and ProgressEvent are now the primary names. The old names remain as aliases:

// Both still work in v3:
import type { Session, SessionState } from '@circadify/web-sdk';
import type { ProgressEvent, MeasurementProgress } from '@circadify/web-sdk';

ScanningUIOptions is gone. Remove any imports that reference it.

Removed: server fallback inference behavior

Section titled “Removed: server fallback inference behavior”

The new onDeviceOnly flag (default true) sends the X-Circadify-On-Device: true header so the backend will not run server-side fallback inference if extraction is sufficient. If you want to opt back into the v2-era server-fallback path, set onDeviceOnly: false on the SDK config.

  • Bump @circadify/web-sdk to ^3.0.0 (and @circadify/react to ^1.0.0 if applicable)
  • Replace every container: … in measureVitals() calls with videoElement: …
  • Render your own <video autoPlay playsInline muted> for the scan
  • Remove any ui: { … } / ScanningUIOptions usage
  • If you used the built-in face guide / status banner, decide: switch to @circadify/react for a drop-in, or build your own from onLandmarks / onQualityState
  • Run a full scan in dev — verify the result confidence is non-zero
  • If you self-host WASM, no changes needed (the WasmConfig keys are unchanged)

Email support@circadify.com with your repo and the v2 integration code; we can advise on the cleanest migration path for your specific UI.