Built and maintained by Avalux, a full-stack AI and automation agency. This repository is scaffolding for a migration you still have to run. It gives you an inventory pass over your IFTTT Applets, the account-conversion gate that blocks every rebuild, and a mapping from each retired Fitbit trigger to a real Fitbit Web API equivalent. It does not give you a finished integration. Credentials, hardening, retry logic, and your actual business rules are yours to add. Part of Avalux Open Source.
IFTTT is retiring its Fitbit service on September 30, 2026. Every Applet with a Fitbit trigger, a Fitbit query, or a Fitbit action stops working on that date. Confirm the exact date and scope against IFTTT's own help center before you plan around it, because deprecation timelines slip and this kit assumes the hard version of the deadline.
The reason this matters more than a normal service deprecation is the failure mode. When a connected service goes away, Applets do not throw an error your client sees. They stop running. The activity feed simply goes quiet. A studio that has been auto-logging member workouts into a Google Sheet for three years will not get an alert saying the pipeline died. They will notice six weeks later when a coach asks why nobody has a streak count anymore, and by then the gap in the data is unrecoverable because Fitbit only retains intraday history for the window your OAuth scopes allow you to read.
The second problem is inventory. Almost nobody knows how many Applets they actually have. In a typical ten-person studio we find Applets spread across the owner's personal IFTTT account, a shared ops account nobody can log into, and the account of a coach who left in 2024. Some are Applets the studio built. Some are published Applets they enabled from the IFTTT gallery, which means the logic is not even theirs to read. Counting them is the first real task.
The third problem is sequencing, and it is the one most teams get wrong. You cannot simply swap the Fitbit service for the new Google Health service on IFTTT and move on. Fitbit accounts created before the Google migration are legacy fitbit.com accounts. Google's health services authenticate against a Google Account. If the login behind your studio's Fitbit connection is still a legacy account, the new service will not connect at all, and the conversion is one way. That conversion has to happen before you touch any Applet, and it has to be coordinated with whoever owns the account, which is frequently a client rather than you.
This kit puts those three problems in order: inventory, conversion gate, rebuild.
This is aimed at operators, not consumers.
- Boutique fitness studios running class attendance, streak tracking, or challenge leaderboards off member Fitbit activity.
- Wellness and health coaches whose client check-in workflows fire when a client logs a workout, a weight, or a sleep session.
- Corporate wellness program administrators running step challenges across a few hundred employees, where the aggregation currently lands in Sheets or Airtable through IFTTT.
- Small agencies and ops consultants who inherited a client's consumer-grade automation stack and now own the migration.
It is not for you if you have one personal Applet that posts your step count to a Discord channel. Delete it and rebuild it by hand in ten minutes. It is also not for you if you already run a health data platform with a warehouse behind it, because you have better tooling than a CSV worksheet.
You will need: Python 3.10 or newer, a registered app at dev.fitbit.com, an HTTPS endpoint you control for webhook delivery, and access to the IFTTT account that owns the Applets.
fitbit-applet-migration-kit/
├── src/
│ └── applet_inventory.py # inventory pass, conversion gate, worksheet output
├── data/
│ └── applets.sample.json # shape the inventory expects
├── .env.example # credentials and endpoint config
├── LICENSE # MIT
└── README.md
applet_inventory.py is the shipped piece. It reads an Applet export, walks every trigger, query, and action step, flags the ones bound to the Fitbit service, resolves each to a rebuild path on the Fitbit Web API, runs a live token check to tell you whether the underlying account still authorizes, and writes a migration worksheet as CSV.
Deliberately not included, because these are the parts that have to be built against your stack rather than copy-pasted: the subscriber endpoint itself, your notification sink, the reconciliation sweep, and per-member token storage. The mapping tables and the handshake details below are what you need to write them, and the "What you still have to build" section is explicit about the work.
git clone https://github.com/elikem2021/fitbit-applet-migration-kit.git
cd fitbit-applet-migration-kit
python3 -m venv .venv && source .venv/bin/activate
pip install requests
cp .env.example .env
# fill in FITBIT_CLIENT_ID, FITBIT_CLIENT_SECRET, FITBIT_ACCESS_TOKEN
export $(grep -v '^#' .env | xargs)
python src/applet_inventory.py \
--applets data/applets.sample.json \
--out migration-worksheet.csvOutput is one row per Fitbit-dependent step, with the owning Applet, the role the step plays, the rebuild path, and the conversion status of the account behind it. Sort by conversion status and you have your work queue.
There is no public REST endpoint that hands you an arbitrary user's Applet inventory, and screen-scraping the IFTTT dashboard is a fragile play we will not ship. Two supported routes:
- The IFTTT MCP server. If you have access,
my_appletsreturns the Applet list for the connected account andget_appletreturns the step detail for each one. Dump those responses to JSON and point the inventory at the file.get_activity_feedis the companion call worth making, because it is how you get a real last-run timestamp instead of a guess. - An IFTTT account data export. Request it from account settings, then normalize it into the shape below.
The inventory expects records like this, and will accept either service_slug or service on each step:
{
"applets": [
{
"id": "aBc123",
"name": "Log member workout to studio roster",
"owner": "ops@example-studio.com",
"status": "enabled",
"last_run": "2026-09-14T06:12:00Z",
"triggers": [{"service_slug": "fitbit", "name": "New activity logged"}],
"actions": [{"service_slug": "google_sheets", "name": "Add row to spreadsheet"}]
}
]
}Run the inventory once per IFTTT account. The forgotten accounts are where the surprises live.
Before anything else, sort every account into one of three states and record it on the worksheet:
| State | Meaning | Action |
|---|---|---|
legacy |
Still signs in with a fitbit.com email and password | Convert to a Google Account first. Nothing downstream works until this is done. |
converted |
Signs in with Google, Fitbit data intact | Ready for the new service and for a fresh OAuth grant. |
unknown |
Nobody at the studio remembers | Treat as legacy until a human confirms by attempting a sign-in. |
Use encodedId from the Fitbit profile as your join key across the migration, not the email address, because emails change during conversion and IDs generally do not. Verify that assumption on a throwaway account of your own before you trust it across a member roster. A usable mapping sheet looks like this:
member_ref encodedId login_type conversion subscription_id last_notified
M-0114 2ABCDE google converted sub-M-0114 2026-09-16T05:02Z
M-0119 3FGHIJ fitbit.com legacy (blocked) (none)
For a corporate wellness program this is the entire project. Two hundred employees each have to convert their own account. You cannot do it for them, so the deliverable is a tracked comms sequence with a deadline, and the worksheet is what you track against.
The replacement for an IFTTT Fitbit trigger is a subscription plus a read, not a poll. Base URL is https://api.fitbit.com. Auth is OAuth 2.0 authorization code with PKCE against https://api.fitbit.com/oauth2/token. Request only the scopes you need: activity, heartrate, sleep, weight, profile. Per-user rate limit is 150 requests per hour, which is the number that kills naive polling designs.
The math: 240 members polled every 15 minutes is 4 requests per member per hour, comfortably inside the limit. Fan that out to five endpoints per poll and you are at 20 per hour per member, still inside, but now you are burning 4,800 requests an hour to learn almost nothing, since most members log nothing most hours. Subscriptions collapse that to one inbound notification per actual change.
Mapping from the retired IFTTT triggers:
| IFTTT Fitbit trigger | Subscription collection | Read after notification |
|---|---|---|
| New activity logged | activities |
GET /1/user/-/activities/list.json |
| Daily activity summary | activities |
GET /1/user/-/activities/date/{date}.json |
| Daily step goal achieved | activities |
summary steps compared against GET /1/user/-/activities/goals/daily.json |
| New sleep logged | sleep |
GET /1.2/user/-/sleep/date/{date}.json |
| New weight logged | body |
GET /1/user/-/body/log/weight/date/{date}.json |
| (no IFTTT equivalent) | userRevokedAccess |
revoke locally, stop all downstream sends |
Subscribe with POST /1/user/-/{collection}/apiSubscriptions/{subscription-id}.json. Pick a subscription-id that is your own stable member reference so notifications route without a lookup table.
The subscriber endpoint handshake has two halves people miss. First, verification: Fitbit sends GET /your-endpoint?verify=<code> and expects 204 when the code matches the one in your dev.fitbit.com app settings and 404 when it does not. Returning 200 for both fails the check. Second, every notification POST carries X-Fitbit-Signature, an HMAC-SHA1 of the raw request body keyed on your client secret with a trailing ampersand, base64 encoded:
import base64, hashlib, hmac
def valid_signature(raw_body: bytes, header: str, client_secret: str) -> bool:
key = (client_secret + "&").encode()
digest = hmac.new(key, raw_body, hashlib.sha1).digest()
return hmac.compare_digest(base64.b64encode(digest).decode(), header)Validate against the raw bytes, before any JSON parsing or framework middleware reformats the body. Verify the current header name and key construction against Fitbit's developer docs when you implement, since these details do change.
Notifications arrive in minutes, not seconds, and delivery is not guaranteed. Build a reconciliation sweep that re-reads the last 48 hours for any member whose data looks thinner than their history suggests it should, and alert when a member with a daily logging pattern goes quiet for longer than their normal gap. That quiet-detection job is the thing that would have caught the original IFTTT failure, so build it even if you never expect to need it.
This repository stops well short of production. You still need token storage with encryption at rest and a refresh loop, idempotency on notification handling because Fitbit will redeliver, a dead letter queue for failed downstream sends, consent and retention handling for health data that your jurisdiction almost certainly regulates, and the actual destination integration that replaces whatever the old Applet's action step was doing. Treat what is here as the first two days of a two-week migration.
Avalux builds automation for small and mid-sized businesses, which means we spend a lot of time inside stacks that were assembled by a founder on a Sunday and then quietly became load-bearing. Consumer glue is genuinely good at getting a business to its first working workflow. It is bad at surviving a vendor deprecation, because the failure is silent and the inventory is unknowable.
We built this kit after watching the same pattern repeat: the deadline is public for months, nobody maps their exposure, and the scramble happens in the last two weeks with incomplete information. The inventory pass is boring and it is the part that actually reduces risk, so it is the part we open sourced.
If you would rather not run this migration yourself, or you want the hardened version with token storage, reconciliation, and monitoring already built, that is the kind of work we do. Reach us at avalux.io.
- freight-eta-toolkit — ETA calculation and exception detection for freight operations.
- Avalux Open Source — the full index of what we publish.
Issues and pull requests are welcome, particularly corrections to the trigger mapping table from anyone who has run this migration in anger.
MIT. See LICENSE. Use it commercially, fork it, ship it to clients, no attribution required.
fitbit ifttt shutdown, google health service migration, fitbit applet replacement, ifttt fitbit service retirement September 30 2026, fitbit web api subscriptions, fitbit legacy account to google account conversion, ifttt applet inventory, fitbit webhook subscriber endpoint, x-fitbit-signature validation, fitness studio automation migration, corporate wellness step challenge api, wellness coach client automation, fitbit oauth2 pkce scopes, fitbit api rate limit 150 requests per hour, replace ifttt applet with api integration