Exports Withings measurements into monthly JSON partitions:
<out_dir>/year=YYYY/month=MM.json
The CLI entrypoint is withings_export.py.
- Python 3.10+ (recommended: 3.12)
- A Withings developer application and OAuth tokens (provided via environment variables)
The code is agnostic to how env vars are injected (dotenv file, CI secrets, Secret Manager, etc). It reads these environment variables:
WITHINGS_APP_CLIENT_IDWITHINGS_APP_CLIENT_SECRETWITHINGS_APP_REFRESH_TOKEN
Optional (will be refreshed/updated automatically if python-dotenv is installed, which it is by default here):
WITHINGS_APP_ACCESS_TOKENWITHINGS_APP_ACCESS_TOKEN_EXPIRES_AT(ISO8601)
By default, the app does not require .env and will just use whatever env vars are already present.
If you want the app to load env vars itself, set:
WITHINGS_ENV_SOURCE:dotenv(load a dotenv file)secret_manager(load a JSON mapping from Google Secret Manager)
WITHINGS_ENV_OVERRIDE: set totrueto override existing env vars (default: false)
Dotenv loader:
WITHINGS_ENV_PATH: path to.env(defaults to./.envif it exists)
Secret Manager loader (expects secret payload JSON object of {"ENV_NAME": "value", ...}):
WITHINGS_ENV_SECRET_RESOURCE: e.g.projects/<project>/secrets/<secret>
Withings refresh can rotate tokens. Persistence is configurable via:
WITHINGS_TOKEN_PERSIST:auto(default): persist to dotenv ifWITHINGS_ENV_PATH/env_pathis set, otherwise no-opdotenv: update the dotenv filesecret_manager: add a new Secret Manager version with updated tokensnoop: never persist
For Secret Manager persistence:
WITHINGS_TOKEN_SECRET_RESOURCE: e.g.projects/<project>/secrets/<secret>
Install deps:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtRun:
python withings_export.py --lookback-days 30 --out-dir withings_measurementsSee all options:
python withings_export.py --helpOn macOS/Linux, building with your host UID/GID helps bind-mounted directories and .env stay writable:
docker build \
--build-arg UID="$(id -u)" \
--build-arg GID="$(id -g)" \
-t withings-export .This mounts:
./.env→/app/.env(so refreshed tokens can be persisted)./withings_measurements→/data/withings_measurements(so exports persist)
mkdir -p withings_measurements
docker run --rm -it \
-v "$PWD/.env:/app/.env" \
-v "$PWD/withings_measurements:/data/withings_measurements" \
-e WITHINGS_ENV_PATH=/app/.env \
withings-export \
--out-dir /data/withings_measurements \
--lookback-days 30Default compose service mounts the same volumes and prints --help by default.
Run an export:
UID="$(id -u)" GID="$(id -g)" docker compose run --rm withings-export \
--out-dir /data/withings_measurements \
--lookback-days 30- Allowed date range:
--startcannot be earlier than2025-08-01(enforced inwithings_export.py). - Timezone handling: if you pass a naive datetime,
--tzcontrols which timezone it’s interpreted in. - GCS output:
--out-dircan be ags://bucket/prefixURI. You must provide Google credentials (Application Default Credentials) in the container and havegoogle-cloud-storageinstalled (it is included inrequirements.txt).
One workable pattern is:
- Put your Withings env vars in Secret Manager as a JSON object mapping env var names to values.
- Run the container with a service account that can access the secret.
- Optionally, allow the container to persist rotated tokens by granting permission to add secret versions and setting
WITHINGS_TOKEN_PERSIST=secret_manager.
Store something like:
{
"WITHINGS_APP_CLIENT_ID": "…",
"WITHINGS_APP_CLIENT_SECRET": "…",
"WITHINGS_APP_REFRESH_TOKEN": "…",
"WITHINGS_APP_ACCESS_TOKEN": "…",
"WITHINGS_APP_ACCESS_TOKEN_EXPIRES_AT": "2026-03-06T12:34:56+00:00"
}Set these when running on GCE:
WITHINGS_ENV_SOURCE=secret_managerWITHINGS_ENV_SECRET_RESOURCE=projects/<project>/secrets/<secret>WITHINGS_TOKEN_PERSIST=secret_managerWITHINGS_TOKEN_SECRET_RESOURCE=projects/<project>/secrets/<secret>
If you only load from Secret Manager:
roles/secretmanager.secretAccessor
If you also persist rotated tokens back to Secret Manager:
roles/secretmanager.secretAccessorroles/secretmanager.secretVersionAdder(or a broader Secret Manager role that can add versions)