NeccessoryNeccessory
Web SDK

Callbacks Reference

The four callbacks the Web SDK exposes — onRealtime, onStage, onResult, onError.

The Web SDK exposes a thin facade: four callbacks. Everything else is internal.

onRealtime(cb)

Fires roughly once per second during a measurement. The payload is a small partial — a live heart rate and the current quality only. Use it to drive live UI; do not treat it as the final result.

m.onRealtime((update) => {
  update.heartRate;      // number | null (live bpm)
  update.quality.level;  // "good" | "fair" | "poor"
  update.quality.score;  // number | null (0..1)
});

onStage(cb)

Fires whenever the measurement moves to a new step, from start() until the result arrives. Use it for progress copy; onRealtime tells you nothing while the camera and the models are still coming up.

m.onStage((stage) => {
  // 'requestingCamera' | 'loadingModels' | 'ready'
  // on-device also: 'preparingWorkers' | 'initializingSdk'
  // cloud also:     'connecting' | 'uploading' | 'processing'
});

'uploading' and 'processing' are cloud-specific and mean the stream did not survive: the SDK is finishing the measurement as a batch upload. Live metrics have stopped at that point, so switch the UI over instead of leaving a pulse frozen on screen. See Cloud overview.

The set is open-ended by design — treat an unrecognized stage as "still working" rather than as an error.

onResult(cb)

Fires once, on completion, with the full measurement result. Metrics are grouped into sections:

m.onResult((result) => {
  result.quality.level;   // "good" | "fair" | "poor" (required, never null)
  result.quality.usable;  // boolean

  result.cardiac.heartRate.value;         // number | null
  result.hrv.sdnnMs;                      // number | null (headline)
  result.hrv.rmssdMs;                     // number | null
  result.respiratory.breathingRate.value; // number | null
  result.stress.index;                    // number | null (0..100)

  // Beta sections — wellness only, nullable, each carries tier: "beta".
  result.bloodPressure.systolicMmHg;      // number | null
  result.spo2.value;                      // number | null
  result.emotion.dominant;                // string | null
  result.behavior.attentionPercent;       // number | null

  result.sdkVersion;                      // "0.1.0" — this package
  result.modelsVersion;                   // "wv-5" — the model bundle it loaded
});

sdkVersion and modelsVersion name the build that produced the numbers. The SDK fills them in and carries them into the submitted body, so the console can show which engine versions are live in production; modelsVersion is absent when a custom driver does not report one. See Submitting measurements.

Any metric may be null when the capture is unreliable — neccessory returns null rather than fabricating a number. When quality.level is "poor" every metric is null: treat that as "no measurement", not "a bad measurement". Always handle null and respect result.quality.usable. See Signal quality.

onError(cb)

Fires on any error during setup or measurement. start() reports failures here rather than rejecting, so this single path covers both.

m.onError((err) => {
  err.code;     // a short machine-readable code
  err.message;  // a human-readable message (no internal details)
});

Next: Configuration.