Circadify

Methods

Reference for all public Circadify Android SDK methods.

Reference for the public methods on CircadifySDK.

measureVitals(options)

Runs the full measurement flow: session creation, camera capture, quality checks, secure upload, and result polling.

lifecycleScope.launch {
    try {
        val result = sdk.measureVitals(
            MeasurementOptions(
                lifecycleOwner = this@MainActivity,
                previewView = previewView,
            ),
        )
 
        showResult(result)
    } catch (error: CircadifyError) {
        showError(error.message)
    }
}
kotlin

Parameters (MeasurementOptions):

NameTypeRequiredDescription
lifecycleOwnerLifecycleOwnerYesLifecycle used by CameraX. Usually an Activity, Fragment, or LifecycleOwner from Compose.
previewViewPreviewView?NoCameraX preview surface owned by your app.
demographicsDemographics?NoOptional age, sex, and Fitzpatrick skin type. See Configuration → Demographics for the full type.
cancellationSignalCancellationSignal?NoCancels this measurement.

Returns: VitalSignsResult

data class VitalSignsResult(
    val heartRate: Double,
    val hrv: Double?,
    val respiratoryRate: Double?,
    val spo2: Double?,
    val systolicBp: Double?,
    val diastolicBp: Double?,
    val confidence: Double,
    val timestamp: Long,
    val sessionId: String,
)
kotlin
Tip

A confidence above 0.7 indicates a reliable measurement. Below 0.4 suggests quality issues and should usually prompt a retry.

Capture behavior

The Android SDK uses a frame-threshold capture policy instead of requiring a fixed 720-frame payload. By default, capture targets 10 FPS and starts upload once at least 150 quality frames have been accepted. The SDK encodes the actual frame count and FPS in the upload payload so the Circadify backend can process measurements from a wider range of Android devices.

If a lower-end device accepts frames more slowly, the SDK continues only until the minimum accepted-frame threshold is reached or the capture timeout is hit. If quality is good, upload starts immediately after enough usable frames are available.

val sdk = CircadifySDK(
    context = context,
    config = CircadifyConfig(
        apiKey = "ck_live_your_key_here",
        measurementDurationSeconds = 30,
        targetCaptureFps = 10,
        minimumAcceptedFrames = 150,
        maximumAcceptedFrames = 720,
    ),
)
kotlin
Note

Prefer the defaults unless you have validated a different policy on your target devices. Lowering targetCaptureFps reduces device load; lowering minimumAcceptedFrames may reduce result confidence.

checkCameraAccess()

Checks whether camera permission is granted and a camera exists on the device. It does not request permission.

if (sdk.checkCameraAccess()) {
    startMeasurement()
} else {
    requestCameraPermission()
}
kotlin

Returns: Boolean

getDeviceCapabilities()

Returns camera support and permission information.

val capabilities = sdk.getDeviceCapabilities()
 
// Check the lens you plan to capture from: hasFrontCamera for the default front
// camera, or hasBackCamera when you set cameraLensFacing = CameraLensFacing.BACK.
if (!capabilities.hasFrontCamera) {
    showMessage("A front camera is required for self-measurement.")
}
kotlin

Returns: DeviceCapabilities

data class DeviceCapabilities(
    val hasCamera: Boolean,
    val hasFrontCamera: Boolean,
    val cameraPermissionGranted: Boolean,
    val mediaDevicesSupported: Boolean = true,
    val isSecureContext: Boolean = true,
    val maxResolution: Resolution? = null,
    val hasBackCamera: Boolean = false,
)
kotlin

CircadifyOverlayView

A standard Android View that renders the SDK's first-party thermal scan overlay — a gold guide oval plus a heat-glow that roves across the forehead and cheeks, tracking the live face and pulsing hotter while a measurement runs. Drop it on top of your CameraX PreviewView (identical bounds, e.g. in a FrameLayout) and feed it geometry from the onScanFace callback.

// Geometry arrives on the onScanFace callback; null when no face is detected.
overlay.scanFace = face
 
// Drive the hotter, faster glow while a measurement runs.
overlay.isScanning = true
 
// Optionally retheme the glow colors and per-region timings.
overlay.style = CircadifyScanStyle()
kotlin
  • scanFace: CircadifyScanFace? — live face geometry to paint, or null to clear the glow. Fed from CircadifyCallbacks.onScanFace.
  • isScanning: Booleantrue drives the hotter, faster glow during an active measurement; false is the calmer idle/framing look.
  • style: CircadifyScanStyle — glow colors and per-region timings. Defaults to the warm thermal ramp; override any field to recolor or re-time the glow.

The view does not intercept touches and animates itself while attached to the window (respecting the system "remove animations" accessibility setting). See Scan Overlay for the full layout, lifecycle, and custom-overlay guide.

cancel()

Cancels an active measurement. The running measureVitals() call throws a CircadifyError with code CANCELLED.

cancelButton.setOnClickListener {
    sdk.cancel()
}
kotlin

You can also cancel by cancelling the coroutine or by passing a CancellationSignal:

val signal = CancellationSignal()
 
lifecycleScope.launch {
    sdk.measureVitals(
        MeasurementOptions(
            lifecycleOwner = this@MainActivity,
            previewView = previewView,
            cancellationSignal = signal,
        ),
    )
}
 
signal.cancel()
kotlin

destroy()

Releases SDK resources and cancels active scanning. Call it when the owning screen is destroyed.

override fun onDestroy() {
    sdk.destroy()
    super.onDestroy()
}
kotlin
Caution

After destroy(), create a new CircadifySDK instance before measuring again.

Next Steps