Healthlog
Read every Google Health data type, and record food, weight and height.
healthlog auth login
healthlog food log "Bean salad" --grams 350 --kcal 420 --protein 25 --fat 12 --carbs 48
healthlog food log --input meal.json
cat meal.json | healthlog food log --input -
healthlog food history
healthlog food history yesterday
healthlog food history 2026-08-17 2026-08-23
healthlog food duplicate POINT_ID --protein 0
healthlog food delete POINT_ID
healthlog weight log 82.4 --unit kg
healthlog weight log 181 --unit lb
healthlog weight history 2026-08-01 2026-08-27 --unit lb
healthlog weight delete POINT_ID
healthlog weight latest
healthlog height log 195 --unit cm
healthlog height latest
healthlog sleep history yesterday
healthlog types
Every data type is a noun and every noun reads the same way, so a caller that
can read one can read all of them. healthlog types lists them, and says which
accept a write. Food, weight and height are the three this version writes.
Every noun also takes latest, which reports the most recent reading however
old it is. A history answers a range, so a height recorded once in 2017 and
unchanged since reads as nothing at all when today is the range; latest asks
what the value is rather than what changed.
Food
JSON input is a flat item carrying name, meal_type, optional time,
optional grams, and nutrient fields. Omit time to use the device's current
local time.
Every new entry needs kcal, protein, fat, and carbs; explicit zero is a
valid value. Use --nutrient NAME=GRAMS for another nutrient; names come from
mealtime-nutrients, the list the mealtime tools share, which holds exactly
one per nutrient. Dietary fibre is fiber, and carbohydrate has its own field,
so it is carbs and never carbohydrates. Explicit flags override the input.
Piped tool output keeps its {"ok":true,"data":...} envelope, and a field this
version has not heard of is dropped, so the other tools stay free to add one.
A bare JSON object is read as hand-written instead: an unrecognised key there
is an error, rather than a nutrient quietly left out of the entry.
grams is written to Google as a gram serving and survives reads. When
it is absent, the shared format treats the nutrients as a 100 g fallback.
An item's nutrients describe the weight that item states, so --grams may not
contradict it: piping a 100 g product and asking for 250 g is refused, because
it would relabel the nutrients rather than convert them. Ask the source for the
weight you mean, as with pantry lookup --grams 250, or state every nutrient
here yourself. Restating the four core macros is not an escape, and is not
accepted as one: an item carrying fibre or sugar would keep those at the old
weight. An item stating no weight has nothing to contradict, so --grams
records what was eaten; an Eatout meal is the usual case.
food duplicate always keeps the source and accepts the same overrides as
food log. To correct an entry, duplicate it with the correction, inspect the
result, then delete the source explicitly. JSON overrides may use null to
remove a value.
A duplicate reports the source it kept, and says it still counts. Two entries
for one meal are totalled twice, so a correction that stops after the copy
inflates the day; the delete is not optional caution, it is the second half of
the edit. Google Health does document a patch method for updating a point in
place, which would avoid the two steps, but it answers 500 for a nutrition
log, so correcting really is copy-then-delete.
Output carries kcal, protein, fat and carbs always, plus only the
nutrients the entry states; an absent key and a null mean the same, while an
explicit zero survives. Missing legacy Google core macros render as zero in
Healthlog output. Unstated nutrients are omitted from writes. --dry-run --json shows the record without authenticating or writing.
food history totals the core macros always. Every other nutrient is totalled
only when an entry states it, over the entries that state it, so a total may
cover part of the range.
Weight and height
weight log requires --unit, which takes kg or lb, the standard
symbols. There is no default, because a defaulted unit records 181 kg for
someone who meant 181 lb, and 181 kg is a weight a person can have, so nothing
downstream can catch it. Google Health stores grams either way, so the unit
chooses only how the figure is read, never what is kept.
weight history takes --unit too, defaulting to kg. A display unit may
default safely, because choosing one cannot change what is stored.
A reading outside 20-500 kg is refused. That guard is for a slipped digit and nothing more: it cannot tell kilograms from pounds, which is why the unit is required rather than guessed.
height log works the same way, taking cm, m or in, and refusing
anything outside 50-250 cm. Google Health states height in whole millimetres as
a string rather than a number, so the record it stores is mm. Height is the
clearest case for latest: it is recorded once and left, so a range read
covering only recent days reports none.
Reading a range
Every history reads today by default. Pass one date for that day or two dates
for an inclusive range; dates may be ISO dates, today, or yesterday. Dates
become UTC bounds using the device's local timezone. Offset-aware ISO datetimes
are exact bounds; the end datetime is exclusive. Points are then compared only
in UTC.
Google Health spells its server-side time filter differently for nearly every data type and rejects a wrong spelling outright, so the range is applied here instead. Points arrive newest first, so a read stops at the first page holding nothing new enough rather than walking a whole history.
Types other than food report each point as the API stated it, under data,
with only the time lifted out — samples state a sampleTime, intervals and
sessions an interval, and daily summaries a civil date. --limit caps a
dense type at 500 points by default; a capped read always says truncated, and
--limit 0 reads every point in the range.
Authentication
healthlog auth login asks for the read scope of every type in
healthlog types, so no future data type needs a second login to be read. It
also asks for four write scopes. Two are used now: one by food, one shared by
weight and height. The other two cover exercise and sleep, the only families
left that this tool could plausibly write, so growing into them costs no
re-login either. It asks for
nothing touching reproductive health, symptoms, mood, location, profile or
settings, because it handles none of that. Google refuses to refresh a
token for a scope it never granted, so a token from an earlier version keeps
working for what it does cover: healthlog auth status reports the scopes it
lacks, and a read it cannot do fails with a 403 naming the re-login.
OAuth tokens remain in ~/.config/healthlog/tokens.json with mode 0600.
Release files for healthlog 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| healthlog-0.3.1.tar.gz | 67.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| healthlog-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 104.8 kB
Release files / healthlog-0.3.1.tar.gz
| Download URL | healthlog-0.3.1.tar.gz |
|---|---|
| Size | 67.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
55390ad8adc0ea06bae2867f0a873bcb5511641116fff6a4d7e69dbba1a9c617
|
|
BLAKE2b-256 checksum How to use checksums |
e36bc6af815a1d2987e4c09909a2797da1177ce3163d09125956971b99105405
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.
Transparency logRelease files / healthlog-0.3.1-py3-none-any.whl
| Download URL | healthlog-0.3.1-py3-none-any.whl |
|---|---|
| Size | 37.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
56084cc7f8ae588da2cbc564ec7d51216ba194b5d3a716e8082eb799f38084fa
|
|
BLAKE2b-256 checksum How to use checksums |
d60edf61f19f73b3d33ce9d20271e0ef774f31243ff3effef5207097317d4dd1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.
Transparency log