Google Health

Other

Read your Google Health data from any agent. Lists data points for every Google Health data type (heart rate, resting heart rate, sleep, steps, distance, weight, blood oxygen, VO2 max, exercise, and more), returns server-side daily roll-ups (one reconciled total per day), gives a parsed view of exercise sessions, and can GET any read-only v4 API path. A self-contained, read-only client for the Google Health v4 API: authenticates via OAuth2 (token cached locally and auto-refreshed) and emits JSON. It does NO filtering, merging, or writing — the caller decides what to do with the data. Single static binary, no Python or other runtime. NOTE: needs your own Google Cloud OAuth client and a one-time interactive browser login; runs headless afterward.

Install

openclaw skills install @stozo04/google-health-cli

Google Health — read-only data extractor

Read your Google Health data from any agent. This is a generic, read-only client for the Google Health v4 API: it authenticates, pulls data points for any data type, and prints JSON. It does no filtering, merging, or interpretation — you get the data and parse whatever you care about. Single static binary — no Python or other runtime.

⚠️ Read-only. It requests only read-only Google Health scopes and never writes your health data.

Setup (one time)

Unlike a simple email/password tool, Google Health uses OAuth, so first-time setup needs a human in a browser once. After that it runs headless (the token auto-refreshes).

  1. Install the binary:
    # A) Download a release for your OS/arch and put it on PATH:
    #    https://github.com/stozo04/google-health-cli/releases
    # B) Or with Go (1.25+):
    go install github.com/stozo04/google-health-cli/cmd/google-health-cli@latest
    
  2. Create a Google Cloud OAuth client (Desktop app, read-only Health scopes, ~10 min, no fees). Full walkthrough: the repo's OAUTH_SETUP.md.
  3. Provide the client via GOOGLE_HEALTH_CLIENT_ID / GOOGLE_HEALTH_CLIENT_SECRET (or a config.json with those keys in the working directory).
  4. Authorize once (opens a browser, asks a human to consent to read-only access):
    google-health-cli auth login
    google-health-cli doctor        # expect "tokenValid": true
    
    The token is cached 0600 and auto-refreshed; every later run is headless.

Credentials

VariableRequiredNotes
GOOGLE_HEALTH_CLIENT_IDOAuth client ID (Desktop app)
GOOGLE_HEALTH_CLIENT_SECRETOAuth client secret
GOOGLE_HEALTH_CONFIGPath to a config.json holding the above instead
GOOGLE_HEALTH_TOKEN_CACHEOverride the cached-token path
GOOGLE_HEALTH_BASE_URLOverride the API base URL

config.json (gitignored) is an alternative to the env vars:

{
  "client_id": "PASTE_CLIENT_ID",
  "client_secret": "PASTE_CLIENT_SECRET"
}

Commands

Discover the data types

google-health-cli types list                 # all types ( * = supports list )
google-health-cli types describe heart-rate   # one type's record shape, scope, time field

Read data points (the core)

google-health-cli data list heart-rate --days 1        # last 1 day
google-health-cli data list sleep --days 14             # last 14 days
google-health-cli data list daily-resting-heart-rate --days 30
google-health-cli data list steps --date 2026-06-16     # one civil day
google-health-cli data list weight --from 2026-01-01T00:00:00Z --to 2026-07-01T00:00:00Z
google-health-cli data list distance --all              # everything, no time filter

stdout is always a JSON array of the raw data points (verbatim from the API); a one-line count goes to stderr. Window flags (precedence: --all > --from/--to > --date/--days): --date today|yesterday|YYYY-MM-DD, --days N (default 7), --from/--to (RFC3339, together), --all (no filter).

Example (data list daily-resting-heart-rate):

[
  {
    "dataSource": { "platform": "FITBIT", "device": { "displayName": "Google Pixel Watch 4 (45mm)" } },
    "dailyRestingHeartRate": { "date": { "year": 2026, "month": 6, "day": 17 }, "beatsPerMinute": "78" }
  }
]

A few types are roll-up/reconcile-only and can't be listed (types list marks listable ones with *); read those with rollup daily <type> instead (below).

Daily roll-ups (server-side totals)

google-health-cli rollup daily steps --days 7           # one reconciled total per civil day
google-health-cli rollup daily active-minutes --days 7   # a roll-up-only type (no `data list`)

rollup daily <type> returns the API's daily roll-up rows — one value per civil (local) calendar day — instead of the raw per-minute/per-sample points data list returns. It's the cheap way to get daily totals (e.g. a steps total per day rather than a per-minute dump) and the only way to read the roll-up-only types that have no list op (active-minutes, total-calories, floors, calories-in-heart-rate-zone, time-in-heart-rate-zone). stdout is a JSON array of the raw roll-up rows; an N <type> daily rollup(s) count goes to stderr. Each value is reconciled across data sources (and excludes off-wrist intervals), so it is not a naive sum of data list points. Window flags mirror data list minus --all (the range is required).

[
  {
    "civilStartTime": { "date": { "year": 2026, "month": 6, "day": 16 }, "time": {} },
    "civilEndTime":   { "date": { "year": 2026, "month": 6, "day": 17 }, "time": {} },
    "steps": { "countSum": "8000" }
  }
]

Parsed exercise sessions (convenience)

google-health-cli sessions --days 14 --json    # flattened exercise rows
google-health-cli sessions --raw               # raw exercise data points
[
  { "date": "2026-06-16", "exercise_type": "ELLIPTICAL", "duration_min": 35,
    "avg_hr": 130, "calories": 236, "platform": "FITBIT" }
]

sessions returns all exercise types (no filtering); the caller keeps what it wants.

Raw read-only API access

google-health-cli api get /v4/users/me/profile     # GET any read-only v4 path
google-health-cli api get /v4/users/me/settings

Full command reference

CommandWhat it does--json
auth login | logout | statusOAuth login (one-time browser), token mgmtstatus
doctorConfig + token validity (exit 2 if not authed)always
types list | describe <type>Inspect the data-type catalog (no network)
data list <type>List data points for a type (always JSON)n/a (always)
rollup daily <type>Server-side daily totals, reconciled per civil dayn/a (always)
sessions [--days N] [--raw]Parsed exercise sessions (convenience)
api get <path>Raw read-only GET of any v4 pathn/a
config show | pathInspect resolved config (client_secret masked)show
versionBuild metadata (also --version)
completion <shell>Shell completion (bash/zsh/fish/powershell)

Conventions

  • stdout is parseable; human hints, counts, and logs go to stderr, never interleaved.
  • Exit codes: 0 success, 2 auth/API failure (incl. doctor when unauthenticated), 64 usage error, 78 config error.
  • Read-only: six read-only googlehealth.*.readonly scopes; no write operations exist.
  • Secrets: config.json and the token cache are gitignored — never commit them.
  • Time-filter formats are handled for you per data type (civil wall-clock, RFC3339 instant, or date-only). If a type rejects server-side filtering, re-run with --all.

See the repo's AGENTS.md for the exact --json shapes and exit-code contract.