Configuration
Configure the Circadify Python SDK with API keys, callbacks, capture options, and demographics.
Create one CircadifyClient per process or measurement flow. Only api_key is required — everything else has a sensible default. Never hardcode a key; read it from the environment.
Initialization
The minimal form takes only an API key:
import os
from circadify import CircadifyClient
client = CircadifyClient(api_key=os.environ["CIRCADIFY_API_KEY"])pythonFor full control, pass any of the keyword-only options. All arguments after api_key are keyword-only:
import os
from circadify import CircadifyClient
client = CircadifyClient(
api_key=os.environ["CIRCADIFY_API_KEY"], # "ck_test_..." or "ck_live_..."
base_url="https://api.circadify.com",
timeout=30.0,
poll_interval=2.0,
poll_timeout=120.0,
measurement_duration=20.0,
allow_fallback_vitals=False,
on_progress=lambda p: print(p.phase, p.percent),
on_landmarks=None,
on_quality=None,
on_frame=None,
model_asset_path=None,
debug=False,
)pythonCircadifyClient is a context manager, so prefer with to release the camera and HTTP session deterministically:
with CircadifyClient(api_key=os.environ["CIRCADIFY_API_KEY"]) as client:
result = client.measure_vitals()
print(result.heart_rate, result.confidence)pythonA ck_test_* key targets the free sandbox (zero quota, deterministic synthetic vitals); a ck_live_* key is metered. Read client.key_environment ("test" or "live") to confirm. A malformed key raises InvalidApiKeyError; an empty key raises MissingApiKeyError.
Configuration reference
| Option | Type | Default | Description |
|---|---|---|---|
api_key | str | — | Required. Your API key, ck_test_* (sandbox) or ck_live_* (metered). Never hardcode it. |
base_url | str | "https://api.circadify.com" | API base URL. |
timeout | float | 30.0 | Per-request HTTP timeout in seconds. |
poll_interval | float | 2.0 | Seconds between result polls while the server runs inference. |
poll_timeout | float | 120.0 | Maximum seconds to wait for a result before raising ScanTimeoutError. |
measurement_duration | float | 20.0 | Target capture window in seconds. Also sets the capture watchdog (measurement_duration + 10s). |
allow_fallback_vitals | bool | False | Opt-in. When True, transient infra failures return synthetic vitals with is_fallback=True instead of raising. By default the SDK raises the real error and never fabricates vitals. |
model_asset_path | str | None | — | Path to a local MediaPipe face-landmarker .task asset. Leave unset to auto-download the default model on first use and cache it locally (e.g. for air-gapped installs, point this at a vendored copy). |
debug | bool | False | Enables verbose SDK (Python) logging. Does not silence MediaPipe/TFLite/OpenGL native logs — see Quieting native logs. |
After any call, client.last_rate_limit holds a RateLimitInfo or None.
Quieting native logs
On import and during a scan, MediaPipe / TFLite / OpenGL emit C++ banner lines to the console (e.g. Created TensorFlow Lite XNNPACK delegate for CPU, a GL version … line, init-domain / fiber-init lines). These come from the native libraries, not the SDK's Python logger — so debug=False does not silence them. Set these environment variables before importing circadify (or cv2 / mediapipe), since the native libraries read them at load time:
import os
os.environ["GLOG_minloglevel"] = "2" # MediaPipe / abseil C++ logs (0=info … 3=fatal)
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3" # TFLite / XNNPACK delegate logs
from circadify import CircadifyClient # import AFTER setting the vars abovepythonCallbacks
Pass callbacks to drive a scan UI around the capture engine. All four are optional.
Callbacks fire on the capture worker thread, not the main thread. Marshal back to your UI thread before touching UI state. The SDK swallows any exception raised inside a callback, so a callback bug fails silently rather than aborting the scan.
on_progress — ScanProgress
| Field | Type | Description |
|---|---|---|
phase | Phase | Current capture phase. |
percent | float | Overall progress, 0–100. |
elapsed | float | Seconds elapsed in the current capture. |
remaining | float | Estimated seconds remaining. |
message | str | Human-readable status string. |
on_landmarks
Receives a list of (x, y) face-landmark pixel coordinates per frame. Use it to render a custom overlay.
on_quality — QualityState
| Field | Type | Description |
|---|---|---|
face_detected | bool | Whether a face is present in the frame. |
brightness | float | Estimated frame brightness. |
motion | float | Estimated subject/camera motion. |
yaw_deg | float | Head yaw in degrees. |
pitch_deg | float | Head pitch in degrees. |
is_good | bool | Whether the frame meets quality gates. |
reasons | tuple[str, ...] | Failing reasons, e.g. no_face, face_out_of_frame, too_dark, too_bright, too_much_motion, face_turned, face_tilted. |
on_frame — FrameEvent
| Field | Type | Description |
|---|---|---|
rgb | numpy.ndarray | The current [H, W, 3] RGB frame. |
phase | Phase | Current capture phase. |
landmarks | list | (x, y) landmark coordinates for this frame. |
quality | QualityState | Quality assessment for this frame. |
collected | int | Frames accepted so far. |
target | int | Target frame count for this capture. |
Phase enum
| Phase | Description |
|---|---|
INITIALIZING | Creating a session and preparing capture. |
READINESS | Waiting for a scan-ready face and acceptable quality. |
CAPTURING | Capturing the measurement. |
UPLOADING | Uploading the cropped tensor. |
PROCESSING | Waiting for server inference. |
DONE | Result is ready. |
Capture policy
The frame-rate target, minimum frame count, readiness gate, and watchdogs are fixed and tuned for measurement quality. They are not constructor options.
Capture policy is fixed internal behavior, not constructor arguments. Some values are constants in circadify.config (the ~30 fps capture target TARGET_FPS, and MIN_CAPTURE_FRAMES=150); others are literals in the capture loop (a readiness gate of ≤30s before capture begins, a capture watchdog of measurement_duration + 10s, and a 3s frame-stall watchdog). Adjust the capture window via the measurement_duration constructor option; the rest are not user-configurable.
Demographics
Demographics are optional but can improve measurement accuracy when provided. Every measurement method accepts a Demographics, a plain dict, or None.
from circadify import Demographics, Sex
demographics = Demographics(age=35, sex=Sex.MALE, fitzpatrick=3)
result = client.measure_vitals(demographics=demographics)python| Field | Type | Notes |
|---|---|---|
age | int | None | User age in years. |
sex | str | None | "M" or "F" (or Sex.MALE / Sex.FEMALE). |
fitzpatrick | int | None | Fitzpatrick skin type, 1–6. |
You can also pass the dict form directly:
result = client.measure_vitals(
demographics={"age": 35, "sex": "M", "fitzpatrick": 3},
)pythonKeep timeout, poll_interval, poll_timeout, and measurement_duration at their defaults unless you have validated different values against your own latency and accuracy targets. The defaults are tuned for the standard capture flow.
Next Steps
- Methods — every measurement and REST method on
CircadifyClient. - Face-Glow Overlay — the optional
render_face_glowcamera/glow pipeline you compose your own UI around. - Camera & Input — webcam, video file, and your-own-frames input modes.
- Error Handling — catch
CircadifyError, inspect.code, and retry transient failures.