Circadify

Configuration

Configure the Circadify iOS SDK — initialization, callbacks, and measurement options.

Initialization

The simplest way to initialize the SDK is with just your API key:

import CircadifySDK
 
let sdk = try CircadifySDK(apiKey: "ck_live_your_key_here")
swift

For full control, pass a CircadifyConfig:

let config = CircadifyConfig(
    apiKey: "ck_live_your_key_here",
    baseUrl: "https://api.circadify.com",
    measurementDuration: 30,
    debug: false
)
 
let sdk = try CircadifySDK(config: config)
swift

The Camera

CircadifyCamera owns the single AVCaptureSession that is shared by both the live preview and the measurement. You create one camera, render it with CircadifyCameraPreview(camera:), and hand the same instance to measureVitals(camera:) so the scan records the exact session the user is already looking at.

@State private var camera = CircadifyCamera()
swift

Because the camera and the SDK are decoupled, the preview can be live (and warning the user about framing) before any measurement starts.

CircadifyCameraPreview(camera: camera)
    .ignoresSafeArea()
swift

Front or back camera

By default CircadifyCamera() uses the front (selfie) camera — the right choice for self-scans, where the user watches the live preview to frame their own face. Pass position: .back for the rear camera instead:

let camera = CircadifyCamera(position: .back)
swift

Reach for the rear camera when an operator measures another person (or in a kiosk / tripod setup). Its preview is not mirrored, and because the phone's screen no longer acts as a fill light for the subject (it faces away from them), ensure good ambient lighting. Both positions feed the identical on-device pipeline and produce the same measurements — see init(position:) in the method reference.

Note

CircadifyCamera is @MainActor and @Observable. Call try await camera.start() to prompt for permission and bring the session live, and camera.stop() when the view disappears. See Camera & Permissions for the full lifecycle.

Configuration Reference

public struct CircadifyConfig {
    public let apiKey: String
    public var baseUrl: String
    public var measurementDuration: TimeInterval
    public var debug: Bool
}
swift
PropertyTypeDefaultDescription
apiKeyStringRequired. Your API key (ck_live_*).
baseUrlString"https://api.circadify.com"API base URL.
measurementDurationTimeInterval30Target capture duration in seconds.
debugBoolfalsePrint debug logs to the console.

Callbacks

Progress updates are reported by the SDK, while quality warnings are reported by the camera. Both callbacks are delivered on the main thread.

Progress Updates

Set onProgress on the SDK instance to track a measurement as it runs:

sdk.onProgress = { update in
    print("Phase: \(update.phase)\(Int(update.percent))%")
}
swift
public struct ProgressUpdate {
    public let percent: Double       // 0-100
    public let phase: Phase          // .initializing, .capturing, .uploading, .processing
    public let elapsed: TimeInterval
    public let remaining: TimeInterval?
}
swift
PhaseDescription
.initializingSetting up camera capture
.capturingCapturing the measurement
.uploadingUploading the measurement payload
.processingWaiting for results

Quality Warnings

Quality warnings come from the camera, not the SDK. Set onQualityWarning on your CircadifyCamera. Warnings fire while the user is framing themselves in the live preview and during the measurement itself, so you can guide the user before and during a scan.

camera.onQualityWarning = { warning in
    print("[\(warning.severity)] \(warning.type): \(warning.message)")
}
swift
public struct QualityWarning {
    public let type: WarningType     // .lighting, .motion, .facePosition, .occlusion
    public let message: String
    public let severity: Severity    // .low, .medium, .high
}
swift
Warning TypeTrigger
.lightingToo dark, too bright, or flickering
.motionExcessive movement
.facePositionHead turned or tilted too far
.occlusionFace partially blocked

Use these to show guidance in your UI — "Hold still", "Move to better lighting", etc.

Measurement Options

Pass MeasurementOptions to measureVitals(camera:) to provide demographics for improved accuracy:

let options = MeasurementOptions(
    demographics: Demographics(age: 35, sex: .male, fitzpatrick: 3)
)
 
let result = try await sdk.measureVitals(camera: camera, options: options)
swift
FieldTypeNotes
ageInt?User age in years.
sexSex?.male or .female. Encoded on the wire as "M" / "F".
fitzpatrickInt?Fitzpatrick skin type. Valid values are 16.

Demographics are optional but can improve measurement accuracy when provided.

Next Steps