Skip to content

Vanilla JavaScript

The Circadify SDK works without any framework. This guide shows how to integrate it with plain HTML and JavaScript.

Load the SDK from the Circadify CDN. This exposes CircadifySDK as a global on window:

<script src="https://cdn.circadify.com/sdk/v1/circadify.min.js"></script>
<script>
const sdk = new CircadifySDK({
apiKey: 'ck_test_your_key_here',
});
</script>

The CDN bundle is a UMD build that works in any browser. WASM dependencies are lazy-loaded from the same CDN origin and cached by the browser.

If you use a bundler (Vite, webpack, esbuild) or native ES modules, import from the npm package:

import { CircadifySDK } from '@circadify/sdk';
const sdk = new CircadifySDK({
apiKey: 'ck_test_your_key_here',
});

The simplest integration: mount the SDK’s built-in UI into a container element, run a scan, and read the results.

<!DOCTYPE html>
<html>
<body>
<div id="scan-container" style="width: 400px; height: 300px;"></div>
<button id="start-btn">Start Scan</button>
<pre id="results"></pre>
<script type="module">
import { CircadifySDK } from '@circadify/sdk';
const sdk = new CircadifySDK({
apiKey: 'ck_test_your_key_here',
onProgress: (progress) => {
console.log(`${progress.phase}: ${progress.percent}%`);
},
onQualityWarning: (warning) => {
console.warn('Quality issue:', warning);
},
});
document.getElementById('start-btn').addEventListener('click', async () => {
try {
const result = await sdk.measureVitals({
container: document.getElementById('scan-container'),
});
document.getElementById('results').textContent =
JSON.stringify(result, null, 2);
} catch (error) {
console.error('Scan failed:', error.message);
}
});
</script>
</body>
</html>

The measureVitals() call handles the full lifecycle: camera access, face detection, measurement, and result delivery. It returns a VitalSignsResult with heartRate, respiratoryRate, hrv, spo2, systolicBp, diastolicBp, confidence, sessionId, and timestamp.

The SDK emits events throughout the session lifecycle. Use .on() to subscribe and build responsive UIs:

// Progress updates during a scan
sdk.on('session:progress', (event) => {
const progressBar = document.getElementById('progress');
progressBar.style.width = `${event.progress * 100}%`;
progressBar.textContent = `${Math.round(event.progress * 100)}%`;
});
// Successful completion
sdk.on('session:complete', (event) => {
document.getElementById('result').textContent =
`Heart Rate: ${event.result.heartRate} BPM`;
});
// Error handling
sdk.on('session:error', (event) => {
document.getElementById('error').textContent = event.error.message;
document.getElementById('error').hidden = false;
});

Each .on() call returns an unsubscribe function. Call it to stop listening:

const unsubscribe = sdk.on('session:progress', handler);
// Later, when you no longer need the listener:
unsubscribe();

Use an AbortController to let the user cancel a scan mid-session:

const controller = new AbortController();
document.getElementById('cancel-btn').addEventListener('click', () => {
controller.abort();
});
try {
const result = await sdk.measureVitals({
container: document.getElementById('scan-container'),
signal: controller.signal,
});
} catch (error) {
if (error.code === 'CANCELLED') {
console.log('Scan cancelled by user.');
}
}

Call sdk.destroy() when you are done with the SDK to release all resources. This stops active camera streams, unloads WASM modules, removes event listeners, and cleans up any DOM elements the SDK created.

// When navigating away or tearing down
sdk.destroy();

For pages that load and unload dynamically (SPA routing), tie cleanup to your router’s lifecycle:

// Example: cleanup on page visibility change or navigation
window.addEventListener('beforeunload', () => {
sdk.destroy();
});