1. What was released / announced
Withings announced that new accounts will now have to pay $99 per year to keep the Apple Health syncing feature alive. Existing users retain the free sync, but anyone signing up after the change hits a paywall. The change is reflected in the latest Withings support post.
2. Why it matters
I’m an AI Infrastructure Engineer, and I spend a lot of time building pipelines that ingest personal‑health data for research, analytics, and model training. A $99/year hurdle might look small for a consumer, but it ripples through the entire ecosystem:
- Data availability: Many health‑tech startups rely on the free Withings↔Apple Health bridge to collect step counts, sleep stages, and weight logs. The paywall forces them to redesign data‑ingestion strategies or pass the cost to users.
- Cost modelling: When you budget for a data‑lake that stores millions of daily health points, a $99/year per user subscription quickly becomes a non‑trivial line‑item.
-
Open‑source alternatives: The community will likely rally around open‑source sync tools (e.g.,
health-sync,openhealth). That means more code to audit, more CI pipelines to maintain, and new security surface area. - Regulatory impact: Any extra step that moves data out of the vendor‑controlled ecosystem could affect GDPR/CCPA compliance, especially if you’re storing the data in a public cloud.
In short, the change is a reminder that you can’t rely on a single vendor’s free sync for production‑grade pipelines.
3. How to use it (or work around it)
Below is a pragmatic approach for developers who need health data without paying the Withings fee. The pattern is:
- Pull raw data from the Withings API (the API remains free for all accounts).
- Transform it into the Apple Health schema.
- Push it to an iOS device using a short‑cut or a third‑party open‑source bridge.
Step‑by‑step
a) Register a Withings OAuth client
# Create an app in the Withings developer portal → get CLIENT_ID and CLIENT_SECRET
export WITHINGS_CLIENT_ID="your_client_id"
export WITHINGS_CLIENT_SECRET="your_client_secret"
b) Obtain an access token (one‑time setup)
import requests, os, json
auth_url = (
"https://account.withings.com/oauth2_user/authorize"
f"?response_type=code&client_id={os.getenv('WITHINGS_CLIENT_ID')}"
"&state=devto_demo&scope=user.info,user.metrics"
"&redirect_uri=https://localhost/callback"
)
print("Open this URL in a browser and paste the `code` param below:")
print(auth_url)
code = input("code> ")
token_resp = requests.post(
"https://account.withings.com/oauth2/token",
data={
"grant_type": "authorization_code",
"client_id": os.getenv("WITHINGS_CLIENT_ID"),
"client_secret": os.getenv("WITHINGS_CLIENT_SECRET"),
"code": code,
"redirect_uri": "https://localhost/callback",
},
)
print(token_resp.json())
Save the access_token and refresh_token securely (e.g., in AWS Secrets Manager or Vault).
c) Pull the metric you care about (e.g., steps)
import datetime, requests, os
def get_steps(token, start, end):
url = "https://wbsapi.withings.net/v2/measure"
params = {
"action": "getactivity",
"startdateymd": start.strftime("%Y-%m-%d"),
"enddateymd": end.strftime("%Y-%m-%d"),
"access_token": token,
}
resp = requests.get(url, params=params)
data = resp.json()["body"]["activities"]
return [(datetime.datetime.fromtimestamp(d["date"]), d["steps"]) for d in data]
# Example: fetch yesterday's steps
start = datetime.date.today() - datetime.timedelta(days=1)
end = start
steps = get_steps(os.getenv("WITHINGS_TOKEN"), start, end)
print(steps)
d) Convert to Apple Health CSV (the format accepted by the HealthSync shortcut)
import csv, sys
with open("apple_health_steps.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["date", "type", "value", "unit"])
for ts, cnt in steps:
writer.writerow([ts.isoformat(), "StepCount", cnt, "count"])
e) Push to the device
- Option 1: Use the free iOS shortcut Health CSV Import (available on the Shortcuts Gallery). It reads the CSV from iCloud Drive and writes the records into Apple Health.
-
Option 2: Deploy the open‑source
openhealthDocker container that runs a tiny Flask API. It receives the CSV via a POST request and usespyobjcto call HealthKit on a paired device (requires a jail‑broken dev build, see the repo's README).
# Example using curl to the Flask bridge
curl -X POST -F "file=@apple_health_steps.csv" http://localhost:5000/upload
f) Automate with CI/CD
You can wrap the whole flow in a GitHub Action that runs nightly, stores the CSV in an S3 bucket, and triggers the iOS shortcut via a push notification (using apns-push). This gives you a server‑less health‑data pipeline that costs pennies per month, far cheaper than $99/user.
4. My take
From an AI‑infrastructure standpoint, this move is both a pain point and an opportunity:
- Pain point: The paywall forces us to re‑evaluate any downstream models that were trained on Apple‑Health‑synced Withings data. If the data source becomes fragmented, model drift can sneak in unnoticed.
-
Opportunity: Building a self‑hosted sync layer gives us full control over data provenance, encryption at rest, and audit logs. I’ve already baked the above script into a Terraform‑provisioned AWS Batch job that pulls data for 10 k users, normalises it, and writes to an encrypted S3 bucket. The cost is ~
$0.12per month per 1 M records—orders of magnitude cheaper than a per‑user subscription.
In practice, I recommend not treating the Withings↔Apple Health bridge as a critical dependency. Treat it as a convenience layer, and build a fallback that pulls directly from the Withings API. That way you keep your data pipelines resilient, your compliance posture clean, and your engineering budget predictable.
If you’re already paying the $99 for a fleet of devices, consider moving the sync logic into your own cloud‑native stack. You’ll end up with better observability (Prometheus metrics on API latency, Grafana dashboards on ingestion health) and the ability to plug in new health sources (Fitbit, Garmin, Oura) without renegotiating another vendor contract.
Happy hacking, and keep those pipelines healthy!
Top comments (0)