Skip to Content
Health DataHealth Score

Health Score

@loop/health-score calculates a composite 0–100 health score by combining data from three sources: wearables (40%), check-ins (30%), and lab results (30%).

Installation

pnpm add @loop/health-score

Quick Start

import { calculateHealthScore } from '@loop/health-score'; const { score, breakdown } = calculateHealthScore({ wearables: { ouraReadiness: 82, whoopRecovery: 75, hrv: 45, }, checkIns: { energy: 7, mood: 8, focus: 6, sleepQuality: 8, }, labs: { biomarkerCount: 15, biomarkerScore: 78, }, }); console.log(score); // 77 console.log(breakdown); // { wearables: 79, checkIns: 73, labs: 78 }

Scoring Weights

SourceWeightData
Wearables40%Oura readiness, Whoop recovery, HRV
Check-ins30%Energy, mood, focus, sleep quality (0–10 scale)
Labs30%Biomarker count and composite biomarker score

API Reference

calculateHealthScore(input)

Calculate the health score from all available data sources.

Parameters:

interface HealthScoreInput { wearables?: { ouraReadiness?: number; // 0-100 whoopRecovery?: number; // 0-100 hrv?: number; // milliseconds }; checkIns?: { energy?: number; // 0-10 mood?: number; // 0-10 focus?: number; // 0-10 sleepQuality?: number; // 0-10 }; labs?: { biomarkerCount?: number; // number of recent biomarkers biomarkerScore?: number; // 0-100 composite lab score }; }

Returns:

interface HealthScoreResult { score: number; // 0-100 composite score breakdown: { wearables: number; // 0-100 wearable sub-score checkIns: number; // 0-100 check-in sub-score labs: number; // 0-100 lab sub-score }; }

calculate(options)

Full calculation with trend analysis:

import { calculate } from '@loop/health-score'; const result = calculate({ input: { wearables: { ouraReadiness: 82 }, checkIns: { mood: 8 } }, previousScores: [72, 75, 77], }); console.log(result.score); // 79 console.log(result.trend); // 'improving' console.log(result.average); // 75.75

calculateTrend(currentScore, previousScore?)

Determine the trend direction:

import { calculateTrend } from '@loop/health-score'; calculateTrend(80, 72); // 'improving' (>5 point increase) calculateTrend(75, 74); // 'stable' (within 5 points) calculateTrend(60, 75); // 'declining' (>5 point decrease) calculateTrend(80); // undefined (no previous score)

Thresholds:

  • Improving: current is 5+ points above previous
  • Declining: current is 5+ points below previous
  • Stable: within 5 points

calculateAverageScore(scores)

import { calculateAverageScore } from '@loop/health-score'; calculateAverageScore([72, 75, 80, 78]); // 76.25 calculateAverageScore([]); // undefined

How Scoring Works

Wearable Score (40%)

  • Oura Readiness (0–100): Used directly
  • Whoop Recovery (0–100): Used directly
  • HRV: Normalized to 0–100 scale based on population norms
  • Average of available metrics is taken

Check-in Score (30%)

  • Each metric (energy, mood, focus, sleep quality) is on a 0–10 scale
  • Normalized to 0–100 by multiplying by 10
  • Average of available metrics is taken

Lab Score (30%)

  • Based on the composite biomarker score from @loop/health-engine
  • Bonus points for having more biomarker data
  • Score of 0 if no recent labs

Missing Data

If a data source is entirely missing, its weight is redistributed proportionally to the available sources. For example, if no wearable data exists, check-ins get ~43% weight and labs get ~57%.