NeccessoryNeccessory
iOS SDK

Results Reference

The measurement result the iOS SDK delivers on completion.

The iOS SDK delivers the same measurement result as every other platform. This page shows how you read it in Swift.

Realtime callback

onRealtime fires during capture with a small partial — a live heart rate and the current signal-quality level only. Use it to drive live UI (a pulsing number, a "hold still" hint):

sdk.onRealtime = { update in
    update.heartRate         // Int?  — live bpm, nil until it stabilizes
    update.qualityLevel      // .good | .fair | .poor
    update.qualityScore      // Double 0...1
    update.remainingSeconds  // Double — drives a progress ring
    update.hint              // String? — e.g. "faceTooSmall", "tooDark"
}

Do not treat realtime values as the final result — present them as provisional.

Result callback

onResult fires once, on completion, with the full result. Its shape is the canonical measurement result:

sdk.onResult = { result in
    // Required quality — never nil.
    result.quality.level   // .good | .fair | .poor
    result.quality.score   // Double 0...1
    result.quality.usable  // Bool

    // Core sections (values are nil when quality is poor).
    result.cardiac.heartRate.value          // Int?
    result.cardiac.heartRate.confidence     // Double?
    result.hrv.sdnnMs                       // Int?  (headline)
    result.hrv.rmssdMs                      // Int?
    result.hrv.pnn50Pct                     // Double?
    result.respiratory.breathingRate.value  // Int?
    result.stress.index                     // Int?  (0...100)
    result.stress.level                     // .low | .moderate | .high | nil

    // Beta sections — wellness only, nullable, carry tier "beta".
    result.bloodPressure.systolicMmHg   // Int?
    result.bloodPressure.diastolicMmHg  // Int?
    result.spo2.value                   // Int?
}

MeasurementResult is Codable, and encoding it produces exactly the body POST /sdk/v1/measurements accepts — so you can forward it through your own backend without remapping anything. If you initialised the SDK with a secret, try await sdk.submit(result) posts it for you.

Handling null values

Any metric can be nil when the capture is unreliable — neccessory returns nil rather than fabricating a number. Always check for nil and hide or dim the field rather than showing a blank or a zero. When result.quality.usable is false, prompt the user to re-measure. See Signal quality.

Advanced (Beta) metrics

Blood pressure and SpO2 are experimental estimates for wellness only. Render them at lower visual authority than the Core metrics and always show the wellness disclaimer.

Next: Troubleshooting.