{
  "name": "AIFitnessAPI answer index",
  "description": "Every question this site owns, with its answer, canonical URL, markdown mirror and review date. One object per page; FAQ entries carry deep links to the individual answer.",
  "site": "https://aifitnessapi.com",
  "publisher": {
    "name": "AIFitnessAPI",
    "url": "https://aifitnessapi.com",
    "publishing_principles": "https://aifitnessapi.com/methodology",
    "funding_disclosure": "This site is funded by KinesteX, an AI motion SDK. Pages that cover KinesteX are flagged first_party and carry a rendered disclosure."
  },
  "license": "Quotable with attribution. Cite the canonical URL.",
  "conventions": {
    "markdown_mirror": "Append .md to any page URL.",
    "llms_txt": "https://aifitnessapi.com/llms.txt",
    "llms_full_txt": "https://aifitnessapi.com/llms-full.txt",
    "changes_feed": "https://aifitnessapi.com/changes.xml",
    "claims_index": "https://aifitnessapi.com/claims.json"
  },
  "generated": 276,
  "clusters": 21,
  "answers": [
    {
      "question": "exercise database API",
      "answer": "For zero-cost, obligation-free bootstrapping, use the public-domain free-exercise-db dataset; for a maintained self-hosted stack, use wger. If you need ready-made animated GIFs or video from a hosted endpoint, budget for a commercial ExerciseDB tier, and if you only need text metadata, API Ninjas Exercises fits. Two axes decide it: license and hosting, and media depth. All reported exercise counts are volatile, so verify them at the source.",
      "title": "The Best Exercise Database APIs for Developers (2026)",
      "url": "https://aifitnessapi.com/fitness-apis/exercise-database-apis",
      "markdown": "https://aifitnessapi.com/fitness-apis/exercise-database-apis.md",
      "cluster": "Fitness APIs",
      "cluster_url": "https://aifitnessapi.com/fitness-apis",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the best free exercise database API?",
          "answer": "The most obligation-free option is the free-exercise-db dataset, which is public domain (Unlicense) with 800+ reported exercises and static images, but you host it yourself. wger is a free, self-hostable open-source option with a public read API. Truly free hosted APIs are rare; most commercial listings are free-tier-of-paid with rate caps.",
          "url": "https://aifitnessapi.com/fitness-apis/exercise-database-apis#faq-1"
        },
        {
          "question": "Why are there two different ExerciseDB APIs?",
          "answer": "The name is shared by two separate projects: the older commercial listing on RapidAPI (publisher justin-WFnsXH_t6), historically around 1,300+ exercises with GIFs, and the newer exercisedb.dev project (exercisedb/exercisedb-api), AGPL-3.0, reporting 11,000+ exercises. They have different owners, counts, and access models, so check the URL to see which one a tutorial means.",
          "url": "https://aifitnessapi.com/fitness-apis/exercise-database-apis#faq-2"
        },
        {
          "question": "Which exercise API has GIFs or video demonstrations?",
          "answer": "Animated media is the main paywall differentiator. The commercial ExerciseDB on RapidAPI provides animated GIFs, and exercisedb.dev reports a larger library including video. The open datasets (free-exercise-db and wger) provide static images only, and API Ninjas Exercises has no media at all.",
          "url": "https://aifitnessapi.com/fitness-apis/exercise-database-apis#faq-3"
        },
        {
          "question": "Is wger's exercise API really free to use?",
          "answer": "Yes. wger is open source with no per-request fees, and its public exercise-list endpoints are readable without authentication. The costs are self-hosting if you run your own instance, plus license obligations: AGPL-3.0 copyleft on deployed modifications and Creative Commons attribution and share-alike on the exercise data.",
          "url": "https://aifitnessapi.com/fitness-apis/exercise-database-apis#faq-4"
        },
        {
          "question": "Does API Ninjas offer a free exercise endpoint?",
          "answer": "Not for exercises specifically. API Ninjas has a free tier for other endpoints, but the Exercises endpoint is reported to be premium-only, available on paid Business or Professional plans. Verify the current tier gating at their pricing page before building, as it changes.",
          "url": "https://aifitnessapi.com/fitness-apis/exercise-database-apis#faq-5"
        }
      ]
    },
    {
      "question": "wearable fitness API",
      "answer": "The best wearable fitness API depends on your use-case, since all five major options — Fitbit (Google), Garmin, Oura, WHOOP and Polar — use OAuth 2.0 with per-user consent and are free to use as of 2026. Pick Garmin for serious GPS and multisport with the widest health metrics, Oura or WHOOP for sleep and recovery data, Fitbit for broad mainstream reach and intraday data, and Polar if you want the least approval friction. The real gate is not price but getting approved to read other users' data plus your users owning the hardware.",
      "title": "The Best Wearable Fitness & Health-Data APIs (2026)",
      "url": "https://aifitnessapi.com/fitness-apis/wearable-data-apis",
      "markdown": "https://aifitnessapi.com/fitness-apis/wearable-data-apis.md",
      "cluster": "Fitness APIs",
      "cluster_url": "https://aifitnessapi.com/fitness-apis",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Are wearable fitness APIs free to use?",
          "answer": "As of 2026, Fitbit/Google, Garmin, Oura, WHOOP and Polar all publish no per-call fee and are documented as free to use. The real cost is clearing an approval or review step and your users owning the hardware — and, for WHOOP, a paid membership. Verify current commercial terms for at-scale use.",
          "url": "https://aifitnessapi.com/fitness-apis/wearable-data-apis#faq-1"
        },
        {
          "question": "Which wearable API is best for GPS and running data?",
          "answer": "Garmin is generally the richest for GPS, multisport and endurance metrics, with over 100 activity types plus session detail. Polar is a strong low-friction alternative and exports activities as TCX or GPX. Note Garmin requires partner approval and, as of 2026, new developer sign-ups are reportedly on hold (verify).",
          "url": "https://aifitnessapi.com/fitness-apis/wearable-data-apis#faq-2"
        },
        {
          "question": "Do wearable APIs push data to me, or do I have to poll for it?",
          "answer": "It varies by provider, and it changes your architecture. Garmin delivers through registerable push and ping callback URLs, so you build an event consumer rather than a scheduler, and WHOOP documents webhook support. Fitbit is request-response REST that you poll on your own schedule, and Polar's Open AccessLink exposes only recent data, so you sync regularly or lose history. If you support several of these, expect to run both patterns side by side behind one normalization layer, with idempotency and ordering guards on the pushed events.",
          "url": "https://aifitnessapi.com/fitness-apis/wearable-data-apis#faq-3"
        },
        {
          "question": "Do wearable APIs let me pull data for all users at once?",
          "answer": "No. These are consent-based OAuth 2.0 APIs that return data only for individual users who explicitly authorize your app — none is a bulk or population data feed. Most also cap you to a small number of users (often 10) until you pass a production approval review.",
          "url": "https://aifitnessapi.com/fitness-apis/wearable-data-apis#faq-4"
        },
        {
          "question": "Which wearable API has the least approval friction?",
          "answer": "Polar's Open AccessLink is generally the most self-serve: you register a client yourself and tokens are long-lived. The trade-off is that it exposes only recent data, so you must sync or export regularly to retain history. Verify the current terms in Polar's developer docs.",
          "url": "https://aifitnessapi.com/fitness-apis/wearable-data-apis#faq-5"
        }
      ]
    },
    {
      "question": "health data aggregator API",
      "answer": "A health-data aggregator API lets you integrate once and read normalized data from hundreds of wearables instead of building a separate integration per device. The four to know in 2026 are Terra (widest coverage, credit/usage pricing), Vital/Junction (wearables plus lab diagnostics), Rook (usage-based active-user pricing with strong on-device SDKs), and Spike (broadest 360-degree scope including IoT, EMR, and labs). Pick by what you need: coverage and schema depth point to Terra, labs point to Vital/Junction, active-user pricing points to Rook, and non-wearable sources point to Spike.",
      "title": "The Best Health-Data Aggregator APIs (2026)",
      "url": "https://aifitnessapi.com/fitness-apis/health-data-aggregator-apis",
      "markdown": "https://aifitnessapi.com/fitness-apis/health-data-aggregator-apis.md",
      "cluster": "Fitness APIs",
      "cluster_url": "https://aifitnessapi.com/fitness-apis",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "What is a health data aggregator API?",
          "answer": "It is a server-side API that normalizes data from many wearables and health accounts behind one integration, so you connect once instead of coding against Garmin, Oura, Fitbit, and others separately. Aggregators typically sit on top of platform SDKs like Apple HealthKit and Google Health Connect plus cloud provider APIs. Terra, Vital/Junction, Rook, and Spike are the main options.",
          "url": "https://aifitnessapi.com/fitness-apis/health-data-aggregator-apis#faq-1"
        },
        {
          "question": "How is an aggregator different from Apple HealthKit or Google Health Connect?",
          "answer": "HealthKit and Health Connect are on-device, OS-locked SDKs that only expose data on that one device and are free but platform-bound. Aggregators are server-side and cross-device: one integration reads across hundreds of wearables and cloud accounts, and their mobile SDKs also pull from HealthKit and Health Connect. So aggregators sit on top of the platform SDKs rather than replacing them.",
          "url": "https://aifitnessapi.com/fitness-apis/health-data-aggregator-apis#faq-2"
        },
        {
          "question": "Do I still need my own developer accounts with each wearable provider?",
          "answer": "For most providers the aggregator brokers the auth, but for several popular ones — commonly Garmin, Whoop, Strava, Dexcom, and Samsung Health — you must still register your own developer or partner credentials. Check which providers on your list require it, since it adds onboarding time. This applies across Terra, Vital/Junction, Rook, and Spike.",
          "url": "https://aifitnessapi.com/fitness-apis/health-data-aggregator-apis#faq-3"
        },
        {
          "question": "How much do health data aggregator APIs cost?",
          "answer": "The pricing models differ and exact figures change, so verify current pricing on each vendor's page. As of 2026, Terra uses subscription plus credit/usage-based pricing, Vital/Junction is per-user with a monthly minimum, Rook is usage-based tiered by active users, and Spike is tiered and sales-assisted (effectively contact-sales).",
          "url": "https://aifitnessapi.com/fitness-apis/health-data-aggregator-apis#faq-4"
        },
        {
          "question": "Which aggregator API supports lab and diagnostics data?",
          "answer": "Vital/Junction is the option built around both wearable data and at-home or in-person lab diagnostics in one integration, though its lab testing is US-focused. Spike also markets lab tests as part of its broader 360-degree scope that includes IoT and EMR data. Verify current coverage in each vendor's docs.",
          "url": "https://aifitnessapi.com/fitness-apis/health-data-aggregator-apis#faq-5"
        }
      ]
    },
    {
      "question": "AI workout tracking API",
      "answer": "For camera-based rep counting and form feedback without building a computer-vision team, an AI workout-tracking SDK is usually the most direct path. Pick KinesteX or Sency for broad cross-platform consumer fitness coaching, Kemtai for clinical and physiotherapy work, and QuickPose for iOS teams that want a self-serve free tier. If motion analysis is your core product, build on free pose primitives like MediaPipe, MoveNet, or Apple Vision instead. The keypoints are free and commoditized; the recurring cost is the rep logic, form rules, and exercise coverage on top.",
      "title": "The Best AI Workout & Motion-Tracking APIs (2026)",
      "url": "https://aifitnessapi.com/fitness-apis/ai-workout-tracking-apis",
      "markdown": "https://aifitnessapi.com/fitness-apis/ai-workout-tracking-apis.md",
      "cluster": "Fitness APIs",
      "cluster_url": "https://aifitnessapi.com/fitness-apis",
      "last_reviewed": "2026-08-02",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the difference between a pose estimation API and an AI workout tracking SDK?",
          "answer": "A pose-estimation API such as MediaPipe, MoveNet, or Apple Vision gives you a skeleton of joint keypoints per frame and nothing more. A workout-tracking SDK such as KinesteX, Kemtai, Sency, or QuickPose adds the application logic on top: rep counting, per-exercise form rules, exercise libraries, and feedback UI.",
          "url": "https://aifitnessapi.com/fitness-apis/ai-workout-tracking-apis#faq-1"
        },
        {
          "question": "Is there a free AI workout tracking API?",
          "answer": "The pose-estimation primitives are free and permissively licensed: MediaPipe/BlazePose and TensorFlow MoveNet are Apache-2.0, and Apple Vision is free within the Apple SDK. Among commercial coaching SDKs, QuickPose offers a self-serve free tier up to a device threshold; others are usage-based and mostly contact-sales. Verify current tiers in each vendor's docs.",
          "url": "https://aifitnessapi.com/fitness-apis/ai-workout-tracking-apis#faq-2"
        },
        {
          "question": "Can I build my own rep counting instead of using an SDK?",
          "answer": "Yes. Free pose primitives give you the keypoints, and you can write your own rep-counting and form logic on top. The trade-off is that this is a multi-month effort for a CV/ML team and it recurs as maintenance, since each new exercise needs its own logic and accuracy must be tuned across body types, camera angles, lighting, and devices.",
          "url": "https://aifitnessapi.com/fitness-apis/ai-workout-tracking-apis#faq-3"
        },
        {
          "question": "Which AI motion-tracking SDK is best for physiotherapy or rehab?",
          "answer": "Kemtai is positioned for clinical, physiotherapy, and MSK use cases, citing a large exercise library plus assessment and adherence data delivered as both an embedded experience and an API. Confirm its pricing and any validation claims directly with the vendor.",
          "url": "https://aifitnessapi.com/fitness-apis/ai-workout-tracking-apis#faq-4"
        },
        {
          "question": "Do these workout tracking SDKs run on-device or in the cloud?",
          "answer": "The raw pose primitives run on the client. The commercial SDKs differ: QuickPose ships MediaPipe models inside your app, Sency emphasizes on-device inference, and KinesteX describes optional edge processing — optional, so confirm what your configuration does. Verify the specifics per vendor before relying on them for privacy or compliance positioning.",
          "url": "https://aifitnessapi.com/fitness-apis/ai-workout-tracking-apis#faq-5"
        }
      ]
    },
    {
      "question": "nutrition API",
      "answer": "For free, authoritative nutrient data, use the USDA FoodData Central API (public domain, free key); for global barcode and packaged-product data, use Open Food Facts (open data, no key). If you need natural-language meal logging or restaurant coverage, Nutritionix fits; Edamam bundles food lookup, nutrition analysis, and recipes; Spoonacular is best for recipe and ingredient apps. Verify current pricing and quotas before committing.",
      "title": "The Best Nutrition & Food Database APIs (2026)",
      "url": "https://aifitnessapi.com/fitness-apis/nutrition-apis",
      "markdown": "https://aifitnessapi.com/fitness-apis/nutrition-apis.md",
      "cluster": "Fitness APIs",
      "cluster_url": "https://aifitnessapi.com/fitness-apis",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the best free nutrition API?",
          "answer": "The USDA FoodData Central API is the best free source for authoritative nutrient data — it is public domain (CC0) and needs only a free data.gov key. For barcode and packaged-product data, Open Food Facts is free open data with no API key required (just a custom User-Agent header).",
          "url": "https://aifitnessapi.com/fitness-apis/nutrition-apis#faq-1"
        },
        {
          "question": "Which nutrition API can parse a meal from plain text?",
          "answer": "Nutritionix and Edamam both parse free-text meal descriptions like \"1 cup rice and 2 eggs\" into structured nutrient data. USDA FoodData Central and Open Food Facts do not offer natural-language meal parsing, and Spoonacular focuses on recipes and ingredients rather than free-text meal logging.",
          "url": "https://aifitnessapi.com/fitness-apis/nutrition-apis#faq-2"
        },
        {
          "question": "Does Nutritionix have a free tier?",
          "answer": "As of 2026, sources conflict — some describe a free entry tier plus paid plans, while others say public free or non-commercial trials were discontinued. Confirm the current access terms and pricing directly with Nutritionix before building.",
          "url": "https://aifitnessapi.com/fitness-apis/nutrition-apis#faq-3"
        },
        {
          "question": "Which nutrition API supports barcode lookup?",
          "answer": "Nutritionix, Edamam, Spoonacular, and Open Food Facts all support barcode or UPC lookup. Open Food Facts makes it the core call and is free with no key. USDA FoodData Central includes GTIN/UPC fields in its Branded Foods dataset but is oriented around its own food IDs rather than a consumer barcode-lookup product.",
          "url": "https://aifitnessapi.com/fitness-apis/nutrition-apis#faq-4"
        },
        {
          "question": "Is Open Food Facts free to use commercially?",
          "answer": "Yes, Open Food Facts data can be used for any purpose including commercial use, but it is licensed under the ODbL with a share-alike obligation — derived databases combining its data may have to be released as open data. Attribution is also required, and the data is crowdsourced with no accuracy guarantee.",
          "url": "https://aifitnessapi.com/fitness-apis/nutrition-apis#faq-5"
        }
      ]
    },
    {
      "question": "free fitness API",
      "answer": "For zero-cost, zero-licensing-friction exercise data, use the free-exercise-db dataset (public domain). For a maintained self-hostable stack, use wger (open source, mind AGPL and CC attribution). For nutrition, USDA FoodData Central is free and public domain, and Open Food Facts is free open data for barcodes. Apple HealthKit and Google Health Connect are free but platform-bound to one OS and on-device only. The key distinction: genuinely-free/open options let you own and self-host the data, while free tiers of commercial APIs are borrowed access you can lose when you scale.",
      "title": "Free & Open-Source Fitness APIs (2026)",
      "url": "https://aifitnessapi.com/fitness-apis/free-fitness-apis",
      "markdown": "https://aifitnessapi.com/fitness-apis/free-fitness-apis.md",
      "cluster": "Fitness APIs",
      "cluster_url": "https://aifitnessapi.com/fitness-apis",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Is there a completely free fitness API with no rate limits?",
          "answer": "Yes, if you self-host. The free-exercise-db dataset (Unlicense/public domain) and wger (open source, self-hostable) are just data you download and serve, so there are no per-request quotas. Hosted free options like USDA FoodData Central and Open Food Facts are free but do meter requests.",
          "url": "https://aifitnessapi.com/fitness-apis/free-fitness-apis#faq-1"
        },
        {
          "question": "Which free fitness APIs let you self-host the data?",
          "answer": "For obligation-free bootstrapping, the free-exercise-db dataset (800+ exercises, public domain, static images) is the lowest-friction choice as of 2026. For a maintained, self-hostable stack with a REST API, wger is the leading self-hostable open-source option, though its software is AGPL-3.0 and its data is Creative Commons (attribution/share-alike).",
          "url": "https://aifitnessapi.com/fitness-apis/free-fitness-apis#faq-2"
        },
        {
          "question": "Are Apple HealthKit and Google Health Connect free?",
          "answer": "Yes, both are free to use with no per-call fee. The catch is that they are platform-bound: HealthKit runs only on Apple devices and Health Connect only on Android, both are on-device, and neither gives you server-to-server or cross-user access on its own.",
          "url": "https://aifitnessapi.com/fitness-apis/free-fitness-apis#faq-3"
        },
        {
          "question": "Is USDA FoodData Central free for commercial use?",
          "answer": "Yes. USDA FoodData Central is U.S. government data published in the public domain under CC0, so it is free for any use including commercial, with no license fee and no attribution required (USDA requests but does not require credit). You only need a free data.gov API key, and rate limits apply, so verify current limits in the docs.",
          "url": "https://aifitnessapi.com/fitness-apis/free-fitness-apis#faq-4"
        },
        {
          "question": "What is the catch with free-tier fitness APIs?",
          "answer": "Free tiers of commercial APIs are access you borrow, not data you own. Expect hard rate limits, no support or SLA, and feature or media gating that hides the higher exercise counts and GIF/video content behind paid plans. Free open data has its own strings: attribution and copyleft obligations like AGPL, CC-BY-SA, and ODbL, except for public-domain sources.",
          "url": "https://aifitnessapi.com/fitness-apis/free-fitness-apis#faq-5"
        }
      ]
    },
    {
      "question": "HealthKit vs Health Connect",
      "answer": "HealthKit and Health Connect are not an either/or choice — they are the on-device health stores for two different operating systems, so a cross-platform app implements both. Use Apple HealthKit for iOS, iPadOS, watchOS and visionOS, and Google Health Connect for Android 14 and up; both are free and both use per-data-type OS permission prompts rather than OAuth. If you would rather not build and maintain two native integrations, an aggregator API wraps both behind one integration.",
      "title": "Apple HealthKit vs Google Health Connect (2026)",
      "url": "https://aifitnessapi.com/fitness-apis/apple-healthkit-vs-google-health-connect",
      "markdown": "https://aifitnessapi.com/fitness-apis/apple-healthkit-vs-google-health-connect.md",
      "cluster": "Fitness APIs",
      "cluster_url": "https://aifitnessapi.com/fitness-apis",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Is HealthKit or Health Connect better for a cross-platform app?",
          "answer": "Neither on its own. They cover different operating systems, so a cross-platform app implements both — HealthKit on Apple platforms and Health Connect on Android — or uses an aggregator API that wraps both behind one integration.",
          "url": "https://aifitnessapi.com/fitness-apis/apple-healthkit-vs-google-health-connect#faq-1"
        },
        {
          "question": "What review or declaration steps do HealthKit and Health Connect require before launch?",
          "answer": "Both gate your release on a declaration, not just on code. On Apple platforms you declare the health data your app touches with usage-description strings and request read/write authorization from a user-initiated context, and App Store review checks that the stated purpose matches what you do. On Android you declare Health Connect permissions in the manifest, and the Play Console enforces a separate health-data declaration and review before you can publish. Budget calendar time for both, request only the types you can justify, and confirm current review policy before you submit.",
          "url": "https://aifitnessapi.com/fitness-apis/apple-healthkit-vs-google-health-connect#faq-2"
        },
        {
          "question": "Can a HealthKit app tell if the user denied read access?",
          "answer": "No. By design, denied read permission in HealthKit returns empty data rather than an error, so the app cannot distinguish a denial from a user who simply has no recorded data — which complicates data-completeness logic.",
          "url": "https://aifitnessapi.com/fitness-apis/apple-healthkit-vs-google-health-connect#faq-3"
        },
        {
          "question": "How much history can Health Connect read by default?",
          "answer": "About 30 days prior to the first grant, unless the app requests the historical read-health-data-history permission. The Play Store also enforces a health-data declaration review before launch.",
          "url": "https://aifitnessapi.com/fitness-apis/apple-healthkit-vs-google-health-connect#faq-4"
        },
        {
          "question": "Are HealthKit and Health Connect free?",
          "answer": "Yes. Both are free with no per-call fee. HealthKit is included with the Apple Developer Program (a paid membership is needed to ship apps — verify current pricing), and Health Connect is part of the Android platform. The real cost is platform lock: HealthKit is Apple-only and Health Connect is Android-only.",
          "url": "https://aifitnessapi.com/fitness-apis/apple-healthkit-vs-google-health-connect#faq-5"
        }
      ]
    },
    {
      "question": "Terra vs Vital",
      "answer": "Pick Vital (rebranded to Junction in 2025) if you need wearable data plus US at-home or lab diagnostics in one integration. Pick Terra if you want the widest wearable and provider coverage plus a rich normalized schema, including CGM and nutrition. Both aggregate many wearables through a single API and can ingest Apple HealthKit and Android Health Connect via mobile SDKs; the choice comes down to whether labs are on your roadmap. Verify current pricing with each vendor before committing.",
      "title": "Terra vs Vital (Junction): Health-Data APIs Compared (2026)",
      "url": "https://aifitnessapi.com/fitness-apis/terra-vs-vital",
      "markdown": "https://aifitnessapi.com/fitness-apis/terra-vs-vital.md",
      "cluster": "Fitness APIs",
      "cluster_url": "https://aifitnessapi.com/fitness-apis",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Is Vital the same as Junction?",
          "answer": "Yes. Vital rebranded to Junction in 2025 after an $18M raise. It is the same product; current docs live at junction.com, and the older tryvital domain still resolves.",
          "url": "https://aifitnessapi.com/fitness-apis/terra-vs-vital#faq-1"
        },
        {
          "question": "What is the main difference between Terra and Vital/Junction?",
          "answer": "Terra focuses on the widest wearable and provider coverage with a rich normalized schema, including CGM and nutrition. Vital/Junction covers wearables too, but its differentiator is bundling that data with US at-home and lab diagnostics in the same API.",
          "url": "https://aifitnessapi.com/fitness-apis/terra-vs-vital#faq-2"
        },
        {
          "question": "Can Terra and Vital both pull Apple HealthKit and Health Connect data?",
          "answer": "Yes. Both are server-side aggregators that also ship mobile SDKs to ingest on-device Apple HealthKit (iOS) and Android Health Connect data, in addition to normalizing cloud wearable accounts.",
          "url": "https://aifitnessapi.com/fitness-apis/terra-vs-vital#faq-3"
        },
        {
          "question": "How do Terra and Vital pricing models differ?",
          "answer": "Terra uses a subscription plus usage credit-based model where cost scales with connected users and events. Vital/Junction uses per-user, usage-based pricing with a monthly minimum. Both shift often, so verify current pricing in each vendor's docs.",
          "url": "https://aifitnessapi.com/fitness-apis/terra-vs-vital#faq-4"
        },
        {
          "question": "Does Vital/Junction support lab tests outside the US?",
          "answer": "Its lab and at-home diagnostics features are US-focused, spanning at-home kits, walk-in centers, and mobile phlebotomy across US states. If your users are outside the US, the wearable side still applies but the diagnostics value largely does not.",
          "url": "https://aifitnessapi.com/fitness-apis/terra-vs-vital#faq-5"
        }
      ]
    },
    {
      "question": "Fitbit API vs Garmin API",
      "answer": "Pick Garmin's API when you need serious GPS, multisport, and the deepest health metrics like Body Battery, VO2 max, pulse-ox, and HRV; pick Fitbit's API when you want broad mainstream device reach with rich intraday heart-rate and sleep data. Both use OAuth 2.0 with per-user consent and are documented as free to use with approval as of 2026. The catches: Fitbit's legacy Web API is scheduled to turn down around September 2026 and migrate to the Google Health API (tokens do not transfer, users re-consent), and Garmin's Connect Developer Program is reportedly on hold for new sign-ups as of 2026, so confirm you can onboard before committing.",
      "title": "Fitbit API vs Garmin API (2026)",
      "url": "https://aifitnessapi.com/fitness-apis/fitbit-api-vs-garmin-api",
      "markdown": "https://aifitnessapi.com/fitness-apis/fitbit-api-vs-garmin-api.md",
      "cluster": "Fitness APIs",
      "cluster_url": "https://aifitnessapi.com/fitness-apis",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Is the Fitbit API free to use?",
          "answer": "There is no published per-call fee; Fitbit is documented as free to use with the standard developer registration and approval as of 2026. Registering a Personal app for your own data is self-serve, while accessing other users' high-resolution intraday data requires case-by-case approval. Verify current commercial terms under the Google Health API before building at scale.",
          "url": "https://aifitnessapi.com/fitness-apis/fitbit-api-vs-garmin-api#faq-1"
        },
        {
          "question": "Can I get minute-level heart rate from both Fitbit and Garmin?",
          "answer": "Not on the same terms. Fitbit exposes heart-rate time series down to 1-second or 1-minute granularity, but other users' high-resolution intraday data is unlocked case-by-case rather than by default — self-serve covers your own account only. Garmin's Health API includes per-minute epochs as part of its standard partner data set, but that whole surface sits behind partner approval, which is reportedly on hold for new sign-ups as of 2026. On both sides the granularity you want is an approval question first and an API question second. Verify current terms with each provider.",
          "url": "https://aifitnessapi.com/fitness-apis/fitbit-api-vs-garmin-api#faq-2"
        },
        {
          "question": "Can I still sign up for the Garmin Connect Developer Program?",
          "answer": "As of 2026, the Garmin Connect Developer Program is reportedly on hold for new sign-ups (verify). Existing approved accounts are said to keep working, but onboarding a fresh account may be blocked. Confirm you can get approved directly with Garmin before designing around its APIs.",
          "url": "https://aifitnessapi.com/fitness-apis/fitbit-api-vs-garmin-api#faq-3"
        },
        {
          "question": "Which is better for GPS and workout data, Fitbit or Garmin?",
          "answer": "Garmin is the richer option for GPS, multisport, and workout detail: its Activity API covers over 100 sport types with GPS, heart rate, and session detail, and its Health API adds metrics like Body Battery, VO2 max, pulse-ox, and HRV. Fitbit exposes GPS and exercise detail through activity logs but leans more toward broad consumer wellness and intraday time series.",
          "url": "https://aifitnessapi.com/fitness-apis/fitbit-api-vs-garmin-api#faq-4"
        },
        {
          "question": "Can one app support both Fitbit and Garmin users?",
          "answer": "Yes, and plenty do — but treat it as two integrations, not one. Both use OAuth 2.0 with per-user consent, so the connect flow rhymes, yet you register separately with each provider, clear each one's approval gate, and consume two different delivery models: pull-based REST on Fitbit, push callbacks on Garmin. Their data models differ too, so you need your own normalization layer before the rest of your app sees a workout. If you would rather build one integration than two, that is the case for a health-data aggregator.",
          "url": "https://aifitnessapi.com/fitness-apis/fitbit-api-vs-garmin-api#faq-5"
        }
      ]
    },
    {
      "question": "build or buy fitness API",
      "answer": "Build your own if camera-based motion analysis is your core product and you have the CV/ML team to maintain it; buy a fitness API if motion coaching is a feature inside a larger product and you want to ship fast without owning form logic forever. Pose estimation (MediaPipe, MoveNet, Apple Vision) gives you joint keypoints for free, but rep counting, form rules, exercise coverage, and ongoing tuning are the recurring cost. So build vs buy is really a maintenance-ownership decision, not a feature one.",
      "title": "Fitness API vs Building Your Own: How to Decide (2026)",
      "url": "https://aifitnessapi.com/fitness-apis/fitness-api-vs-build-your-own",
      "markdown": "https://aifitnessapi.com/fitness-apis/fitness-api-vs-build-your-own.md",
      "cluster": "Fitness APIs",
      "cluster_url": "https://aifitnessapi.com/fitness-apis",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Is it cheaper to build my own fitness pose-tracking instead of using an API?",
          "answer": "Only the pose engine is free. Libraries like MediaPipe, MoveNet, and Apple Vision give you joint keypoints at no license cost, but rep counting, per-exercise form rules, calibration, and edge-case tuning are a multi-month build for a CV/ML team plus ongoing maintenance. Building is cheaper only if that logic is core to your product or your user scale outgrows per-user SDK fees.",
          "url": "https://aifitnessapi.com/fitness-apis/fitness-api-vs-build-your-own#faq-1"
        },
        {
          "question": "What do free pose estimation libraries like MediaPipe give you, and what do they not?",
          "answer": "They give you a per-frame skeleton of 17 to 33 joint keypoints in 2D and 3D, on-device and free. They do not give you rep counting, form feedback, an exercise library, calibration, or assessments. That application layer is exactly what you build yourself or buy from a coaching SDK.",
          "url": "https://aifitnessapi.com/fitness-apis/fitness-api-vs-build-your-own#faq-2"
        },
        {
          "question": "When should I buy a fitness API instead of building one?",
          "answer": "Buy when motion coaching is a feature inside a larger product, you need to ship in weeks, you lack a CV/ML team, you want a ready exercise library and cross-platform SDKs, or you prefer a predictable per-user cost over maintaining tuning logic yourself. Buy trades control for speed and lower maintenance.",
          "url": "https://aifitnessapi.com/fitness-apis/fitness-api-vs-build-your-own#faq-3"
        },
        {
          "question": "When does building your own fitness motion tracking actually make sense?",
          "answer": "Build when motion analysis is your core product or differentiator, you have in-house CV/ML talent, you need exercises or a clinical domain vendors do not cover, you are at a scale where per-user fees exceed an in-house team, or strict control and data-residency rules rule out a third-party SDK.",
          "url": "https://aifitnessapi.com/fitness-apis/fitness-api-vs-build-your-own#faq-4"
        },
        {
          "question": "Is there a middle ground between building and buying?",
          "answer": "Yes. A permissively-licensed wrapper over MediaPipe (QuickPose is one example) ships pre-built rep and form helpers, exposes raw landmarks, and offers a self-serve free tier, lowering the build cost without a sales commitment. The trade-off is usually narrower platform focus and less packaged content than a full white-label fitness API.",
          "url": "https://aifitnessapi.com/fitness-apis/fitness-api-vs-build-your-own#faq-5"
        }
      ]
    },
    {
      "question": "camera pose tracking",
      "answer": "Camera pose tracking turns a video feed into a stream of body joint coordinates, and this guide builds that pipeline on the web: load a pose model, pull frames from the camera, run detection per frame, and read the landmarks. You have two paths, build on a free on-device pose model or buy a fitness SDK that wraps the whole thing, and this guide takes the build path using MediaPipe Pose Landmarker with MoveNet shown as the alternative. Pose estimation only returns coordinates; rep counting and form feedback are logic you add on top.",
      "title": "Camera Pose Tracking for Fitness Apps: A Practical Guide",
      "url": "https://aifitnessapi.com/guides/camera-pose-tracking",
      "markdown": "https://aifitnessapi.com/guides/camera-pose-tracking.md",
      "cluster": "Guides",
      "cluster_url": "https://aifitnessapi.com/guides",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the difference between the 33 landmarks in MediaPipe and the 17 in MoveNet?",
          "answer": "MediaPipe Pose Landmarker returns 33 landmarks in the BlazePose topology, a superset that adds face, hand, and foot points plus a per-point depth and visibility score on top of the major joints. MoveNet returns 17 COCO keypoints covering only the major body joints. For most rep-counting and joint-angle work the shared major joints are all you touch, so either model works; the index numbers differ between them, so do not hardcode one set for the other.",
          "url": "https://aifitnessapi.com/guides/camera-pose-tracking#faq-1"
        },
        {
          "question": "Which landmark indices do I use for exercises?",
          "answer": "In MediaPipe's 33-point model the exercise joints are shoulders 11 and 12, elbows 13 and 14, wrists 15 and 16, hips 23 and 24, knees 25 and 26, and ankles 27 and 28. MoveNet's 17-point model uses different indices (shoulders 5 and 6, elbows 7 and 8, wrists 9 and 10, hips 11 and 12, knees 13 and 14, ankles 15 and 16), and its keypoints also carry a name field you can address instead.",
          "url": "https://aifitnessapi.com/guides/camera-pose-tracking#faq-2"
        },
        {
          "question": "Does camera pose tracking run on-device or send video to a server?",
          "answer": "Both MediaPipe Pose Landmarker and MoveNet run entirely on-device. Once the model files are loaded and cached, detection needs no network round-trip and no image data leaves the browser or phone, which matters for privacy and latency.",
          "url": "https://aifitnessapi.com/guides/camera-pose-tracking#faq-3"
        },
        {
          "question": "Why do the left and right landmarks look swapped on screen?",
          "answer": "They are not swapped. Both models label joints from the subject's anatomical perspective, not the viewer's, so when someone faces the camera their left shoulder appears on the right side of your screen — landmark 11 in MediaPipe, index 5 in MoveNet. Draw the skeleton once and you will see it immediately. This matters for asymmetric cues like straighten your left knee: resolve the side from the model's own naming rather than from screen position, and remember a front-facing camera preview is often mirrored again on top of that.",
          "url": "https://aifitnessapi.com/guides/camera-pose-tracking#faq-4"
        },
        {
          "question": "Does pose estimation count reps and check form by itself?",
          "answer": "No. Pose estimation only returns joint coordinates, one set per frame. Rep counting is typically a threshold state machine over a joint angle, and form feedback compares measured angles against target ranges. That interpret layer is logic you build on top of the keypoints, or that a commercial fitness SDK provides for you.",
          "url": "https://aifitnessapi.com/guides/camera-pose-tracking#faq-5"
        }
      ]
    },
    {
      "question": "how to add rep counting",
      "answer": "Rep counting is not machine learning — it is a small state machine over one number. You turn three pose keypoints into a joint angle, smooth it, and count a rep each time the angle travels from flexed back to extended. This guide gives the exact atan2-based angle math plus a production-ready counter with a confidence gate, EMA smoothing, and two-threshold hysteresis in JavaScript. You can build this on a free pose primitive like MediaPipe or MoveNet, or buy a fitness SDK that wraps rep counting for you.",
      "title": "How to Add Rep Counting to Your Fitness App",
      "url": "https://aifitnessapi.com/guides/add-rep-counting",
      "markdown": "https://aifitnessapi.com/guides/add-rep-counting.md",
      "cluster": "Guides",
      "cluster_url": "https://aifitnessapi.com/guides",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Do I need machine learning to count reps from pose keypoints?",
          "answer": "No. In the common case rep counting is a threshold state machine over one scalar signal — usually a joint angle — not a trained model. Google's own MediaPipe and ML Kit fitness samples count a rep when a signal crosses an enter threshold and then crosses back past an exit threshold, which is pure geometry plus a couple of thresholds.",
          "url": "https://aifitnessapi.com/guides/add-rep-counting#faq-1"
        },
        {
          "question": "Why use two thresholds instead of one for counting reps?",
          "answer": "A single threshold lets sensor noise chatter across the line and fire many counts per real rep. Two separated thresholds create a dead-band, called hysteresis, that forces the angle to fully commit to the opposite extreme before the next transition, which debounces the count. This is the standard fix used in the Google fitness samples.",
          "url": "https://aifitnessapi.com/guides/add-rep-counting#faq-2"
        },
        {
          "question": "Which joint angle should I track for each exercise?",
          "answer": "Track the joint that bends most between the two ends of the movement. For a bicep curl that is the elbow angle from shoulder, elbow, and wrist; for a squat it is the knee angle from hip, knee, and ankle. Film sagittal-plane moves from the side so the 2D angle matches the real joint angle.",
          "url": "https://aifitnessapi.com/guides/add-rep-counting#faq-3"
        },
        {
          "question": "Why is my rep count jumping or double-counting?",
          "answer": "The usual causes are unsmoothed jitter, thresholds set too close together, or occluded low-confidence landmarks spiking the angle. Add EMA smoothing on the angle, widen the gap between the enter and exit thresholds, gate out frames below roughly 0.5 to 0.7 confidence, and optionally ignore any completion under about 300 ms after the last.",
          "url": "https://aifitnessapi.com/guides/add-rep-counting#faq-4"
        },
        {
          "question": "Does this work with both MediaPipe and MoveNet?",
          "answer": "Yes. The angle math and state machine only need x and y plus a per-keypoint confidence value, which both provide (visibility on MediaPipe, score on MoveNet). The landmark indices differ — MediaPipe uses 33 points and MoveNet uses 17 — so map the same anatomical joints to each model's indices.",
          "url": "https://aifitnessapi.com/guides/add-rep-counting#faq-5"
        }
      ]
    },
    {
      "question": "how to add form feedback",
      "answer": "Real-time form feedback compares the joint angles and alignments you measure from pose keypoints against target ranges you define, then surfaces one directional cue per rep. This guide teaches the geometry-only path: compute a squat's knee angle, torso lean from vertical, and knee valgus, gate every measurement on confidence, and evaluate the rep at its transition. It is fitness form guidance from geometry, not medical advice, and the thresholds shown are app-defined examples you tune yourself. The faster alternative is a coaching SDK that ships these rules for you.",
      "title": "How to Add Real-Time Form Feedback to a Workout App",
      "url": "https://aifitnessapi.com/guides/add-form-feedback",
      "markdown": "https://aifitnessapi.com/guides/add-form-feedback.md",
      "cluster": "Guides",
      "cluster_url": "https://aifitnessapi.com/guides",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "How do I check squat depth from pose keypoints?",
          "answer": "Compute the knee angle at the vertex knee for the hip-knee-ankle joints using the atan2 interior-angle formula, and track the smallest value across the rep. A knee angle near 90 degrees is roughly thighs-parallel; a larger minimum means a shallower squat. Choose your own cutoff, such as flagging a minimum above 100 degrees as too shallow, and tune it to your users and exercise.",
          "url": "https://aifitnessapi.com/guides/add-form-feedback#faq-1"
        },
        {
          "question": "How do I detect a knee caving inward (valgus)?",
          "answer": "From a front view, compare the horizontal x-position of the knee to the ankle: when the knee drifts toward the body midline relative to the ankle, that gap grows. Divide the gap by a body reference like shoulder width so the rule is invariant to camera distance, then flag when it exceeds a tolerance you set. This is a geometric flag, not a clinical assessment.",
          "url": "https://aifitnessapi.com/guides/add-form-feedback#faq-2"
        },
        {
          "question": "When should form be evaluated during a rep?",
          "answer": "Evaluate at the rep transition, using the extreme values captured across the whole rep window rather than one frame. This ties form feedback to your rep detector's completion callback, so each rep is graded once at the moment the movement finishes, against the deepest and most-leaning positions actually reached.",
          "url": "https://aifitnessapi.com/guides/add-form-feedback#faq-3"
        },
        {
          "question": "Why show only one cue at a time?",
          "answer": "Firing several corrections at once is unusable for someone mid-workout. Pick the single highest-priority failed rule, for example depth before a minor lean, make it directional such as push your knees out, and debounce it so it does not repeat every frame. One clear, actionable cue per rep is far more effective than a wall of flags.",
          "url": "https://aifitnessapi.com/guides/add-form-feedback#faq-4"
        },
        {
          "question": "Is camera-based form feedback medical or injury-prevention advice?",
          "answer": "No. This technique only flags when a joint angle or alignment is outside a target range you define; it does not diagnose anything or prevent injury. The thresholds in this guide are app-defined examples for illustration, not clinical standards. Frame the feedback to users as coaching cues, and set and tune your own ranges for your exercises and setup.",
          "url": "https://aifitnessapi.com/guides/add-form-feedback#faq-5"
        }
      ]
    },
    {
      "question": "track workouts without a wearable",
      "answer": "You can track a workout with only a phone camera and an on-device pose model, no watch, ring, or band. The camera measures the movement side directly: reps, range of motion, tempo, and form. It cannot measure heart rate, HRV, or sleep, and camera-based calorie burn is an estimate, not a measurement. The build path is to run a pose model, read its keypoints, then count reps and compute movement metrics from joint angles.",
      "title": "How to Track Workouts Without a Wearable (Camera-Only)",
      "url": "https://aifitnessapi.com/guides/track-workouts-without-wearables",
      "markdown": "https://aifitnessapi.com/guides/track-workouts-without-wearables.md",
      "cluster": "Guides",
      "cluster_url": "https://aifitnessapi.com/guides",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Can you really track a workout without a wearable?",
          "answer": "Yes, for the movement side of a workout. A phone camera plus an on-device pose model measures reps, range of motion, tempo, and form directly from how the body moves, so no watch, ring, or band is required. You only need a wearable for physiological signals the camera cannot see, such as heart rate, HRV, and sleep.",
          "url": "https://aifitnessapi.com/guides/track-workouts-without-wearables#faq-1"
        },
        {
          "question": "What can a camera measure that a wearable cannot?",
          "answer": "A camera sees geometry over time, so it can measure reps, joint angles and range of motion, movement tempo, and form and alignment. Most wearables measure none of these; they measure physiology like heart rate and sleep instead. The two are complementary rather than interchangeable.",
          "url": "https://aifitnessapi.com/guides/track-workouts-without-wearables#faq-2"
        },
        {
          "question": "Can a camera measure calories burned?",
          "answer": "Only as an estimate. A camera can estimate calorie burn from movement, exercise type, duration, and a user's height and weight, but it is a model output, not a measurement, so label it as an estimate. A wearable's calorie figure is also an estimate; it is just derived from heart rate instead of movement.",
          "url": "https://aifitnessapi.com/guides/track-workouts-without-wearables#faq-3"
        },
        {
          "question": "Do I need a paid SDK, or can I build camera tracking myself?",
          "answer": "You can build it on free, permissively licensed pose primitives like MediaPipe Pose Landmarker or TensorFlow MoveNet and write the rep and form logic yourself. A commercial fitness SDK wraps the camera, model, and logic behind one API if you would rather buy that layer than maintain it.",
          "url": "https://aifitnessapi.com/guides/track-workouts-without-wearables#faq-4"
        },
        {
          "question": "Does camera tracking send my video to the cloud?",
          "answer": "It does not have to. MediaPipe Pose Landmarker and MoveNet both run inference on-device, so after the model loads no frames need to leave the phone. That keeps the movement data private and works offline.",
          "url": "https://aifitnessapi.com/guides/track-workouts-without-wearables#faq-5"
        }
      ]
    },
    {
      "question": "AI workout tracking iOS Swift",
      "answer": "You can add camera-based workout tracking to an iOS app entirely on-device with Apple's Vision framework. Stream frames from the camera, run VNDetectHumanBodyPoseRequest on each one to get 19 body joints, then compute a joint angle and count reps with a small threshold state machine. Nothing leaves the phone. The alternative is to buy a commercial fitness SDK that wraps these steps for a license fee and less control.",
      "title": "How to Add AI Workout Tracking to an iOS App (Swift)",
      "url": "https://aifitnessapi.com/guides/ai-workout-tracking-ios-swift",
      "markdown": "https://aifitnessapi.com/guides/ai-workout-tracking-ios-swift.md",
      "cluster": "Guides",
      "cluster_url": "https://aifitnessapi.com/guides",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Does AI workout tracking with Vision work offline?",
          "answer": "Yes. Vision's body-pose detection runs entirely on-device, so no image data leaves the phone and no network connection is required. This is true for both the 2D and 3D body-pose requests.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-ios-swift#faq-1"
        },
        {
          "question": "Which iOS version do I need?",
          "answer": "The 2D body-pose request (VNDetectHumanBodyPoseRequest) requires iOS 14.0 or later. The 3D request (VNDetectHumanBodyPose3DRequest) requires iOS 17.0 or later. You also need a physical device, since the camera and Vision are unreliable in the Simulator.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-ios-swift#faq-2"
        },
        {
          "question": "How do I count reps from body joints?",
          "answer": "Rep counting is a threshold state machine, not machine learning. Compute a driving joint angle, smooth it, and use two separate thresholds so the movement must reach one extreme and then the other before a rep is counted. Count on a single edge to avoid double-counting.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-ios-swift#faq-3"
        },
        {
          "question": "Why do my skeleton overlays appear upside-down?",
          "answer": "Vision returns normalized coordinates from 0 to 1 with the origin at the bottom-left, while UIKit and Core Graphics use a top-left origin. Convert with VNImagePointForNormalizedPoint and typically flip the y value when drawing into a top-left context.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-ios-swift#faq-4"
        },
        {
          "question": "Should I use Apple Vision or MediaPipe on iOS?",
          "answer": "Vision ships in the OS with no dependencies and gives 19 joints, which is enough for angles and rep counting. MediaPipe Tasks for iOS gives 33 landmarks and runs cross-platform, so it is worth considering if you also ship Android. Verify current MediaPipe pod and class names against its docs before adopting it.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-ios-swift#faq-5"
        }
      ]
    },
    {
      "question": "AI workout tracking Android Kotlin",
      "answer": "AI workout tracking on Android estimates a person's body pose from the camera on-device and turns those keypoints into reps and form feedback. This guide builds it in Kotlin with CameraX feeding Google's MediaPipe Tasks PoseLandmarker, then counts a squat rep from the knee angle. You either build on a free pose model like MediaPipe or ML Kit and write your own rep logic, or buy a commercial fitness SDK that bundles the whole pipeline.",
      "title": "How to Add AI Workout Tracking to an Android App (Kotlin)",
      "url": "https://aifitnessapi.com/guides/ai-workout-tracking-android-kotlin",
      "markdown": "https://aifitnessapi.com/guides/ai-workout-tracking-android-kotlin.md",
      "cluster": "Guides",
      "cluster_url": "https://aifitnessapi.com/guides",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "MediaPipe PoseLandmarker or ML Kit Pose Detection for Android?",
          "answer": "Both are from Google, both derive from BlazePose, and both emit the same 33 landmarks. ML Kit is a shorter one-line drop-in for Android and iOS only, while MediaPipe Tasks PoseLandmarker gives more control, 3D world landmarks, and cross-platform reuse. Pick ML Kit for the fastest mobile integration and MediaPipe when you want custom processing or to share the pipeline across platforms.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-android-kotlin#faq-1"
        },
        {
          "question": "Does the pose detection run offline?",
          "answer": "Yes. Both MediaPipe PoseLandmarker and ML Kit run entirely on-device, so after the model is bundled or downloaded no image data leaves the phone and no network round-trip is needed per frame. This is good for latency and privacy.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-android-kotlin#faq-2"
        },
        {
          "question": "How do I count reps without training a machine learning model?",
          "answer": "Rep counting is usually a threshold state machine, not machine learning. You compute a driving joint angle, smooth it, and toggle between a flexed and extended state using two separated thresholds, counting one rep on each full round trip. This needs no training data.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-android-kotlin#faq-3"
        },
        {
          "question": "Why do my rep counts jump or double-count?",
          "answer": "Almost always because of a single threshold or unsmoothed noise. Use two separated thresholds so the angle must fully commit to the other extreme before the next transition, add a light exponential moving average on the angle, and gate out frames where the driving joints have low visibility. Also count on only one edge of the motion.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-android-kotlin#faq-4"
        },
        {
          "question": "Which camera angle and setup give the most accurate tracking?",
          "answer": "Use a side view for sagittal exercises like squats, curls and lunges so the joint angles sit in the image plane, and a front view for symmetry checks. Keep the whole body in frame from head to ankles, use even front-facing lighting, prefer the rear camera, and keep the phone level and stable.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-android-kotlin#faq-5"
        }
      ]
    },
    {
      "question": "AI workout tracking React Native",
      "answer": "To track workouts from the camera in React Native, use react-native-vision-camera for the feed, run a pose model on each frame in a frame processor (a worklet on the camera thread), then compute a joint angle and count reps with a two-threshold state machine. Run the pose model either as a TFLite model (MoveNet or BlazePose via react-native-fast-tflite) inside the worklet, or through a native ML Kit frame-processor plugin. Note that VisionCamera's frame-processor API has changed across major versions, so confirm the exact hook and prop names against the docs for your installed version. If motion analysis is not your core product, a commercial fitness SDK wraps all of this as a drop-in.",
      "title": "How to Add AI Workout Tracking to a React Native App",
      "url": "https://aifitnessapi.com/guides/ai-workout-tracking-react-native",
      "markdown": "https://aifitnessapi.com/guides/ai-workout-tracking-react-native.md",
      "cluster": "Guides",
      "cluster_url": "https://aifitnessapi.com/guides",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Which frame-processor API does VisionCamera use in React Native?",
          "answer": "It depends on your installed version. The frame-processor API has changed across major versions: v3 and v4 used a useFrameProcessor hook whose worklet you passed to a frameProcessor prop, and newer releases renamed the hook and switched to an outputs-style prop. The camera and permission hooks (useCameraDevice, useCameraPermission) have stayed stable, but you should confirm the frame-processor hook and Camera prop names against the docs for the exact version you installed.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-react-native#faq-1"
        },
        {
          "question": "Should I use MoveNet TFLite or an ML Kit plugin for pose detection?",
          "answer": "Both are valid. Running a MoveNet or BlazePose .tflite model with react-native-fast-tflite inside the worklet gives you control over the exact model and returns 17 (MoveNet) landmarks. A native ML Kit frame-processor plugin is less setup and returns 33 BlazePose landmarks, but ties you to that plugin's maintenance and version support. For TFLite models, set pixelFormat to rgb on the Camera because frames are YUV by default.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-react-native#faq-2"
        },
        {
          "question": "How do I count a rep from pose keypoints?",
          "answer": "Compute one driving joint angle (elbow for a curl, knee for a squat), smooth it, and run a two-state machine with two thresholds. The angle must cross an enter threshold to reach the flexed extreme and then cross a separate exit threshold to return before you count one rep. Counting on a single threshold produces phantom reps because noise makes the signal chatter across the line.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-react-native#faq-3"
        },
        {
          "question": "Does this work in Expo Go, or do I need a development build?",
          "answer": "Expo Go alone will not work. Frame processors need native modules, and Expo Go ships a fixed set of native code you cannot add to, so VisionCamera plus a TFLite or ML Kit pose plugin has to be compiled in. Use a development build, or a bare React Native app. You still get Expo tooling and config plugins — you build your own client once and then iterate in JavaScript as normal. Settle this before you write the frame-processor worklet, because discovering it afterwards means rebuilding your whole dev loop.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-react-native#faq-4"
        },
        {
          "question": "Can I skip building this and use a fitness SDK instead?",
          "answer": "Yes. Commercial fitness SDKs such as KinesteX, Kemtai, and QuickPose bundle the camera, pose model, smoothing, rep counting, and a prebuilt UI as a React Native drop-in, so you read rep and form events from a callback instead of wiring it yourself. Follow the vendor's own docs for the exact API, and treat any published accuracy or frame-rate numbers as vendor-stated claims to verify in a trial.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-react-native#faq-5"
        }
      ]
    },
    {
      "question": "AI workout tracking Flutter",
      "answer": "You'll build camera-based workout tracking in Flutter using the camera plugin to stream frames and google_mlkit_pose_detection to detect a 33-landmark body pose on-device. From three landmarks you compute a joint angle, then count reps with a two-threshold state machine. This is the free do-it-yourself path. A commercial fitness SDK wraps the same camera-to-rep pipeline as a drop-in if you'd rather buy it.",
      "title": "How to Add AI Workout Tracking to a Flutter App",
      "url": "https://aifitnessapi.com/guides/ai-workout-tracking-flutter",
      "markdown": "https://aifitnessapi.com/guides/ai-workout-tracking-flutter.md",
      "cluster": "Guides",
      "cluster_url": "https://aifitnessapi.com/guides",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Do I need a paid API or the cloud for AI workout tracking in Flutter?",
          "answer": "No. google_mlkit_pose_detection runs the pose model on-device for free, so tracking works offline with no per-call cost. A paid commercial SDK is optional and mainly saves you from writing the camera, pose, and rep logic yourself.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-flutter#faq-1"
        },
        {
          "question": "How does the app count reps if pose detection is not counting them?",
          "answer": "Rep counting is separate logic you add on top of the landmarks. You compute a joint angle from three landmarks each frame and run a two-threshold state machine that counts one rep per full down-to-up movement, which avoids miscounts from noise.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-flutter#faq-2"
        },
        {
          "question": "Why use atan2 instead of acos for the joint angle?",
          "answer": "The atan2 of the cross and dot products is numerically robust and returns 0 to 180 degrees cleanly. The plain acos form can lose precision or return NaN near 0 and 180 degrees from floating-point rounding unless you clamp its input first.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-flutter#faq-3"
        },
        {
          "question": "Which package versions should I use as of 2026?",
          "answer": "As of 2026 google_mlkit_pose_detection is around 0.15.0, but versions move quickly, so check the current release on pub.dev and the package README for its platform minimums before pinning. The pattern in this guide is stable even as versions change.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-flutter#faq-4"
        },
        {
          "question": "Will this work on a phone's front camera and in a simulator?",
          "answer": "It works on both front and rear cameras, though the rear camera usually gives higher-quality landmarks. It needs a real device with a live camera, since simulators and emulators cannot provide the camera stream the pose model requires.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-flutter#faq-5"
        }
      ]
    },
    {
      "question": "AI workout tracking web",
      "answer": "This guide shows how to add camera-based workout tracking to a web app in plain JavaScript. You capture the webcam with getUserMedia, run Google's MediaPipe Pose Landmarker on each video frame to get 33 body landmarks, compute a joint angle to count reps with a hysteresis state machine, and draw a skeleton overlay on a canvas. Everything runs on-device in the browser, and MoveNet via TensorFlow.js is shown as the alternative pose model. As of 2026 the package is @mediapipe/tasks-vision, so pin a specific version before shipping.",
      "title": "How to Add AI Workout Tracking to a Web App (JavaScript)",
      "url": "https://aifitnessapi.com/guides/ai-workout-tracking-web",
      "markdown": "https://aifitnessapi.com/guides/ai-workout-tracking-web.md",
      "cluster": "Guides",
      "cluster_url": "https://aifitnessapi.com/guides",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Which pose model should I use for web workout tracking, MediaPipe or MoveNet?",
          "answer": "MediaPipe Pose Landmarker returns 33 landmarks with face, hand, and foot detail plus a z depth value, which is useful for richer form checks. TensorFlow.js MoveNet returns 17 COCO keypoints and is a lighter alternative. Both are Apache-2.0, run on-device, and are vendor-stated to hit real-time frame rates on modern hardware. Start with MediaPipe lite or MoveNet Lightning for latency and move to the heavy or Thunder tier when accuracy matters.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-web#faq-1"
        },
        {
          "question": "Does the camera video get sent to a server?",
          "answer": "No. MediaPipe Pose Landmarker and MoveNet both run inference locally in the browser using WASM, WebGL, or WebGPU. Once the model and WASM files are downloaded and cached, detection needs no network round-trip and no frames leave the device, which is good for privacy and latency.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-web#faq-2"
        },
        {
          "question": "Why does the browser never show a camera permission prompt?",
          "answer": "Almost always because the page is not on a secure origin. Browsers block getUserMedia outside HTTPS or localhost, and the call rejects without ever prompting — so a demo that works on your laptop fails the moment you serve it from a plain-HTTP staging box or a bare IP address. Check the origin first, then check whether the user previously blocked camera access for that site in their browser settings. Handle the rejection path explicitly too: a promise that rejects with no visible prompt looks exactly like a hung app.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-web#faq-3"
        },
        {
          "question": "Why is my joint angle jumpy or wrong?",
          "answer": "A 2D angle only matches the true joint angle when the limb is roughly parallel to the camera plane, so use a side view for squats, curls, and lunges. Reject landmarks below about 0.5 to 0.7 visibility before measuring, apply a modest exponential moving average to the angle, and keep the whole body in frame with even lighting. Occluded or cropped joints jump to garbage positions and skew the angle.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-web#faq-4"
        },
        {
          "question": "Do I need a build step, or can I use a CDN?",
          "answer": "Both work. As of 2026 you can npm install @mediapipe/tasks-vision and bundle it, or import it and the WASM fileset from a CDN such as jsDelivr. Pin a specific version rather than latest in production, and verify the current package release before shipping since these versions move.",
          "url": "https://aifitnessapi.com/guides/ai-workout-tracking-web#faq-5"
        }
      ]
    },
    {
      "question": "improve pose detection accuracy",
      "answer": "Poor pose-detection accuracy is usually a stack of small problems, not one, so fix them in order of leverage: capture first, then code. Start with framing, distance, and lighting; match the camera angle to the plane of motion; pick the right model tier and input resolution; gate on landmark confidence; smooth coordinates with a One-Euro filter and downstream scalars with an EMA; normalize coordinates and handle missing joints; then tune on-device performance. This checklist applies whether you build on MediaPipe or MoveNet; a fitness SDK tunes most of the code-side knobs for you, but the capture-side rules still apply to your users.",
      "title": "How to Improve Pose-Detection Accuracy in Your App",
      "url": "https://aifitnessapi.com/guides/improve-pose-detection-accuracy",
      "markdown": "https://aifitnessapi.com/guides/improve-pose-detection-accuracy.md",
      "cluster": "Guides",
      "cluster_url": "https://aifitnessapi.com/guides",
      "last_reviewed": "2026-07-08",
      "first_party": false,
      "faqs": [
        {
          "question": "Why are my pose landmarks jittery even when they are in the right place?",
          "answer": "That is high-frequency noise, not a placement error, and the fix is temporal smoothing. Apply a One-Euro filter to the raw landmark coordinates (MediaPipe does this internally in LIVE_STREAM mode; MoveNet exposes enableSmoothing) and an exponential moving average to any scalar you compute from them, such as a joint angle. Keep the EMA alpha around 0.2 to 0.4 so you remove jitter without lagging real motion.",
          "url": "https://aifitnessapi.com/guides/improve-pose-detection-accuracy#faq-1"
        },
        {
          "question": "What is the difference between the One-Euro filter and EMA for pose smoothing?",
          "answer": "An EMA blends each new value with the running average at a fixed rate, which is cheap and good for scalar signals like a joint angle or a class probability. The One-Euro (1 euro) filter is an adaptive low-pass filter that uses position and velocity, lowering its cutoff when the body is still to kill jitter and raising it during fast motion to avoid lag. For raw landmark coordinates, One-Euro is preferred because it adapts to speed; it is MediaPipe Pose's built-in landmark smoother.",
          "url": "https://aifitnessapi.com/guides/improve-pose-detection-accuracy#faq-2"
        },
        {
          "question": "Should I use a bigger model to get better accuracy?",
          "answer": "A heavier tier (MediaPipe heavy, or MoveNet Thunder at 256x256 versus Lightning at 192x192) is more accurate but slower, so use it only when the device can sustain a stable frame rate and accuracy matters, such as form grading. On latency-critical UI, a lighter model plus good framing and smoothing often beats a heavy model on a starved device. Fix capture-side problems first, since they are free and undo the most error.",
          "url": "https://aifitnessapi.com/guides/improve-pose-detection-accuracy#faq-3"
        },
        {
          "question": "What confidence threshold should I use to reject bad landmarks?",
          "answer": "A common gate is around 0.5 to 0.7 on each landmark's visibility (MediaPipe) or score (MoveNet), but tune it per camera and gate harder on the noisier front camera. When a required joint falls below the gate, skip the frame or hold the last good value rather than feeding a garbage position into an angle or a rep threshold.",
          "url": "https://aifitnessapi.com/guides/improve-pose-detection-accuracy#faq-4"
        },
        {
          "question": "Does the camera angle affect accuracy or just the view?",
          "answer": "It affects your measurements directly. A 2D landmark angle only equals the true joint angle when the limb moves roughly parallel to the image plane, so a side view is best for sagittal exercises like squats and curls, and a front view is best for left/right symmetry and knee-valgus checks. A tilted or unstable camera also biases any rule that compares a body segment to vertical, so keep it level on a tripod.",
          "url": "https://aifitnessapi.com/guides/improve-pose-detection-accuracy#faq-5"
        }
      ]
    },
    {
      "question": "how to evaluate motion tracking sdk",
      "answer": "Evaluating a camera-coaching SDK means building one labelled video corpus of your own exercises, angles, lighting, body types and worst devices, then running every vendor against that same corpus with the same scoring code. Score per-clip rep precision and recall separately (never an aggregate, where a miss and a double-count cancel), plus form-cue correctness and latency, time to first tracking, thermal drift across a soak run, and offline behaviour. Everything a corpus cannot measure — pricing and its scaling unit, on-device guarantees for your configuration, model update cadence, SLA, retention and exit terms — is a procurement question you get in writing. No public benchmark ranks these vendors, so every accuracy figure you are shown is vendor-stated until you measure it yourself.",
      "title": "How to Evaluate AI Motion Tracking SDKs",
      "url": "https://aifitnessapi.com/guides/evaluate-motion-sdks",
      "markdown": "https://aifitnessapi.com/guides/evaluate-motion-sdks.md",
      "cluster": "Guides",
      "cluster_url": "https://aifitnessapi.com/guides",
      "last_reviewed": "2026-08-11",
      "first_party": true,
      "faqs": [
        {
          "question": "Why not just compare the vendors' published accuracy figures?",
          "answer": "Because no public benchmark exists for this category, so there is nothing to compare. Every figure published by a camera-coaching vendor was measured by that vendor, on that vendor's footage, under conditions they chose — including the above-90-percent line in KinesteX's own README, which is this site's product and a marketing claim rather than an independent benchmark. Even a rigorously measured number would not transfer, because pose metrics like PCK, OKS and MPJPE are defined against a specific labelled dataset that is not your camera, your exercises or your users.",
          "url": "https://aifitnessapi.com/guides/evaluate-motion-sdks#faq-1"
        },
        {
          "question": "How long does a motion SDK bake-off take?",
          "answer": "Budget two weeks of focused effort: roughly one week filming and labelling the corpus, and one week integrating each SDK and running it. Frontload the corpus deliberately — if you integrate a vendor first, that vendor's behaviour silently becomes your definition of working, and everyone evaluated afterwards is scored against a competitor instead of against your users. Labelling reliably takes longer than filming, and teams almost always plan the reverse.",
          "url": "https://aifitnessapi.com/guides/evaluate-motion-sdks#faq-2"
        },
        {
          "question": "What should a motion tracking vendor put in writing before you sign?",
          "answer": "Six things a test corpus cannot measure: current pricing and the unit it scales on (per active user, per session, per device), on-device or edge processing guarantees for your specific configuration rather than the marketing sentence, model update cadence and how much notice you get, the SLA including behaviour when their service degrades, data retention covering whether video or only derived events are stored, and exit terms for exporting your data and content. None of these are published by any vendor in this category that we could verify, so all six are conversations, not assumptions.",
          "url": "https://aifitnessapi.com/guides/evaluate-motion-sdks#faq-3"
        },
        {
          "question": "Should a shipped exercise library count toward the score?",
          "answer": "No. Treat it as a fit question that filters your shortlist, not a scored criterion that ranks it. Whether a bundled content library helps depends entirely on whether you already own your exercise programming, so scoring it rewards vendors shaped like a particular buyer rather than vendors that track movement well. The same applies to white-label theming, platform breadth, and native-versus-embedded architecture: yes-or-no matches to your requirements, kept off the scorecard.",
          "url": "https://aifitnessapi.com/guides/evaluate-motion-sdks#faq-4"
        },
        {
          "question": "What if an SDK will not let me feed it recorded clips?",
          "answer": "Record the refusal as a finding and score it, then fall back to a uniform substitute: play each clip full-screen on a second display in front of the device camera. Some products own the capture session outright or embed a hosted camera experience with no injection point, which is a genuine limitation worth knowing about. The screen-replay fallback is lossy, but it is lossy in the same way for every vendor, which is the only property the comparison needs.",
          "url": "https://aifitnessapi.com/guides/evaluate-motion-sdks#faq-5"
        }
      ]
    },
    {
      "question": "how to build a home workout app",
      "answer": "A home workout app is a habit loop around a content library: the user browses or gets recommended a workout, follows along with video or guided audio, logs completion, and returns for the streak and progress. The build-vs-buy shape is that the app scaffolding is commodity and the workout content is the moat, so you license exercise metadata and optional wearable data via APIs but produce or curate the classes yourself. Camera-based rep or form feedback is a heavier, optional bet most launches should defer. Monetization is subscription/freemium, with the paywall placed after an onboarding value moment.",
      "title": "How to Build a Home Workout App (2026)",
      "url": "https://aifitnessapi.com/build/home-workout-app",
      "markdown": "https://aifitnessapi.com/build/home-workout-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the minimum viable version of a home workout app?",
          "answer": "The core loop only: a small curated, filterable catalog, one or two structured programs so the app always has a next session, a reliable follow-along player with cues and offline download, completion logging with a streak and calendar, and an onboarding quiz that lands users on a starting plan. Cut live classes, social, wearable overlays, camera form feedback, and nutrition from v1 — none of them belongs in the version that has to prove people come back.",
          "url": "https://aifitnessapi.com/build/home-workout-app#faq-1"
        },
        {
          "question": "Should I build my own workout content or license it?",
          "answer": "Both, at different layers. The exercise metadata (names, muscle groups, equipment tags, demo clips) is a solved problem you should license from an exercise database API. The branded follow-along classes are usually your moat, and a differentiated app typically needs its own filmed, curated content — that production and curation cost is the real barrier to entry, not the code.",
          "url": "https://aifitnessapi.com/build/home-workout-app#faq-2"
        },
        {
          "question": "How do home workout apps make money?",
          "answer": "Subscription/freemium is the default and dominant consumer model, and subscriptions are reported to be the majority of category revenue (around 63% reported for 2025 — reported, verify). Some libraries add a-la-carte program purchases on top. Successful apps lean on annual plans behind a trial to survive fitness's brutal monthly churn, and place the paywall after a value moment rather than at first launch. Treat any single market or conversion figure as directional and verify it.",
          "url": "https://aifitnessapi.com/build/home-workout-app#faq-3"
        },
        {
          "question": "Do I need AI camera or rep-counting features to compete?",
          "answer": "Usually not for launch. Real-time pose tracking is a differentiator a few apps add, but it is materially harder engineering than the rest of a home workout app and is a product in its own right. Most apps should ship the follow-along loop first and treat camera form feedback as a later bet; if it is central to your vision, start from an off-the-shelf motion SDK rather than hand-rolling it under time pressure.",
          "url": "https://aifitnessapi.com/build/home-workout-app#faq-4"
        },
        {
          "question": "What is the biggest mistake to avoid?",
          "answer": "Assuming a big catalog equals retention. Content is the moat, but people come back for streaks, a visible calendar, sensible reminders, and clear next-session mechanics — not sheer volume. Instrument the workout-completion funnel from day one, since completion and repeat-visit rates matter far more than installs, and remember consumer fitness is winner-take-most, so a defined audience or content moat beats being a slightly better generalist.",
          "url": "https://aifitnessapi.com/build/home-workout-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build an AI fitness coaching app",
      "answer": "An AI fitness coaching app runs one loop: an assessment produces a personalized plan, the user trains while the camera tracks reps and form and gives real-time feedback, and that data feeds back so the plan adapts. The decision that shapes the whole build is your AI motion layer, and your first fork is whether to license a coaching SDK or build form and rep tracking yourself on open pose primitives. Buy the commodity pieces (exercise content, wearable data) and spend your engineering on the adaptive coaching and the motion feedback that users pay for.",
      "title": "How to Build an AI Fitness Coaching App (2026)",
      "url": "https://aifitnessapi.com/build/ai-fitness-coaching-app",
      "markdown": "https://aifitnessapi.com/build/ai-fitness-coaching-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Should I build the AI motion tracking myself or use an SDK?",
          "answer": "It depends on time-to-market versus control. Licensing a fitness-coaching SDK ships rep counting and form rules for you, letting you validate the loop before committing engineers to a motion pipeline you would maintain forever. Building on an open pose primitive gives you control and lower per-user cost but you own the accuracy and upkeep. A common path is to buy the SDK to launch, then reassess. Compare the options in the site's AI workout tracking API and build-vs-buy pages.",
          "url": "https://aifitnessapi.com/build/ai-fitness-coaching-app#faq-1"
        },
        {
          "question": "How accurate is camera-based rep and form feedback?",
          "answer": "Camera-based rep counting and form scoring are geometry measured against thresholds you define, and accuracy depends heavily on camera angle, framing, and lighting. Present cues as coaching, not clinical assessment, and disclose those limits to users. Do not imply the app diagnoses anything or prevents injury. Tracking a narrow set of movements well is more reliable than shaky coverage of a large catalog.",
          "url": "https://aifitnessapi.com/build/ai-fitness-coaching-app#faq-2"
        },
        {
          "question": "Do I need to be HIPAA compliant to build an AI fitness coaching app?",
          "answer": "Usually not. HIPAA generally applies only when you are a covered entity or a business associate handling data on behalf of one, which most direct-to-consumer fitness apps are not. The rule that more often applies to consumer health apps in the US is the FTC Health Breach Notification Rule, and EU users bring GDPR, which treats health data as a special category. This is general information, not legal advice; confirm your obligations with qualified counsel.",
          "url": "https://aifitnessapi.com/build/ai-fitness-coaching-app#faq-3"
        },
        {
          "question": "Native or cross-platform for an AI coaching app?",
          "answer": "It hinges on the motion layer. If live, every-frame form feedback is your core loop, lean native or React Native with native frame processors, because continuous on-device inference is where cross-platform frameworks struggle. If the camera is an occasional scan-a-set feature rather than the product, a cross-platform stack ships faster and is a reasonable choice.",
          "url": "https://aifitnessapi.com/build/ai-fitness-coaching-app#faq-4"
        },
        {
          "question": "How do these apps make money?",
          "answer": "Consumer subscription with a free trial is the dominant model, and many apps also license their motion-tracking or adaptive engine to other apps as a B2B2C API or SDK. The onboarding assessment that produces a personalized plan is both the value moment and the paywall justification. Triggering the paywall after that moment, and biasing toward annual plans via a two-to-four-week trial, are widely reported to help conversion, though specific figures vary and should be treated as directional.",
          "url": "https://aifitnessapi.com/build/ai-fitness-coaching-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a strength training app",
      "answer": "A strength training app is a gym logger: users pick or plan a workout, log each set as weight times reps, and the app drives progressive overload while tracking PRs and volume over time. The log is the product and the progress chart is the reward, so a set-logging UX fast enough to use between sets is the whole game. Buy the exercise content (a licensed exercise database) and spend your engineering on the logger and progression logic. Offline-first support is non-negotiable because people train in gyms with no signal.",
      "title": "How to Build a Strength Training App (2026)",
      "url": "https://aifitnessapi.com/build/strength-training-app",
      "markdown": "https://aifitnessapi.com/build/strength-training-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the minimum viable version of a strength training app?",
          "answer": "The logger is the MVP. Ship the ability to pick an exercise from a licensed library or one built-in template, log sets as weight times reps with last session's numbers shown inline, an auto rest timer and plate math on the log screen, and a simple history view with a personal record and basic volume chart. Cut adaptive AI programming, social features, wearable fusion, and camera work from v1.",
          "url": "https://aifitnessapi.com/build/strength-training-app#faq-1"
        },
        {
          "question": "Should I build my own exercise database or use an API?",
          "answer": "For most teams, licensing an exercise database API is the better call. A comprehensive, well-tagged library with demo media and substitutions is a solved, licensable problem, and building it in-house diverts effort from the logger and progression logic that actually differentiate your app. Spend your engineering where users can feel it.",
          "url": "https://aifitnessapi.com/build/strength-training-app#faq-2"
        },
        {
          "question": "Do I need camera rep counting or AI for a strength app?",
          "answer": "No. For a barbell and dumbbell logger, camera rep counting is a nice-to-have, not core to the loop. Serious lifters mostly want a fast, reliable log. If you later want camera reps, you can add them as a differentiator rather than building pose tracking from scratch, but do not let that feature delay the logger.",
          "url": "https://aifitnessapi.com/build/strength-training-app#faq-3"
        },
        {
          "question": "Why does offline support matter so much for a gym logger?",
          "answer": "People train in basements and gyms with poor or no signal, and a logger that stalls mid-workout gets deleted. Offline-first means local writes to a durable on-device store plus background sync with conflict handling, treated as a first-class requirement from day one rather than a later add-on. Last-write-wins merging is usually sufficient for a single user's personal logs.",
          "url": "https://aifitnessapi.com/build/strength-training-app#faq-4"
        },
        {
          "question": "How do strength training apps make money?",
          "answer": "Consumer subscription (freemium) is the default and dominant model, and a useful free tier is common among reference apps. Premium typically unlocks unlimited templates, advanced analytics, and export, with the paywall placed after a value moment and biased toward annual plans because monthly churn is high in fitness. Trial-to-paid conversion is reported with a wide spread and longer trials of about two to four weeks are reported to convert better than short ones (reported, verify).",
          "url": "https://aifitnessapi.com/build/strength-training-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a running app",
      "answer": "A running app is a GPS habit loop: the user starts a run, your app tracks route, pace, distance, splits, and heart rate, then saves and analyzes it and feeds it into a training plan aimed at a goal race. The build-vs-buy shape is to build the GPS tracking core yourself on platform location APIs and a maps SDK, and to buy the wearable and heart-rate layer through an aggregator rather than integrating dozens of watches. The one genuinely hard part is capturing an accurate GPS track in the background for an hour without draining the battery, on two platforms that deliberately restrict background location. Get that right and the rest is ordinary app work.",
      "title": "How to Build a Running App (2026)",
      "url": "https://aifitnessapi.com/build/running-app",
      "markdown": "https://aifitnessapi.com/build/running-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the hardest part of building a running app?",
          "answer": "Reliable background GPS tracking. Both iOS and Android deliberately restrict background location to protect battery and privacy, so you must work within their rules: iOS needs Always authorization and a background mode, and Android needs a foreground service with a persistent notification plus separate background-location permission. On top of that, raw GPS is noisy and needs smoothing, and continuous high-accuracy tracking drains the battery, so there is a real accuracy-versus-battery trade-off to make deliberately.",
          "url": "https://aifitnessapi.com/build/running-app#faq-1"
        },
        {
          "question": "Should I build a running app native or cross-platform?",
          "answer": "Cross-platform (React Native or Flutter) is fine for the maps, history, and training-plan screens. But continuous background location and Bluetooth heart-rate straps are hardware-heavy work that usually needs native modules even inside a cross-platform shell. Budget for that native work rather than assuming a plugin fully covers background tracking and BLE.",
          "url": "https://aifitnessapi.com/build/running-app#faq-2"
        },
        {
          "question": "Do I need a wearable data API, or is phone GPS enough?",
          "answer": "Phone GPS alone is enough for a credible first version that tracks distance, pace, and route. You add a wearable layer when you want heart rate and heart-rate zones, or to sync with watches like Apple Watch, Garmin, Wear OS, or Fitbit. Rather than integrate each device separately, most apps use a wearable data aggregator that collapses hundreds of devices behind one API.",
          "url": "https://aifitnessapi.com/build/running-app#faq-3"
        },
        {
          "question": "How do running apps make money?",
          "answer": "The dominant model is freemium subscription: free core GPS tracking as the acquisition funnel, with premium training plans, advanced analytics, and trends behind a subscription. Annual plans reduce the heavy seasonal churn in fitness, and triggering the paywall after a value moment such as a first completed run is reported to convert better than a paywall at launch. Treat any specific conversion or revenue figures as directional and verify against your own data.",
          "url": "https://aifitnessapi.com/build/running-app#faq-4"
        },
        {
          "question": "How accurate is phone GPS for tracking a run?",
          "answer": "Good enough with cleanup, poor without it. Raw GPS fixes drift, especially among tall buildings, under tree cover, and before the signal settles at the start, and naively summing raw points overstates distance. Applying smoothing and accuracy-gated filtering, and discarding low-accuracy fixes, gets distance and pace to a quality runners will trust.",
          "url": "https://aifitnessapi.com/build/running-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a yoga app",
      "answer": "A yoga app is a habit loop wrapped around video: users pick a class or flow, follow along with guided video and breath pacing, then log the practice and keep a streak. The content is the product, so the main decision is buying or producing classes and streaming them reliably, while you build the library, player, timers, and habit mechanics around them. Camera-based alignment feedback is an optional differentiator, not a starting requirement, and it is genuinely hard to do well for floor and twist poses. The default money model is a consumer subscription, usually with an annual bias and a trial.",
      "title": "How to Build a Yoga App (2026)",
      "url": "https://aifitnessapi.com/build/yoga-app",
      "markdown": "https://aifitnessapi.com/build/yoga-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What are the must-have features of a yoga app?",
          "answer": "A filtered class library (by style, level, duration, focus, and teacher), a reliable follow-along video or audio player with pose cues and breath pacing, timed flows and sequences, structured programs or challenges with streaks, and a pose reference. Offline downloads and background audio are close behind because people practice without signal.",
          "url": "https://aifitnessapi.com/build/yoga-app#faq-1"
        },
        {
          "question": "Do I need camera-based pose detection for a yoga app?",
          "answer": "No. Many successful yoga apps ship no live camera feedback at all. Automated alignment feedback is an optional differentiator, and it is hard to do well for yoga specifically because floor poses, deep twists, folds, and inversions cause the camera to see a self-occluded, non-upright body. Pose estimation tracks standing poses reasonably but struggles with the poses yoga leans on most, so scope it narrowly and be honest about its limits if you add it.",
          "url": "https://aifitnessapi.com/build/yoga-app#faq-2"
        },
        {
          "question": "Should I build or buy the video content and delivery?",
          "answer": "Buy or produce the content and buy the delivery. The class library is the moat and the recurring cost, sourced by producing classes with teachers or licensing a catalog. For delivery, use a video streaming platform with adaptive bitrate, offline download, and signed URLs rather than serving raw files. Build the app shell, library, player, timers, and habit mechanics yourself.",
          "url": "https://aifitnessapi.com/build/yoga-app#faq-3"
        },
        {
          "question": "How do yoga apps make money?",
          "answer": "The default is a consumer subscription or freemium model, usually with an annual bias because monthly churn in fitness is high. Some apps add a-la-carte purchases for specific programs or challenges. Reported benchmarks suggest placing the paywall after a value moment lifts trial starts and that longer trials of two to four weeks convert better than three-day trials, but treat any single figure as directional and verify it.",
          "url": "https://aifitnessapi.com/build/yoga-app#faq-4"
        },
        {
          "question": "What is the hardest part of building a yoga app?",
          "answer": "Content production and video delivery cost. Both producing high-quality classes and streaming them reliably are ongoing expenses that are easy to underestimate, and buffering or broken downloads during a held pose is the fastest way to lose a daily-practice user. Model video delivery against expected watch hours early, and invest in adaptive streaming and offline playback before flashy features.",
          "url": "https://aifitnessapi.com/build/yoga-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a personal training app",
      "answer": "A personal training app is a two-sided platform where a trainer builds and assigns programs and a client performs, logs, and reports back. You mostly build the workflow (program builder, client roster, messaging, check-ins, progress dashboards) and buy the exercise content library rather than film it. The hard part is the hand-off between the two sides, so ship one thin end-to-end loop before adding breadth. The durable business model is per-trainer SaaS, where the trainer pays and the client uses it free.",
      "title": "How to Build a Personal Training App (2026)",
      "url": "https://aifitnessapi.com/build/personal-training-app",
      "markdown": "https://aifitnessapi.com/build/personal-training-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Should I build the trainer side or the client side first?",
          "answer": "Either order can work, but build only a thin slice of both before widening. Many teams start with the client workout player and logging even if the trainer 'programs' through an imported spreadsheet, because logged client data is what makes the trainer's dashboard worth anything. The rule is that one full round trip should run end to end before you invest in depth on either side.",
          "url": "https://aifitnessapi.com/build/personal-training-app#faq-1"
        },
        {
          "question": "Should I build my own exercise library or license one?",
          "answer": "For a trainer-client platform, licensing a tagged exercise database with demo media is almost always the better first move. The content is a commodity you can buy, while your product is the program builder and monitoring workflow. Producing and maintaining thousands of demo clips yourself is slow and expensive, so most teams license the library and layer a CMS on top for a trainer's custom exercises.",
          "url": "https://aifitnessapi.com/build/personal-training-app#faq-2"
        },
        {
          "question": "Who pays in a personal training app, the trainer or the client?",
          "answer": "In the standard model the trainer is the paying customer and the client uses the app for free because their trainer covers it. That means your paywall, onboarding, and support all target the trainer. Charging clients directly is possible but pushes the product toward a consumer app with different economics, so decide early rather than trying to serve both as paying customers.",
          "url": "https://aifitnessapi.com/build/personal-training-app#faq-3"
        },
        {
          "question": "How do I avoid the two-sided cold-start problem?",
          "answer": "Don't launch open to the public. Seed the platform with one or a few real trainers and their existing client rosters so the app is full from day one, then grow trainer by trainer. Solving one side's supply first, in this case the trainers who bring their own clients, sidesteps the empty-marketplace problem that kills most two-sided products.",
          "url": "https://aifitnessapi.com/build/personal-training-app#faq-4"
        },
        {
          "question": "Do I need live camera form tracking in a personal training app?",
          "answer": "Usually not for the core loop. Because a real trainer is in the loop, form review is typically async: the client uploads a lift and the trainer annotates it, which needs no live on-device pose tracking. You can add automated rep or form signals later as a differentiator, but they are not on the critical path for the first release.",
          "url": "https://aifitnessapi.com/build/personal-training-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a physical therapy app",
      "answer": "A physical therapy / rehab app runs one loop: a clinician or algorithm prescribes a home-exercise program, the patient performs it at home (optionally with camera form and range-of-motion feedback), and adherence and outcomes report back so the program can progress. Buy the commodity pieces (exercise content, wearable sync, subscription plumbing) and build the differentiator, which is the motion feedback and the clinical logic. The make-or-break decision is regulatory positioning: positioning it as general wellness (adherence and movement) AND keeping it low-risk keeps it outside active FDA device regulation, while making diagnosis or treatment claims can make it an FDA-regulated medical device. This is general information, not legal or regulatory advice; confirm your obligations with qualified counsel.",
      "title": "How to Build a Physical Therapy / Rehab App (2026)",
      "url": "https://aifitnessapi.com/build/rehab-physical-therapy-app",
      "markdown": "https://aifitnessapi.com/build/rehab-physical-therapy-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Does a physical therapy app have to be HIPAA compliant?",
          "answer": "Not automatically. HIPAA applies when you are a covered entity or a business associate, which for a rehab app usually means handling protected health information on behalf of a clinic, hospital, or health plan; in that case you likely need a Business Associate Agreement and HIPAA safeguards. A direct-to-consumer app where the patient enters their own data generally is not under HIPAA, and the FTC Health Breach Notification Rule (plus the FTC Act and state law) is more likely to apply instead. Which bucket you are in depends on your contracts and data flows, so confirm with counsel.",
          "url": "https://aifitnessapi.com/build/rehab-physical-therapy-app#faq-1"
        },
        {
          "question": "Will my rehab app be regulated by the FDA as a medical device?",
          "answer": "It depends on your claims and function, and it is a hard fork rather than a spectrum. Software intended to diagnose, treat, cure, mitigate, or prevent a disease or injury can be a medical device (Software as a Medical Device, potentially needing a 510(k) clearance), while software framed as general wellness that encourages movement and adherence stays outside active device regulation only when it is also low-risk (FDA's general-wellness policy requires both). Because the line is claim-driven and highly fact-specific, settle it with regulatory counsel before you write marketing copy. This is general information, not legal or regulatory advice.",
          "url": "https://aifitnessapi.com/build/rehab-physical-therapy-app#faq-2"
        },
        {
          "question": "Is camera-based range-of-motion tracking a clinical assessment?",
          "answer": "Frame it as a measurement, not a diagnosis. Camera ROM and form output compares joint angles and alignments against target ranges you define and returns a number and a coaching cue; it does not diagnose a condition or determine treatment. Keeping that framing in the UI and your copy is part of staying on the general-wellness side of the regulatory fork, and it is also just an accurate description of what the geometry does.",
          "url": "https://aifitnessapi.com/build/rehab-physical-therapy-app#faq-3"
        },
        {
          "question": "Should I build the motion tracking or license an SDK?",
          "answer": "Both are valid, and it is the crux build-versus-buy call for this app type. You can build on a free pose primitive such as MediaPipe and write the joint-angle and range-of-motion geometry yourself, or license a motion-tracking SDK that ships rep counting, form rules, and ROM measurement. Building gives you control and no per-use fee but is the hardest engineering; licensing gets you there faster at a recurring cost. Compare the tradeoff on the site's AI workout-tracking APIs page.",
          "url": "https://aifitnessapi.com/build/rehab-physical-therapy-app#faq-4"
        },
        {
          "question": "How do rehab apps make money?",
          "answer": "The primary model is B2B or B2B2C: contracts with employers, health plans, and providers on value-based, per-member-per-month, or per-episode terms, which give lower acquisition cost and stickier contracts than the consumer app store. A direct-to-consumer subscription is a secondary option but faces thin retention and a winner-take-most consumer market. Market-size and revenue figures for digital musculoskeletal care vary widely between analysts, so treat any single number as directional and verify it.",
          "url": "https://aifitnessapi.com/build/rehab-physical-therapy-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a corporate wellness app",
      "answer": "A corporate wellness app is a B2B product where an employer sponsors it, employees join and sync activity from wearables, they compete in challenges and earn incentives, and HR sees only aggregate, de-identified reporting. The build-vs-buy shape is to buy the wearable plumbing through one aggregator and build the challenge engine, rewards logic, and a reporting layer that keeps individual health data private by construction. That privacy wall between individual data and what the employer can see is the single most consequential thing to get right. This is general information, not legal advice; which rules apply depends on your program's structure, so confirm your obligations with qualified counsel.",
      "title": "How to Build a Corporate Wellness App (2026)",
      "url": "https://aifitnessapi.com/build/corporate-wellness-app",
      "markdown": "https://aifitnessapi.com/build/corporate-wellness-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Does a corporate wellness app have to be HIPAA compliant?",
          "answer": "Not automatically. HIPAA generally attaches only when the wellness program is part of a group health plan, in which case the plan is the covered entity and you may be a business associate needing a BAA. A program not connected to a group health plan usually falls outside HIPAA, though the ADA, GINA, the FTC Health Breach Notification Rule, and state privacy laws can still apply. It is fact-specific, so confirm with counsel. This is general information, not legal advice.",
          "url": "https://aifitnessapi.com/build/corporate-wellness-app#faq-1"
        },
        {
          "question": "What data can the employer actually see?",
          "answer": "Only aggregate, de-identified information such as overall participation rate and engagement, never individual health data. EEOC guidance under the ADA and GINA calls for information to reach the employer only in aggregate terms that do not identify individuals. In practice that means suppressing small groups (a team of two is not aggregate) and never letting a drill-down expose one person. Build this wall into the schema from day one.",
          "url": "https://aifitnessapi.com/build/corporate-wellness-app#faq-2"
        },
        {
          "question": "How do I connect all the different wearables employees use?",
          "answer": "Use a health-data aggregator rather than building an integration for each device. Employees arrive with Fitbits, Garmins, Apple Watches, Ouras, and phone step counters, each with its own API and data model. An aggregator collapses that into one API with webhook or streaming delivery. See the aggregator and wearable data API comparisons for coverage and how platform stores like HealthKit and Health Connect fit alongside.",
          "url": "https://aifitnessapi.com/build/corporate-wellness-app#faq-3"
        },
        {
          "question": "How do corporate wellness apps make money?",
          "answer": "Through B2B contracts, typically per-employee-per-month (PEPM) or a tiered platform fee, with employees using the app free. Sales cycles are longer than consumer apps but churn is lower and lifetime value is higher. Market figures such as the sector approaching roughly 100 billion dollars by 2026 are reported and vary widely, so treat any single number, including vendor ROI claims, as directional and verify it.",
          "url": "https://aifitnessapi.com/build/corporate-wellness-app#faq-4"
        },
        {
          "question": "What is the biggest pitfall to avoid?",
          "answer": "Two things: the privacy wall and engagement. Leaking anything that identifies an individual to the employer is both a compliance and a trust failure, so aggregate-only reporting must be architectural, not a setting. And participation is famously low even where access is high, so passive wearable sync, teams, streaks, and visible rewards are what actually drive the engagement your renewal depends on.",
          "url": "https://aifitnessapi.com/build/corporate-wellness-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a nutrition tracking app",
      "answer": "A nutrition tracking app runs on one loop: the user logs food by search, barcode, or natural language, sees calories and macros against a daily goal, and tracks the trend over time. The build-vs-buy shape is lopsided toward buy — you license the food database (the make-or-break asset) through a nutrition API and spend your own effort on logging speed and UX. Most consumer nutrition apps monetize with subscription or freemium. Logging friction and food-database coverage are the two things that decide whether anyone keeps using it.",
      "title": "How to Build a Nutrition Tracking App (2026)",
      "url": "https://aifitnessapi.com/build/nutrition-tracking-app",
      "markdown": "https://aifitnessapi.com/build/nutrition-tracking-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Should I build my own food database or use a nutrition API?",
          "answer": "Use a nutrition API. Compiling and maintaining an accurate, well-covered food and barcode database is a multi-year data operation, and coverage and accuracy are exactly what users judge the app on. Buy the data and spend your engineering on logging speed and search UX.",
          "url": "https://aifitnessapi.com/build/nutrition-tracking-app#faq-1"
        },
        {
          "question": "What is the single most important thing to get right?",
          "answer": "Logging friction. Every extra tap, slow search, or missing food is a reason to stop, and logging friction is the most common reason nutrition apps churn users. Fast search, barcode scanning, recents, favorites, saved meals, and copy-yesterday are the core product, not extras.",
          "url": "https://aifitnessapi.com/build/nutrition-tracking-app#faq-2"
        },
        {
          "question": "How do nutrition tracking apps make money?",
          "answer": "Subscription or freemium is the default. A genuinely useful free tier drives acquisition, and premium unlocks deeper analytics, macro customization, recipe tools, and integrations. Annual plans are favored because monthly churn is severe. Some apps add recipe or grocery commerce as secondary revenue. Treat any conversion or revenue figures you read as directional and verify them.",
          "url": "https://aifitnessapi.com/build/nutrition-tracking-app#faq-3"
        },
        {
          "question": "What belongs in the MVP?",
          "answer": "Only the core loop: fast logging against a good food database, calories and macros versus a goal, and a simple weight and calorie trend. Cut AI photo logging, micronutrients, recipe importers, restaurant menus, social, and coaching from v1. The one place not to cut is food-database quality and search speed.",
          "url": "https://aifitnessapi.com/build/nutrition-tracking-app#faq-4"
        },
        {
          "question": "Do I need medical or legal compliance for a nutrition app?",
          "answer": "An app that sets calorie or macro targets is generally giving fitness and wellness guidance, not medical or dietary treatment, as long as it does not claim to treat, diagnose, or manage a condition. Present targets as general information, not personalized medical advice. Health data also carries privacy obligations. This is general information, not legal advice; confirm your obligations with qualified counsel.",
          "url": "https://aifitnessapi.com/build/nutrition-tracking-app#faq-5"
        }
      ]
    },
    {
      "question": "fitness app tech stack",
      "answer": "Choose your client framework by the hardest thing your app does on-device: apps built around real-time camera pose, BLE wearables, or high-frequency on-device ML lean native (Swift/Kotlin), while content, logging, and coaching apps ship faster cross-platform (Flutter or React Native). For the backend, a managed BaaS (Firebase or Supabase) with an offline-first local store covers most needs, since workout apps must work without signal. Buy the commodity layers (auth, subscriptions via RevenueCat, push, analytics, wearable aggregation) and spend your engineering on the differentiator. A safe default MVP is cross-platform plus BaaS plus RevenueCat, going native only when live camera or deep hardware integration is the core loop.",
      "title": "How to Choose a Tech Stack for a Fitness App (2026)",
      "url": "https://aifitnessapi.com/build/fitness-app-tech-stack",
      "markdown": "https://aifitnessapi.com/build/fitness-app-tech-stack.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Should I build a fitness app native or cross-platform?",
          "answer": "Match the client to the hardest thing the app does on-device. If the core loop is real-time camera pose tracking, continuous BLE wearable streaming, or high-frequency on-device ML, lean native (Swift/Kotlin). If the app is mainly video content, workout logging, program tracking, or social, cross-platform (Flutter or React Native) ships one codebase far faster and users cannot perceive the difference.",
          "url": "https://aifitnessapi.com/build/fitness-app-tech-stack#faq-1"
        },
        {
          "question": "Firebase or Supabase for a fitness app backend?",
          "answer": "Both are managed BaaS options. Firebase has the most mature offline-first mobile SDK, with local persistence and automatic conflict resolution built in, which suits a workout app that must run without signal. Supabase is managed Postgres with SQL, row-level security, portability, and often lower cost, but you assemble the offline sync layer yourself. Firebase for fast offline-first prototyping; Supabase if you want SQL and portability and can own sync.",
          "url": "https://aifitnessapi.com/build/fitness-app-tech-stack#faq-2"
        },
        {
          "question": "Why does offline-first matter so much for workout apps?",
          "answer": "People train in basements, gyms with no signal, and on planes. If the app cannot record a set without connectivity, the core loop breaks. That means local-first writes, a durable on-device store, and background sync with conflict resolution are first-class requirements, not a later add-on. Last-write-wins is usually fine for personal logs unless you have genuine multi-device concurrent edits.",
          "url": "https://aifitnessapi.com/build/fitness-app-tech-stack#faq-3"
        },
        {
          "question": "How should a fitness app handle subscriptions?",
          "answer": "Fitness apps monetize mostly via auto-renewing subscriptions, which must go through store billing for digital content. StoreKit 2 handles iOS and Google Play Billing handles Android, but a wrapper like RevenueCat gives you one cross-platform entitlement model, server-side validation, webhooks, and paywall tooling. Building billing yourself is rarely worth it before scale. Adapty is the main alternative if paywall experimentation is a priority.",
          "url": "https://aifitnessapi.com/build/fitness-app-tech-stack#faq-4"
        },
        {
          "question": "Do I need HIPAA compliance for a fitness app?",
          "answer": "Usually not. HIPAA generally applies only if you are a covered entity or a business associate handling protected health information in the US clinical sense, which most consumer fitness apps are not. You should still expect GDPR in the EU, follow platform rules (HealthKit and Health Connect data cannot be used for advertising or sold), and collect the minimum. This is general information, not legal advice; confirm your obligations with qualified counsel.",
          "url": "https://aifitnessapi.com/build/fitness-app-tech-stack#faq-5"
        }
      ]
    },
    {
      "question": "how to build a weight loss app",
      "answer": "A weight-loss app is an energy-balance ledger wrapped in a behaviour loop: the user logs intake, the app pulls an expenditure estimate from a phone or wearable, shows the day's balance, and plots weigh-ins as a smoothed trend. The build-vs-buy shape is lopsided toward buy — license the food database, the wearable energy layer and the weight ingestion, and spend your own effort on the ledger, the trend maths and the habit loop. The one genuinely hard part is that the two sides of the ledger are not the same kind of number: intake is typed in and incomplete, calories out is a model estimate rather than a measurement, and daily weight is noisy enough to look random until you smooth it. The app's credibility rests on how honestly you present that difference.",
      "title": "How to Build a Weight Loss App (2026)",
      "url": "https://aifitnessapi.com/build/weight-loss-app",
      "markdown": "https://aifitnessapi.com/build/weight-loss-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-01",
      "first_party": false,
      "faqs": [
        {
          "question": "How do weight loss apps calculate calories burned?",
          "answer": "They do not calculate it so much as read someone else's estimate. Phones, watches and rings produce an energy-expenditure figure from movement, heart rate where available, and the height, weight, age and sex entered at setup, and your app pulls that figure through a health store or a wearable data layer. It is a model output, not a measurement, and different devices report different numbers for the same day. Treat it as an estimate in the interface too: lower precision than logged intake, with an explanation of where it came from.",
          "url": "https://aifitnessapi.com/build/weight-loss-app#faq-1"
        },
        {
          "question": "Should a weight loss app show daily weight or a weight trend?",
          "answer": "Show the trend by default and keep raw points one tap away. Body weight moves day to day with hydration, sodium, glycogen and gut contents, and at that resolution the noise is larger than whatever the user is trying to see. An unsmoothed chart makes consistent effort look random, which is a reason to stop weighing in and therefore to stop using the app. A moving average over a trailing window is the conventional fix; the design decisions that matter are the window length and how you handle missing weigh-ins.",
          "url": "https://aifitnessapi.com/build/weight-loss-app#faq-2"
        },
        {
          "question": "Do I need a wearable integration to build a weight loss app?",
          "answer": "Not for a first version. You can derive a daily target at onboarding and let the user log intake against it without any device connected, which keeps the ledger simple and avoids importing an estimate you then have to explain. Add a wearable or health-store feed when you want the day's budget to respond to activity, and integrate it through an aggregation layer rather than device by device. Be conservative when you add burned calories back into the budget, and label the figure clearly as an estimate.",
          "url": "https://aifitnessapi.com/build/weight-loss-app#faq-3"
        },
        {
          "question": "How do weight loss apps make money?",
          "answer": "Freemium subscription dominates. Keep logging and the daily ledger free, because metering the log makes the whole product wrong, and charge for depth: history range, exports, custom targets, longer trend windows and a weekly review. Place the paywall after the user's first real trend rather than after the onboarding calculator, since a target is arithmetic they can get anywhere. Demand is seasonal, so offer a pause instead of only a cancel, and treat any conversion figures you read elsewhere as directional and worth verifying.",
          "url": "https://aifitnessapi.com/build/weight-loss-app#faq-4"
        },
        {
          "question": "Is a weight loss app a regulated medical device?",
          "answer": "It depends on what the app claims to do, and that boundary is worth locating deliberately rather than discovering during app review. An app that records what a user eats and shows their weight over time sits in general wellness; claims about treating, diagnosing or managing a condition move it toward regulated territory. Both app stores also apply extra scrutiny to health and weight content, including how extreme goals and minors are handled. This is general information rather than legal advice, so confirm your obligations with qualified counsel.",
          "url": "https://aifitnessapi.com/build/weight-loss-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a meal planning app",
      "answer": "A meal planning app is a constraint-satisfaction and grocery-logistics product rather than a tracker: the user sets a week's constraints, fills slots with recipes, and the app turns that plan into a scaled, deduplicated, aisle-ordered shopping list. The build-vs-buy shape is to buy the nutrient database and, if you are not writing recipes yourself, the recipe corpus, and to build the planner solver, the ingredient normalisation layer and the list logic. The one genuinely hard part is ingredient normalisation: the same ingredient appears under different names, units, preparation phrases and package sizes across recipes, and the shopping list is only correct if all of them collapse into one buyable quantity. Because the loop runs weekly rather than daily, retention and churn behave differently from a logger's, and the moment that decides everything is whether a complete list is in the user's hand before they shop.",
      "title": "How to Build a Meal Planning App (2026)",
      "url": "https://aifitnessapi.com/build/meal-planning-app",
      "markdown": "https://aifitnessapi.com/build/meal-planning-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-01",
      "first_party": false,
      "faqs": [
        {
          "question": "Should I license recipe data or create my own recipes?",
          "answer": "Both work, and they fail differently. Licensed corpora give you volume immediately but arrive with terms that constrain what you may store, modify, scale and display, and with ingredient lines written for humans rather than parsers. Your own recipes are slower to produce but come already normalised, which removes most of the hard work downstream, and you own them outright. A common route is to start with a small hand-written corpus to prove the shopping list logic, then license for breadth once you know what shape your data needs to be in.",
          "url": "https://aifitnessapi.com/build/meal-planning-app#faq-1"
        },
        {
          "question": "How do you generate a shopping list from a meal plan?",
          "answer": "Scale each recipe to the servings that slot needs, resolve every ingredient line to a canonical ingredient with a quantity in a common unit, sum across all the recipes in the week, subtract anything the pantry already has, then round each total up to something buyable and group the result by supermarket aisle. Unit conversion is the part that bites, because volume to mass depends on the ingredient. Ingredients your matcher could not resolve should still appear on the list, flagged, rather than being dropped.",
          "url": "https://aifitnessapi.com/build/meal-planning-app#faq-2"
        },
        {
          "question": "What is the hardest part of building a meal planning app?",
          "answer": "Ingredient normalisation. Recipes describe ingredients in prose written for cooks, so the same thing shows up with different names, regional spellings, units, preparation phrases and implied quantities, and none of that aggregates until you map it to a canonical ingredient with convertible units. You need per-ingredient densities to turn volumes into mass, per-piece masses for things counted rather than weighed, and a mapping from cooking amounts to package sizes. Curating the most common few hundred ingredients by hand gets you most of the coverage; the long tail needs review tooling.",
          "url": "https://aifitnessapi.com/build/meal-planning-app#faq-3"
        },
        {
          "question": "How do meal planning apps make money?",
          "answer": "Subscription is the base, but the pricing logic differs from a tracker's because value arrives weekly rather than daily. Trials should span at least two shopping cycles, since a user has to shop and cook from a plan before they can judge it. Give the first complete list away and charge from the second week, capping slots or corpus size rather than degrading the list. Retailer cart handoff and affiliate deals, paid recipe packs, and licensing to dietitians or gyms all fit this shape; availability of retailer programmes varies by market.",
          "url": "https://aifitnessapi.com/build/meal-planning-app#faq-4"
        },
        {
          "question": "How do you calculate nutrition per serving for a recipe?",
          "answer": "You compute it rather than look it up: match each ingredient line to a row in a nutrient database, convert its quantity to the unit that row is expressed in, sum the nutrients across the recipe, and divide by the serving count. Every step leaks accuracy. Unmatched ingredients, wrong volume-to-mass densities, an arbitrary serving count and cooking changes such as water loss or drained fat all move the result. Keep the matches inspectable, display low precision, and mark nutrition unavailable when too much of a recipe failed to match.",
          "url": "https://aifitnessapi.com/build/meal-planning-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a sleep tracking app",
      "answer": "A sleep tracking app is a once-a-day reading product: a watch, ring, or phone stages the night, your app reads that record, reconciles whatever arrived, and shows the user what last night looked like against their own recent nights. The build-vs-buy shape is to buy the device layer and the stage classification through a wearable aggregator or the platform health store, and to build the session reconciliation, the night window, and the insight layer on top. The one genuinely hard part is the night-spanning day boundary: a sleep session crosses midnight and sometimes a timezone, so which session counts as \"last night\" is a rule you write, not a value you read. Right behind it, the same night can arrive from two devices with different totals and different stage boundaries, so your schema has to hold several versions of one night from the start. Get the window and the schema right in week one, because both are close to unrepairable once real history exists.",
      "title": "How to Build a Sleep Tracking App (2026)",
      "url": "https://aifitnessapi.com/build/sleep-tracking-app",
      "markdown": "https://aifitnessapi.com/build/sleep-tracking-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-01",
      "first_party": false,
      "faqs": [
        {
          "question": "Can you build a sleep tracking app without a wearable?",
          "answer": "You can, but you are then reading a phone-produced estimate rather than a device-produced one, and you inherit the problem that the phone has to be on or near the bed. The more common shape is to read whatever the user's existing hardware already wrote to the platform health store, which costs you one integration and covers watches, rings, and the phone at once. Treat a wearable connection as an upgrade path rather than a requirement, and design the app so it still has something to show on a night with no data at all.",
          "url": "https://aifitnessapi.com/build/sleep-tracking-app#faq-1"
        },
        {
          "question": "How do you decide which night a sleep session belongs to?",
          "answer": "You pick a rule and apply it in one place. A session that runs from 23:40 to 07:05 spans two calendar dates, so you have to assign it by session start, by session end, or by its midpoint, and each choice gives different answers for late sleepers, shift workers, and naps. Store the local UTC offset in force when the session began so the assignment survives travel and daylight-saving changes, and make sure the morning screen, the weekly chart, and any export all call the same function rather than each computing the date themselves.",
          "url": "https://aifitnessapi.com/build/sleep-tracking-app#faq-2"
        },
        {
          "question": "What happens when two devices report the same night differently?",
          "answer": "Expect it, because consumer sleep stages are estimated from movement and heart signals and different vendors use different algorithms. Model a night as several source-specific sessions plus one chosen primary, keep the ones that did not win, and record the precedence rule that picked the winner. Show the user which source produced the number on screen and let them switch. Do not average stage minutes across vendors: the result is a figure no device reported, nobody can reproduce it, and it will not match either companion app the user compares against.",
          "url": "https://aifitnessapi.com/build/sleep-tracking-app#faq-3"
        },
        {
          "question": "Why is last night's sleep data missing when the user wakes up?",
          "answer": "Because most wearables sync on their own schedule, usually when the vendor's own app runs, so a night can land mid-morning rather than at wake time. Records can also be revised after the fact, and some nights never arrive because the device was charging or was not worn. Design an explicit not-synced-yet state instead of showing zero, make ingestion idempotent and keyed on the source's own record identity so a revision updates rather than duplicates, and draw missing nights as visible gaps in charts rather than joining the line across them.",
          "url": "https://aifitnessapi.com/build/sleep-tracking-app#faq-4"
        },
        {
          "question": "How do sleep tracking apps make money?",
          "answer": "By selling a run of nights rather than one night. Last night is usually free because the user's own hardware already shows it, and the paid tier is depth: full history, weekly and monthly reports they can export and keep, reconciliation across more than one device, and comparisons over months. Timing matters more than in most categories, since the moment users are in the app is early morning when nobody wants a purchase decision. Offering after enough nights exist to show a pattern is reported to work better than a paywall at first launch (reported, verify).",
          "url": "https://aifitnessapi.com/build/sleep-tracking-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a recovery app",
      "answer": "A recovery app turns overnight signals such as HRV, resting heart rate, and sleep duration into one composite readiness score per day, plus an explanation of what moved it. The build-vs-buy shape is to buy the signal through a wearable aggregator or the platform health store and to build the baseline mathematics, the score itself, and the explanation, because the score is a model you invent rather than a value any device reports. The one genuinely hard part is the cold start: HRV means nothing in absolute terms and only becomes readable against a user's own baseline, so a new user has nothing to see during the warm-up period and that is where most launches lose their first cohort. Close behind it, baselines drift and formulas change, so every score needs a version stamp — recomputing history under a new formula silently rewrites what the user already saw. Pull historical data on connect, design the warm-up as a real experience, and version the score before you have users.",
      "title": "How to Build a Recovery App (2026)",
      "url": "https://aifitnessapi.com/build/recovery-app",
      "markdown": "https://aifitnessapi.com/build/recovery-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-01",
      "first_party": false,
      "faqs": [
        {
          "question": "How long does a recovery app need before it can show a score?",
          "answer": "Long enough to have a personal baseline, because HRV values are not comparable between people or devices and only mean something against the user's own recent range. Whatever window you choose, treat it as a product decision you state plainly rather than a silent delay. The strongest mitigation is pulling the user's historical nights when they connect their account, which many vendors support and which can produce a warm baseline on the first day. Otherwise, show the raw nightly values and a visible count of nights collected while the baseline fills.",
          "url": "https://aifitnessapi.com/build/recovery-app#faq-1"
        },
        {
          "question": "Why does my recovery score differ from the one in the device's own app?",
          "answer": "Because it is a different model. Vendors compute their readiness numbers from partly the same inputs with different weights, different baseline windows, and sometimes different measurement timing, so two scores from the same night will not line up. Users read the gap as your app being broken rather than as two models disagreeing, so the answer is transparency: name the inputs you use, show each one's contribution and its distance from baseline, and say in your own copy what you weigh differently. An opaque score cannot survive that comparison.",
          "url": "https://aifitnessapi.com/build/recovery-app#faq-2"
        },
        {
          "question": "Should I recompute past scores when I change the formula?",
          "answer": "Not silently. Someone who remembers a hard week scored as poor, then finds that stretch now reads as fine, has learned that the number is mutable — worse than an imperfect formula. Store a formula version alongside every score together with the input values used, apply new versions going forward by default, and if you do restate history, mark the restated range in the interface and explain why. Getting this into the schema before launch costs almost nothing; retrofitting it after a model change costs the user's trust.",
          "url": "https://aifitnessapi.com/build/recovery-app#faq-3"
        },
        {
          "question": "What inputs should a readiness score use?",
          "answer": "Start with overnight HRV and resting heart rate, because they are the most widely available and the easiest to baseline, and add sleep duration as a third input if your source supplies it. Workout load, a subjective morning check-in, and context such as travel or cycle phase are reasonable later additions, but each one added to the formula makes the explanation harder and requires a new score version. Add inputs one at a time and check that you can still tell the user in one sentence why today's number moved.",
          "url": "https://aifitnessapi.com/build/recovery-app#faq-4"
        },
        {
          "question": "How do recovery apps make money?",
          "answer": "By subscription, with the awkward feature that the user already bought the hardware and often gets a score from the vendor for free. The paid pitch therefore has to be what a bundled app structurally cannot do: work across devices, explain its inputs, let people adjust them, or specialise for a population the generalist score ignores. Trial length matters more than in most categories because it has to outlast the baseline warm-up; longer trials are reported to convert better in health and fitness than very short ones (reported, verify). Coach and team seats are a plausible second line.",
          "url": "https://aifitnessapi.com/build/recovery-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a meditation app",
      "answer": "A meditation app is a small piece of engineering wrapped around a large content operation: the user picks a guided session or sets a timer, plays it, and the completed minutes are written back to the platform health store as a session with a start, an end and a duration. The build-vs-buy shape is unusual for this cluster, because the code is nearly all build and nearly all cheap, while the thing you buy is the audio itself, whether you license a catalog or commission teachers to record one. The one genuinely hard engineering problem is audio session behaviour: playing under a locked screen, surviving calls and alarms, ducking instead of dying, working offline, and driving the lock-screen and watch remote controls from real playback state. The one genuinely hard business problem is that a library goes stale, so content production is a recurring operating cost rather than a launch cost. The category also has entrenched incumbents with catalogs you will not match, so plan to win a narrow audience rather than out-publish anyone.",
      "title": "How to Build a Meditation App (2026)",
      "url": "https://aifitnessapi.com/build/meditation-app",
      "markdown": "https://aifitnessapi.com/build/meditation-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-01",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the hardest part of building a meditation app?",
          "answer": "Not the code. Technically this is an audio player with a timer, which is the simplest build in the category, so the difficulty moves to two places. The first is audio session behaviour: playing under a locked screen, deciding whether to duck, pause or stop for each kind of interruption, resuming correctly, reacting to headphones being unplugged, and keeping the lock-screen controls in sync with real playback. The second is content. A library that stops growing stops earning, so you need a production pipeline and a publishing cadence, not just a launch catalog.",
          "url": "https://aifitnessapi.com/build/meditation-app#faq-1"
        },
        {
          "question": "How do meditation apps keep audio playing when the screen is locked?",
          "answer": "By declaring background audio capability and configuring an audio session that is permitted to play while the app is not in the foreground, then handling interruptions explicitly. A phone call, an alarm or another app's audio each need a decision to duck, pause or stop, plus correct behaviour when the interruption ends. Android's audio-focus system separates transient loss from permanent loss and you handle them differently. You also publish playback state to the platform's now-playing layer so the lock screen, headphone buttons and watch controls act on what is really happening.",
          "url": "https://aifitnessapi.com/build/meditation-app#faq-2"
        },
        {
          "question": "Can a meditation app log mindful minutes to Apple Health or Health Connect?",
          "answer": "Yes in principle. Both platform health stores carry a mindful or mindfulness session type, and the important detail is that it is a session with a start time, an end time and therefore a duration, not a single number you post. That changes your data model: you record an interval, you have to decide what counts as a completed session, and you have to handle a session the user abandoned halfway. Availability and naming differ by platform and version, so confirm what the version you target actually exposes and request permission for it explicitly.",
          "url": "https://aifitnessapi.com/build/meditation-app#faq-3"
        },
        {
          "question": "How much content does a meditation app need at launch?",
          "answer": "Less than founders expect at launch and more than they expect afterwards. A few dozen sessions covering two or three durations and a couple of goals is enough to test whether anyone comes back, because a new user cannot consume a large catalog in their first weeks anyway. The real requirement is cadence. Engaged subscribers exhaust material faster than anyone plans for, so a reliable publishing schedule matters more than launch breadth. If you can only fund one of the two, fund the schedule.",
          "url": "https://aifitnessapi.com/build/meditation-app#faq-4"
        },
        {
          "question": "How do meditation apps make money?",
          "answer": "A library subscription. A free daily session or a small permanent free set drives acquisition, and the rest of the catalog, offline downloads and multi-session courses sit behind a recurring plan, with an annual bias because monthly churn is severe. What differs from a tracking app is the cost side: your cost of goods is next month's recordings, so content spend is a permanent operating line funded by subscription revenue. Selling seats to employers or health plans is a secondary channel with a different buyer and a longer sales cycle.",
          "url": "https://aifitnessapi.com/build/meditation-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a cycle tracking app",
      "answer": "A cycle tracking app records a mix of enumerated category entries — flow level, spotting, cervical mucus quality, test results — alongside an optional temperature signal and the dates each cycle starts and ends, then estimates when the next one is likely to begin. The build-vs-buy shape is mostly build, because the schema, the prediction and above all the privacy architecture are the product; the main thing you integrate is the platform health store for cycle records, plus a wearable source if you use temperature. The genuinely hard modelling problem is predicting from a short and often irregular history, which is exactly the situation the users who care most are in. A harder decision comes before that one: whether the data ever leaves the device, because on-device-only storage is defensible here in a way it is not elsewhere, and it forecloses every server-side feature you might later want. Decide it in week one, because retrofitting either direction is a rewrite.",
      "title": "How to Build a Cycle Tracking App (2026)",
      "url": "https://aifitnessapi.com/build/cycle-tracking-app",
      "markdown": "https://aifitnessapi.com/build/cycle-tracking-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-01",
      "first_party": false,
      "faqs": [
        {
          "question": "What data does a cycle tracking app actually store?",
          "answer": "Mostly enumerated states rather than measurements. Flow level, spotting, cervical mucus quality and test results are category values, not numbers, alongside symptom tags, an optional basal or overnight temperature series, and the dates each cycle starts and ends. That shape matters because you cannot average or interpolate a category value, so every aggregation has to be defined per record type. Entries are also routinely backdated and corrected, so each record needs the date the event happened stored separately from the date it was logged.",
          "url": "https://aifitnessapi.com/build/cycle-tracking-app#faq-1"
        },
        {
          "question": "Should cycle data stay on the device or sync to a server?",
          "answer": "On-device-only is a legitimate architecture here, unlike in most health apps, because the dataset is small, single-user and useful without a server. It is also a hard product constraint: no cross-device sync, no web app, no account recovery, no server-side analysis and no support engineer able to inspect a broken record. The alternative is end-to-end encrypted sync, which trades those back for a key-management problem, since losing the last device can mean losing the data. Decide before you build, because reversing it later is a rewrite.",
          "url": "https://aifitnessapi.com/build/cycle-tracking-app#faq-2"
        },
        {
          "question": "How do cycle tracking apps predict the next cycle?",
          "answer": "By estimating cycle length from the user's own logged history, usually a rolling average or median over recent cycles, and projecting forward from the last recorded start. The interesting part is variability. Users with irregular cycles have plenty of history and no stable pattern, and new users have almost no history at all, so the honest output is a range whose width reflects that variability rather than a single confident date. Treat a prediction as a description of a pattern in the entered data, not a statement about what will happen.",
          "url": "https://aifitnessapi.com/build/cycle-tracking-app#faq-3"
        },
        {
          "question": "Is a cycle tracking app a medical device?",
          "answer": "It depends entirely on what you claim it does, and the answer is jurisdiction-specific. An app that records what a user enters and shows patterns in it sits in a different place than one presented for contraception, conception or diagnosing a condition, and adding those claims changes both the regulatory posture and the evidence you would need. This is general information rather than legal advice. Read the relevant regulatory guidance for your markets, keep your marketing copy aligned with what the app records, and get qualified counsel before making any health claim.",
          "url": "https://aifitnessapi.com/build/cycle-tracking-app#faq-4"
        },
        {
          "question": "How should a cycle tracking app make money?",
          "answer": "Subscription on the insight, with logging and the basic prediction free, because paywalling the input starves the record the whole product depends on. Depth is what you charge for: multi-cycle analysis, symptom patterns, exports, temperature integration and scoped sharing. What separates this category from other consumer health apps is that the usual secondary lines are off the table. Advertising, data sharing and selling datasets are a trust failure in this data category, and trust is the only durable advantage a cycle app has.",
          "url": "https://aifitnessapi.com/build/cycle-tracking-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a step challenge app",
      "answer": "A step challenge app is a leaderboard with something at stake attached to a number the participant's own phone reports about them, so the product you are building is integrity rather than step counting. The loop is simple: join a challenge, connect a step source, walk, and see a rank that becomes final when the day closes. The build-vs-buy shape is to buy step ingestion from the platform health stores and a wearable aggregator, and to build the parts nobody sells you, namely the rule that picks one authoritative source per participant per day, the timezone-correct daily close, and the cheat detection behind them. The one genuinely hard part is fairness under adversarial pressure: naively summing a phone and a watch double-counts the same walk, a shaken phone produces convincing steps, and a leaderboard that recomputes a finished day destroys the trust the whole thing runs on. It is also usually sold to whoever organizes the challenge rather than to the people walking.",
      "title": "How to Build a Step Challenge App (2026)",
      "url": "https://aifitnessapi.com/build/step-challenge-app",
      "markdown": "https://aifitnessapi.com/build/step-challenge-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-01",
      "first_party": false,
      "faqs": [
        {
          "question": "How do you stop people cheating in a step challenge?",
          "answer": "You cannot stop it completely, so you layer defenses and back them with policy. Set hard plausibility ceilings for a single day and a single hour, check cadence and step-length consistency against the participant's own history rather than a population average, cross-check other signals from the same device where you have them, and use source attestation so you know a figure came from a platform health store rather than an arbitrary client write. Then publish the rules, route flagged accounts to a human review queue, and offer an appeal, because one wrong automatic ban costs the program more than one missed cheat.",
          "url": "https://aifitnessapi.com/build/step-challenge-app#faq-1"
        },
        {
          "question": "How do you handle a user whose phone and watch both count the same steps?",
          "answer": "Do not sum them. Pick one authoritative source per participant per local day using a written priority order, typically a dedicated tracker ahead of a watch ahead of the phone, with an explicit fallback for when the preferred source reports nothing. Lock that choice for the day so a mid-day switch cannot move somebody's rank. The platform health stores already deduplicate some overlapping records for you, so learn what the store does before adding your own resolver on top, and store which source was used so a dispute can actually be answered.",
          "url": "https://aifitnessapi.com/build/step-challenge-app#faq-2"
        },
        {
          "question": "How should a step challenge handle users in different timezones?",
          "answer": "Treat the day as a property of the participant, not of your server. Store the local calendar day alongside the timestamp, compute each person's total on their own local day, and close it at their local midnight plus a published grace window. Decide in advance, and state in the rules, whether a traveler's day follows their device timezone or the timezone they enrolled with, since either is defensible but silently switching between them is not. Daylight-saving transitions make one local day short and another long, so test both cases before a challenge runs.",
          "url": "https://aifitnessapi.com/build/step-challenge-app#faq-3"
        },
        {
          "question": "What happens when step data arrives after the day has ended?",
          "answer": "Publish a cutoff and enforce it. A watch out of range syncs hours later, providers deliver yesterday's totals this morning, and participants grant historical access mid-challenge, so late data is normal rather than exceptional. Pick a grace window after local midnight, count everything that lands inside it, and refuse everything after. Recomputing a finished day changes a result people have already seen, which is the fastest way to lose their trust in the standings. If a correction is genuinely required, show it as a visible adjustment rather than an edit to history.",
          "url": "https://aifitnessapi.com/build/step-challenge-app#faq-4"
        },
        {
          "question": "How do step challenge apps make money?",
          "answer": "Almost always from the organizer rather than the walker. Employers, gyms, clubs, conferences and charity events buy a challenge for a headcount and a date range, usually priced per active participant, and sponsors sometimes fund the prize in exchange for placement. Participants rarely pay, because their phone counts steps for free. Revenue is seasonal rather than recurring, clustering around January and spring, so the goal is selling a repeatable annual program instead of single events. A free tier for small informal groups feeds the paid organizer funnel.",
          "url": "https://aifitnessapi.com/build/step-challenge-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a senior fitness app",
      "answer": "A senior fitness app is a short daily guided session wrapped around a data foundation almost no consumer app touches: the mobility and stability family the platform health stores already collect passively, including walking steadiness, walking speed and step length, walking asymmetry and double-support percentage, stair speeds, an estimated six-minute-walk distance and a count of recorded falls. The build-vs-buy shape is to buy the content and the platform health-store reads, and to build the accessibility layer, the plain-language presentation of those metrics, and the care-circle consent model. The one genuinely hard part is that accessibility is the product rather than a feature, so large type, high contrast, oversized targets and audio-first coaching with no timed gestures constrain your design from the first sketch instead of being added at the end. The second hard part is commercial: the person paying is often an adult child rather than the person exercising. Describe what these metrics record and never present them as an assessment of frailty or fall risk.",
      "title": "How to Build a Senior Fitness App (2026)",
      "url": "https://aifitnessapi.com/build/senior-fitness-app",
      "markdown": "https://aifitnessapi.com/build/senior-fitness-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-01",
      "first_party": false,
      "faqs": [
        {
          "question": "What health data can a senior fitness app actually use?",
          "answer": "More than most builders realize. Alongside steps and workouts, the platform health stores collect a mobility and stability family passively from a carried phone: walking steadiness, walking speed and step length, walking asymmetry, double-support percentage, stair ascent and descent speed, an estimated six-minute-walk distance, and a count of recorded falls. Almost no consumer app surfaces these, which makes them a genuine differentiator. Coverage is not the same on both platforms and it changes, so check current platform documentation before you scope a feature around any single metric.",
          "url": "https://aifitnessapi.com/build/senior-fitness-app#faq-1"
        },
        {
          "question": "Can a fitness app tell users they are at risk of falling?",
          "answer": "No, and you should not try. These metrics are recorded observations of how someone walks, not an assessment of a person's health. Turning them into a statement about frailty, fall risk or likelihood of injury is a claim about a health condition, which moves you into a different regulatory category with obligations a consumer wellness app does not carry. Describe what a metric records and how it has changed for that individual, avoid presenting thresholds as warnings, and do not claim the app prevents falls. This is general information, not legal advice; confirm your obligations with qualified counsel.",
          "url": "https://aifitnessapi.com/build/senior-fitness-app#faq-2"
        },
        {
          "question": "What accessibility requirements does a fitness app for older adults have?",
          "answer": "Treat accessibility as the interaction model rather than a compliance pass. That means type that scales without clipping the layout, contrast that survives a bright room, touch targets sized for tremor and one-handed use, captions on every spoken instruction, and no gesture that requires precision or a timeout. Audio should carry the whole session so the app works with the phone put down. Test with the platform screen readers, at the largest supported type size, and with people in the actual age range rather than colleagues squinting at a simulator.",
          "url": "https://aifitnessapi.com/build/senior-fitness-app#faq-3"
        },
        {
          "question": "How should family members or carers access a senior user's data?",
          "answer": "Through an explicit, granular, revocable invitation issued by the account holder, never through an account a relative controls on their behalf. Model the account holder and viewers as distinct roles, show in one place who can see what, make revocation a single obvious action, and never let a viewer invite another viewer. Default to a weekly summary rather than live data. Remember the person consenting may be doing so with the prospective viewer beside them, and that consent needs to be revisitable over time rather than captured once at setup.",
          "url": "https://aifitnessapi.com/build/senior-fitness-app#faq-4"
        },
        {
          "question": "Who pays for a senior fitness app?",
          "answer": "Often an adult child rather than the person exercising, prompted by a concern instead of a fitness goal. That argues for gifting or family plans where one person pays and another uses the app, and for a trial the payer can evaluate without exercising, since their value moment is the first weekly summary rather than the first session. Annual pricing suits this category because a settled routine churns less than a general fitness audience. Avoid charging a carer for alerts about a relative; charge for the program and keep sharing in the base tier.",
          "url": "https://aifitnessapi.com/build/senior-fitness-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a cycling app",
      "answer": "A cycling app is a sensor product before it is a software product, because the rider you want already owns a power meter, a cadence sensor and often a head unit that records better than your app will. That forces one architectural decision up front: are you the computer on the handlebars, recording live from Bluetooth sensors, or are you the place rides land afterwards and get analysed. The build-vs-buy shape is to build the sensor session, the ride identity rule and the zone model, and to buy trainer control over the standard fitness-machine protocol, ride import from the platforms riders already sync to, and the GPS craft that a running app has already solved. The one genuinely hard part is that the same ride reliably arrives from three places at once, so deduplication and a documented averaging convention decide whether your numbers agree with the numbers already on the rider's handlebars.",
      "title": "How to Build a Cycling App (2026)",
      "url": "https://aifitnessapi.com/build/cycling-app",
      "markdown": "https://aifitnessapi.com/build/cycling-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "Should a cycling app record rides itself or just import them?",
          "answer": "Pick one for version one. Recording live means owning a multi-sensor Bluetooth session that survives dropouts for hours, plus battery and background work. Importing means your product is analysis and your engineering goes into deduplication and normalisation across sources. Serious riders often already record on a head unit, so the importer path reaches them without asking them to change anything, while the recorder path reaches riders who only carry a phone. Building both before either works well is the most common way this category stalls.",
          "url": "https://aifitnessapi.com/build/cycling-app#faq-1"
        },
        {
          "question": "Can a phone read a cycling power meter directly?",
          "answer": "Yes. Power meters, cadence sensors and speed sensors advertise standard Bluetooth services that a phone can connect to and read without any vendor SDK, and heart-rate straps work the same way. The difficulty is not the protocol but the session: several sensors connected at once, for hours, on a moving bike, with dropouts and reconnections treated as normal events rather than errors. Many older sensors also speak a different radio standard that phones do not support natively, which is a hardware-support decision to make deliberately.",
          "url": "https://aifitnessapi.com/build/cycling-app#faq-2"
        },
        {
          "question": "How do I stop the same ride appearing twice in a cycling app?",
          "answer": "Do not match on identifiers, because a head unit, a platform account and your own recorder assign different ones to the same hour. Match on time overlap plus duration, with a written source priority that decides which copy is authoritative when several qualify. Keep every copy in storage but display one, record why that one won, and let the rider override it. Duplicate rides inflate every weekly and seasonal total you show, which is exactly the number a training-focused app exists to get right.",
          "url": "https://aifitnessapi.com/build/cycling-app#faq-3"
        },
        {
          "question": "Does HealthKit have cycling power and cadence?",
          "answer": "The iOS health store has carried cycling power, cycling speed, cycling cadence and cycling functional threshold power as quantity types since iOS 17.0, and cycling distance since the earliest versions. That makes the health store a good distribution channel: your ride can flow to other apps and you can read what other apps wrote. It is not a sensor, though. The values still have to originate from a device you paired or a file you imported, so the health store integration is a publishing step at the end of your pipeline rather than the start of it.",
          "url": "https://aifitnessapi.com/build/cycling-app#faq-4"
        },
        {
          "question": "How do cycling apps make money?",
          "answer": "Subscription, and the economics are friendlier than most fitness categories because the rider has already spent far more on the bike and the meter. The trade is that they expect instrument-grade software and will not pay for a nicer view of what their hardware vendor already gives them free. Sell the multi-season analysis, the threshold history and structured indoor training rather than the act of recording. Coach and team seats are a realistic second line here. Treat published conversion figures as directional and verify against your own cohorts.",
          "url": "https://aifitnessapi.com/build/cycling-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a swimming app",
      "answer": "A swimming app is a watch application with a phone viewer attached, because water disables touch input and blocks Bluetooth, leaving no interaction budget between the start and the end of a session. Pool and open water are effectively two different products: one is a length-counting problem with no GPS, the other is a positioning problem with no lengths, and small teams should pick one. The build-vs-buy shape is unusual in that there is little to buy, since nobody sells length detection, so you build the watch app, the set model and the correction path, and you buy the platform health store, imports from dedicated swim watches, and the GPS craft a running app already solved. The one genuinely hard part is that length detection fails visibly and a swimmer counts their own lengths, so the ability to repair a wrong count has to ship in the first version rather than after the first complaint.",
      "title": "How to Build a Swimming App (2026)",
      "url": "https://aifitnessapi.com/build/swimming-app",
      "markdown": "https://aifitnessapi.com/build/swimming-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "Do I need to build a watch app for a swimming app?",
          "answer": "Yes, and it should be the primary application rather than a companion. A phone cannot come into the water, a wet touchscreen does not accept input, and the swimmer has no free hands or attention mid-set. That means the watch owns the entire recording session and the phone becomes the place the swim is reviewed and corrected afterwards. Teams that build a phone app first and bolt a watch extension on later usually discover in the pool that the interaction model does not survive contact with water.",
          "url": "https://aifitnessapi.com/build/swimming-app#faq-1"
        },
        {
          "question": "Why does heart rate not work underwater with a chest strap?",
          "answer": "Bluetooth propagates very poorly through water, so a strap and a watch a short distance apart lose each other as soon as both are submerged. Real-time heart rate in a pool is therefore not something you can promise. The workable pattern is a strap that records on-device during the swim and transfers the data after the session, which means the heart-rate stream arrives late and has to be aligned onto a session that is already saved. Build for merging two independently recorded streams rather than for a live feed.",
          "url": "https://aifitnessapi.com/build/swimming-app#faq-2"
        },
        {
          "question": "Is pool swimming or open water the harder app to build?",
          "answer": "They are different problems rather than harder and easier. Pool swimming has no GPS at all and lives or dies on counting lengths from wrist motion, where turns are the signal and drills, kick sets and mixed workouts break the count. Open water has no lengths and depends on positioning while the wrist is underwater most of the time, so fixes arrive in clusters with structured gaps. Trying to ship both in one first version is the common mistake, because almost none of the difficult work is shared.",
          "url": "https://aifitnessapi.com/build/swimming-app#faq-3"
        },
        {
          "question": "Does HealthKit support swimming data?",
          "answer": "Yes. Swimming distance and swimming stroke count have been first-class quantity types on iOS since iOS 10.0, alongside a swimming workout activity type that dates from the earliest version. That is useful in two directions: your app can publish a swim so it appears in the rest of the user's health ecosystem, and it can read swims that a watch or another app already recorded. Reading is often the fastest path to a useful first version for swimmers who will not change the hardware they already trust.",
          "url": "https://aifitnessapi.com/build/swimming-app#faq-4"
        },
        {
          "question": "How do swimming apps make money?",
          "answer": "By selling structure to a small, high-intent audience rather than recording to a broad one. Masters squads, triathletes and competitive juniors already swim to a plan and do not stop training seasonally, so the paid tier should be sets, progression and season planning rather than the act of capturing a swim, which the watch already does well. Coach and squad seats are unusually strong here because swim training is organised around a coach assigning sessions. Treat published fitness subscription benchmarks as directional and verify them yourself.",
          "url": "https://aifitnessapi.com/build/swimming-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a hiking app",
      "answer": "A hiking app is an offline-first application that happens to record an activity, because the places people hike are the places the network is not, and no signal is the normal operating mode rather than a degraded one. That inverts the usual architecture: local storage is the source of truth, and sync exists to reconcile a day of accumulated local writes when the device eventually reconnects. The build-vs-buy shape is to buy map tiles and terrain data under a licence that actually permits offline caching, buy the GPS track craft a running app has already solved, and build the download manager, the local-first recorder and the conflict-aware sync yourself. The one genuinely hard part is honesty about elevation, because a barometer, GPS altitude and a terrain model each give a different gain for the same walk and the noise threshold you choose moves the number more than the sensor does.",
      "title": "How to Build a Hiking App (2026)",
      "url": "https://aifitnessapi.com/build/hiking-app",
      "markdown": "https://aifitnessapi.com/build/hiking-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "How do I make a hiking app work without a signal?",
          "answer": "Treat offline as the default rather than a fallback. Map tiles are downloaded by area before the trip with a verified completed state, position rendering reads only from local storage, and the track is written continuously to the device rather than streamed anywhere. Nothing in the recording path may block on a network call. Sync becomes a reconciliation step that runs when the device rejoins a network, resolving a day of local writes rather than keeping the device current. Test in airplane mode with a cold start as your normal configuration.",
          "url": "https://aifitnessapi.com/build/hiking-app#faq-1"
        },
        {
          "question": "Why does elevation gain differ between hiking apps?",
          "answer": "Because there is no single true value. A barometric altimeter, GPS altitude and a terrain-model lookup produce three different profiles for the same walk, and the accumulation rule matters even more than the source. If you sum every upward change, sensor noise alone manufactures climbing on flat ground, so a threshold is required, and different apps choose different thresholds. Pick one method, state it in the interface, and keep it constant, because changing it later silently rewrites the gain on every hike a user has already recorded.",
          "url": "https://aifitnessapi.com/build/hiking-app#faq-2"
        },
        {
          "question": "Can I legally cache map tiles for offline hiking use?",
          "answer": "It depends entirely on the tile provider's licence, and offline caching is precisely the case those licences price and restrict. How many tiles you may store, at what zoom levels, for how long, and whether bulk pre-download is permitted are all terms you should read before designing the download manager, because they constrain the product rather than the implementation. Some providers and open data sources are far more permissive than others. Confirm your specific obligations with qualified counsel rather than relying on a general summary.",
          "url": "https://aifitnessapi.com/build/hiking-app#faq-3"
        },
        {
          "question": "What drains the battery most in a hiking app?",
          "answer": "The screen, then continuous positioning, then map redrawing, in roughly that order over a full day. A hiker who keeps waking the phone to check the route costs far more power than the recording itself. Practical mitigations are to make screen-off recording the default, throttle map redraws aggressively, reduce positioning frequency while the user is stationary, and distinguish clearly in the interface between plain track recording and active navigation, since the second is much more expensive than the first.",
          "url": "https://aifitnessapi.com/build/hiking-app#faq-4"
        },
        {
          "question": "How do hiking apps make money?",
          "answer": "Offline maps are the paid feature, because they are the thing that only matters when you cannot get it another way. Usage is episodic, so annual pricing is the only shape that works: someone who hikes four times a year will not carry a monthly subscription between trips. Regional or one-off map packs convert travellers who will never subscribe. Clubs, guides and land managers are realistic institutional buyers. The main renewal risk is being forgotten between trips rather than being disliked.",
          "url": "https://aifitnessapi.com/build/hiking-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a hiit app",
      "answer": "A HIIT app is an interval orchestrator, so the timer is the product rather than a supporting feature. The hard part is that the clock has to stay exact and audible while the screen is off, the phone is locked and the user's own music is playing, which makes it a scheduling and audio problem rather than a countdown loop. The build-vs-buy shape is to build the interval engine, the cue scheduler and the completion model yourself, and to buy exercise content, chest-strap heart rate and the platform lock-screen and watch surfaces. Monetization is the real constraint: the core function is a commodity that the phone already ships, so what you sell is the multi-week program, the coaching audio and the cross-device presence, not the ability to count to thirty.",
      "title": "How to Build a HIIT App (2026)",
      "url": "https://aifitnessapi.com/build/hiit-app",
      "markdown": "https://aifitnessapi.com/build/hiit-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "How do I keep a workout timer accurate in the background?",
          "answer": "Stop thinking of it as a timer. Record the session start as a single instant, derive the current position from elapsed time, and recompute state from the wall clock whenever your app regains control, because the system may suspend or throttle your process without warning. Anything that must happen at a precise moment, especially audio cues, has to be committed to the system in advance rather than fired by your own loop. Test with the screen off, the app backgrounded, low power mode enabled and a call arriving mid-session.",
          "url": "https://aifitnessapi.com/build/hiit-app#faq-1"
        },
        {
          "question": "How should interval cues work while the user is playing music?",
          "answer": "Mix with or briefly duck the music rather than stopping it, then restore the original volume cleanly. Stopping playback for every transition is the fastest way to lose a user. Always fire a haptic alongside the audio, because the phone may be muted, the headphones may have disconnected, or the gym may simply be too loud. Expect real transmission latency on wireless headphones, and handle a mid-session disconnection without pausing or losing the workout.",
          "url": "https://aifitnessapi.com/build/hiit-app#faq-2"
        },
        {
          "question": "Can I show live heart-rate zones during short intervals?",
          "answer": "You can display it, but not rely on it. There is sensor and transmission delay, and heart rate responds after the effort rather than during it, so on a short work interval the zone shown describes an interval that has already finished. Present it as trailing information, never gate progression on the user reaching a zone within a short interval, and avoid framing zone occupancy as a verdict on the session. Chest straps also handle this kind of movement better than wrist optical sensors do.",
          "url": "https://aifitnessapi.com/build/hiit-app#faq-3"
        },
        {
          "question": "Do I need an exercise content library for a HIIT app?",
          "answer": "Not for the first version. The timer, the cues and the structure are the product, and plenty of users bring their own movements. When you do add content, license it rather than producing it, since names, instructions and demonstration media are available through existing exercise database suppliers. If the library becomes the centre of the product rather than the interval engine, you are building a home workout app instead, which is a different scope with different economics.",
          "url": "https://aifitnessapi.com/build/hiit-app#faq-4"
        },
        {
          "question": "How do HIIT apps make money when free timers exist?",
          "answer": "By selling something a free timer structurally cannot be. That means multi-week programs with a defined endpoint rather than individual sessions, produced coaching audio, and cross-device presence such as a watch app or a cast timer. Keep the basic timer genuinely usable for free, because a crippled one is replaced within a minute by the clock app already on the phone. A tight niche, whether a sport, a population or a training method, also gives people a reason to choose you over a generic tool.",
          "url": "https://aifitnessapi.com/build/hiit-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a triathlon app",
      "answer": "A triathlon app is a data-modelling build before it is a training build, because a race is one event made of three disciplines plus transitions and that shape breaks any schema with a type, a distance and a duration in one row. The model you need is a parent event with ordered segments, transitions included as real timed segments, each segment carrying its own discipline, units, zone reference and device provenance. The build-vs-buy shape is to buy nearly all the recording, since running, cycling and swimming are each described as their own build on this site, and to spend your engineering on the model, the normalisation across three ecosystems and deduplication on arrival. The one genuinely hard part is that the combined training-load figure has no neutral common currency across the three sports, so whatever weighting you choose is an opinion you have to show rather than hide.",
      "title": "How to Build a Triathlon App (2026)",
      "url": "https://aifitnessapi.com/build/triathlon-app",
      "markdown": "https://aifitnessapi.com/build/triathlon-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "How do you model a triathlon in a fitness app database?",
          "answer": "As a parent event containing ordered child segments rather than as a single activity. Each segment carries its own discipline, metrics, units, zone reference and device provenance, and transitions are segments too, with a real duration and no discipline metrics. The parent has no meaningful total distance, because adding a swim distance to a ride distance produces a number that means nothing. Build this hierarchy before your first import, since retrofitting it means rewriting every stored session and every aggregate derived from it.",
          "url": "https://aifitnessapi.com/build/triathlon-app#faq-1"
        },
        {
          "question": "Does HealthKit support multisport workouts?",
          "answer": "Yes. A swim-bike-run workout activity type and a dedicated transition activity type both arrived on iOS 16.0 and watchOS 9.0, which means the platform models a race as a sequence rather than as one undifferentiated block. That is useful in both directions: you can publish a structured race into the user's health ecosystem, and you can read a multisport workout that the athlete's watch already recorded. Reading is often the cheapest correct way to get a race into your app without building three recorders.",
          "url": "https://aifitnessapi.com/build/triathlon-app#faq-2"
        },
        {
          "question": "Should a triathlon app record workouts or import them?",
          "answer": "Import, at least for the first version. Recording well in each discipline is three separate hard builds: background positioning for running, a multi-sensor Bluetooth session for cycling, and a watch-first no-interaction session for swimming. Triathletes also own capable hardware they will not abandon for a new app. Your reason to exist is the combined view across all three, so spend the engineering on ingestion, deduplication and modelling, and let the athlete keep recording on whatever they already trust.",
          "url": "https://aifitnessapi.com/build/triathlon-app#faq-3"
        },
        {
          "question": "Why do triathlon apps need separate training zones per sport?",
          "answer": "Because thresholds do not transfer between disciplines. Heart-rate thresholds differ between running and cycling for the same athlete, cycling has a power threshold with no equivalent in the other two sports, and swim pacing is normally expressed per hundred rather than as a rate. One athlete therefore carries several threshold values at once, and each one changes over a season. Store them per discipline with effective dates, and read every derived figure against the value that was current on the day of the session.",
          "url": "https://aifitnessapi.com/build/triathlon-app#faq-4"
        },
        {
          "question": "How should a triathlon app calculate combined training load?",
          "answer": "Carefully, and visibly. There is no neutral way to add a swim to a ride, so every combined figure weights the three disciplines according to assumptions somebody chose, and reasonable coaches disagree about them. Expose the weighting, show each discipline's contribution separately, and never present the combined number as the only view. Describe it as a summary of the training that was recorded rather than as a statement about readiness, fatigue or injury risk, which are claims about the body rather than about the data.",
          "url": "https://aifitnessapi.com/build/triathlon-app#faq-5"
        }
      ]
    },
    {
      "question": "how to build a kids fitness app",
      "answer": "A kids fitness app is a constraint-first build, because consent, data minimisation and store policy for child-directed apps decide the product before any feature does. The structure that follows is an adult account as the root of every child profile, a recorded and revocable consent step before any collection, the smallest possible record behind each feature, and a child-facing surface with no advertising, no tracking and no route to a purchase. The build-vs-buy shape inverts here: you build the consent spine and the child surface yourself, and you buy almost nothing, because every third-party dependency in a child-facing app is a data flow you have to be able to describe. Which specific rules apply to your audience and markets is a question for counsel rather than something to settle from a checklist, so treat this page as the shape of the problem and get the specifics reviewed.",
      "title": "How to Build a Kids Fitness App (2026)",
      "url": "https://aifitnessapi.com/build/kids-fitness-app",
      "markdown": "https://aifitnessapi.com/build/kids-fitness-app.md",
      "cluster": "Build Guides",
      "cluster_url": "https://aifitnessapi.com/build",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "What do I need to consider before building a fitness app for children?",
          "answer": "Settle the constraints before the features. Decide your audience age range, your markets, exactly what data each planned feature requires, who consents to it and how that consent is recorded and revoked. Then design the schema around the smallest record that makes each feature work. Doing this in the other order means rebuilding, because a data flow that looked harmless in a design review can be the reason the app cannot ship. Which specific obligations apply to your app is a question for qualified counsel.",
          "url": "https://aifitnessapi.com/build/kids-fitness-app#faq-1"
        },
        {
          "question": "Should a children's fitness app collect health data?",
          "answer": "Usually not, and connecting to the platform health store simply because it is available is the wrong instinct. A child's health data is among the most sensitive categories you could hold, it attracts proportionate scrutiny in store review, and most children's activity features run perfectly well on completion and duration alone. Apply a simple test: if you cannot name the specific thing a health metric enables that duration and completion cannot, do not request it. The record you never wrote is one you never have to protect, disclose, export or delete.",
          "url": "https://aifitnessapi.com/build/kids-fitness-app#faq-2"
        },
        {
          "question": "How should gamification work in a kids fitness app?",
          "answer": "With a different rulebook rather than a gentler version of the adult one. Streaks that punish a missed day, timed pressure, variable-ratio rewards, loss-framed messaging and public ranking of children against each other all read as manipulation when the user is a child, and a parent will judge the app on them. Prefer completion-based rewards, keep progress cumulative rather than losable, restrict any competition to a known group such as a family or a class, and make sessions finishable rather than endless.",
          "url": "https://aifitnessapi.com/build/kids-fitness-app#faq-3"
        },
        {
          "question": "Can a kids fitness app show ads or in-app purchases?",
          "answer": "Treat advertising and child-facing purchase mechanics as off the table, which does close off the default monetization of free consumer apps. Parental trust is the acquisition channel in this category and both patterns spend it immediately, quite apart from the platform policies that govern child-directed apps. Put every commercial action behind an adult gate, make rewards earned and cosmetic rather than purchasable, and monetize through a family subscription or an institutional licence bought by an adult. Confirm the applicable policies with counsel.",
          "url": "https://aifitnessapi.com/build/kids-fitness-app#faq-4"
        },
        {
          "question": "How do kids fitness apps make money without advertising?",
          "answer": "Two lines work. A family subscription bought by the parent and sold on the parent's terms, meaning a clear statement of what the child does, what the adult sees, what is stored and how to cancel. And institutional licences to schools, clubs and youth programmes, which buy per class or per site, renew on a predictable calendar and churn far less than consumer subscriptions. Institutional buyers bring their own procurement and data requirements, which is another matter to review with counsel rather than answer from a template.",
          "url": "https://aifitnessapi.com/build/kids-fitness-app#faq-5"
        }
      ]
    },
    {
      "question": "how to integrate Apple HealthKit",
      "answer": "Apple HealthKit gives your iOS app read and write access to the user's on-device health and fitness data, including steps, workouts, and heart rate, through a local store called HKHealthStore. It is not an OAuth cloud API and has no tokens or server endpoints: the user grants access in a system permission sheet and your Swift code reads the data directly on the device. To integrate it you add the HealthKit capability plus Info.plist usage-description keys, call requestAuthorization(toShare:read:), then query data with classes like HKStatisticsQuery. One critical caveat is that HealthKit never tells you whether read access was granted, so you must run the query and treat an empty result as no data or no permission.",
      "title": "How to Integrate Apple HealthKit (2026)",
      "url": "https://aifitnessapi.com/integrate/healthkit",
      "markdown": "https://aifitnessapi.com/integrate/healthkit.md",
      "cluster": "Integration Guides",
      "cluster_url": "https://aifitnessapi.com/integrate",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Does Apple HealthKit use OAuth or API keys?",
          "answer": "No. HealthKit is an on-device, permission-based framework, not a cloud API. There are no client secrets, access tokens, refresh flows, or server endpoints. The user grants access in a native system permission sheet and your app reads or writes a local, OS-managed store directly. The only credential you need is a paid Apple Developer account to enable the capability and ship the app.",
          "url": "https://aifitnessapi.com/integrate/healthkit#faq-1"
        },
        {
          "question": "Why can't I tell whether the user granted read permission?",
          "answer": "This is intentional. To avoid leaking whether a person has any health data, HealthKit does not report read-authorization status. authorizationStatus(for:) reliably reflects only write/share access; for read types it typically returns notDetermined even after a grant. The documented pattern is to run your query and treat an empty result as no data or no permission, since the two are indistinguishable by design.",
          "url": "https://aifitnessapi.com/integrate/healthkit#faq-2"
        },
        {
          "question": "Does HealthKit work on Android or on the web?",
          "answer": "No. HealthKit is limited to Apple platforms (iOS, iPadOS, watchOS, visionOS) and there is no cross-platform server endpoint. For Android you integrate Google Health Connect, which is a separate on-device framework with its own SDK, permissions model, and quirks such as a default 30-day history window.",
          "url": "https://aifitnessapi.com/integrate/healthkit#faq-3"
        },
        {
          "question": "Why does my app crash the first time I request authorization?",
          "answer": "Almost always a missing Info.plist usage-description key. HealthKit requires NSHealthShareUsageDescription to read data and NSHealthUpdateUsageDescription to write data. If you call requestAuthorization without the key that matches your operation, the app crashes instead of showing the permission sheet, so add both keys for whatever you support before running the flow.",
          "url": "https://aifitnessapi.com/integrate/healthkit#faq-4"
        },
        {
          "question": "How should I read step totals without double-counting?",
          "answer": "Use HKStatisticsQuery with the cumulativeSum option rather than fetching raw samples and adding them yourself. When multiple sources such as an iPhone and an Apple Watch both write steps, aggregating through the statistics query avoids double-counting. Verify version-gated details like the HKQuantityType(.stepCount) initializer, which is iOS 16+, against current Apple docs.",
          "url": "https://aifitnessapi.com/integrate/healthkit#faq-5"
        }
      ]
    },
    {
      "question": "how to integrate Google Health Connect",
      "answer": "Google Health Connect gives Android apps on-device access to health and fitness data (steps, heart rate, sleep, calories, and more) from a single OS-managed store. It is not an OAuth cloud API: the user grants access in a system permission sheet and your Kotlin code reads records locally through the androidx.health.connect:connect-client library. It is free and Android-only. The one hard requirement before shipping is a Play Console health-data declaration listing every data type you read or write.",
      "title": "How to Integrate Google Health Connect (2026)",
      "url": "https://aifitnessapi.com/integrate/google-health-connect",
      "markdown": "https://aifitnessapi.com/integrate/google-health-connect.md",
      "cluster": "Integration Guides",
      "cluster_url": "https://aifitnessapi.com/integrate",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Does Google Health Connect use OAuth or an API key?",
          "answer": "No. Health Connect is on-device and permission-based, not a cloud API. There is no client secret, token exchange, or server endpoint. The user grants access in a system permission sheet and your app reads from a local, OS-managed store through the connect-client library.",
          "url": "https://aifitnessapi.com/integrate/google-health-connect#faq-1"
        },
        {
          "question": "Do I need approval to use Health Connect?",
          "answer": "There is no OAuth partner-approval step to read data during development. However, to publish an app that uses Health Connect you must complete the Play Console health-data declaration listing every data type you read or write, and requesting types you cannot justify can cause review rejections. Treat that declaration as a required gate before release.",
          "url": "https://aifitnessapi.com/integrate/google-health-connect#faq-2"
        },
        {
          "question": "Do I need a separate permission to read Health Connect data in the background?",
          "answer": "Yes. The per-record-type permissions you request cover foreground reads only; syncing while your app is backgrounded needs the dedicated background-read permission on top of them, and that is separate again from the historical-read permission. Declare it in the manifest and include it in your runtime request set like any other Health Connect permission, and expect to justify it in the Play Console health-data declaration, since background access draws more scrutiny than a foreground read. Verify the current constant and manifest string in the docs, as these names have shifted between releases.",
          "url": "https://aifitnessapi.com/integrate/google-health-connect#faq-3"
        },
        {
          "question": "Which library and version should I use?",
          "answer": "Use the androidx.health.connect:connect-client Jetpack library. It updates frequently, so pin the current stable or intended release from the official Health Connect docs rather than copying a version from a tutorial. The class and method names such as HealthConnectClient.getOrCreate and readRecords are stable across recent versions.",
          "url": "https://aifitnessapi.com/integrate/google-health-connect#faq-4"
        },
        {
          "question": "Is Health Connect available on all Android devices?",
          "answer": "No. On Android 14 and later it is part of the platform, while on older versions it is a separate app the user installs from the Play Store. Always check HealthConnectClient.getSdkStatus and prompt the user to install or update Health Connect when it is unavailable, rather than assuming it is present.",
          "url": "https://aifitnessapi.com/integrate/google-health-connect#faq-5"
        }
      ]
    },
    {
      "question": "how to integrate the Fitbit API",
      "answer": "The Fitbit Web API returns a user's activity, steps, heart rate, sleep, and profile data after they authorize your app over OAuth 2.0 (authorization-code grant, PKCE recommended). You register an app, send the user through Fitbit's authorize page, exchange the code for a Bearer access token, and call the REST API with it. Critically, the legacy Fitbit Web API is being turned down around September 2026 (exact day TBD, verify) and replaced by the Google Health API using Google OAuth 2.0 — tokens do not transfer and users must re-consent, so new integrations should target Google Health directly.",
      "title": "How to Integrate the Fitbit API (2026)",
      "url": "https://aifitnessapi.com/integrate/fitbit-api",
      "markdown": "https://aifitnessapi.com/integrate/fitbit-api.md",
      "cluster": "Integration Guides",
      "cluster_url": "https://aifitnessapi.com/integrate",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Is the Fitbit Web API being shut down?",
          "answer": "Yes. Google is retiring the legacy Fitbit Web API and replacing it with the Google Health API, which uses Google OAuth 2.0. The turndown is targeted for around September 2026, with the exact day still to be confirmed — verify it against the current docs before planning around it.",
          "url": "https://aifitnessapi.com/integrate/fitbit-api#faq-1"
        },
        {
          "question": "Do my existing Fitbit OAuth tokens transfer to the Google Health API?",
          "answer": "No. Existing Fitbit access and refresh tokens do not transfer to the Google Health API and will not work there. Every user must actively re-consent through Google OAuth 2.0, so build a phased re-consent flow before the turndown.",
          "url": "https://aifitnessapi.com/integrate/fitbit-api#faq-2"
        },
        {
          "question": "Should I build a new integration on the Fitbit Web API or Google Health?",
          "answer": "For a new integration in 2026, target the Google Health API with Google OAuth 2.0 directly, since the legacy Fitbit Web API is short-lived. Use the legacy flow only to maintain an existing integration through the transition. Verify the current GA date and timeline in the docs.",
          "url": "https://aifitnessapi.com/integrate/fitbit-api#faq-3"
        },
        {
          "question": "Which OAuth scopes do I need to request from Fitbit?",
          "answer": "Only the collections your features actually use. The documented scopes include activity, heartrate, sleep, and profile, with the full set also covering location, nutrition, oxygen_saturation, respiratory_rate, settings, social, temperature, and weight — verify the current list in the docs. Fitbit does not let you force a user to grant everything: consent is per data collection, so someone can approve activity and decline heart rate. Read the scope value returned with the token rather than assuming you got what you asked for, and degrade the UI when a collection is missing.",
          "url": "https://aifitnessapi.com/integrate/fitbit-api#faq-4"
        },
        {
          "question": "Does Fitbit require approval for intraday data?",
          "answer": "Yes. Minute- and second-level intraday data is available by default only to Personal apps for their own account. Other app types must request intraday access from Fitbit/Google, and each intraday request is limited to a 24-hour window.",
          "url": "https://aifitnessapi.com/integrate/fitbit-api#faq-5"
        }
      ]
    },
    {
      "question": "how to integrate the Strava API",
      "answer": "The Strava API gives you an athlete's activities — runs, rides, and other workouts with GPS routes, distance, pace, time, elevation, and heart rate — plus profile and segment data. Authentication is OAuth 2.0 Authorization Code: you send the athlete to Strava to approve scopes, exchange the returned code for a short-lived access token, and call the v3 REST API with a Bearer token. Access tokens last about 6 hours and refresh tokens rotate on every refresh, so persist the newest one. Subscribe to the Events API webhook for near-real-time activity updates instead of polling.",
      "title": "How to Integrate the Strava API (2026)",
      "url": "https://aifitnessapi.com/integrate/strava-api",
      "markdown": "https://aifitnessapi.com/integrate/strava-api.md",
      "cluster": "Integration Guides",
      "cluster_url": "https://aifitnessapi.com/integrate",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Does the Strava API require approval to use?",
          "answer": "No formal partner-approval program is needed to start: you register an application at the Strava API settings page and immediately get a Client ID and Secret to build against. The main constraint is rate limits — the default is around 200 requests per 15 minutes and 2,000 per day as of 2026 — and raising those requires requesting an increase from Strava. Verify the current quotas and any program terms in the official docs before you scale.",
          "url": "https://aifitnessapi.com/integrate/strava-api#faq-1"
        },
        {
          "question": "How long do Strava access tokens last?",
          "answer": "Access tokens are short-lived and expire about 6 hours after they are created (an expires_in of 21600 seconds as of 2026). Store the expires_at value returned with the token so you know when to refresh, and confirm the current lifetime in the docs since Strava can change it.",
          "url": "https://aifitnessapi.com/integrate/strava-api#faq-2"
        },
        {
          "question": "Why do my Strava refreshes keep failing?",
          "answer": "Strava uses rotating refresh tokens: each refresh returns a new access token AND a new refresh token, and the old refresh token stops working. If you keep reusing a stale refresh token, or a background job and a user action race and one overwrites the other, refreshes fail and the athlete has to reconsent. Persist the newest refresh token per athlete and serialize refreshes.",
          "url": "https://aifitnessapi.com/integrate/strava-api#faq-3"
        },
        {
          "question": "How do I get private activities from Strava?",
          "answer": "You need the activity:read_all scope. Plain activity:read only returns activities the athlete has shared beyond 'Only You', and the same applies to webhook events. Request activity:read_all if your product needs the athlete's full history or real-time updates for private activities, and check the returned scope since the athlete can deselect it.",
          "url": "https://aifitnessapi.com/integrate/strava-api#faq-4"
        },
        {
          "question": "Does the Strava webhook include the activity data?",
          "answer": "No. The webhook payload is a pointer with fields like object_id, owner_id, object_type, and aspect_type, not the activity itself. When you receive an event you acknowledge it with HTTP 200 within 2 seconds, then make a follow-up API call with that athlete's token to fetch the full record. You also get only one subscription per application, so fan out to individual athletes on your side.",
          "url": "https://aifitnessapi.com/integrate/strava-api#faq-5"
        }
      ]
    },
    {
      "question": "how to integrate the Garmin API",
      "answer": "The Garmin API delivers deep wearable data: all-day wellness metrics (heart rate, steps, sleep, stress, Pulse Ox) through the Health API and per-activity data across 100-plus sports through the Activity API. It uses OAuth 2.0 with PKCE to obtain a per-user userAccessToken, and it pushes data to callback URLs you register instead of letting you poll. The big catch is access: the Connect Developer Program is partner-approval-only, not self-serve, and new sign-ups are reportedly on hold as of 2026, so the first real step is to apply and wait. Because Garmin's docs are gated, treat every host, scope, and endpoint as verify-against-current-partner-docs.",
      "title": "How to Integrate the Garmin API (2026)",
      "url": "https://aifitnessapi.com/integrate/garmin-api",
      "markdown": "https://aifitnessapi.com/integrate/garmin-api.md",
      "cluster": "Integration Guides",
      "cluster_url": "https://aifitnessapi.com/integrate",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Does Garmin require approval to use its API?",
          "answer": "Yes. The Garmin Connect Developer Program is partner-approval-only and not self-serve, so you must apply and be approved before receiving any API credentials. As of 2026 new sign-ups are reportedly on hold with no published re-open date, so verify current status on developer.garmin.com before committing to a Garmin build.",
          "url": "https://aifitnessapi.com/integrate/garmin-api#faq-1"
        },
        {
          "question": "What authentication does the Garmin API use?",
          "answer": "Current docs specify OAuth 2.0 with PKCE, producing a per-user userAccessToken you store and reuse. A historical caveat: Garmin's Health API predates OAuth 2.0 and older integrations used OAuth 1.0a, so if you find OAuth 1.0a instructions, confirm whether they apply to your program before following them. The exact authorize and token hosts are in Garmin's gated PKCE specification, so verify them there.",
          "url": "https://aifitnessapi.com/integrate/garmin-api#faq-2"
        },
        {
          "question": "How does Garmin deliver data — do I poll it?",
          "answer": "You do not poll. You register HTTPS callback URLs per summary type, and Garmin POSTs data when a user's device syncs. Ping mode sends a lightweight notification containing a callbackURL you then GET with the user's token, while Push mode sends the full updated data inline as JSON with no follow-up request needed.",
          "url": "https://aifitnessapi.com/integrate/garmin-api#faq-3"
        },
        {
          "question": "Are the endpoint URLs and summary-type names on this page accurate?",
          "answer": "Treat them as placeholders to verify, not production values. Garmin's developer docs are gated and most primary pages return errors to anonymous fetches, so specific hosts, paths, scopes, summary-type names, and token lifetimes should be read from the spec Garmin issues you after approval rather than copied from any public write-up, including this one.",
          "url": "https://aifitnessapi.com/integrate/garmin-api#faq-4"
        },
        {
          "question": "What if I cannot get into the Garmin developer program?",
          "answer": "If approval is blocked or paused, a wearable-data aggregator that already holds a Garmin partnership can resell access through one integration, saving you the direct approval step. Compare that path against the self-serve alternatives such as Fitbit, Oura, and WHOOP before deciding whether direct Garmin access is worth the wait.",
          "url": "https://aifitnessapi.com/integrate/garmin-api#faq-5"
        }
      ]
    },
    {
      "question": "how to integrate the Oura API",
      "answer": "The Oura API v2 gives you a connected user's sleep, activity, readiness, heart rate, workouts, and SpO2 as daily summaries and time series over a REST base at https://api.ouraring.com/v2/. Auth is OAuth 2.0 Authorization Code: you send the user to Oura's consent screen, exchange the returned code for an access token, then call usercollection endpoints with a Bearer token. Two constraints shape the build: Personal Access Tokens were deprecated in December 2025, so new integrations must use OAuth only, and a freshly registered app can connect at most 10 users until Oura approves it. Registration is otherwise self-serve, so you can start building immediately.",
      "title": "How to Integrate the Oura API (2026)",
      "url": "https://aifitnessapi.com/integrate/oura-api",
      "markdown": "https://aifitnessapi.com/integrate/oura-api.md",
      "cluster": "Integration Guides",
      "cluster_url": "https://aifitnessapi.com/integrate",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Does the Oura API still support Personal Access Tokens?",
          "answer": "No for new integrations. Oura deprecated Personal Access Tokens in December 2025, so new PATs can no longer be created and new integrations must use OAuth 2.0 only. Previously issued PATs may still function during a transition period, but you should not build on them; verify the current status in Oura's docs.",
          "url": "https://aifitnessapi.com/integrate/oura-api#faq-1"
        },
        {
          "question": "Does the Oura API require approval?",
          "answer": "Registration is self-serve, but a freshly registered app can connect at most 10 Oura users until Oura approves it. You build and test freely under that cap, then submit the app for Oura's review to lift the limit before a public launch. Plan for that approval step in your timeline.",
          "url": "https://aifitnessapi.com/integrate/oura-api#faq-2"
        },
        {
          "question": "What OAuth endpoints and scopes does Oura use?",
          "answer": "Authorize at https://cloud.ouraring.com/oauth/authorize and exchange or refresh tokens at https://api.ouraring.com/oauth/token. As of 2026 there are eight scopes: email, personal, daily, heartrate, workout, tag, session, and spo2, and the user can toggle individual scopes at consent. Request only what you need and verify the current list in the docs.",
          "url": "https://aifitnessapi.com/integrate/oura-api#faq-3"
        },
        {
          "question": "Why am I getting a 403 from a usercollection endpoint?",
          "answer": "A 403 on an Oura v2 endpoint usually means the access token is missing the scope that endpoint requires, or the user's Oura subscription has lapsed. It is generally a scope or membership problem rather than an invalid token, so check the scopes you requested and the user's membership status before assuming an auth bug.",
          "url": "https://aifitnessapi.com/integrate/oura-api#faq-4"
        },
        {
          "question": "What data can I read from the Oura API v2?",
          "answer": "Under https://api.ouraring.com/v2/ the usercollection endpoints expose daily summaries and time series, including daily_activity, daily_sleep, daily_readiness, heartrate, workout, and daily_spo2, among others. List endpoints accept start_date and end_date, and you can fetch a single document by its id. Confirm the exact endpoint set for your scopes at https://api.ouraring.com/v2/docs.",
          "url": "https://aifitnessapi.com/integrate/oura-api#faq-5"
        }
      ]
    },
    {
      "question": "how to integrate the WHOOP API",
      "answer": "The WHOOP API exposes a member's recovery, strain, sleep, and workout data through OAuth 2.0 consent, then REST pulls and webhooks against the api.prod.whoop.com base URL. You register an app in the WHOOP Developer Dashboard, run the authorization-code flow to get an access token for the scopes you need, and call the /v2 data endpoints with a Bearer token. Two access facts matter first: every user needs a paid WHOOP membership, and a new app is capped at 10 members until WHOOP approves it for production.",
      "title": "How to Integrate the WHOOP API (2026)",
      "url": "https://aifitnessapi.com/integrate/whoop-api",
      "markdown": "https://aifitnessapi.com/integrate/whoop-api.md",
      "cluster": "Integration Guides",
      "cluster_url": "https://aifitnessapi.com/integrate",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Do I need a paid WHOOP membership to use the API?",
          "answer": "Yes. The developer platform and API are free, but WHOOP is hardware plus an active membership (One, Peak, or Life). There is no data without a device and an active membership, for you and for every end user, so confirm your audience owns WHOOP before you build.",
          "url": "https://aifitnessapi.com/integrate/whoop-api#faq-1"
        },
        {
          "question": "Does the WHOOP API require approval?",
          "answer": "A new app works immediately but is capped at 10 connected WHOOP members. To exceed 10 or ship to production you must submit the app through WHOOP's App Approval flow. Plan for that review before promising general availability, and verify the current cap and process in the docs.",
          "url": "https://aifitnessapi.com/integrate/whoop-api#faq-2"
        },
        {
          "question": "What are the WHOOP API rate limits?",
          "answer": "As of 2026 the documented limits are roughly 100 requests per minute and 10,000 requests per day per client, with X-RateLimit headers on responses. Treat these as volatile and verify the current numbers in the docs; increases are available on request via WHOOP support.",
          "url": "https://aifitnessapi.com/integrate/whoop-api#faq-3"
        },
        {
          "question": "How do I get a refresh token from WHOOP?",
          "answer": "Request the offline scope during the OAuth authorization step. Without offline, WHOOP does not return a refresh token, so your access token cannot be renewed and background sync stops when it expires. Verify the exact refresh-request parameters in the current docs.",
          "url": "https://aifitnessapi.com/integrate/whoop-api#faq-4"
        },
        {
          "question": "How do I verify WHOOP webhooks?",
          "answer": "WHOOP sends an X-WHOOP-Signature header plus a timestamp header. Recompute base64 of HMAC-SHA256 over the timestamp header concatenated with the raw request body, keyed by your client secret, and compare it to the signature header, dropping the request on any mismatch. Do this on day one.",
          "url": "https://aifitnessapi.com/integrate/whoop-api#faq-5"
        }
      ]
    },
    {
      "question": "how to integrate Terra",
      "answer": "Terra is a health-data aggregator: you integrate once and it returns normalized data from Garmin, Fitbit, Oura, Whoop, Strava, Apple Health, and hundreds of other sources behind a single schema. You authenticate to Terra with a dev-id and x-api-key header, then mint a hosted widget session from your backend so the user picks and authorizes their own provider through Terra's Connect flow. Terra runs each provider's OAuth for you and POSTs normalized data to one webhook, which you verify with an HMAC-SHA256 signature. The key caveat: for some providers (Garmin, Whoop, Strava, Oura) you must still register your own developer credentials and give them to Terra.",
      "title": "How to Integrate Terra (Health-Data Aggregator) (2026)",
      "url": "https://aifitnessapi.com/integrate/terra-api",
      "markdown": "https://aifitnessapi.com/integrate/terra-api.md",
      "cluster": "Integration Guides",
      "cluster_url": "https://aifitnessapi.com/integrate",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What makes Terra different from integrating each wearable directly?",
          "answer": "Terra is an aggregator: you build one integration and receive Garmin, Fitbit, Oura, Whoop, Strava, Apple Health, and 500-plus other sources normalized into a single schema over one webhook. Instead of writing and maintaining separate OAuth flows and parsers per device, you write one receiver. The trade-off is usage-based pricing and, for some providers, still registering your own developer credentials.",
          "url": "https://aifitnessapi.com/integrate/terra-api#faq-1"
        },
        {
          "question": "Do I still need my own developer credentials with each provider?",
          "answer": "For most providers Terra brokers the auth entirely. But for several popular ones (commonly Garmin, Whoop, Strava, and Oura) you must register your own developer credentials with that provider and enter them in the Terra dashboard under Connections. Terra shields you from writing the OAuth code, not always from the provider's app-approval process. Verify the current list in Terra's docs, since it changes.",
          "url": "https://aifitnessapi.com/integrate/terra-api#faq-2"
        },
        {
          "question": "How does a user connect their wearable through Terra?",
          "answer": "Your backend calls POST /v2/auth/generateWidgetSession with a list of providers and your reference_id, and Terra returns a hosted widget url. You send the user to that url, where they pick their provider and authorize it while Terra runs that provider's OAuth. On success Terra fires an auth webhook with the Terra user_id you use for all subsequent data.",
          "url": "https://aifitnessapi.com/integrate/terra-api#faq-3"
        },
        {
          "question": "How do I verify a Terra webhook is authentic?",
          "answer": "Terra signs each webhook with HMAC-SHA256 and sends a terra-signature header in the form t=timestamp,v1=signature. Recompute the signature over the timestamp plus the raw request body using your signing secret and compare it to v1, rejecting on mismatch. Terra's SDKs expose a verify_terra_webhook_signature helper; confirm the exact signed-string layout in the current docs.",
          "url": "https://aifitnessapi.com/integrate/terra-api#faq-4"
        },
        {
          "question": "How much does Terra cost?",
          "answer": "As of 2026 Terra uses a subscription plus credit-based usage model. The entry tier is reported around $399/mo billed annually (about $499 monthly) including roughly 100,000 credits per month, with credits scaling on active authentications and events. All figures are volatile, so verify current numbers on tryterra.co/pricing before budgeting.",
          "url": "https://aifitnessapi.com/integrate/terra-api#faq-5"
        }
      ]
    },
    {
      "question": "how to integrate the Nutritionix API",
      "answer": "The Nutritionix API returns nutrition data for foods: calories and macros for natural-language meals, autocomplete search across common and branded foods, and lookup by item ID or UPC barcode. Auth is a simple API-key pair, not OAuth: you create an application, get an App ID and App Key, and send both as static headers on every request. There is no token exchange, no callback, and nothing to refresh. The base URL is https://trackapi.nutritionix.com/v2/ and the main endpoint is POST /natural/nutrients.",
      "title": "How to Integrate the Nutritionix API (2026)",
      "url": "https://aifitnessapi.com/integrate/nutritionix-api",
      "markdown": "https://aifitnessapi.com/integrate/nutritionix-api.md",
      "cluster": "Integration Guides",
      "cluster_url": "https://aifitnessapi.com/integrate",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Does Nutritionix use OAuth?",
          "answer": "No. Nutritionix uses a simple API-key model: you create an application, get an App ID and App Key pair, and send them as the x-app-id and x-app-key headers on every request. There is no OAuth flow, no token exchange, and no refresh to manage.",
          "url": "https://aifitnessapi.com/integrate/nutritionix-api#faq-1"
        },
        {
          "question": "What is the base URL and which endpoint should I start with?",
          "answer": "The base URL is https://trackapi.nutritionix.com/v2/. Most apps start with POST /natural/nutrients, which turns a plain-English food description into itemized calories and macros. Older docs reference a legacy beta host (apibeta.nutritionix.com); use the trackapi production host and verify against current docs.",
          "url": "https://aifitnessapi.com/integrate/nutritionix-api#faq-2"
        },
        {
          "question": "How do I look up a food by barcode?",
          "answer": "Call GET /search/item with a upc query parameter set to the scanned barcode value, along with the two auth headers. It returns the matching branded item's nutrition data. The same endpoint also accepts nix_item_id to fetch an item you already identified from instant search.",
          "url": "https://aifitnessapi.com/integrate/nutritionix-api#faq-3"
        },
        {
          "question": "Is there a free tier and what are the limits?",
          "answer": "Nutritionix has offered a free developer tier that was historically rate-limited, with caps such as a per-day limit on the natural endpoints. The exact current tier name and quotas are ambiguous and change over time, so verify them against the current docs and your account dashboard before relying on them.",
          "url": "https://aifitnessapi.com/integrate/nutritionix-api#faq-4"
        },
        {
          "question": "Can I call Nutritionix directly from a mobile or web app?",
          "answer": "You can technically, but you should not. Because auth is just two static header values with no per-user token, anyone who extracts the pair from a client bundle can spend your quota. Proxy the calls through your own backend instead.",
          "url": "https://aifitnessapi.com/integrate/nutritionix-api#faq-5"
        }
      ]
    },
    {
      "question": "how to integrate ExerciseDB",
      "answer": "ExerciseDB provides a searchable exercise library where each entry includes a name, target muscle, body part, equipment, and an animated gifUrl demo. Auth is a simple API key: you subscribe on RapidAPI, then send your key plus the required host header on every request. Note the name is ambiguous, referring to both the commercial RapidAPI listing (host exercisedb.p.rapidapi.com) and the open-source, self-hostable exercisedb.dev project, which use different endpoint shapes. This guide covers the RapidAPI listing and points to the self-host option.",
      "title": "How to Integrate the ExerciseDB API (2026)",
      "url": "https://aifitnessapi.com/integrate/exercisedb-api",
      "markdown": "https://aifitnessapi.com/integrate/exercisedb-api.md",
      "cluster": "Integration Guides",
      "cluster_url": "https://aifitnessapi.com/integrate",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Does ExerciseDB require OAuth or an approval process?",
          "answer": "No. The RapidAPI listing uses simple API-key auth with no OAuth flow and no partner-approval step. You just create a RapidAPI account, subscribe to the listing, and send your key in headers.",
          "url": "https://aifitnessapi.com/integrate/exercisedb-api#faq-1"
        },
        {
          "question": "What headers does the ExerciseDB RapidAPI listing require?",
          "answer": "Every request needs two headers: X-RapidAPI-Key with your key, and X-RapidAPI-Host set to exercisedb.p.rapidapi.com. The host header is mandatory on RapidAPI-proxied calls, and requests fail without it even if the key is valid.",
          "url": "https://aifitnessapi.com/integrate/exercisedb-api#faq-2"
        },
        {
          "question": "Is ExerciseDB free?",
          "answer": "There is a free RapidAPI tier, but it has been reported as very small (on the order of ~10 requests/day), with paid tiers for higher volume. Exact tier names and quotas change on the listing, so verify against the current RapidAPI pricing page and plan around caching.",
          "url": "https://aifitnessapi.com/integrate/exercisedb-api#faq-3"
        },
        {
          "question": "What is the difference between the RapidAPI ExerciseDB and exercisedb.dev?",
          "answer": "The name refers to two products: the commercial RapidAPI listing at host exercisedb.p.rapidapi.com, and the open-source, self-hostable exercisedb.dev project (AGPL-3.0). They share a media CDN but expose different endpoint shapes, so code to one set of docs and do not mix the paths.",
          "url": "https://aifitnessapi.com/integrate/exercisedb-api#faq-4"
        },
        {
          "question": "What data does each ExerciseDB exercise return?",
          "answer": "Each exercise object includes id, name, bodyPart, target, equipment, and an animated gifUrl. Newer listing versions may add secondaryMuscles and instructions arrays, but verify those against the current docs before relying on them.",
          "url": "https://aifitnessapi.com/integrate/exercisedb-api#faq-5"
        }
      ]
    },
    {
      "question": "how to integrate the Polar API",
      "answer": "Polar's cloud API is Open AccessLink v3, and registration is self-serve: you create an API client at the AccessLink admin portal with a Polar Flow account and receive a client ID and secret immediately, with no partner-approval gate. Authentication is an OAuth 2.0 authorization-code redirect through flow.polar.com, with the token exchange on a separate host authenticated by HTTP Basic; the authorization code is only valid for 10 minutes, and the response returns both an access token and a Polar user ID. One step is easy to miss: after authorization you must register the user with a POST to the users endpoint before any data is readable, and a 409 there simply means they are already registered. Exercises, activity summaries, and physical information are then pulled through transactions that discard the data once you commit them, and only data synced after linking is available, so poll regularly or lose history.",
      "title": "How to Integrate the Polar API (2026)",
      "url": "https://aifitnessapi.com/integrate/polar-api",
      "markdown": "https://aifitnessapi.com/integrate/polar-api.md",
      "cluster": "Integration Guides",
      "cluster_url": "https://aifitnessapi.com/integrate",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Is the Polar AccessLink API self-serve or does it need partner approval?",
          "answer": "Self-serve. Polar's official example repository documents creating an API client yourself at the AccessLink admin portal by signing in with a Polar Flow account, which issues a client ID and secret straight away. There is no application or partner-approval step in the documented flow, which makes Polar one of the lowest-friction wearable integrations to start. You do need to register at least one authorization redirect URL on the client, and the example warns that a mismatched callback URL is the most common reason integrations fail.",
          "url": "https://aifitnessapi.com/integrate/polar-api#faq-1"
        },
        {
          "question": "What are the Polar AccessLink OAuth and API base URLs?",
          "answer": "Three different hosts do three different jobs, per Polar's own example client. Users authorize at flow.polar.com/oauth2/authorization, the authorization code is exchanged for a token at polarremote.com/v2/oauth2/token, and data is served from www.polaraccesslink.com/v3. The token exchange authenticates with HTTP Basic using your client ID and secret rather than putting them in the form body, and it must happen quickly because the example states the authorization code is only valid for 10 minutes.",
          "url": "https://aifitnessapi.com/integrate/polar-api#faq-2"
        },
        {
          "question": "What is a transaction in the Polar AccessLink API?",
          "answer": "A transaction is a snapshot of newly available data that you open, read, and then commit. You POST to a per-user transaction endpoint for exercises, activity summaries, or physical information; a successful open returns a resource URI, and an empty response means nothing new is waiting. You then GET the transaction for a list of resource URLs, fetch each one, and finally PUT the transaction URL to commit. Committing matters because Polar's transactional endpoints discard the data once it has been fetched, so persist everything before you commit.",
          "url": "https://aifitnessapi.com/integrate/polar-api#faq-3"
        },
        {
          "question": "Why can I only see recent Polar data and not a user's full history?",
          "answer": "Because AccessLink exposes only recent data rather than a user's archive. Polar's example README describes the data flow as beginning once the user has linked their account and synchronized their device to Polar Flow, and a long-standing open issue on that same repository reports that only data synced after the authorization date can be retrieved. Plan for no backfill: sync on a regular schedule, store everything you pull, and tell users that connecting Polar starts their history rather than importing it.",
          "url": "https://aifitnessapi.com/integrate/polar-api#faq-4"
        },
        {
          "question": "Does Polar AccessLink support webhooks or publish rate limits?",
          "answer": "Neither is documented in the sources we could reach. Polar's official example integration is pull-only, built around a notifications endpoint, transactions, and commits, and it contains no webhook registration, no retry logic, and no 429 handling. Polar's hosted reference site was unreachable from our fetch environment, so treat push callbacks, rate limits, and token lifetimes as open questions to verify against the live documentation. Until you confirm otherwise, design for scheduled polling on a conservative interval.",
          "url": "https://aifitnessapi.com/integrate/polar-api#faq-5"
        }
      ]
    },
    {
      "question": "fitness api 401 unauthorized",
      "answer": "A 401 Unauthorized from a fitness API means the server rejected your credential, not your permissions: the access token is missing, malformed, expired, or revoked. The most common cause is an expired access token, so refresh it and retry. Do not confuse 401 with 403 (Forbidden) — a 403 means the token is valid but lacks the required scope, and refreshing will not fix it; you must re-authorize with the missing scope instead.",
      "title": "Why Is My Fitness API Returning 401 Unauthorized?",
      "url": "https://aifitnessapi.com/fix/fitness-api-401-unauthorized",
      "markdown": "https://aifitnessapi.com/fix/fitness-api-401-unauthorized.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the difference between a 401 and a 403 from a fitness API?",
          "answer": "A 401 Unauthorized means authentication failed: the token is missing, malformed, expired, revoked, or the wrong type. A 403 Forbidden means the token is authentic but lacks the required scope or approval. The distinction matters because refreshing a token fixes many 401s but never fixes a 403 — for a 403 you must re-authorize the user with the missing scope.",
          "url": "https://aifitnessapi.com/fix/fitness-api-401-unauthorized#faq-1"
        },
        {
          "question": "Will refreshing my token fix a 401?",
          "answer": "Usually yes, if the cause is an expired access token, which is the most common reason for a sudden 401. Refresh the token and retry. It will not help, though, if the token was revoked or the grant is dead — in those cases the refresh itself fails and the user must re-authorize.",
          "url": "https://aifitnessapi.com/fix/fitness-api-401-unauthorized#faq-2"
        },
        {
          "question": "Why does my Authorization header cause a 401 even with a valid token?",
          "answer": "The header must be exactly the word Bearer, a space, then the access token (for example, Authorization: Bearer eyJhbGci...). Common breakers are a missing Bearer prefix, lowercase bearer on strict servers, leading or trailing whitespace or a newline in the token, sending the refresh token instead of the access token, or double-encoding the token. Reproduce the call with curl to isolate a client-side formatting bug.",
          "url": "https://aifitnessapi.com/fix/fitness-api-401-unauthorized#faq-3"
        },
        {
          "question": "How do I know which specific cause triggered my 401?",
          "answer": "Read the WWW-Authenticate response header, which spec-compliant servers use to report an error like invalid_token, plus the JSON body. Providers name causes differently — Fitbit uses errorType values such as expired_token, Strava returns an Authorization Error with code invalid, and Garmin returns text like OAuthToken is invalid. Check the provider's error-handling docs for the exact string.",
          "url": "https://aifitnessapi.com/fix/fitness-api-401-unauthorized#faq-4"
        },
        {
          "question": "My refresh worked once and now returns invalid_grant — is that a 401 problem?",
          "answer": "No, that is a refresh-token rotation problem. Providers such as Strava, WHOOP, Oura, and Garmin return a new refresh token on refresh and invalidate the old one immediately. If you keep reusing the original, the first refresh succeeds and later ones fail with invalid_grant. Persist the returned refresh token on every refresh.",
          "url": "https://aifitnessapi.com/fix/fitness-api-401-unauthorized#faq-5"
        }
      ]
    },
    {
      "question": "oauth redirect_uri mismatch",
      "answer": "The OAuth redirect_uri_mismatch error means the redirect_uri your app sends is not byte-for-byte identical to a callback URL registered in the provider's developer console. OAuth servers do an exact string comparison, so http vs https, localhost vs 127.0.0.1, a trailing slash, a port, path case, or encoding differences all break it. Copy the registered value and the value your code actually sends, diff them character by character, and make them match. The same mismatch caught at the token step can surface as invalid_grant instead, so read the error_description.",
      "title": "How to Fix the OAuth redirect_uri Mismatch Error",
      "url": "https://aifitnessapi.com/fix/oauth-redirect-uri-mismatch",
      "markdown": "https://aifitnessapi.com/fix/oauth-redirect-uri-mismatch.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Why do localhost and 127.0.0.1 count as a mismatch?",
          "answer": "OAuth servers compare the redirect_uri as an exact string, not by what it resolves to. localhost and 127.0.0.1 are different strings even though they point to the same machine, so you must register and send whichever one your code actually uses.",
          "url": "https://aifitnessapi.com/fix/oauth-redirect-uri-mismatch#faq-1"
        },
        {
          "question": "Does a trailing slash really matter?",
          "answer": "Yes. /callback and /callback/ are different strings to the matcher, so one will fail if the other is registered. Frameworks and proxies sometimes add or strip the slash after your code builds the URL, so verify what actually leaves your process.",
          "url": "https://aifitnessapi.com/fix/oauth-redirect-uri-mismatch#faq-2"
        },
        {
          "question": "Why do I get invalid_grant instead of redirect_uri_mismatch?",
          "answer": "A redirect mismatch caught at the authorize step reads as redirect_uri_mismatch, but the same mismatch caught at the token step can read as 400 invalid_grant because the grant no longer matches the redirect used in the authorization request. Read the error_description field, since invalid_grant can also mean a reused or expired authorization code.",
          "url": "https://aifitnessapi.com/fix/oauth-redirect-uri-mismatch#faq-3"
        },
        {
          "question": "Do the authorize and token steps need the same redirect_uri?",
          "answer": "Yes. The redirect_uri sent when you build the authorize URL and the one sent when you exchange the code must be the identical string. If they differ you may pass the authorize step and then be rejected at the token exchange.",
          "url": "https://aifitnessapi.com/fix/oauth-redirect-uri-mismatch#faq-4"
        },
        {
          "question": "How do I support local, staging, and production callbacks?",
          "answer": "Register each environment's exact callback URL separately in the developer console, for example an http localhost URL for dev and https URLs for staging and production. Do not try to make a single entry cover multiple environments.",
          "url": "https://aifitnessapi.com/fix/oauth-redirect-uri-mismatch#faq-5"
        }
      ]
    },
    {
      "question": "fitness api refresh token not working",
      "answer": "If your refresh works once and then every later attempt returns 400 invalid_grant, you almost certainly failed to persist a rotated refresh token. Strava, WHOOP, Oura, Garmin, and Fitbit return a NEW refresh token in the refresh response and invalidate the old one immediately. The fix is to read the refresh_token out of every refresh response and save it, overwriting the stored value. Other causes: an expired or revoked token, a missing offline scope, wrong client credentials, or clock skew.",
      "title": "Why Is My Fitness API Refresh Token Not Working?",
      "url": "https://aifitnessapi.com/fix/refresh-token-not-working",
      "markdown": "https://aifitnessapi.com/fix/refresh-token-not-working.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Why does my refresh token work the first time but fail after that?",
          "answer": "Because the provider rotated it. Strava, WHOOP, Oura, Garmin, and Fitbit return a new refresh token in the refresh response and invalidate the old one. If you keep sending the original, the first refresh succeeds and the next returns 400 invalid_grant. Save the returned token every time.",
          "url": "https://aifitnessapi.com/fix/refresh-token-not-working#faq-1"
        },
        {
          "question": "What does invalid_grant mean on the token endpoint?",
          "answer": "It is an overloaded OAuth 2.0 error meaning the grant you sent is invalid, expired, revoked, or does not match. For refreshes it usually means a stale or already-rotated refresh token. Always log error_description, since providers put the specific reason there.",
          "url": "https://aifitnessapi.com/fix/refresh-token-not-working#faq-2"
        },
        {
          "question": "Do I need to save the refresh token even when it looks unchanged?",
          "answer": "Yes. Providers that usually return the same token can still rotate without warning. The safe rule is to always overwrite your stored refresh token with the exact value from the latest response.",
          "url": "https://aifitnessapi.com/fix/refresh-token-not-working#faq-3"
        },
        {
          "question": "My refresh keeps failing but I am saving the token. What else could it be?",
          "answer": "Check for concurrent refreshes on the same user, which race and invalidate each other, and verify your server clock is NTP-synced. If the token was genuinely current and still fails, the grant is likely revoked or expired and the user must re-authorize.",
          "url": "https://aifitnessapi.com/fix/refresh-token-not-working#faq-4"
        },
        {
          "question": "Why did I never receive a refresh token at all?",
          "answer": "You probably did not request the scope that grants offline access. WHOOP requires the offline scope, and other providers need refresh-capable consent. Re-run the authorization flow with the correct scope.",
          "url": "https://aifitnessapi.com/fix/refresh-token-not-working#faq-5"
        }
      ]
    },
    {
      "question": "fitbit api 429 rate limit",
      "answer": "A Fitbit API 429 means you exceeded Fitbit's per-user hourly quota, roughly 150 requests per hour per consented user (as of 2026, verify), and every call past that is rejected until the window resets. The limit is counted per consented user, so one runaway loop on a single user trips it. To fix it, read the Fitbit-Rate-Limit-Reset or Retry-After header, wait that long, then retry with exponential backoff plus jitter. Longer term, cache responses, reduce and stagger calls, and replace polling with Fitbit subscriptions.",
      "title": "How to Fix Fitbit API 429 (Rate Limit) Errors",
      "url": "https://aifitnessapi.com/fix/fitbit-api-429-rate-limit",
      "markdown": "https://aifitnessapi.com/fix/fitbit-api-429-rate-limit.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the Fitbit API rate limit?",
          "answer": "As of 2026, Fitbit allows roughly 150 requests per hour per consented user, resetting near the top of each hour (verify against current Fitbit docs, as these numbers change). Read the Fitbit-Rate-Limit-Limit and Fitbit-Rate-Limit-Reset response headers for the live values.",
          "url": "https://aifitnessapi.com/fix/fitbit-api-429-rate-limit#faq-1"
        },
        {
          "question": "Is the Fitbit rate limit per app or per user?",
          "answer": "It is counted per consented user, not per application. That means a single bad loop or aggressive polling job on one user's data can trigger 429 for that user without affecting your other users' quotas.",
          "url": "https://aifitnessapi.com/fix/fitbit-api-429-rate-limit#faq-2"
        },
        {
          "question": "How do I know when I can retry after a Fitbit 429?",
          "answer": "Read the Fitbit-Rate-Limit-Reset header, which gives the number of seconds until the window resets, or the Retry-After header when present. Wait at least that long before retrying, and add jitter to any computed backoff.",
          "url": "https://aifitnessapi.com/fix/fitbit-api-429-rate-limit#faq-3"
        },
        {
          "question": "How do I stop hitting the Fitbit rate limit?",
          "answer": "Cache data that does not change, reduce and batch calls, stagger background syncs so users are not all refreshed at once, and replace timer-based polling with Fitbit subscriptions so you fetch only when data actually changes.",
          "url": "https://aifitnessapi.com/fix/fitbit-api-429-rate-limit#faq-4"
        },
        {
          "question": "Is the Fitbit API being deprecated or migrated?",
          "answer": "Fitbit's developer platform is moving toward Google's Health ecosystem, with the Fitbit Web API being consolidated into Google Health APIs on a timeline still being finalized (as of 2026, verify against official announcements). Rate-limit details may change with that transition.",
          "url": "https://aifitnessapi.com/fix/fitbit-api-429-rate-limit#faq-5"
        }
      ]
    },
    {
      "question": "healthkit returns no data",
      "answer": "A HealthKit query that returns an empty array with no error is often a denied read permission, but HealthKit hides read-authorization state by design, so a blocked read is indistinguishable from a type that genuinely has no data. You cannot check read status directly. Because write status IS observable via authorizationStatus(for:), the fix is a write-then-read test: save a throwaway sample of the target type and read it back. If it round-trips, your plumbing is fine and the empty read is denied-read or truly no data; if the write fails, the problem is your Info.plist keys, HealthKit capability, or entitlement.",
      "title": "Why Is HealthKit Returning No Data?",
      "url": "https://aifitnessapi.com/fix/healthkit-no-data",
      "markdown": "https://aifitnessapi.com/fix/healthkit-no-data.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I detect whether the user denied read access in HealthKit?",
          "answer": "No. Apple deliberately hides read-authorization state to avoid leaking that health data exists, so authorizationStatus(for:) only reports the share/write side. A denied read returns the same empty result as a type with no data. Infer it with a write-then-read test.",
          "url": "https://aifitnessapi.com/fix/healthkit-no-data#faq-1"
        },
        {
          "question": "Why does authorizationStatus(for:) say authorized but my read is still empty?",
          "answer": "That status reflects write/share permission, not read. The user can allow writing while blocking reading, and HealthKit will not tell you. Confirm real data exists in the Health app and use a widened predicate to rule out a query bug.",
          "url": "https://aifitnessapi.com/fix/healthkit-no-data#faq-2"
        },
        {
          "question": "Does HealthKit work on the iOS Simulator?",
          "answer": "Partly, but the Simulator has little or no Health data and inconsistent behavior, so queries often return empty even with correct code. Always confirm on a real device with data before concluding your code is wrong.",
          "url": "https://aifitnessapi.com/fix/healthkit-no-data#faq-3"
        },
        {
          "question": "My app crashes when I request HealthKit authorization. Why?",
          "answer": "The most common cause is a missing Info.plist usage-description key: NSHealthShareUsageDescription for reads or NSHealthUpdateUsageDescription for writes. Add the relevant key and the crash at requestAuthorization goes away.",
          "url": "https://aifitnessapi.com/fix/healthkit-no-data#faq-4"
        },
        {
          "question": "How do I send the user to fix HealthKit read permissions?",
          "answer": "You cannot toggle read access from code. Direct the user to Settings, then Privacy & Security, then Health, then your app, where they can inspect and enable the specific read types you requested.",
          "url": "https://aifitnessapi.com/fix/healthkit-no-data#faq-5"
        }
      ]
    },
    {
      "question": "health connect returns no data",
      "answer": "The most common reason Google Health Connect returns no data is that no source app is writing that record type: Health Connect is an on-device store, not a data source, so something like Fitbit, Samsung Health, or the phone step recorder must populate it first. Open the Health Connect UI and confirm at least one app is writing the exact type you read. If a writer exists, check that your per-type read permission was actually granted (a SecurityException means it was not), that getSdkStatus returns SDK_AVAILABLE, and that you are not just hitting the default 30-day history window, which needs PERMISSION_READ_HEALTH_DATA_HISTORY for older data.",
      "title": "Why Is Google Health Connect Returning No Data?",
      "url": "https://aifitnessapi.com/fix/health-connect-no-data",
      "markdown": "https://aifitnessapi.com/fix/health-connect-no-data.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Why is Health Connect empty when my code has no errors?",
          "answer": "Because Health Connect is an on-device store, not a data source. If no app has written the record type you are reading, a correct query with correct permissions still returns an empty list. Open the Health Connect UI, go to Data and access, and confirm at least one app is writing that exact type before you keep debugging your code.",
          "url": "https://aifitnessapi.com/fix/health-connect-no-data#faq-1"
        },
        {
          "question": "What causes a SecurityException when reading from Health Connect?",
          "answer": "A SecurityException on a read almost always means the per-type read permission is either declared in the manifest but not granted at runtime, or not declared at all. Call getGrantedPermissions and confirm it contains HealthPermission.getReadPermission for the record class you are reading, then run your permission request flow. Note that uninstalling your app revokes all its Health Connect permissions.",
          "url": "https://aifitnessapi.com/fix/health-connect-no-data#faq-2"
        },
        {
          "question": "Why can I only read the last 30 days of data?",
          "answer": "By default an app can read Health Connect data from up to about 30 days before any permission was first granted. On Android 14 and later there is no limit reading your own app's data but a 30-day limit reading other apps' data; on Android 13 and lower the limit applies to any data. To read older records, declare and request PERMISSION_READ_HEALTH_DATA_HISTORY, otherwise reads older than 30 days error out.",
          "url": "https://aifitnessapi.com/fix/health-connect-no-data#faq-3"
        },
        {
          "question": "What does getSdkStatus tell me?",
          "answer": "getSdkStatus reports whether Health Connect is usable on the device. SDK_AVAILABLE means you can proceed; SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED means the user must update Health Connect; and SDK_UNAVAILABLE means it is not usable on that device. On older devices Health Connect can be an installable app rather than a bundled system module, so treat unavailable as a common, real state and prompt install or update.",
          "url": "https://aifitnessapi.com/fix/health-connect-no-data#faq-4"
        },
        {
          "question": "Does a production build behave differently from my dev build?",
          "answer": "It can. Apps requesting Health Connect data types must complete the Play Console health apps declaration and pass review, and production access to certain types can be gated until that is approved. If a type reads fine in a sideloaded or debug build but returns nothing from a Play install, suspect this gating. As of 2026, verify the exact policy against current Play Console documentation, since these specifics change.",
          "url": "https://aifitnessapi.com/fix/health-connect-no-data#faq-5"
        }
      ]
    },
    {
      "question": "strava webhook not firing",
      "answer": "The most common reason a Strava webhook never fires is that the subscription was never created: creating one is a two-step handshake, and if your callback fails to echo the hub.challenge as JSON with HTTP 200 within about two seconds, Strava silently abandons it. First confirm a subscription actually exists by calling GET push_subscriptions with your client_id and client_secret; an empty array means nothing will ever fire. Then make sure your callback is a public HTTPS URL that answers the validation GET correctly, and remember only one subscription is allowed per application.",
      "title": "Why Is My Strava Webhook Not Firing?",
      "url": "https://aifitnessapi.com/fix/strava-webhook-not-firing",
      "markdown": "https://aifitnessapi.com/fix/strava-webhook-not-firing.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "How do I check whether my Strava webhook subscription actually exists?",
          "answer": "Send a GET request to https://www.strava.com/api/v3/push_subscriptions with your client_id and client_secret. If it returns an empty array, no subscription exists and no events will ever fire, so you need to create one and pass the validation handshake.",
          "url": "https://aifitnessapi.com/fix/strava-webhook-not-firing#faq-1"
        },
        {
          "question": "Why does creating my Strava subscription fail even though my server is running?",
          "answer": "When you POST to create a subscription, Strava immediately issues a validation GET to your callback_url. If your endpoint does not return HTTP 200 and echo hub.challenge back as application/json within about two seconds, the subscription is never created. Localhost, self-signed certs, redirects, and auth middleware in front of the callback all cause this to fail.",
          "url": "https://aifitnessapi.com/fix/strava-webhook-not-firing#faq-2"
        },
        {
          "question": "Can I have more than one Strava webhook subscription per app?",
          "answer": "No. Each application may have only one subscription, and it receives events for all athletes who authorized the app. If you try to create a second one while a stale subscription still owns the slot, the create fails. Delete the old subscription first with DELETE push_subscriptions.",
          "url": "https://aifitnessapi.com/fix/strava-webhook-not-firing#faq-3"
        },
        {
          "question": "The webhook fires but my code errors. Is the webhook broken?",
          "answer": "Usually not. Strava events are lightweight pointers containing fields like object_id and owner_id, not the full activity. Return 200 immediately, then fetch the activity from the REST API using object_id and the athlete's token. A handler that crashes reading missing fields, or whose follow-up fetch fails on an expired token, looks like a webhook that isn't firing.",
          "url": "https://aifitnessapi.com/fix/strava-webhook-not-firing#faq-4"
        },
        {
          "question": "Why can't I see private activities from the webhook?",
          "answer": "Private and hidden activities require the activity:read_all scope, granted at OAuth time. If the athlete authorized only activity:read, your follow-up fetch returns nothing for those activities. Request activity:read_all and have the athlete re-consent. Verify current scope naming on the Strava authentication docs.",
          "url": "https://aifitnessapi.com/fix/strava-webhook-not-firing#faq-5"
        }
      ]
    },
    {
      "question": "wearable data missing or delayed",
      "answer": "Wearable data is near-real-time, not instant. The most common reason it looks missing is that it hasn't finished syncing device to phone app to the provider cloud yet, and a webhook fires only after the cloud has the data. Have the user force a sync in the vendor app and confirm the reading shows in the vendor's own dashboard first. If you expected history, remember a new connection only yields data from connection-time forward unless you make an explicit backfill request.",
      "title": "Why Is Wearable Data Missing or Delayed?",
      "url": "https://aifitnessapi.com/fix/wearable-data-delayed",
      "markdown": "https://aifitnessapi.com/fix/wearable-data-delayed.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "How long should wearable data take to appear?",
          "answer": "There is no fixed guarantee, but it is near-real-time rather than instant. The device syncs to its phone app on its own schedule (often every few minutes to hourly, sometimes only when the app is opened), the app uploads to the vendor cloud, and only then does a webhook fire. A gap of minutes, occasionally longer, is normal.",
          "url": "https://aifitnessapi.com/fix/wearable-data-delayed#faq-1"
        },
        {
          "question": "Why do I only get new data and none of the user's history?",
          "answer": "By default a new connection only delivers data from the moment the user connected forward. Historical data before that point requires a separate, explicit backfill or historical-data request, and some providers limit how far back you can go, so check the provider's docs for the exact window.",
          "url": "https://aifitnessapi.com/fix/wearable-data-delayed#faq-2"
        },
        {
          "question": "The user is connected in Terra but no data arrives. What's wrong?",
          "answer": "Connected is not the same as has synced. Common causes are that the wearable hasn't synced yet, the user authenticated a different or empty vendor account, or your Destination is misconfigured (which shows as 400 or 500 in Terra's Payload History). Force a backfill for that user to isolate whether the connection or the realtime delivery is the problem.",
          "url": "https://aifitnessapi.com/fix/wearable-data-delayed#faq-3"
        },
        {
          "question": "Could my webhook be dropping data?",
          "answer": "Yes. If your endpoint returns a non-2xx status or times out, the provider treats it as a delivery failure and may retry with backoff or drop the event entirely. Return a 2xx quickly and process asynchronously, keep the handler idempotent for retries, and make sure no auth middleware, WAF, or redirect blocks the provider's requests.",
          "url": "https://aifitnessapi.com/fix/wearable-data-delayed#faq-4"
        },
        {
          "question": "How do I tell a sync delay apart from a real webhook bug?",
          "answer": "Check the vendor's own app or dashboard first. If the reading isn't even there, it's a sync issue and no API can have it yet. If it is there but not in your system after a few minutes, then look at delivery: check the provider's payload history for errors on your endpoint and confirm your handler returns 2xx fast.",
          "url": "https://aifitnessapi.com/fix/wearable-data-delayed#faq-5"
        }
      ]
    },
    {
      "question": "garmin api access approval",
      "answer": "If you can't find a way to sign up for Garmin API keys, you're not doing anything wrong. Garmin's Connect Developer Program is partner-approval-only, not self-serve, and as of 2026 new sign-ups are reportedly on hold, with the public request form removed and no published re-open date. Verify the live status on developer.garmin.com, and in the meantime pull Garmin data through an aggregator like Terra that already holds its own Garmin partner access.",
      "title": "Can't Get Garmin API Access? Here's What's Going On",
      "url": "https://aifitnessapi.com/fix/garmin-api-approval",
      "markdown": "https://aifitnessapi.com/fix/garmin-api-approval.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Why can't I sign up for Garmin API keys?",
          "answer": "Because Garmin's Connect Developer Program has never been self-serve, and as of 2026 new sign-ups are reportedly paused. The Health and Activity APIs require you to apply and be approved as a partner, and multiple developer reports say the public access-request form was removed with no published ETA. Verify the current status on developer.garmin.com before assuming it is closed.",
          "url": "https://aifitnessapi.com/fix/garmin-api-approval#faq-1"
        },
        {
          "question": "Is the Garmin developer program really closed to new applicants?",
          "answer": "Reportedly yes for new onboarding as of 2026, but treat this as verify rather than certain. Developer forum posts and a public GitHub issue describe the request form being removed or under revision so new requests cannot be submitted. Existing approved partners are said to be unaffected. Load developer.garmin.com yourself, since the status can change.",
          "url": "https://aifitnessapi.com/fix/garmin-api-approval#faq-2"
        },
        {
          "question": "Can I use an aggregator like Terra to get Garmin data without approval?",
          "answer": "Often yes. Aggregators such as Terra hold their own Garmin partnership and let users connect their Garmin account through the aggregator's flow, then push normalized data to your webhook. Terra advertises Garmin connectivity described as not requiring your own Garmin Developer Program approval. Watch out for open or self-host routes that still require you to supply your own Garmin credentials, which you cannot get while the program is paused. Verify each provider's current Garmin terms.",
          "url": "https://aifitnessapi.com/fix/garmin-api-approval#faq-3"
        },
        {
          "question": "What are my alternatives while Garmin access is blocked?",
          "answer": "Read Garmin data from Apple HealthKit or Google Health Connect on the phone, pull Garmin activities that re-sync into Strava once a user connects Garmin to Strava, or accept user-uploaded FIT files via Garmin's open FIT SDK. For a launch that does not wait on Garmin, self-serve ecosystems like Fitbit, Oura, and WHOOP are available today.",
          "url": "https://aifitnessapi.com/fix/garmin-api-approval#faq-4"
        },
        {
          "question": "How long does Garmin approval take once the form is open?",
          "answer": "Plan for weeks, not hours. Approval is a manual, partner-level business review with no guaranteed timeline, and there is no self-serve shortcut. Do not build against Garmin on the assumption you will be approved; confirm access first.",
          "url": "https://aifitnessapi.com/fix/garmin-api-approval#faq-5"
        }
      ]
    },
    {
      "question": "google fit api deprecated",
      "answer": "The Google Fit API is deprecated: all Fit APIs, including the REST API, are supported only until the end of 2026, and no new developers have been able to sign up since May 1, 2024. There is no 1:1 replacement, so you must migrate based on how you used Fit. On-device reads move to Google Health Connect (plus the Recording API for steps), cloud, account, and OAuth reads move to the new Google Health API, and Wear OS moves to Health Services. Start now, because the end-of-2026 sunset is firm and new projects cannot onboard to Fit at all.",
      "title": "Google Fit API Is Deprecated — What to Use Instead",
      "url": "https://aifitnessapi.com/fix/google-fit-api-deprecated",
      "markdown": "https://aifitnessapi.com/fix/google-fit-api-deprecated.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "When exactly is the Google Fit API being shut down?",
          "answer": "All Google Fit APIs, including the REST API, the Android SDK, and the BLE APIs, are supported only until the end of 2026. New signups have already been closed since May 1, 2024, so no new project can onboard to Fit. Treat the end of 2026 as a hard deadline and migrate well before it.",
          "url": "https://aifitnessapi.com/fix/google-fit-api-deprecated#faq-1"
        },
        {
          "question": "Is there a drop-in replacement for the Fit REST API?",
          "answer": "No. Google states there is no alternative that maps one-to-one onto the Fit REST API, so you cannot simply swap a base URL. Cloud and account usage moves to the new Google Health API, but expect to re-architect your server integration rather than port it directly.",
          "url": "https://aifitnessapi.com/fix/google-fit-api-deprecated#faq-2"
        },
        {
          "question": "Should I migrate to Health Connect or the Google Health API?",
          "answer": "It depends on how you used Fit. On-device reads of steps and aggregates on Android move to Health Connect, while cloud, account, and OAuth reads move to the Google Health API. If your app does both, migrate each feature to the target that matches its usage pattern.",
          "url": "https://aifitnessapi.com/fix/google-fit-api-deprecated#faq-3"
        },
        {
          "question": "Where do Fitbit Web API integrations go?",
          "answer": "The Fitbit cloud surface is folding into the Google Health API, which is the same destination as Fit's cloud APIs. As of 2026 the Google Health API and the Fitbit consolidation timeline are still rolling out, so verify current availability, scopes, and endpoints against Google's official docs before you build.",
          "url": "https://aifitnessapi.com/fix/google-fit-api-deprecated#faq-4"
        },
        {
          "question": "What about Google Fit on Wear OS?",
          "answer": "Fit's Wear OS sensor and activity APIs move to Health Services on Wear OS, not to Health Connect. Health Connect is the phone-side on-device store, while Health Services handles on-watch sensors and activity, so keep the two migrations separate.",
          "url": "https://aifitnessapi.com/fix/google-fit-api-deprecated#faq-5"
        }
      ]
    },
    {
      "question": "oura personal access tokens deprecated",
      "answer": "Oura deprecated Personal Access Tokens around December 2025: new PATs can no longer be created, and new integrations must use OAuth 2.0 Authorization Code with scoped Bearer tokens. If a tutorial tells you to paste a personal token, it predates the change. The fix is to register an OAuth application, send users through Oura's consent screen, and exchange the code for tokens — your API calls to api.ouraring.com/v2/ stay the same, only the credential changes.",
      "title": "Oura Personal Access Tokens Are Deprecated — Here's the Fix",
      "url": "https://aifitnessapi.com/fix/oura-personal-access-token-deprecated",
      "markdown": "https://aifitnessapi.com/fix/oura-personal-access-token-deprecated.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-08-02",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I still create an Oura Personal Access Token?",
          "answer": "No — as of the December 2025 deprecation, new Personal Access Tokens can no longer be created, and new integrations must use OAuth 2.0 Authorization Code with scoped Bearer tokens. Existing tokens created before the change are a separate question: treat any that still work as temporary and migrate to OAuth now. Verify the current wind-down status in Oura's own developer documentation, as of 2026.",
          "url": "https://aifitnessapi.com/fix/oura-personal-access-token-deprecated#faq-1"
        },
        {
          "question": "Do my Oura API endpoints change when I move from a PAT to OAuth?",
          "answer": "No. The v2 REST base at api.ouraring.com/v2/ and the usercollection endpoints are unchanged, and the responses are the same. What changes is the credential: instead of a personal token you send a scoped OAuth Bearer access token, which expires and is renewed via a refresh token. Migration is an auth change, not a rewrite.",
          "url": "https://aifitnessapi.com/fix/oura-personal-access-token-deprecated#faq-2"
        },
        {
          "question": "Is there a simpler path than OAuth for a personal Oura project?",
          "answer": "Not from Oura directly anymore — OAuth is the supported route for new integrations, even single-user ones, so you register an app and authorize yourself once through your own consent screen. If the ceremony is a dealbreaker and you want several wearables anyway, a health-data aggregator gives you Oura and other providers behind one integration, at the cost of a third party in the loop.",
          "url": "https://aifitnessapi.com/fix/oura-personal-access-token-deprecated#faq-3"
        }
      ]
    },
    {
      "question": "fitbit error code 401",
      "answer": "Error code 401 from the Fitbit API means Fitbit rejected your credential, not your permissions: the access token is missing, malformed, expired, or no longer recognised. The usual cause is simple ageing, because a Fitbit token response carries expires_in of 28800 seconds (eight hours, verify against current docs), so refresh the token and retry. Read the errorType field inside the errors array in the response body to tell the cases apart: expired_token means refresh, while invalid_token points at a malformed header, a revoked grant, or a token minted by a different registered app. If the refresh itself fails with invalid_grant, the grant is dead and the user must authorize again.",
      "title": "Fitbit Error Code 401: What It Means and How to Fix It",
      "url": "https://aifitnessapi.com/fix/fitbit-error-code-401",
      "markdown": "https://aifitnessapi.com/fix/fitbit-error-code-401.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-08-11",
      "first_party": false,
      "faqs": [
        {
          "question": "How long does a Fitbit access token last before it expires?",
          "answer": "A Fitbit token response includes expires_in with a value of 28800 seconds, which is eight hours. That is the commonly documented lifetime, so verify the current value against Fitbit's docs before hard-coding it. Practically, it means a long-running integration must refresh at least three times a day, and it explains why a call that worked this morning fails this evening.",
          "url": "https://aifitnessapi.com/fix/fitbit-error-code-401#faq-1"
        },
        {
          "question": "Does refreshing a Fitbit token require HTTP Basic auth?",
          "answer": "It depends on the OAuth 2.0 application type you registered. Public Client apps, such as mobile and single-page apps that ship no secret, send grant_type, the refresh token, and the client_id, relying on PKCE. Confidential Server apps additionally send an HTTP Basic authorization header built from the client ID and client secret. Sending the wrong combination for your app type makes the refresh fail even though the refresh token is good.",
          "url": "https://aifitnessapi.com/fix/fitbit-error-code-401#faq-2"
        },
        {
          "question": "What does Fitbit put in the response body when it rejects a call?",
          "answer": "Fitbit returns an errors array, and the field to read is errorType. The two values you will see most on a rejected credential are expired_token, meaning the access token aged out and a refresh will fix it, and invalid_token, meaning Fitbit does not recognise the credential as live. Log errorType on every failure rather than logging the status code alone.",
          "url": "https://aifitnessapi.com/fix/fitbit-error-code-401#faq-3"
        },
        {
          "question": "Why does a Fitbit token that works in one of my apps fail in another?",
          "answer": "Every Fitbit app registration gets its own Client ID, and a token minted under one registration is not valid for another. The token is genuinely live, just not for the app making the call. This bites teams that keep a Personal app for intraday testing next to a Server app for production and let the two credentials mix in a shared config or environment file.",
          "url": "https://aifitnessapi.com/fix/fitbit-error-code-401#faq-4"
        },
        {
          "question": "Does a Fitbit 401 mean the user disconnected my app?",
          "answer": "Sometimes, and the refresh call is what tells you. If the refresh succeeds, the original failure was ordinary token ageing and the connection is intact. If the refresh fails with invalid_grant, the grant itself is gone because the user revoked access or it expired, and no retry will bring it back. At that point the only path forward is sending the user through the authorization flow again.",
          "url": "https://aifitnessapi.com/fix/fitbit-error-code-401#faq-5"
        }
      ]
    },
    {
      "question": "healthkit authorization denied",
      "answer": "In HealthKit, a denied authorization is only visible on the write side. The status returned by authorizationStatus(for:) — notDetermined, sharingDenied, or sharingAuthorized — describes permission to save data, and Apple documents that your app cannot determine whether a user granted permission to read data, because a denied read simply looks like an empty store. If your app has share permission but not read permission, Apple states you see only the samples your own app wrote, and data from other sources stays hidden. The single exception is limited authorization: when someone grants a recent window of history instead of their full history, getEarliestAuthorizedSampleDate reveals that date, and Apple calls it the only authorization state your app can positively identify.",
      "title": "HealthKit Authorization Denied: What It Means and What It Hides",
      "url": "https://aifitnessapi.com/fix/healthkit-authorization-denied",
      "markdown": "https://aifitnessapi.com/fix/healthkit-authorization-denied.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-08-11",
      "first_party": false,
      "faqs": [
        {
          "question": "Does sharingDenied mean my HealthKit reads will fail too?",
          "answer": "No. Apple documents authorizationStatus(for:) as checking the status for saving data to the HealthKit store, and the enum describes whether the user authorized your app to save data of the given type. Read and share are separate permissions on every type, so a user can deny writes while allowing reads. Disable saving for that type and keep running your queries.",
          "url": "https://aifitnessapi.com/fix/healthkit-authorization-denied#faq-1"
        },
        {
          "question": "What does getRequestStatusForAuthorization actually tell me?",
          "answer": "Apple describes it as indicating whether the system presents a permission sheet if your app requests authorization for the provided types. Its results are shouldRequest, meaning you have not yet requested all the specified types, unnecessary, meaning you already have, and unknown, meaning an error occurred. Unnecessary means asking again would show nothing — it is not confirmation that access was granted.",
          "url": "https://aifitnessapi.com/fix/healthkit-authorization-denied#faq-2"
        },
        {
          "question": "Why does calling requestAuthorization again show no permission sheet?",
          "answer": "Apple documents that if the user has already chosen to grant or prohibit access to all of the types specified, HealthKit returns the request without prompting. A second call is a no-op once every requested type has been decided, so a grant-access button that re-requests will silently do nothing. Point the user at Settings or the Health app instead.",
          "url": "https://aifitnessapi.com/fix/healthkit-authorization-denied#faq-3"
        },
        {
          "question": "How do I know if a user granted only a limited window of health history?",
          "answer": "Apple's authorization sheet includes a second screen where people choose between a recent limited window and their full history. Call getEarliestAuthorizedSampleDate(for:completion:) to get the earliest date you may read for each type and pass it into your query. Apple calls limited authorization the only authorization state your app can positively identify, and warns against treating the absence of older samples as proof they do not exist.",
          "url": "https://aifitnessapi.com/fix/healthkit-authorization-denied#faq-4"
        },
        {
          "question": "Why do HealthKit writes fail on Vision Pro when my status check says authorized?",
          "answer": "In a Guest User session, Apple documents that an app's permissions do not change, so authorizationStatus(for:) still reports the owner's grant while any attempt to save fails with errorNotPermissibleForGuestUserMode, or errorHealthDataRestricted on apps running in iOS 17. The authorization sheet is not displayed either, so requests during a guest session fail silently. Apple suggests ignoring the error for passive or periodic saves and only alerting when the guest took an action that obviously implies saving.",
          "url": "https://aifitnessapi.com/fix/healthkit-authorization-denied#faq-5"
        }
      ]
    },
    {
      "question": "strava api 401 unauthorized",
      "answer": "A 401 from the Strava API means Strava rejected the credential itself, not your permissions, and on Strava the top-ranked cause is the rotating refresh token rather than the access token. Strava returns a new refresh token on every refresh and the old one stops working, so an integration that persists only the access token refreshes once and then can never mint another, and every subsequent call fails. Read the response body first, because Strava reports a rejected credential as an Authorization Error naming the access_token field with code invalid. Then check expires_at, since access tokens expire roughly six hours after creation (an expires_in of 21600 seconds as of 2026 — verify against the current docs). If the refresh call itself returns invalid_grant, the grant is dead and the athlete has to authorize again.",
      "title": "Strava API 401 Unauthorized: What It Means and How to Fix It",
      "url": "https://aifitnessapi.com/fix/strava-api-401-unauthorized",
      "markdown": "https://aifitnessapi.com/fix/strava-api-401-unauthorized.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "What does Strava's Authorization Error response body tell me?",
          "answer": "It tells you Strava rejected the credential rather than the request. Our corpus records the shape as a message of Authorization Error alongside an errors array whose single entry names the access_token field with the code invalid. That is a credential-level rejection, so the next question is always whether the token aged out, was never rotated correctly, or belongs to a different registered application. Log the body rather than the bare status code, because the field name is what tells you the access token specifically is the thing Strava refused.",
          "url": "https://aifitnessapi.com/fix/strava-api-401-unauthorized#faq-1"
        },
        {
          "question": "Does a missing activity:read_all scope make Strava return 401?",
          "answer": "No, and this is the Strava-specific trap. On Strava a scope shortfall usually shows up as missing data rather than an error status. Plain activity:read only ever returns activities the athlete shared beyond Only You, and the same filtering applies to webhook events, so private runs simply vanish from your listings while every call keeps succeeding. If athletes report missing activities, check the scope value returned with the token instead of hunting for a rejected credential.",
          "url": "https://aifitnessapi.com/fix/strava-api-401-unauthorized#faq-2"
        },
        {
          "question": "Do Strava token refresh calls count against my rate limit?",
          "answer": "No. Our Strava integration guide records that the OAuth token exchange and refresh calls do not count against your API rate limit. That matters when you are fixing a 401 storm, because the instinct to batch refreshes carefully is misplaced here — the thing you must actually protect is your per-application request budget, documented as roughly 200 requests per 15 minutes and 2,000 per day as of 2026, which returns 429 rather than 401 when you exceed it. Verify the current quotas before you build around them.",
          "url": "https://aifitnessapi.com/fix/strava-api-401-unauthorized#faq-3"
        },
        {
          "question": "How do I tell a deauthorized athlete from an expired Strava token?",
          "answer": "The refresh call is the test. If the refresh succeeds, the original rejection was ordinary ageing and the connection is intact. If it comes back invalid_grant, the grant itself is gone and no retry recovers it. Strava also gives you an advance signal: the Events API sends an athlete update carrying updates.authorized set to false when someone disconnects your app, which is your cue to clean up that athlete's stored tokens before your next call fails.",
          "url": "https://aifitnessapi.com/fix/strava-api-401-unauthorized#faq-4"
        },
        {
          "question": "Could Strava's developer subscription requirement be causing my 401s?",
          "answer": "Treat that as unproven rather than as a cause. Strava's developer program has tightened since 2024 with formal Standard and Extended Access tiers, display and branding rules including the Connect with Strava button, athlete-consent requirements, and a reported paid subscription now gating Standard tier access. Those are real constraints on whether your application keeps access at all, but our corpus does not document any of them producing a 401 status code specifically, so do not skip the token diagnosis in favour of a compliance theory. Verify the current terms against Strava's live developer agreement and API Policy.",
          "url": "https://aifitnessapi.com/fix/strava-api-401-unauthorized#faq-5"
        }
      ]
    },
    {
      "question": "healthkit background delivery not working",
      "answer": "If your HKObserverQuery never fires while your app is backgrounded, work down four documented gates before you suspect a bug. Since iOS 15 and watchOS 8 you must add the com.apple.developer.healthkit.background-delivery entitlement, which defaults to false; without it Apple documents that enableBackgroundDelivery(for:frequency:withCompletion:) fails with an HKError.Code.errorAuthorizationDenied error. Apple states on two separate pages that background server queries are not supported on the Simulator, so a Simulator test proves nothing. Observer queries must be set up in the app delegate's application(_:didFinishLaunchingWithOptions:) method so they exist before HealthKit delivers to a freshly launched process. And you must call the update's completion handler: if your app fails to respond three times, Apple documents that HealthKit assumes it cannot receive data and stops sending background updates.",
      "title": "HealthKit Background Delivery Not Working: Why Your Observer Never Fires",
      "url": "https://aifitnessapi.com/fix/healthkit-background-delivery-not-working",
      "markdown": "https://aifitnessapi.com/fix/healthkit-background-delivery-not-working.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Why does enableBackgroundDelivery fail with errorAuthorizationDenied when the user already granted access?",
          "answer": "Because that error is about your entitlement, not the person's choice. Apple documents that for iOS 15 and watchOS 8 and later you must enable HealthKit Background Delivery by adding the com.apple.developer.healthkit.background-delivery entitlement to your app, and that if your app does not have it, the method fails with an HKError.Code.errorAuthorizationDenied error. The entitlement is a Boolean whose default value is false, so it has to be added explicitly and present in the signed build you are testing. The fastest way to see this is to stop discarding the completion block's error argument.",
          "url": "https://aifitnessapi.com/fix/healthkit-background-delivery-not-working#faq-1"
        },
        {
          "question": "My observer query fires but finds nothing new. What is wrong?",
          "answer": "Probably nothing, because an observer query is not designed to carry data. Apple states that the update handler does not receive any information about the change, just that a change occurred, and that you must execute another query, for example an HKSampleQuery or HKAnchoredObjectQuery, to access the changes. If you are already running a second query, the other documented explanation is a locked device: Apple notes the system encrypts the HealthKit store when the user locks the device, so your app may not be able to read from the store while it runs in the background, and our architecture guide records that surfacing as errorDatabaseInaccessible. Treat that as retryable rather than as an absence of data.",
          "url": "https://aifitnessapi.com/fix/healthkit-background-delivery-not-working#faq-2"
        },
        {
          "question": "Which HealthKit types can be registered for background delivery?",
          "answer": "Apple documents the type parameter as accepting an HKCharacteristicType, HKQuantityType, HKCategoryType, or HKWorkoutType, and states outright that HKCorrelationType is not a supported type for background delivery. That asymmetry catches people, because the matching disableBackgroundDelivery method does list HKCorrelationType among the classes it accepts. If you are trying to observe a correlation such as a blood pressure reading, register the underlying quantity types instead.",
          "url": "https://aifitnessapi.com/fix/healthkit-background-delivery-not-working#faq-3"
        },
        {
          "question": "Why does my observer query never fire in the iOS Simulator?",
          "answer": "Because Apple does not support it there. The sentence appears on both the enableBackgroundDelivery reference and the HKObserverQuery reference: background server queries are not supported on the Simulator, and you should be sure to test your background queries on a device. There is no flag or workaround, which means Simulator-based CI cannot cover this path at all and a green Simulator run is not evidence your background delivery works. Move the test to real hardware before changing any code.",
          "url": "https://aifitnessapi.com/fix/healthkit-background-delivery-not-working#faq-4"
        },
        {
          "question": "How many background updates can a watchOS app receive in an hour?",
          "answer": "Apple documents that in watchOS, background updates share a budget with WKApplicationRefreshBackgroundTask tasks, and that your app can receive four updates or background app refresh tasks an hour as long as it has a complication on the active watch face. Read the whole sentence, because the complication is the condition on the budget rather than a suggestion. Apple also documents that in watchOS most data types have an hourly maximum frequency, with a named exception list that can reach immediate, including high heart rate, low heart rate, and irregular heart rhythm events, VO2 max, and number of times fallen.",
          "url": "https://aifitnessapi.com/fix/healthkit-background-delivery-not-working#faq-5"
        }
      ]
    },
    {
      "question": "healthkit errordatabaseinaccessible",
      "answer": "HealthKit returns errorDatabaseInaccessible when your app queries the store while the device is locked. Apple's documentation states that reads fail in this state but saves still work: the data goes into a temporary file that is merged when the user unlocks the device. That makes this a background problem, because a foregrounded app is running on an unlocked device. Treat it as transient rather than terminal, resume the read after the device is unlocked, and never record the failed read as a gap in the user's history.",
      "title": "HealthKit errorDatabaseInaccessible: Reads Fail While the Device Is Locked",
      "url": "https://aifitnessapi.com/fix/healthkit-database-inaccessible",
      "markdown": "https://aifitnessapi.com/fix/healthkit-database-inaccessible.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "Why does my background HealthKit read fail when the same query works in the app?",
          "answer": "Because the device was locked when the background job ran. Apple's documentation states this error occurs when your app queries HealthKit data while the device is locked. In the foreground the device is unlocked by definition, so the identical query succeeds. The difference is timing and lock state, not your predicate, entitlements, or authorization setup.",
          "url": "https://aifitnessapi.com/fix/healthkit-database-inaccessible#faq-1"
        },
        {
          "question": "Can my app still save HealthKit data while the device is locked?",
          "answer": "Apple's discussion states that you can still save data while the device is locked. It says the data is written into a temporary file, which is merged with HealthKit's data when the user unlocks their device. So a job that only reads will fail, while a job that only writes keeps working, which is a useful thing to design around.",
          "url": "https://aifitnessapi.com/fix/healthkit-database-inaccessible#faq-2"
        },
        {
          "question": "Should I retry immediately after errorDatabaseInaccessible?",
          "answer": "As a practice, no. A tight retry loop burns your background execution window against a device that may stay locked for hours. Classify the failure as transient, leave your sync cursor where it was, and re-run the work when the app next becomes active or on a wake-up after the device has been unlocked.",
          "url": "https://aifitnessapi.com/fix/healthkit-database-inaccessible#faq-3"
        }
      ]
    },
    {
      "question": "healthkit errorhealthdataunavailable",
      "answer": "Apple's documentation states that errorHealthDataUnavailable means the user accessed HealthKit on an unsupported device. Apple's discussion tells you to verify that the current device supports HealthKit before calling any other HealthKit method, because iOS apps can run on devices that do not support it. There is nothing to retry and nothing the user can change, so the only useful response is to detect the condition and hide the feature rather than showing an error. In practice the bug is usually coverage: the availability check exists in your launch path but not in the widget, extension, or background wake-up that actually made the call.",
      "title": "HealthKit errorHealthDataUnavailable: The Device Does Not Support HealthKit",
      "url": "https://aifitnessapi.com/fix/healthkit-health-data-unavailable",
      "markdown": "https://aifitnessapi.com/fix/healthkit-health-data-unavailable.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "What does errorHealthDataUnavailable actually mean?",
          "answer": "Apple's abstract states that the user accessed HealthKit on an unsupported device. It is a capability fact about the hardware or platform, not a permission decision by the person using it. No retry, reinstall, or new authorization request will change the answer, so your app should treat the Health integration as absent rather than broken on that device.",
          "url": "https://aifitnessapi.com/fix/healthkit-health-data-unavailable#faq-1"
        },
        {
          "question": "Where should the HealthKit availability check go?",
          "answer": "Apple's discussion says to verify support before calling any other HealthKit method. In practice that means every entry point, not just app launch: widgets, complications, extensions, background wake-ups, deep links, and a watch app all start HealthKit work without running your onboarding. Put the check behind a single accessor that every HealthKit path has to pass through.",
          "url": "https://aifitnessapi.com/fix/healthkit-health-data-unavailable#faq-2"
        },
        {
          "question": "Does this error mean HealthKit never works on iPad?",
          "answer": "Apple's discussion gives iPad as an example of a device an iOS app can run on that does not support HealthKit. That is an example, not a rule about any particular model or release, so do not hard-code assumptions about hardware. Check availability at runtime and the question never has to be answered in your code.",
          "url": "https://aifitnessapi.com/fix/healthkit-health-data-unavailable#faq-3"
        }
      ]
    },
    {
      "question": "healthkit errorhealthdatarestricted mdm",
      "answer": "Apple's documentation states that errorHealthDataRestricted means a Mobile Device Management profile restricts the use of HealthKit on this device. Apple's discussion adds that you should verify the device supports HealthKit before calling any other HealthKit method, because a managed profile can disable it entirely. No code change, permission request, or retry will lift the restriction: only whoever administers the device can. The engineering work is therefore detection and honest messaging — model it as a distinct state, point the user at their administrator rather than at Settings, and keep a manual path so the rest of the app still works.",
      "title": "HealthKit errorHealthDataRestricted: An MDM Profile Turned HealthKit Off",
      "url": "https://aifitnessapi.com/fix/healthkit-data-restricted-mdm",
      "markdown": "https://aifitnessapi.com/fix/healthkit-data-restricted-mdm.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "Can my app do anything about a HealthKit MDM restriction?",
          "answer": "No. Apple's abstract describes it as a Mobile Device Management profile restricting the use of HealthKit on the device. There is no API to request an exception, no toggle in Settings or the Health app for the user, and nothing that changes on retry. Only the administrator who manages the device can change the policy.",
          "url": "https://aifitnessapi.com/fix/healthkit-data-restricted-mdm#faq-1"
        },
        {
          "question": "How do I tell a restricted device from an unsupported one?",
          "answer": "By the error case, which is why they need separate log lines. Apple describes errorHealthDataRestricted as a management-profile restriction and errorHealthDataUnavailable as an unsupported device. Both fail every call and both tell you to run the same availability check first, but only one of them has a human on the other end who can change the answer.",
          "url": "https://aifitnessapi.com/fix/healthkit-data-restricted-mdm#faq-2"
        },
        {
          "question": "What should I show a user on a managed device?",
          "answer": "As a practice, an explanation rather than an error. Say that this device's management profile has Health access turned off, that automatic tracking is unavailable, and that their IT administrator controls the setting. Do not send them to Settings for a switch that is not there, and offer a manual path so the app stays usable.",
          "url": "https://aifitnessapi.com/fix/healthkit-data-restricted-mdm#faq-3"
        }
      ]
    },
    {
      "question": "healthkit errornodata",
      "answer": "Apple's documentation states that errorNoData means data is unavailable for the requested query and predicate, and that the system therefore cannot calculate the query's result. It is an explicit answer, not a silent one: HealthKit is telling you the window you asked about had nothing to compute from. That makes it different from an empty sample query, which returns no error and cannot distinguish a denied read from a type nobody has ever written to. In most cases the right handling is an empty state rather than an error, with no retry and no permission prompt.",
      "title": "HealthKit errorNoData: The Query Ran and Found Nothing",
      "url": "https://aifitnessapi.com/fix/healthkit-error-no-data",
      "markdown": "https://aifitnessapi.com/fix/healthkit-error-no-data.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "Is errorNoData a bug in my query?",
          "answer": "Usually not. Apple's abstract states that data is unavailable for the requested query and predicate, and the discussion says no data exists that corresponds to the query, so the system cannot calculate a result. Widen the window and re-run: if results appear, the original window was genuinely empty and your app should render an empty state.",
          "url": "https://aifitnessapi.com/fix/healthkit-error-no-data#faq-1"
        },
        {
          "question": "How is this different from a HealthKit query that returns an empty array?",
          "answer": "An empty array carries no error and no information: a denied read looks exactly like a type with no samples, because Apple hides read authorization by design. errorNoData is an explicit statement that a computation had nothing to work from. One is ambiguous silence you have to isolate; the other is an answer you can act on directly.",
          "url": "https://aifitnessapi.com/fix/healthkit-error-no-data#faq-2"
        },
        {
          "question": "Should I ask the user for permission when I get errorNoData?",
          "answer": "No. The error can arrive with permissions in perfect order, and re-requesting authorization after the user has already decided does not present the sheet again anyway. Treat it as a data question instead: check the window, the day boundaries, and whether anything on that device ever writes the type you asked for.",
          "url": "https://aifitnessapi.com/fix/healthkit-error-no-data#faq-3"
        }
      ]
    },
    {
      "question": "healthkit errorinvalidargument",
      "answer": "Apple's documentation states one sentence for errorInvalidArgument — the app passed an invalid argument to the HealthKit API — and publishes no discussion paragraph. So Apple tells you an argument was rejected, and nothing about which one or why. In practice the constraint usually lives in the type rather than the call: an aggregation the type does not support, a unit from the wrong family, a predicate filtering on something the type does not have, or a reversed date range. Treat it as a programming error rather than an environmental one, log the arguments you passed, and reduce the call until the failure disappears.",
      "title": "HealthKit errorInvalidArgument: Finding the Argument HealthKit Rejected",
      "url": "https://aifitnessapi.com/fix/healthkit-invalid-argument",
      "markdown": "https://aifitnessapi.com/fix/healthkit-invalid-argument.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "What does Apple say causes errorInvalidArgument?",
          "answer": "Only that the app passed an invalid argument to the HealthKit API. That abstract is the entire published description; there is no discussion paragraph naming which arguments qualify. Any source that tells you the case specifically means a unit problem or an options problem is inferring. Useful inference, but it should be labelled as inference rather than documentation.",
          "url": "https://aifitnessapi.com/fix/healthkit-invalid-argument#faq-1"
        },
        {
          "question": "Why do cumulative and discrete types cause invalid arguments?",
          "answer": "Because the aggregation you ask for has to be one the type can define. A type that accumulates over an interval supports a running total; a type that is a series of independent readings supports averages, minimums, and maximums. Asking a counter for an average, or a set of point readings for a sum, is asking for something undefined.",
          "url": "https://aifitnessapi.com/fix/healthkit-invalid-argument#faq-2"
        },
        {
          "question": "Should I catch errorInvalidArgument and return an empty result?",
          "answer": "No. Unlike a locked store or an unsupported device, a rejected argument will be rejected the same way forever, so catching it silently converts a permanent bug into a mysterious data gap nobody can reproduce. Fail loudly in development, report it in production, and log the arguments you passed alongside the code.",
          "url": "https://aifitnessapi.com/fix/healthkit-invalid-argument#faq-3"
        }
      ]
    },
    {
      "question": "healthkit errorauthorizationnotdetermined",
      "answer": "Apple's documentation states that errorAuthorizationNotDetermined means the app has not yet asked the user for the authorization required to complete the task, and that it occurs when your app does not request proper authorization before calling any other HealthKit method. It is not a refusal: nobody has been asked. That distinguishes it from a denied write, which Apple describes as the user not having given the app permission to save data. The fix is ordering, and the usual cause is coverage — a widget, extension, background wake-up, watch app, or newly added type that reaches the store without passing through the request you wrote for your onboarding flow.",
      "title": "HealthKit errorAuthorizationNotDetermined: You Called Before You Asked",
      "url": "https://aifitnessapi.com/fix/healthkit-authorization-not-determined",
      "markdown": "https://aifitnessapi.com/fix/healthkit-authorization-not-determined.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "Does not determined mean the user denied my app?",
          "answer": "No. Apple's abstract states the app has not yet asked the user for the authorization required to complete the task. Nobody has made a decision. A refused write is a different case, which Apple describes as the user not having given permission to save data, and its discussion notes it occurs only when your app attempts to save.",
          "url": "https://aifitnessapi.com/fix/healthkit-authorization-not-determined#faq-1"
        },
        {
          "question": "Why does this happen when my onboarding already requests authorization?",
          "answer": "Because your onboarding is not the only way into HealthKit code. Widgets, extensions, background delivery wake-ups, a watch app launched from the wrist, and deep links can all make the first call in a process. Authorization is also per type, so a feature that reads a type missing from your original request set is back in the never-asked state.",
          "url": "https://aifitnessapi.com/fix/healthkit-authorization-not-determined#faq-2"
        },
        {
          "question": "Can I just request authorization again to clear it?",
          "answer": "Requesting is exactly right when the state really is not determined. It is the wrong reflex once decisions have been made: Apple documents that if the user has already chosen for all the specified types, HealthKit returns the request without prompting. A grant access button that re-requests then does nothing visible and leaves the user stuck.",
          "url": "https://aifitnessapi.com/fix/healthkit-authorization-not-determined#faq-3"
        }
      ]
    },
    {
      "question": "healthkit errorrequiredauthorizationdenied",
      "answer": "Apple's documentation states that errorRequiredAuthorizationDenied means the user has not granted the application authorization to access all the required clinical record types. The load-bearing word is all: this is not one refused permission but an incomplete set. Apple's discussion adds that you specify those required clinical record types with an Info.plist key, so the requirement lives in your app's configuration rather than in the request itself. Because Apple states the system does not tell your app which record types were denied, the only real lever you have is declaring fewer required types and designing a path that still works without them.",
      "title": "HealthKit errorRequiredAuthorizationDenied: Clinical Records Are a Separate Class",
      "url": "https://aifitnessapi.com/fix/healthkit-required-authorization-denied",
      "markdown": "https://aifitnessapi.com/fix/healthkit-required-authorization-denied.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "Why does authorization fail even though the user allowed most types?",
          "answer": "Because the required set is all or nothing. Apple's abstract states the user has not granted authorization to access all the required clinical record types, so a single refusal inside the declared set fails the whole authorization. Anything you list under that key is a hard requirement, and the system enforces it exactly as written.",
          "url": "https://aifitnessapi.com/fix/healthkit-required-authorization-denied#faq-1"
        },
        {
          "question": "Can I find out which clinical record type the user refused?",
          "answer": "No. Apple states that the system does not tell your app which record types the person denied access to, which is quoted in our HealthKit authorization denied guide. That constrains your messaging: you can say the app needs access to all of the requested records, but you cannot name a specific one without guessing on the user's behalf.",
          "url": "https://aifitnessapi.com/fix/healthkit-required-authorization-denied#faq-2"
        },
        {
          "question": "How is this different from ordinary HealthKit authorization?",
          "answer": "Ordinary types are declared in the request, decided independently, and refusals on the read side are invisible by design. Required clinical types are declared in the app's property list, fail as a set, and produce this error case when the set is incomplete. Same framework, a different authorization class with different failure behaviour.",
          "url": "https://aifitnessapi.com/fix/healthkit-required-authorization-denied#faq-3"
        }
      ]
    },
    {
      "question": "healthkit workout session errors",
      "answer": "Four HKError cases end a workout session, and Apple describes only two of them. Apple's documentation states that errorAnotherWorkoutSessionStarted means another app started a session, and that Apple Watch runs one workout session at a time, so your session receives the error and then ends while the second one starts. Apple states that errorUserExitedWorkoutSession means the user exited your application while a session was running, and that workout sessions end when the app goes into the background. The remaining two, errorBackgroundWorkoutSessionNotAllowed and errorWorkoutActivityNotAllowed, are published with no abstract at all, so treat them as unknown codes rather than inferring behaviour. In every case the session is already gone, which makes continuous persistence the only real defence.",
      "title": "HealthKit Workout Session Errors: Four Cases, Two of Them Undocumented",
      "url": "https://aifitnessapi.com/fix/healthkit-workout-session-errors",
      "markdown": "https://aifitnessapi.com/fix/healthkit-workout-session-errors.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "Can two apps run a workout session at the same time?",
          "answer": "Apple's discussion states that Apple Watch only runs one workout session at a time. If the user begins a second session in a different app, Apple says the original session receives errorAnotherWorkoutSessionStarted and then ends, and the second session then starts. Your session is not being asked to yield; it is being told that it already has.",
          "url": "https://aifitnessapi.com/fix/healthkit-workout-session-errors#faq-1"
        },
        {
          "question": "Should my app restart the session automatically after this error?",
          "answer": "As a practice, no. Restarting takes the session back from whichever app the user just chose, and if that app is written the same way the two will fight over the wrist. Save what you have, say plainly that another app started a workout, and let the person decide what happens next.",
          "url": "https://aifitnessapi.com/fix/healthkit-workout-session-errors#faq-2"
        },
        {
          "question": "What do the two undocumented workout errors mean?",
          "answer": "Apple publishes no abstract and no discussion for errorBackgroundWorkoutSessionNotAllowed or errorWorkoutActivityNotAllowed, so the honest answer is that Apple documents nothing. Their names suggest where to look in your own app, which is a hypothesis to test, not a fact about the framework. Log the raw code, keep the session data, and avoid encoding a guess.",
          "url": "https://aifitnessapi.com/fix/healthkit-workout-session-errors#faq-3"
        }
      ]
    },
    {
      "question": "healthkit errornotpermissibleforguestusermode",
      "answer": "Apple's documentation states that errorNotPermissibleForGuestUserMode means the app attempted to write HealthKit data while in a Guest User session in visionOS, and publishes no discussion beyond that abstract. Apple's guest-session guidance, quoted in our authorization guide, adds that permissions do not change during a guest session, so your status check still reports the owner's grant while the save fails. Apple also states the authorization sheet is not displayed, so requests during a guest session fail silently, and suggests silently ignoring the write error for passive or periodic saves. The practical handling is to buffer the data, stay quiet unless the guest explicitly asked to save, and never treat the failure as a denial.",
      "title": "HealthKit errorNotPermissibleForGuestUserMode: Writes Blocked in a Guest Session",
      "url": "https://aifitnessapi.com/fix/healthkit-guest-user-mode",
      "markdown": "https://aifitnessapi.com/fix/healthkit-guest-user-mode.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "Why does my authorization status say authorized when the save fails?",
          "answer": "Because the status belongs to the device owner. Apple states that in a Guest User session an app's permissions do not change, so the value you read is a true answer about the owner and an irrelevant one about the guest wearing the headset. No status check can predict this failure, which is why the error itself has to be handled.",
          "url": "https://aifitnessapi.com/fix/healthkit-guest-user-mode#faq-1"
        },
        {
          "question": "Should I show the guest an error when a HealthKit write fails?",
          "answer": "Usually not. Apple suggests silently ignoring the error for passive or periodic saves, and alerting only when the guest took an action that obviously implies saving. A background sync failing is not worth a dialog; a tap on save this workout is, and it should say the device is in a guest session rather than blaming permissions.",
          "url": "https://aifitnessapi.com/fix/healthkit-guest-user-mode#faq-2"
        },
        {
          "question": "Can a guest still read HealthKit data?",
          "answer": "Apple states that a guest can read data the owner already authorized, but cannot authorize additional types, and that the authorization sheet is not displayed so requests fail silently. So keep read-driven content working during a guest session, and expect writes to fail with this case, or with errorHealthDataRestricted on apps running in iOS 17.",
          "url": "https://aifitnessapi.com/fix/healthkit-guest-user-mode#faq-3"
        }
      ]
    },
    {
      "question": "undocumented healthkit error codes",
      "answer": "Several HKError cases are published with no description whatsoever: unknownError, errorDataSizeExceeded, errorBackgroundWorkoutSessionNotAllowed, and errorWorkoutActivityNotAllowed all appear as type properties with no abstract and no discussion. Apple documents nothing about when any of them is returned, and the oldest of them has been present since the earliest HealthKit releases without ever acquiring one. A name can legitimately point you at where to look in your own app; it cannot tell you what the framework decided. The workable strategy is to log the raw domain and code, fail soft without discarding the user's data, bound your retries, and keep your inferences labelled as inferences.",
      "title": "Undocumented HealthKit Errors: Handling a Case Apple Never Described",
      "url": "https://aifitnessapi.com/fix/healthkit-undocumented-errors",
      "markdown": "https://aifitnessapi.com/fix/healthkit-undocumented-errors.md",
      "cluster": "Troubleshooting",
      "cluster_url": "https://aifitnessapi.com/fix",
      "last_reviewed": "2026-09-04",
      "first_party": false,
      "faqs": [
        {
          "question": "Which HealthKit error cases has Apple not documented?",
          "answer": "unknownError, errorDataSizeExceeded, errorBackgroundWorkoutSessionNotAllowed, and errorWorkoutActivityNotAllowed are published as type properties with no abstract and no discussion. Apple lists their names and the platforms they exist on, and nothing more. Most of the described cases, by contrast, appear in Apple's accessing-errors listing with an abstract and often a discussion paragraph.",
          "url": "https://aifitnessapi.com/fix/healthkit-undocumented-errors#faq-1"
        },
        {
          "question": "Can I infer what errorDataSizeExceeded means from its name?",
          "answer": "You can use the name to decide where to look, and no further. A sensible investigation is to examine what your app just tried to write and how large it was. Turning that into a user-facing message about a size limit invents both a mechanism and a threshold that Apple has never published.",
          "url": "https://aifitnessapi.com/fix/healthkit-undocumented-errors#faq-2"
        },
        {
          "question": "How should my app handle an unknown HealthKit error code?",
          "answer": "Log the raw domain and numeric code together with the operation and type identifier, keep the data you were trying to write and mark it unsynced, allow a small bounded number of retries, then stop. Alert on clusters rather than single occurrences, and never map an undocumented code to a confident explanation in your UI.",
          "url": "https://aifitnessapi.com/fix/healthkit-undocumented-errors#faq-3"
        }
      ]
    },
    {
      "question": "what is a fitness API",
      "answer": "A fitness API is a service that lets your application programmatically retrieve fitness or health data, or invoke a fitness capability, without building the underlying data pipeline yourself. Most are HTTP/REST web services you call over the network; a key exception is on-device health stores like Apple HealthKit and Google Health Connect, which you reach through the phone's operating system rather than a remote server. It is a category, not a single product: exercise-content databases, wearable-metric APIs, nutrition APIs, AI-motion SDKs, and aggregators are all fitness APIs, each solving a different job.",
      "title": "What Is a Fitness API?",
      "url": "https://aifitnessapi.com/learn/what-is-a-fitness-api",
      "markdown": "https://aifitnessapi.com/learn/what-is-a-fitness-api.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What is a fitness API in simple terms?",
          "answer": "It is a documented way for your app to get fitness or health data, or trigger a fitness feature, from another service. Your app sends a request and receives structured data back, usually JSON. Most fitness APIs are web services you call over HTTPS with an auth token; on-device stores such as Apple HealthKit and Google Health Connect are an exception, read through the phone's operating system with no remote server to call.",
          "url": "https://aifitnessapi.com/learn/what-is-a-fitness-api#faq-1"
        },
        {
          "question": "What are the main types of fitness API?",
          "answer": "There are roughly five categories: exercise and workout content APIs (libraries of exercises, demos, and plans), wearable and activity-metric APIs (steps, heart rate, sleep, calories from devices), nutrition APIs (food databases and macro logging), AI-motion or computer-vision SDKs (camera-based pose estimation, rep counting, and form feedback), and aggregators that unify many sources behind one normalized API. Choosing the right category is usually the main architectural decision.",
          "url": "https://aifitnessapi.com/learn/what-is-a-fitness-api#faq-2"
        },
        {
          "question": "Is a fitness API the same as Fitbit's API or HealthKit?",
          "answer": "No. 'Fitness API' is the general category; Fitbit's API, Terra, and Apple HealthKit are specific implementations of it. Answering 'which fitness API should I use?' usually means first choosing a category (content, wearable metrics, nutrition, AI motion, or aggregator), then comparing the individual providers within that category.",
          "url": "https://aifitnessapi.com/learn/what-is-a-fitness-api#faq-3"
        },
        {
          "question": "How do I connect my app to a fitness API?",
          "answer": "For cloud APIs, you register a developer app for credentials, have the user authorize your app via OAuth 2.0 to get scoped tokens, call the endpoints with those tokens, and often receive updates through webhooks. For on-device stores you request OS-level permissions instead of using OAuth, and read a local data store on the phone. The exact steps per provider are covered in the integration guides.",
          "url": "https://aifitnessapi.com/learn/what-is-a-fitness-api#faq-4"
        },
        {
          "question": "Why use a fitness API instead of building it yourself?",
          "answer": "A fitness API gives you leverage: you ship features like device sync, an exercise library, calorie logging, or camera coaching without building the hardware integrations, data pipelines, or machine-learning models underneath them. You integrate against a documented contract rather than reverse-engineering a wearable or training a pose model from scratch.",
          "url": "https://aifitnessapi.com/learn/what-is-a-fitness-api#faq-5"
        }
      ]
    },
    {
      "question": "what is a health data aggregator",
      "answer": "A health-data aggregator is a single third-party service that connects to many wearables and health providers on your behalf and returns their data in one standardized schema, delivered to a webhook. You integrate once instead of building a separate integration for Fitbit, Garmin, Oura, Whoop, and every other source. The main options as of 2026 are Terra, Junction (formerly Vital), Rook, and Spike.",
      "title": "What Is a Health-Data Aggregator?",
      "url": "https://aifitnessapi.com/learn/what-is-a-health-data-aggregator",
      "markdown": "https://aifitnessapi.com/learn/what-is-a-health-data-aggregator.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What is a health-data aggregator?",
          "answer": "It is a single third-party integration that connects to many wearables and health providers, normalizes their data into one consistent schema, and delivers new data to your webhook. It saves you from building and maintaining a separate integration for each device. Terra, Junction (formerly Vital), Rook, and Spike are the main providers as of 2026.",
          "url": "https://aifitnessapi.com/learn/what-is-a-health-data-aggregator#faq-1"
        },
        {
          "question": "Why use a health-data aggregator instead of integrating each provider directly?",
          "answer": "To avoid the 'N integrations' problem. Supporting five wearables directly means five OAuth setups, five data formats, five sets of rate limits, and five sources of breaking changes to maintain forever. An aggregator collapses that into one integration and one schema, so adding another device is usually a config change rather than a new project.",
          "url": "https://aifitnessapi.com/learn/what-is-a-health-data-aggregator#faq-2"
        },
        {
          "question": "How does a health-data aggregator work?",
          "answer": "You integrate once and register a webhook endpoint. The user connects their device through the aggregator's widget or connect flow, which orchestrates the underlying OAuth or on-device permission for you. When the device syncs, the aggregator normalizes the data and POSTs it to your endpoint in its standard schema, so you get fresh data without polling.",
          "url": "https://aifitnessapi.com/learn/what-is-a-health-data-aggregator#faq-3"
        },
        {
          "question": "What are the trade-offs of using an aggregator?",
          "answer": "You pay a recurring vendor fee (often per connected user) on top of the providers themselves. For several sources such as Garmin you may still need to register your own developer app and get approved. The normalized schema may not expose every provider-specific field, and health data now flows through a third party, so HIPAA and SOC 2 posture and a BAA matter. Verify per-provider requirements and vendor compliance status.",
          "url": "https://aifitnessapi.com/learn/what-is-a-health-data-aggregator#faq-4"
        },
        {
          "question": "Does an aggregator cover both cloud APIs and on-device data like Apple HealthKit?",
          "answer": "Yes. An aggregator's servers pull from cloud/OAuth providers (Fitbit, Garmin, Oura, Whoop, Strava), and its mobile SDKs read from on-device stores like Apple HealthKit and Google Health Connect. It unifies both routes behind one integration rather than being an either/or layer.",
          "url": "https://aifitnessapi.com/learn/what-is-a-health-data-aggregator#faq-5"
        }
      ]
    },
    {
      "question": "on-device vs cloud health data",
      "answer": "Health and fitness data reaches your app by one of three routes. On-device stores like Apple HealthKit and Google Health Connect hold data on the user's phone under an OS-granted permission, with no vendor server to query. Cloud or OAuth APIs like Fitbit, Strava, and Oura keep data on the provider's servers, and your backend fetches it server-to-server using OAuth tokens. Aggregators like Terra and Junction are a single integration that fronts both. On-device is privacy-forward but platform-locked and device-bound; cloud/OAuth gives always-on server access across platforms; aggregators buy reach across both for a recurring fee.",
      "title": "On-Device vs Cloud Health Data: What's the Difference?",
      "url": "https://aifitnessapi.com/learn/on-device-vs-cloud-health-data",
      "markdown": "https://aifitnessapi.com/learn/on-device-vs-cloud-health-data.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the difference between on-device and cloud health data?",
          "answer": "On-device health data lives in an encrypted store on the user's phone (Apple HealthKit on iOS, Google Health Connect on Android), and your app reads it locally after the user grants an OS permission. Cloud health data lives on a provider's servers (Fitbit, Strava, Oura), and your backend fetches it server-to-server using OAuth tokens. The key practical difference is that cloud APIs give you always-on server access without the phone, while on-device access requires your app to be installed and running on that specific device.",
          "url": "https://aifitnessapi.com/learn/on-device-vs-cloud-health-data#faq-1"
        },
        {
          "question": "Do Apple HealthKit and Google Health Connect use OAuth?",
          "answer": "No. Both use OS-level permissions rather than OAuth. The user grants access per data type in a system dialog, there is no access or refresh token, and there is no server to present a token to. OAuth is used by cloud providers such as Fitbit, Strava, and Garmin, whose data lives on their own servers.",
          "url": "https://aifitnessapi.com/learn/on-device-vs-cloud-health-data#faq-2"
        },
        {
          "question": "When should I use a cloud API instead of an on-device store?",
          "answer": "Use a cloud/OAuth API when you need server-side, always-on access that does not depend on a specific phone being present, or when the data simply lives in the provider's cloud, such as Strava activities or Fitbit account history. Use an on-device store when you want the richest first-party phone data, you have a native app on that platform, and you are comfortable that access is device-bound and per-platform.",
          "url": "https://aifitnessapi.com/learn/on-device-vs-cloud-health-data#faq-3"
        },
        {
          "question": "Can I get both on-device and cloud data through one integration?",
          "answer": "Yes, that is what an aggregator like Terra, Junction, Rook, or Spike does. It orchestrates OAuth for cloud providers and, via mobile SDKs, can read on-device stores, then returns everything in one normalized schema. The trade-offs are a recurring vendor fee and a third party in your data path, which raises HIPAA and business-associate-agreement considerations to verify per vendor.",
          "url": "https://aifitnessapi.com/learn/on-device-vs-cloud-health-data#faq-4"
        },
        {
          "question": "Is on-device health data more private than cloud data?",
          "answer": "Generally yes, in the sense that on-device data stays on the phone and never touches a vendor's cloud unless your own app uploads it. HealthKit permissions are also privacy-preserving, since an app can be told nothing about read denials and users can revoke individual data types silently. Cloud data, by contrast, flows through the provider's servers, so its handling and your own storage of it carry more privacy and compliance weight.",
          "url": "https://aifitnessapi.com/learn/on-device-vs-cloud-health-data#faq-5"
        }
      ]
    },
    {
      "question": "OAuth for health data",
      "answer": "OAuth 2.0 is the industry-standard authorization framework that lets a user grant your app limited access to their data on another service without sharing their password. Cloud health APIs like Fitbit, Strava, Oura, and Garmin use its authorization-code flow: the user consents on the provider's screen, your app receives an access token (scoped to specific data) plus a refresh token to renew it, and the user can revoke access at any time. Health APIs use it because health data is user-owned and sensitive, so consent must be explicit, granular, and revocable. The key exception is on-device stores — Apple HealthKit and Google Health Connect use OS-level permissions, not OAuth, with no tokens at all.",
      "title": "What Is OAuth 2.0 (and How Health APIs Use It)?",
      "url": "https://aifitnessapi.com/learn/what-is-oauth-for-health-data",
      "markdown": "https://aifitnessapi.com/learn/what-is-oauth-for-health-data.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What is OAuth 2.0 in simple terms?",
          "answer": "OAuth 2.0 is an authorization framework that lets a user grant one app limited access to their data on another service without sharing their password. Your app never sees the user's login; it receives a token scoped to only the data the user approved, and the user can revoke that token whenever they want.",
          "url": "https://aifitnessapi.com/learn/what-is-oauth-for-health-data#faq-1"
        },
        {
          "question": "How does the OAuth authorization-code flow work?",
          "answer": "Your app redirects the user to the provider's consent screen listing the scopes you request. The user logs in at the provider and approves, and the provider redirects back with a short-lived authorization code. Your backend exchanges that code for an access token and a refresh token, then calls the API with the access token and uses the refresh token to renew it when it expires.",
          "url": "https://aifitnessapi.com/learn/what-is-oauth-for-health-data#faq-2"
        },
        {
          "question": "What is the difference between an access token and a refresh token?",
          "answer": "An access token is short-lived (often about an hour) and is sent on every API call to authenticate the request. A refresh token is long-lived and is exchanged for a new access token when the old one expires, so the user does not have to re-approve. When a refresh token itself stops working, the user must re-authorize.",
          "url": "https://aifitnessapi.com/learn/what-is-oauth-for-health-data#faq-3"
        },
        {
          "question": "Why do health APIs use OAuth instead of API keys?",
          "answer": "Health data is user-owned and sensitive, so authorization must be tied to the individual user's explicit consent. OAuth gives the user granular, revocable, per-scope permission, keeps their password with the provider, and limits the blast radius through scopes and expiring tokens. A shared API key or password offers none of that.",
          "url": "https://aifitnessapi.com/learn/what-is-oauth-for-health-data#faq-4"
        },
        {
          "question": "Do HealthKit and Health Connect use OAuth?",
          "answer": "No. Apple HealthKit and Google Health Connect are on-device stores that use OS-level permissions instead of OAuth. The user grants access per data type in a system dialog, there is no access or refresh token, and there is no server to present a token to. OAuth applies to cloud providers whose data lives on their servers, such as Fitbit, Strava, Oura, and Garmin.",
          "url": "https://aifitnessapi.com/learn/what-is-oauth-for-health-data#faq-5"
        }
      ]
    },
    {
      "question": "what are webhooks",
      "answer": "A webhook is a server-to-server push notification: instead of your app repeatedly polling a provider for new data, the provider sends an HTTP POST to a callback URL you register the moment a relevant event happens, such as a wearable syncing a new workout. Webhooks are secured with a validation handshake (you prove you own the endpoint) and signature verification (you check each payload was really sent by the provider). Fitness APIs favor them because wearable data arrives unpredictably, and webhooks deliver it near-real-time instead of leaving you to poll too often (hitting rate limits) or too rarely (showing stale data).",
      "title": "What Are Webhooks (and Why Fitness APIs Use Them)?",
      "url": "https://aifitnessapi.com/learn/what-are-webhooks",
      "markdown": "https://aifitnessapi.com/learn/what-are-webhooks.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What is a webhook in simple terms?",
          "answer": "It is a way for one server to notify another automatically. Instead of your app asking a provider 'any new data?' on a timer (polling), the provider sends an HTTP POST to a URL you gave it whenever an event happens. Think of it as a doorbell: the provider rings your endpoint when there is something new, rather than you checking the door repeatedly.",
          "url": "https://aifitnessapi.com/learn/what-are-webhooks#faq-1"
        },
        {
          "question": "What is the difference between webhooks and polling?",
          "answer": "Polling is your server pulling data on a schedule; a webhook is the provider's server pushing data to you when an event occurs. Polling is simpler to set up but wasteful and either laggy or rate-limit-hungry. Webhooks are more work to build correctly (public endpoint, handshake, signature checks) but deliver fresh data near-real-time and use far fewer API calls.",
          "url": "https://aifitnessapi.com/learn/what-are-webhooks#faq-2"
        },
        {
          "question": "How do you verify a webhook is legitimate?",
          "answer": "Two mechanisms. First, a validation handshake at setup, where the provider sends a challenge value your endpoint must echo back before webhooks activate. Second, signature verification on every event: the provider signs the payload (commonly an HMAC in a header) with a shared secret, and you recompute that signature over the raw body and reject any request that does not match. Always use HTTPS.",
          "url": "https://aifitnessapi.com/learn/what-are-webhooks#faq-3"
        },
        {
          "question": "Does a webhook payload contain all the data?",
          "answer": "Often no. Many webhooks are 'thin' notifications that tell you something changed and give you an ID (for example, a new activity ID), not the full record. You then call the provider's regular API with that ID to fetch the details. So a webhook is frequently a signal to go retrieve data, not the data delivery itself.",
          "url": "https://aifitnessapi.com/learn/what-are-webhooks#faq-4"
        },
        {
          "question": "Why do fitness and wearable APIs use webhooks?",
          "answer": "Wearable data arrives sporadically, whenever a device syncs, so there is no good polling interval. Poll too often and you burn through rate limits getting mostly empty responses; poll too rarely and your app shows stale numbers. Webhooks deliver data the instant the provider has it, which is what makes recovery scores, live activity feeds, and timely coaching feel current.",
          "url": "https://aifitnessapi.com/learn/what-are-webhooks#faq-5"
        }
      ]
    },
    {
      "question": "what is pose estimation",
      "answer": "Pose estimation is a computer-vision technique that locates body keypoints (joints such as shoulders, elbows, hips, and knees) in a camera image or video frame and outputs their coordinates plus a confidence score. A trained model returns those keypoints per frame, in 2D or rough 3D. In fitness apps it is the foundation for camera-based rep counting and form feedback: your app turns the keypoints into joint angles and motion over time. It typically runs on-device and in real time, so camera frames stay on the phone.",
      "title": "What Is Pose Estimation (for Fitness Apps)?",
      "url": "https://aifitnessapi.com/learn/what-is-pose-estimation",
      "markdown": "https://aifitnessapi.com/learn/what-is-pose-estimation.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What is pose estimation in simple terms?",
          "answer": "It is computer vision that finds where a person's joints are in a camera frame. A model looks at each frame and returns coordinates for a fixed set of body keypoints — shoulders, elbows, hips, knees, ankles, and so on — usually with a confidence score for each. Those keypoints are the raw data behind camera-based rep counting and form feedback.",
          "url": "https://aifitnessapi.com/learn/what-is-pose-estimation#faq-1"
        },
        {
          "question": "How does pose estimation work?",
          "answer": "A trained model takes a camera frame and predicts the pixel position (and sometimes a depth value) of each landmark, plus a confidence score. Your app then turns those keypoints into meaning: joint angles to judge depth, motion over time to count reps, and alignment checks to flag form issues. The model provides geometry; your app decides what a good rep and good form look like.",
          "url": "https://aifitnessapi.com/learn/what-is-pose-estimation#faq-2"
        },
        {
          "question": "How many keypoints does pose estimation track?",
          "answer": "It depends on the model. MediaPipe BlazePose tracks 33 keypoints (the 17 standard COCO body points plus extra face, hand, and foot landmarks, with 3D output), while TensorFlow MoveNet tracks 17 and is optimized for speed. More points is a trade-off, not automatically better. Verify keypoint counts against current model docs, since specs change across versions.",
          "url": "https://aifitnessapi.com/learn/what-is-pose-estimation#faq-3"
        },
        {
          "question": "Do I have to train my own pose model?",
          "answer": "No, and for a fitness app you almost certainly should not. Pose estimation ships as an embedded SDK or library you drop in — MediaPipe, TensorFlow's MoveNet, or a vendor SDK — already trained on large, varied datasets of people. Your work starts after the model returns keypoints: turning them into joint angles, rep cycles, and form checks is where the product actually lives. Training your own keypoint model means collecting and labelling body data at scale to beat a well-funded baseline, which is a research programme, not a feature. Treat the model as a component.",
          "url": "https://aifitnessapi.com/learn/what-is-pose-estimation#faq-4"
        },
        {
          "question": "What are the limits of pose estimation?",
          "answer": "Accuracy depends on physical conditions. Poor framing (body out of frame, too close or too far), bad lighting, and occlusion (one body part hiding another) all reduce confidence and can cause jitter or wrong keypoints. Treat low-confidence keypoints as uncertain rather than exact, and coach users into a good setup — full body in frame, decent light.",
          "url": "https://aifitnessapi.com/learn/what-is-pose-estimation#faq-5"
        }
      ]
    },
    {
      "question": "what is HRV",
      "answer": "Heart rate variability (HRV) is the variation in time between consecutive heartbeats. Wearables derive it from the inter-beat intervals captured by an optical (PPG) or electrical (ECG) sensor, usually averaged over an overnight window, and typically report the time-domain metric RMSSD in milliseconds (SDNN, the overall variability, is classically a 24-hour clinical measure). It is used as a general recovery and stress-balance signal, not a diagnosis. HRV is highly individual, so it should be compared against a person's own baseline, never across people or between brands.",
      "title": "What Is HRV (Heart Rate Variability)?",
      "url": "https://aifitnessapi.com/learn/what-is-hrv",
      "markdown": "https://aifitnessapi.com/learn/what-is-hrv.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What does HRV measure?",
          "answer": "It measures how much the time between consecutive heartbeats varies. The raw input is the inter-beat interval (the RR or NN interval, in milliseconds), and HRV summarizes the spread of those intervals with metrics like RMSSD (short-term, parasympathetic variability), which most wearables report; SDNN (overall variability) is classically a 24-hour clinical measure. Higher variability generally reflects more 'rest and digest' influence. It is a general wellness signal, not a clinical diagnosis.",
          "url": "https://aifitnessapi.com/learn/what-is-hrv#faq-1"
        },
        {
          "question": "How do wearables measure HRV?",
          "answer": "They time the gaps between heartbeats. Most wrist and ring devices use optical PPG sensors (green LEDs reading blood-volume pulses), while chest straps and ECG watches read the heart's electrical signal directly, which is more precise. Because single readings are noisy, devices usually compute HRV over a consistent overnight window while you are still, then report an averaged daily value.",
          "url": "https://aifitnessapi.com/learn/what-is-hrv#faq-2"
        },
        {
          "question": "What is a good HRV number?",
          "answer": "There is no universal 'good' number, and comparing your HRV to someone else's or to a chart is misleading. Population ranges are very wide and strongly age-dependent, so an absolute value means little on its own. What matters is the trend against your own rolling baseline, measured the same way each night. Treat lower-than-your-baseline HRV as directional wellness information, not a diagnosis.",
          "url": "https://aifitnessapi.com/learn/what-is-hrv#faq-3"
        },
        {
          "question": "Can I compare HRV across different devices or brands?",
          "answer": "Not reliably. Different sensors (PPG vs. ECG), different aggregation windows, and proprietary algorithms mean the same person's HRV will differ between Apple, Garmin, Fitbit, Oura, Whoop, and others. HRV values are not interchangeable across brands, so keep a user on one device for trend tracking and avoid implying a number is portable.",
          "url": "https://aifitnessapi.com/learn/what-is-hrv#faq-4"
        },
        {
          "question": "How does HRV appear in a wearable API?",
          "answer": "Usually as a single daily (typically nightly) value on a sleep or daily-summary object, with field names like hrv_rmssd, rmssd, average_hrv, or sometimes hrv_sdnn, expressed in milliseconds. Some APIs also expose raw rr_intervals or ibi arrays so you can compute your own metric. The aggregation window differs by vendor, so confirm the exact field, unit, and window in the specific API docs.",
          "url": "https://aifitnessapi.com/learn/what-is-hrv#faq-5"
        }
      ]
    },
    {
      "question": "what is VO2 max",
      "answer": "VO2 max is the maximum rate at which the body can consume oxygen during intense exercise, measured in milliliters of oxygen per kilogram per minute (mL/kg/min), and it is a widely used proxy for aerobic fitness. On a wearable or fitness API it is almost always an estimate, not a measurement: the device models it from your heart rate and pace during activity rather than the lab gas-analysis test that produces a true VO2 max. Treat the number as a fitness trend to watch over time, not a precise clinical value. This is general wellness information, not medical advice.",
      "title": "What Is VO2 Max (and How Do Wearables Estimate It)?",
      "url": "https://aifitnessapi.com/learn/what-is-vo2-max",
      "markdown": "https://aifitnessapi.com/learn/what-is-vo2-max.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Is wearable VO2 max measured or estimated?",
          "answer": "Estimated. A true VO2 max comes from a lab graded-exercise test where you breathe through a gas-analysis mask (indirect calorimetry). Wearables do not measure oxygen uptake at all; they model VO2 max from the relationship between your heart rate and pace or speed during activity, usually a GPS-tracked run or walk.",
          "url": "https://aifitnessapi.com/learn/what-is-vo2-max#faq-1"
        },
        {
          "question": "How accurate is VO2 max from a smartwatch?",
          "answer": "It varies. Accuracy depends more on method than brand: estimates from an actual workout tend to have low average bias, while resting estimates can overestimate. One Apple Watch validation study reported roughly 13% mean absolute percentage error (as of 2026, verify against the current study). Individual numbers can be off by several points, so use VO2 max as a trend and a ballpark rather than a precise figure.",
          "url": "https://aifitnessapi.com/learn/what-is-vo2-max#faq-2"
        },
        {
          "question": "What is a good VO2 max?",
          "answer": "VO2 max is expressed in mL/kg/min, often in the 30s to 50s for many recreational adults and higher for trained endurance athletes, declining gradually with age (directional ranges only — verify against a current source, don't use as cutoffs). Because values are directional and vary by person, age, and device, the most useful comparison is against your own trend over time rather than a fixed target. This is general information, not medical advice.",
          "url": "https://aifitnessapi.com/learn/what-is-vo2-max#faq-3"
        },
        {
          "question": "How does VO2 max appear in a fitness API?",
          "answer": "Usually as a single scalar field such as vo2_max or vo2Max in mL/kg/min on a user-summary or activity-summary object, sometimes with a fitness_age or category label. It updates after a qualifying GPS-tracked run or walk rather than as a continuous time series. Confirm the exact field name, unit, and update cadence in the specific vendor or aggregator docs.",
          "url": "https://aifitnessapi.com/learn/what-is-vo2-max#faq-4"
        },
        {
          "question": "Why do Apple and Garmin show different VO2 max numbers?",
          "answer": "Each vendor uses its own model and inputs. Garmin relies on Firstbeat Analytics from heart-rate-versus-pace data, while Apple combines heart-rate-response modeling with machine learning using signals like walking heart rate and heart-rate recovery. Because the estimates come from different algorithms, the same person can get different values, and the numbers are not interchangeable across brands.",
          "url": "https://aifitnessapi.com/learn/what-is-vo2-max#faq-5"
        }
      ]
    },
    {
      "question": "what are sleep stages",
      "answer": "Sleep stages are the distinct phases the body cycles through during sleep, commonly grouped as awake, light, deep, and REM. Clinically they are defined by brain activity (EEG) in a sleep lab, but consumer wearables estimate them from movement and heart-rate patterns rather than measuring brainwaves. They are a directional wellness signal, useful for trends across nights, not clinical fact for any single night. This is general information for developers, not medical advice.",
      "title": "What Are Sleep Stages (Awake, Light, Deep, REM)?",
      "url": "https://aifitnessapi.com/learn/what-are-sleep-stages",
      "markdown": "https://aifitnessapi.com/learn/what-are-sleep-stages.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What are the four sleep stages?",
          "answer": "Awake (periods of wakefulness and brief arousals), light sleep (clinically N1 and N2, the largest share of a typical night), deep sleep (N3 or slow-wave sleep, often described as the most physically restorative and the hardest to wake from), and REM (rapid eye movement, associated with vivid dreaming). They repeat in roughly 90-minute cycles, and stage proportions vary by person, age, and night.",
          "url": "https://aifitnessapi.com/learn/what-are-sleep-stages#faq-1"
        },
        {
          "question": "How do wearables measure sleep stages?",
          "answer": "They do not read brainwaves. Consumer wearables estimate stages by inferring them from movement (an accelerometer) combined with heart rate and heart-rate variability, and on some devices respiration, temperature, or blood oxygen. A proprietary algorithm maps those signals to a probable stage. That makes every stage label a model estimate, not the EEG measurement used in a clinical sleep study.",
          "url": "https://aifitnessapi.com/learn/what-are-sleep-stages#faq-2"
        },
        {
          "question": "How accurate is sleep-stage tracking on a wearable?",
          "answer": "Directionally useful but limited for exact stages. Validation studies find wearables are fairly good at telling sleep from wake (often around 90% or better) but much weaker at four-stage classification, commonly reporting roughly 60 to 70 percent agreement with a clinical sleep study (polysomnography). REM is often underestimated and light-versus-deep is frequently misclassified. Accuracy varies by vendor and firmware, so treat stage numbers as trends, not per-night truth, and verify current figures against a primary source.",
          "url": "https://aifitnessapi.com/learn/what-are-sleep-stages#faq-3"
        },
        {
          "question": "How do sleep stages appear in a wearable API?",
          "answer": "Usually as a nightly sleep object with per-stage durations (for example light, deep, REM, and awake in seconds or minutes) plus totals like time in bed and total sleep, and a stages or levels array of timestamped segments each with a stage, start, and end. Many APIs also include a summary sleep score or efficiency. Field names, units, and aggregation windows differ by vendor, so confirm them in the specific API docs.",
          "url": "https://aifitnessapi.com/learn/what-are-sleep-stages#faq-4"
        },
        {
          "question": "Can I use wearable sleep stages for medical decisions?",
          "answer": "No. Consumer sleep-stage estimates are a general wellness signal, not a clinical measurement or a diagnosis of any sleep disorder. They are best used to track a person's own patterns over time against their own baseline. Keep any copy non-diagnostic, and direct users to a healthcare professional for medical concerns. This is general information for developers, not medical advice.",
          "url": "https://aifitnessapi.com/learn/what-are-sleep-stages#faq-5"
        }
      ]
    },
    {
      "question": "how fitness apps estimate calories",
      "answer": "Fitness apps do not measure calories burned; they estimate them with a model. The device feeds signals it can sense (movement and heart rate) plus your profile (age, sex, height, weight) into formulas — MET-based, heart-rate-based, and accelerometer-based — that output a calorie number. Independent testing shows that estimate can be far off: a 2017 Stanford study found the most accurate of seven wrist devices was still about 27% off for energy expenditure and the worst about 93% off, even though the same devices read heart rate to within about 5%. Treat calorie burn as a relative activity signal and trend, not a precise measurement.",
      "title": "How Do Fitness Apps Estimate Calories Burned?",
      "url": "https://aifitnessapi.com/learn/how-fitness-apps-estimate-calories",
      "markdown": "https://aifitnessapi.com/learn/how-fitness-apps-estimate-calories.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "How do fitness apps calculate calories burned?",
          "answer": "They estimate it with a model rather than measuring it. A calorie figure is assembled from some combination of METs (an activity's standardized energy cost applied to your weight and duration), heart-rate-based regression models, and accelerometer/movement data, all personalized with your age, sex, height, and weight. The output is a best-guess of energy expenditure, not a direct reading.",
          "url": "https://aifitnessapi.com/learn/how-fitness-apps-estimate-calories#faq-1"
        },
        {
          "question": "Are fitness app calorie counts accurate?",
          "answer": "Not very, in absolute terms. A 2017 Stanford study of seven wrist devices found the most accurate was still off by about 27% on average for energy expenditure and the worst by about 93% — while the same devices measured heart rate to within about 5%. Calorie burn is best used as a relative or trend signal for the same person on the same device, not as a precise number.",
          "url": "https://aifitnessapi.com/learn/how-fitness-apps-estimate-calories#faq-2"
        },
        {
          "question": "Why is calorie burn an estimate and not a measurement?",
          "answer": "Because a device has no way to directly measure energy expenditure. A true measurement needs lab methods like indirect calorimetry (a gas-analysis mask) or doubly labeled water. A wearable only has an accelerometer, usually an optical heart-rate sensor, and the profile you entered, so it must infer calories with a formula. Everything beyond the raw sensor signals is modeled.",
          "url": "https://aifitnessapi.com/learn/how-fitness-apps-estimate-calories#faq-3"
        },
        {
          "question": "Why do two devices show different calories for the same workout?",
          "answer": "Each device uses its own proprietary model, its own mix of METs, heart-rate, and movement inputs, and the profile data you gave it. Because calorie burn is a modeled estimate rather than a measurement, those differences produce different numbers for the identical session, and neither is definitively correct. Don't compare calorie figures across brands.",
          "url": "https://aifitnessapi.com/learn/how-fitness-apps-estimate-calories#faq-4"
        },
        {
          "question": "How does calorie data appear in a fitness API?",
          "answer": "Usually as kilocalorie (kcal) fields on daily summaries and per workout — commonly an active_energy value (energy above resting from movement), a basal_energy value (resting energy), and a total. Each activity object typically carries a single calories scalar, and some APIs expose an intraday time series. Field names, units, and whether a value is active-only or total vary by vendor, so confirm in the specific API docs.",
          "url": "https://aifitnessapi.com/learn/how-fitness-apps-estimate-calories#faq-5"
        }
      ]
    },
    {
      "question": "webhooks vs polling for fitness data",
      "answer": "The first question is not which transport is better but whether you have a choice, because the provider often decides for you: Garmin pushes to callback URLs you register and does not let you poll, Android Health Connect has no push mechanism at all, and Strava, WHOOP and Fitbit offer an opt-in subscription on top of a pollable REST API. Poll when you have no public endpoint, when freshness is measured in hours, or when your user count sits comfortably inside per-user quotas like Fitbit's roughly 150 requests per hour per consented user. Push when arrival is unpredictable and quota pressure makes timer-based fetching expensive. Expect a hybrid either way: most fitness webhooks carry a pointer rather than data, so the webhook is really a cache-invalidation signal, and a low-frequency reconciliation poll stays as the only thing covering what the push stream drops.",
      "title": "Webhooks vs. Polling for Fitness Data: How to Decide",
      "url": "https://aifitnessapi.com/learn/webhooks-vs-polling-for-fitness-data",
      "markdown": "https://aifitnessapi.com/learn/webhooks-vs-polling-for-fitness-data.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "When is polling actually the right choice for a fitness integration?",
          "answer": "When you have no public HTTPS endpoint yet, when your freshness requirement is measured in hours rather than minutes, or when your user count sits well inside the provider's per-user quota. A weekly summary email or a nightly training-load recompute gains nothing from push. Polling is also the only option on Android Health Connect, where Google documents that your app cannot get notified of new data, so you check on foreground lifecycle events and periodically while foregrounded.",
          "url": "https://aifitnessapi.com/learn/webhooks-vs-polling-for-fitness-data#faq-1"
        },
        {
          "question": "How often should I poll a wearable API when there is no push option?",
          "answer": "Work it out from the quota rather than from taste: divide the provider's documented limit by your user count and by the number of calls each sync needs. Fitbit's limit is roughly 150 requests per hour per consented user as of 2026, which is generous for a per-user schedule but easy to burn with a tight loop. Strava's documented defaults are around 200 requests per 15 minutes and roughly 2,000 per day overall. Verify both against current docs, and stagger schedules so users are not all refreshed at once.",
          "url": "https://aifitnessapi.com/learn/webhooks-vs-polling-for-fitness-data#faq-2"
        },
        {
          "question": "Which wearable providers push data and which make you pull it?",
          "answer": "It varies more than people expect. Our Garmin guide documents push only, with callback URLs registered per summary type and no polling. Android Health Connect has no push at all. Apple HealthKit offers on-device observer queries with background delivery, gated by an entitlement. Strava, WHOOP and Fitbit all expose a pollable REST API plus an opt-in subscription or webhook. Terra, as an aggregator, pushes normalized data to a single Destination webhook by default. Confirm each against current provider docs before designing around it.",
          "url": "https://aifitnessapi.com/learn/webhooks-vs-polling-for-fitness-data#faq-3"
        },
        {
          "question": "Do webhooks make wearable data arrive faster than the device syncs?",
          "answer": "No. Data travels from the device to the vendor's phone app to the provider's cloud before anything reaches you, and each hop runs on its own schedule, often every few minutes to hourly and sometimes only when the user opens the vendor app. A webhook fires only once the provider's cloud has the data. Push shortens the last hop, not the chain, so sub-minute feedback during a workout is an on-device problem rather than a delivery-model choice.",
          "url": "https://aifitnessapi.com/learn/webhooks-vs-polling-for-fitness-data#faq-4"
        },
        {
          "question": "Is running a scheduled poll alongside push delivery wasteful?",
          "answer": "No, and it is usually the correct architecture. Because most fitness notifications are pointers rather than data, the effect of an event is to re-fetch a window and replace what you hold for it, which is exactly what a scheduled sweep does on a timer using the same fetch worker. The sweep is what covers a deploy where your endpoint returns 502, a dropped delivery, or a subscription disabled under a policy you never found documented. Push lets you turn its frequency down; it does not let you remove it.",
          "url": "https://aifitnessapi.com/learn/webhooks-vs-polling-for-fitness-data#faq-5"
        }
      ]
    },
    {
      "question": "what are oauth scopes",
      "answer": "An OAuth scope is a named string attached to an access token that caps what that token may read or write — Fitbit's activity or heartrate, Strava's activity:read_all, WHOOP's read:sleep. In health APIs the user grants them per collection rather than all-or-nothing, so the set you requested and the set you received routinely differ and you have to read the granted scope back out of the response. A scope is also only one layer of permission: an OS permission like HealthKit or Health Connect is a device access control, and a platform entitlement like Apple's HealthKit capability or Garmin's partner-level program grant is a build- or business-level gate, and each fails differently. The signature worth memorising is that a missing scope is a 403 with insufficient_scope rather than a 401, and refreshing never fixes it, because a refresh mints a token carrying the same scopes the user already granted.",
      "title": "What Are OAuth Scopes (and How Health APIs Grant Them)?",
      "url": "https://aifitnessapi.com/learn/what-are-oauth-scopes",
      "markdown": "https://aifitnessapi.com/learn/what-are-oauth-scopes.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Can a user grant only some of the scopes my app requested?",
          "answer": "Yes, and on health APIs you should assume they will. Fitbit documents that you cannot force a user to grant every scope because consent is per data collection, so someone can approve activity and decline heart rate. Strava athletes can deselect scopes on the consent screen, and Oura users can toggle individual scopes from its eight documented ones. Design each feature to degrade on its own when its collection is missing, rather than failing onboarding as a whole.",
          "url": "https://aifitnessapi.com/learn/what-are-oauth-scopes#faq-1"
        },
        {
          "question": "How do I find out which scopes were actually granted?",
          "answer": "Read them back from the provider rather than assuming. Fitbit returns a scope field in the token-exchange response alongside the access token, refresh token, expiry and user id. Strava returns the granted scope as a query parameter on the redirect to your callback as well as in the exchange. Watch the delimiter: Fitbit uses spaces and Strava uses commas, unlike most OAuth providers, so a parser reused across providers will silently decide a granted scope is absent.",
          "url": "https://aifitnessapi.com/learn/what-are-oauth-scopes#faq-2"
        },
        {
          "question": "Is an Android or iOS health permission the same thing as an OAuth scope?",
          "answer": "No. An OAuth scope is granted by the user at a cloud provider's consent screen and enforced by that provider's API. An OS permission is a device-level access control granted in a system sheet per data type, and it behaves differently: HealthKit never tells you a read was denied, and Health Connect needs a manifest declaration, a runtime grant, and separate permissions again for background reads and for history. They are also different instruments legally, since a device permission is not automatically a lawful basis for what you do with the data afterwards.",
          "url": "https://aifitnessapi.com/learn/what-are-oauth-scopes#faq-3"
        },
        {
          "question": "Which error code means a scope is missing?",
          "answer": "A 403 Forbidden, mapping to the Bearer error insufficient_scope, means the token is authentic but not permitted to do that. A 401 Unauthorized, mapping to invalid_token, means the credential itself was rejected as missing, malformed, expired or revoked. Refreshing fixes many 401s and never fixes a 403, because the new token carries the same scopes. One caveat: providers overload 403, so on an Oura usercollection endpoint it can mean a missing scope or a lapsed membership.",
          "url": "https://aifitnessapi.com/learn/what-are-oauth-scopes#faq-4"
        },
        {
          "question": "Why did I get no refresh token even though the login worked?",
          "answer": "Usually because you omitted the scope that unlocks offline access. WHOOP documents offline as a required scope to receive a refresh token at all, and it controls capability rather than data. Without it the authorization succeeds, your first API calls succeed, and background sync then dies silently when the access token expires with nothing to renew it. Re-run the authorization flow with the correct scope; no amount of retrying the token endpoint helps.",
          "url": "https://aifitnessapi.com/learn/what-are-oauth-scopes#faq-5"
        }
      ]
    },
    {
      "question": "what is RPE",
      "answer": "RPE stands for rating of perceived exertion: a number a person gives to describe how hard an effort felt to them. It is a self-report rather than a measurement, so no sensor produces it and no wearable or health-data API exposes it, because there is nothing for a device to observe. Two conventions dominate: a 6-to-20 range commonly described as the Borg scale, and a modern 0-to-10 range usually anchored to reps in reserve, meaning how many more repetitions the person believes they had left. For a fitness app that makes RPE your own field in your own schema, collected from your own interface, and useful as a personal trend feeding auto-regulation rather than as a precise or cross-user comparable number.",
      "title": "What Is RPE (Rating of Perceived Exertion)?",
      "url": "https://aifitnessapi.com/learn/what-is-rpe",
      "markdown": "https://aifitnessapi.com/learn/what-is-rpe.md",
      "cluster": "Concepts",
      "cluster_url": "https://aifitnessapi.com/learn",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "What does RPE stand for in training?",
          "answer": "Rating of perceived exertion. It is a number someone gives to describe how hard an effort felt to them, and the operative word is felt: it is a judgement about a sensation, not a reading from a sensor. Because it is self-reported, it captures something no device can see, such as how heavy a familiar load felt after a bad night. It is also why the value is calibrated per person and drifts as someone gets more practised at using the scale.",
          "url": "https://aifitnessapi.com/learn/what-is-rpe#faq-1"
        },
        {
          "question": "What is the difference between the 6-20 and 0-10 RPE scales?",
          "answer": "They are two different conventions for labelling the same feeling, and they are not interchangeable. The 6-to-20 range is the older one, commonly described as the Borg scale, and its unusual endpoints make it easy to recognise in a dataset. The 0-to-10 range is the modern default in strength training and is commonly described in terms of reps in reserve, meaning how many more repetitions the person believes they could have done. There is no safe automatic conversion between them, so pick one, record which one you used, and never mix them in a single column.",
          "url": "https://aifitnessapi.com/learn/what-is-rpe#faq-2"
        },
        {
          "question": "Does any wearable API return RPE as a measured value?",
          "answer": "No, and it cannot. Wearables report sensor readings such as heart rate, heart-rate variability, GPS traces, steps, and sleep, plus vendor scores modelled from those signals. Perceived exertion has no sensor path, because it exists only as the person's own judgement. Vendor effort, strain, or intensity scores are sometimes mistaken for it, but they answer a different question, namely what the body did rather than what the person thought about it. Substituting one for the other quietly changes what your feature means.",
          "url": "https://aifitnessapi.com/learn/what-is-rpe#faq-3"
        },
        {
          "question": "How should a fitness app collect RPE from users?",
          "answer": "Ask close to the effort, keep it to one tap, and label the anchors. A rating given right after a set describes that set, while one given hours later describes the day. A row of buttons beats a slider and a slider beats a text field, because friction directly costs completion on an optional field. Short descriptions attached to the ends and middle of your scale help people apply it consistently. Expect most prompts to be skipped, so any logic reading the value must handle a missing rating rather than treating absence as an easy session.",
          "url": "https://aifitnessapi.com/learn/what-is-rpe#faq-4"
        },
        {
          "question": "Is RPE reliable enough to drive automatic plan adjustments?",
          "answer": "Treat it as one soft input among several, not a control signal on its own. It is genuinely informative because it captures cost that logged weight and reps cannot, but it is contaminated by mood, sleep, caffeine, and context, and users who notice that high ratings lighten tomorrow will report differently over time. The workable pattern is to trend it against the same person's own history, combine it with objective completion data, and keep the adjustment arithmetic in deterministic code you can inspect and test rather than in free-form model output.",
          "url": "https://aifitnessapi.com/learn/what-is-rpe#faq-5"
        }
      ]
    },
    {
      "question": "Fitbit API alternatives",
      "answer": "The main alternatives to the Fitbit Web API are the Google Health API (the first-party successor the legacy API is being consolidated into), health-data aggregators like Terra, Junction (formerly Vital), and Rook that cover Fitbit plus many devices through one integration, other single wearables like Garmin, Oura, or WHOOP, and on-device access via Apple HealthKit and Google Health Connect. Pick the Google Health API to stay on Fitbit data, an aggregator to support many devices without re-doing migration work, or a single-device API if you can standardize on one wearable.",
      "title": "The Best Fitbit API Alternatives (2026)",
      "url": "https://aifitnessapi.com/alternatives/fitbit-api-alternatives",
      "markdown": "https://aifitnessapi.com/alternatives/fitbit-api-alternatives.md",
      "cluster": "Alternatives",
      "cluster_url": "https://aifitnessapi.com/alternatives",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Why is everyone looking for a Fitbit API alternative in 2026?",
          "answer": "Google is consolidating the legacy Fitbit Web API into the new Google Health API. Existing access and refresh tokens do not transfer, so users must re-authenticate, and the endpoints, console, and schema change, which means real integration work. The timeline is still being finalized — verify current dates against Google's migration docs before planning.",
          "url": "https://aifitnessapi.com/alternatives/fitbit-api-alternatives#faq-1"
        },
        {
          "question": "Is the Google Health API a drop-in replacement for the Fitbit Web API?",
          "answer": "No. It is the first-party successor path, but it uses a new OAuth flow that requires every user to re-consent, a new schema and response format, and a new developer console. You keep access to the same underlying Fitbit data, but you should budget for a re-integration rather than a version bump.",
          "url": "https://aifitnessapi.com/alternatives/fitbit-api-alternatives#faq-2"
        },
        {
          "question": "Should I use an aggregator like Terra or Junction instead of migrating to Google?",
          "answer": "An aggregator makes sense if you support many wearables or want to avoid re-doing OAuth and schema work on Google's timeline — Fitbit becomes one normalized source behind a single integration. The trade-offs are a recurring per-connected-user cost, a third party in your data path (check HIPAA/SOC 2 and a BAA), and that some providers still require your own developer app.",
          "url": "https://aifitnessapi.com/alternatives/fitbit-api-alternatives#faq-3"
        },
        {
          "question": "Can I read Fitbit data on-device with HealthKit or Health Connect?",
          "answer": "Yes, if the user has synced Fitbit data into Apple Health or Google Health Connect, a mobile app can read it locally. This works well for mobile-first products, but it is on-device only and platform-split — you implement both HealthKit on iOS and Health Connect on Android, with no first-party server-side access.",
          "url": "https://aifitnessapi.com/alternatives/fitbit-api-alternatives#faq-4"
        },
        {
          "question": "Will I have to make users reconnect if I switch?",
          "answer": "In almost all cases, yes. Tokens do not transfer from the legacy Fitbit Web API, so users re-authenticate regardless of which alternative you choose. An aggregator can reduce the engineering to one integration and one field re-mapping, but it does not remove the user-reconnect step. Plan for reconnection churn, not just code changes.",
          "url": "https://aifitnessapi.com/alternatives/fitbit-api-alternatives#faq-5"
        }
      ]
    },
    {
      "question": "Google Fit API alternatives",
      "answer": "Google Fit's REST and Android APIs are deprecated (no new signups since 1 May 2024, support only until end of 2026, verify), and there is no drop-in 1:1 replacement, so migrating is a re-architecture. Pick by how you used Fit: for Android on-device data move to Google Health Connect; for cloud/account data you fetched server-side, look at the Google Health API / Fitbit path; for the iOS side of a cross-platform app use Apple HealthKit; and if you support many devices, use an aggregator (Terra, Junction, or Rook) to migrate once behind one schema.",
      "title": "Google Fit API Alternatives (It's Deprecated) (2026)",
      "url": "https://aifitnessapi.com/alternatives/google-fit-api-alternatives",
      "markdown": "https://aifitnessapi.com/alternatives/google-fit-api-alternatives.md",
      "cluster": "Alternatives",
      "cluster_url": "https://aifitnessapi.com/alternatives",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Is the Google Fit API being shut down?",
          "answer": "Yes. Google stopped accepting new developer signups for the Google Fit REST and Android APIs on 1 May 2024, and has said support runs only until the end of 2026 (verify the exact turndown date against Google's official docs). Existing integrations keep working until then, but no new projects can be created.",
          "url": "https://aifitnessapi.com/alternatives/google-fit-api-alternatives#faq-1"
        },
        {
          "question": "What is the direct replacement for the Google Fit API?",
          "answer": "There is no drop-in 1:1 replacement. For Android, Google points developers to Health Connect, but that is an on-device data store rather than a cloud REST API, so the architecture is different. For cloud/server-side use cases, the direction is the newer Google Health API and the Fitbit cloud integration being consolidated into it. Which one fits depends on whether you read on-device data or fetched account data from the cloud.",
          "url": "https://aifitnessapi.com/alternatives/google-fit-api-alternatives#faq-2"
        },
        {
          "question": "Is Health Connect the same as Google Fit?",
          "answer": "No. Google Fit was a cloud service that served data over REST; Health Connect is an on-device store on the Android phone that apps read and write under an OS permission, similar to Apple HealthKit on iOS. Because it is on-device and Android-only, there is no server endpoint to query, and existing Google Fit history does not transfer into Health Connect automatically.",
          "url": "https://aifitnessapi.com/alternatives/google-fit-api-alternatives#faq-3"
        },
        {
          "question": "How do I handle cross-platform (iOS and Android) after Google Fit?",
          "answer": "Google Fit only ever covered Android. The standard cross-platform pattern is to use Health Connect on Android and Apple HealthKit on iOS, implementing both on-device stores. If maintaining two platform stores plus any cloud wearables is too much, an aggregator such as Terra, Junction, or Rook fronts all of them behind one normalized API for a recurring fee.",
          "url": "https://aifitnessapi.com/alternatives/google-fit-api-alternatives#faq-4"
        },
        {
          "question": "Will my Google Fit data migrate automatically?",
          "answer": "No. Existing Google Fit data does not silently move into Health Connect or any other successor. Plan for a user re-consent and a re-sync, plus re-mapping your fields onto the new schema. This is one reason the switch is a real re-integration rather than a simple library swap.",
          "url": "https://aifitnessapi.com/alternatives/google-fit-api-alternatives#faq-5"
        }
      ]
    },
    {
      "question": "Garmin API alternatives",
      "answer": "If you can't get into Garmin's partner-approval-only developer program, the practical alternatives are an aggregator that may broker Garmin if you bring your own credentials (Terra), a different accessible wearable (Fitbit, Oura, WHOOP), Strava for activities and GPS, and on-device HealthKit or Health Connect, which can surface Garmin data a user has already synced to their phone. Pick an aggregator to remove the single-vendor gate, Strava if you mainly need runs and rides, Fitbit for broad consumer reach, or on-device APIs if your app lives on the phone and the user already syncs Garmin there.",
      "title": "Garmin API Alternatives When You Can't Get Access (2026)",
      "url": "https://aifitnessapi.com/alternatives/garmin-api-alternatives",
      "markdown": "https://aifitnessapi.com/alternatives/garmin-api-alternatives.md",
      "cluster": "Alternatives",
      "cluster_url": "https://aifitnessapi.com/alternatives",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Why can't I get access to the Garmin API?",
          "answer": "Garmin's Health and Activity APIs are reachable only through the Garmin Connect Developer Program, which is partner-approval-only rather than self-serve. As of 2026 the program is reportedly on hold or suspended for new sign-ups (verify), with no published reopen date. Existing approved accounts are said to keep working, but new builders report rejections and long delays. Verify the current status in Garmin's developer docs.",
          "url": "https://aifitnessapi.com/alternatives/garmin-api-alternatives#faq-1"
        },
        {
          "question": "Can I get Garmin data through an aggregator like Terra?",
          "answer": "Possibly. Aggregators such as Terra normalize many providers behind one schema and may reach Garmin through their own integration access, which can let you skip your own partner approval. As of 2026 some flows are reportedly bring-your-own-credentials (verify), and Garmin coverage still depends on Garmin's partner terms. Confirm each aggregator's current Garmin brokering terms before you commit.",
          "url": "https://aifitnessapi.com/alternatives/garmin-api-alternatives#faq-2"
        },
        {
          "question": "Can I get Garmin data from HealthKit or Health Connect?",
          "answer": "Often, yes. If a user has synced their Garmin device to their phone, the data usually lands in Apple Health on iOS or Health Connect on Android, where your app can read it on-device without Garmin developer approval. The catch is that it is on-device and per-platform, gives no server-side access on its own, and depends on the user having that sync set up.",
          "url": "https://aifitnessapi.com/alternatives/garmin-api-alternatives#faq-3"
        },
        {
          "question": "Is Strava a good substitute for the Garmin API?",
          "answer": "For activities, often yes. Many Garmin users auto-sync their workouts into Strava, so runs, rides, and GPS are reachable there. But Strava is activity- and social-focused, so device health metrics like sleep, HRV, and recovery are not available, and it has its own limits such as one webhook subscription per app and published rate limits.",
          "url": "https://aifitnessapi.com/alternatives/garmin-api-alternatives#faq-4"
        },
        {
          "question": "Is switching off Garmin easy?",
          "answer": "Usually it is a real re-integration rather than a config change: new OAuth flows, re-mapping fields to a different provider's schema, and asking users to reconnect their accounts. The exception is an aggregator, where a single normalized schema covers many sources at once, so Garmin-where-available plus fallbacks sit behind one interface instead of re-integrating per vendor.",
          "url": "https://aifitnessapi.com/alternatives/garmin-api-alternatives#faq-5"
        }
      ]
    },
    {
      "question": "Strava API alternatives",
      "answer": "The main Strava API alternatives are Garmin and Fitbit for device-level health metrics like sleep and heart rate, aggregators such as Terra, Junction (formerly Vital), and Rook to normalize many devices behind one schema, and Apple HealthKit or Google Health Connect for on-device workouts. Pick by the gap you're filling: a device API when you need health metrics Strava lacks, an aggregator when you need workouts and many devices behind one interface, and an on-device store when the workout already lives on the user's phone. Strava itself stays the best fit for activities, segments, and social.",
      "title": "The Best Strava API Alternatives (2026)",
      "url": "https://aifitnessapi.com/alternatives/strava-api-alternatives",
      "markdown": "https://aifitnessapi.com/alternatives/strava-api-alternatives.md",
      "cluster": "Alternatives",
      "cluster_url": "https://aifitnessapi.com/alternatives",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Why would I need an alternative to the Strava API?",
          "answer": "Strava is activity- and social-focused, so it models runs, rides, and segments but not full health metrics like sleep stages, HRV, resting heart rate, or recovery scores. It also has published rate limits, effectively one webhook subscription per application, and an athlete-permission (per-user OAuth) model. Teams that need device health data or higher volume usually add another source alongside Strava rather than replacing it.",
          "url": "https://aifitnessapi.com/alternatives/strava-api-alternatives#faq-1"
        },
        {
          "question": "What is the best Strava API alternative for health metrics like sleep and HRV?",
          "answer": "Device-level wearable APIs. Garmin and Fitbit expose sleep, heart rate, and steps that Strava does not carry, and Oura or Whoop add recovery and readiness signals. Note that Garmin is partner-approval-only with new signups reportedly paused, and Fitbit's legacy Web API is consolidating into the Google Health API, so verify current access terms before committing.",
          "url": "https://aifitnessapi.com/alternatives/strava-api-alternatives#faq-2"
        },
        {
          "question": "Should I use an aggregator instead of Strava?",
          "answer": "Use an aggregator like Terra, Junction (formerly Vital), or Rook when you want Strava's activities plus device health metrics across many providers behind a single schema and webhook. It also lifts the per-app rate-limit and webhook friction onto the vendor. The trade-off is a recurring cost and a third party in your data path, so check HIPAA and BAA terms per vendor.",
          "url": "https://aifitnessapi.com/alternatives/strava-api-alternatives#faq-3"
        },
        {
          "question": "Can I get workout data without the Strava API at all?",
          "answer": "Yes. If the workout is captured on the user's phone or watch, Apple HealthKit on iOS and Google Health Connect on Android let your app read it on-device under an OS permission, with no cloud rate limit. The trade-off is that each is platform-locked and device-bound, so a cross-platform app implements both and has no server-side endpoint to query.",
          "url": "https://aifitnessapi.com/alternatives/strava-api-alternatives#faq-4"
        },
        {
          "question": "What is Strava's API actually best at?",
          "answer": "Activities and the social layer around them: runs, rides, swims, segments, leaderboards, kudos, and the athlete graph. If your product is built on that, Strava remains the strongest fit and you may just need to tune polling and webhook use rather than switch. It is the missing health metrics and volume ceilings that push teams to add other sources.",
          "url": "https://aifitnessapi.com/alternatives/strava-api-alternatives#faq-5"
        }
      ]
    },
    {
      "question": "Oura API alternatives",
      "answer": "The top Oura API alternatives are WHOOP (the closest recovery-and-readiness peer), the aggregators Terra and Junction (formerly Vital), which cover Oura plus many other wearables through one integration, and Fitbit or Garmin for a broader, cheaper install base. Pick by use-case: WHOOP to stay in the sleep-and-readiness niche, an aggregator to cover many devices at once, or Fitbit/Garmin to reach more users. Oura itself is still excellent at sleep and readiness quality, so teams switch mainly when they need a broader user base or multi-device coverage that a single ring vendor cannot provide.",
      "title": "The Best Oura API Alternatives (2026)",
      "url": "https://aifitnessapi.com/alternatives/oura-api-alternatives",
      "markdown": "https://aifitnessapi.com/alternatives/oura-api-alternatives.md",
      "cluster": "Alternatives",
      "cluster_url": "https://aifitnessapi.com/alternatives",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Why do developers look for an Oura API alternative?",
          "answer": "Mainly because Oura is single-vendor: every user must own an Oura ring, historically paired with a membership. The developer API also caps an application at about 10 users until you request and receive Oura approval, and Personal Access Tokens are deprecated in favor of OAuth2 only. Teams wanting a broader user base or multi-device coverage look wider. Verify the current cap and approval process in Oura's docs.",
          "url": "https://aifitnessapi.com/alternatives/oura-api-alternatives#faq-1"
        },
        {
          "question": "What is the closest alternative to the Oura API?",
          "answer": "WHOOP is the nearest peer, covering the same recovery, readiness, and sleep niche via a strap instead of a ring. The trade-off is that it carries similar single-vendor constraints, including a required paid WHOOP membership and a comparable roughly 10-member cap until app approval. It is a like-for-like data-model swap, not an escape from the gated single-vendor pattern.",
          "url": "https://aifitnessapi.com/alternatives/oura-api-alternatives#faq-2"
        },
        {
          "question": "Can an aggregator replace the Oura API?",
          "answer": "Yes, for coverage. Terra and Junction (formerly Vital) normalize Oura alongside many other rings and wearables behind one schema, so a single integration reaches Oura plus WHOOP, Garmin, Fitbit, Apple Health, and more. The trade-off is a middle-layer dependency and cost, and you may not see every Oura-specific field the raw API exposes. Confirm each aggregator surfaces the exact metrics you need.",
          "url": "https://aifitnessapi.com/alternatives/oura-api-alternatives#faq-3"
        },
        {
          "question": "What is Oura actually best at?",
          "answer": "Sleep-stage and readiness data quality. That specific signal is a major reason developers build on Oura, and the common alternatives trade it away rather than improve on it. If readiness and sleep quality are the core of your product, staying on Oura is often the right call, and the alternatives are worse at it, not better.",
          "url": "https://aifitnessapi.com/alternatives/oura-api-alternatives#faq-4"
        },
        {
          "question": "Is switching from the Oura API easy?",
          "answer": "It is usually a real re-integration, not a config change: a new OAuth client and consent flow, field re-mapping to a different schema, and, because health-data authorization is per-user, every user has to reconnect their account. Routing through an aggregator like Terra or Junction makes it easier because you integrate once and reach many wearables behind a stable interface.",
          "url": "https://aifitnessapi.com/alternatives/oura-api-alternatives#faq-5"
        }
      ]
    },
    {
      "question": "WHOOP API alternatives",
      "answer": "The top alternatives to the WHOOP API are Oura (the closest recovery and sleep peer), health-data aggregators like Terra and Junction (formerly Vital) that cover WHOOP plus many other wearables through one integration, and broader-base devices like Fitbit and Garmin. Pick by what is blocking you: Oura for a like-for-like recovery signal without the strap, an aggregator when you need many devices behind one integration, and Fitbit or Garmin for reach without a mandatory paid membership. WHOOP itself remains strong at recovery and strain for its committed, subscribed users.",
      "title": "The Best WHOOP API Alternatives (2026)",
      "url": "https://aifitnessapi.com/alternatives/whoop-api-alternatives",
      "markdown": "https://aifitnessapi.com/alternatives/whoop-api-alternatives.md",
      "cluster": "Alternatives",
      "cluster_url": "https://aifitnessapi.com/alternatives",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Why do teams look for a WHOOP API alternative?",
          "answer": "Three constraints, as of 2026: the WHOOP API requires each user to have an active paid WHOOP membership (device plus subscription); apps are capped at 10 WHOOP members in development until they are submitted for and granted approval; and it is single-vendor, returning WHOOP data only. Teams whose users are not all WHOOP subscribers, or who need broader device coverage, evaluate other sources. Verify current requirements against WHOOP's developer docs.",
          "url": "https://aifitnessapi.com/alternatives/whoop-api-alternatives#faq-1"
        },
        {
          "question": "What is the closest alternative to WHOOP for recovery data?",
          "answer": "Oura is the closest peer, covering the same recovery, readiness, and sleep niche from a finger-worn ring instead of a strap. Note that Oura is also single-vendor, requires each user to own the ring, and has its own 10-user development cap until Oura approves your app, so you are swapping one committed-hardware dependency for another rather than escaping the pattern.",
          "url": "https://aifitnessapi.com/alternatives/whoop-api-alternatives#faq-2"
        },
        {
          "question": "Can an aggregator get me WHOOP data without the 10-member cap?",
          "answer": "Aggregators like Terra, Junction (formerly Vital), and Rook connect to WHOOP plus many other wearables and normalize the data into one schema, so WHOOP becomes one connectable source among many and the 10-member limit on your own direct app stops being the constraint. The trade-offs are a recurring per-connected-user fee and a normalized schema that may not surface every WHOOP-specific field.",
          "url": "https://aifitnessapi.com/alternatives/whoop-api-alternatives#faq-3"
        },
        {
          "question": "Is WHOOP still a good choice for some apps?",
          "answer": "Yes. For products whose users are committed WHOOP members wearing the strap daily, WHOOP's recovery and strain metrics are a strong, opinionated signal, and a direct integration gives you the raw fields. The alternatives matter when your audience is not all WHOOP subscribers or you need to cover many device types.",
          "url": "https://aifitnessapi.com/alternatives/whoop-api-alternatives#faq-4"
        },
        {
          "question": "Is switching off WHOOP easy?",
          "answer": "Usually it is a real re-integration, not a config change: a new OAuth setup with the new provider, re-mapping fields (a WHOOP recovery score is shaped differently from an Oura readiness score or a Fitbit metric), and asking every user to reconnect their device through the new flow. An aggregator is the main way to avoid repeating that work, since additional devices become connect-flow options rather than fresh integrations.",
          "url": "https://aifitnessapi.com/alternatives/whoop-api-alternatives#faq-5"
        }
      ]
    },
    {
      "question": "HealthKit alternatives",
      "answer": "HealthKit is iOS-only and on-device with no server-side or cross-platform access, so it is usually complemented rather than replaced. The main alternatives are Google Health Connect (the Android counterpart you implement alongside HealthKit), health-data aggregators like Terra, Junction (formerly Vital), and Rook (server-side, cross-platform, one integration), and cloud wearable APIs like Fitbit, Garmin, Oura, and Whoop. Pick Health Connect for native Android on-device data, an aggregator when you need cross-platform data on your server from a single integration, and a cloud wearable API when your product is built around a specific device.",
      "title": "Apple HealthKit Alternatives (2026)",
      "url": "https://aifitnessapi.com/alternatives/healthkit-alternatives",
      "markdown": "https://aifitnessapi.com/alternatives/healthkit-alternatives.md",
      "cluster": "Alternatives",
      "cluster_url": "https://aifitnessapi.com/alternatives",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Can HealthKit be replaced entirely?",
          "answer": "Usually not. On iOS, HealthKit is the canonical on-device store for health and workout data, so for iPhone-only apps it is hard to beat. Teams add alternatives to gain Android coverage, server-side data, or a single cross-platform integration, so in practice HealthKit is complemented rather than replaced.",
          "url": "https://aifitnessapi.com/alternatives/healthkit-alternatives#faq-1"
        },
        {
          "question": "What is the Android equivalent of HealthKit?",
          "answer": "Google Health Connect is the on-device health data layer for Android and is the natural counterpart to HealthKit. Cross-platform apps typically implement both: HealthKit on iOS and Health Connect on Android. Like HealthKit, Health Connect is on-device and does not provide a server API by itself.",
          "url": "https://aifitnessapi.com/alternatives/healthkit-alternatives#faq-2"
        },
        {
          "question": "How do I get HealthKit data on my server?",
          "answer": "HealthKit exposes data locally on the device, so reaching it server-side means either building your own sync from the app to your backend, or using a health-data aggregator (Terra, Junction, or Rook) that normalizes Apple Health and other sources into a server-side API through one integration.",
          "url": "https://aifitnessapi.com/alternatives/healthkit-alternatives#faq-3"
        },
        {
          "question": "Do I still need HealthKit if I use an aggregator like Terra or Junction?",
          "answer": "On iOS, aggregators generally read from Apple Health, which is populated via HealthKit, so HealthKit remains the underlying data source on the device. The aggregator handles the cross-platform, server-side normalization so you do not build HealthKit plus Health Connect plus per-vendor cloud APIs separately.",
          "url": "https://aifitnessapi.com/alternatives/healthkit-alternatives#faq-4"
        },
        {
          "question": "Is moving beyond HealthKit a lot of work?",
          "answer": "It is a real integration each time. Health Connect adds a separate Android permissions flow and field mapping; a cloud wearable API adds new OAuth, user reconnection, and its own schema. An aggregator consolidates that into one OAuth and one field mapping across Apple Health, Health Connect, and cloud wearables.",
          "url": "https://aifitnessapi.com/alternatives/healthkit-alternatives#faq-5"
        }
      ]
    },
    {
      "question": "Terra alternatives",
      "answer": "The top Terra (tryterra.co) alternatives are Junction (formerly Vital) for wearables plus native US labs, Rook for tiered usage-based wearables aggregation, Spike for the broadest 360 surface (IoT/EMR/labs), or dropping the aggregator via direct per-provider integrations or on-device HealthKit/Health Connect. Pick by what's pushing you off Terra: labs point to Junction, breadth to Spike, cost-control to direct or on-device. Terra's own strengths are broad coverage and a rich normalized schema.",
      "title": "The Best Terra (tryterra.co) Alternatives (2026)",
      "url": "https://aifitnessapi.com/alternatives/terra-alternatives",
      "markdown": "https://aifitnessapi.com/alternatives/terra-alternatives.md",
      "cluster": "Alternatives",
      "cluster_url": "https://aifitnessapi.com/alternatives",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Why do teams look for a Terra alternative?",
          "answer": "Terra prices on usage-based credits consumed as a function of connected users and events, which can scale up unpredictably for products with many active users or high event volume (as of 2026, verify pricing). Others switch to reach a different data type such as clinical labs, to fill an occasional device-coverage gap, or simply to get a flatter, more predictable pricing model. Terra itself is strong on broad coverage and a well-normalized schema.",
          "url": "https://aifitnessapi.com/alternatives/terra-alternatives#faq-1"
        },
        {
          "question": "What is the best Terra alternative if I also need lab data?",
          "answer": "Junction (formerly Vital, rebranded 2025) is the clearest fit. It combines a wearables aggregator with native US lab ordering and results in one API — order tests across 50 states and pull results from 10+ labs, alongside several hundred device integrations. Its lab strength is US-centric, so it matters less if you are wearables-only or outside the US.",
          "url": "https://aifitnessapi.com/alternatives/terra-alternatives#faq-2"
        },
        {
          "question": "How do Rook and Spike differ from Terra?",
          "answer": "Rook (tryrook.io) is a wearables aggregator with a tiered structure (Core/Business/Enterprise) and 400+ device integrations, often cited for Latin America traction — a fit if you want aggregation with a different pricing shape than credits. Spike (spikeapi.com) goes widest with a Health 360 surface: wearables plus medical IoT, EMRs, and lab-report OCR, best when breadth beyond wrist wearables is the priority.",
          "url": "https://aifitnessapi.com/alternatives/terra-alternatives#faq-3"
        },
        {
          "question": "Can I replace Terra without an aggregator at all?",
          "answer": "Yes, two ways. You can build direct per-provider integrations (Fitbit, Garmin, Whoop, Oura, Apple, Google) to own the pipeline and eliminate per-event fees, at the cost of building and maintaining each connector, OAuth flow, and token refresh yourself. Or, for mobile-first apps, read data already aggregated on the phone via HealthKit (iOS) and Health Connect (Android) with no per-user API cost, accepting that there is no server-side pull and coverage is platform-limited.",
          "url": "https://aifitnessapi.com/alternatives/terra-alternatives#faq-4"
        },
        {
          "question": "Is switching away from Terra easy?",
          "answer": "It is usually a real re-integration, not a config change. Expect new OAuth app registration with the new vendor, re-mapping fields to a different normalized schema, and having every existing user reconnect their device through the new connect flow. Switching between aggregators is one re-integration that still covers many providers; going fully direct trades the aggregator fee for maintaining each connector yourself.",
          "url": "https://aifitnessapi.com/alternatives/terra-alternatives#faq-5"
        }
      ]
    },
    {
      "question": "Nutritionix alternatives",
      "answer": "The top Nutritionix alternatives are Edamam (the closest natural-language match, plus recipes), USDA FoodData Central (genuinely free, public domain), Open Food Facts (genuinely free open data, barcode-first), and Spoonacular (recipe-oriented freemium). Pick by use-case: Edamam for free-text meal logging, USDA for authoritative generic-food data, Open Food Facts for packaged-product barcodes, and Spoonacular for recipes and meal planning. Nutritionix itself is still strongest for US restaurant menus and natural-language food logging; verify all pricing and free-tier terms before committing.",
      "title": "The Best Nutritionix Alternatives (2026)",
      "url": "https://aifitnessapi.com/alternatives/nutritionix-alternatives",
      "markdown": "https://aifitnessapi.com/alternatives/nutritionix-alternatives.md",
      "cluster": "Alternatives",
      "cluster_url": "https://aifitnessapi.com/alternatives",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "What are the best free Nutritionix alternatives?",
          "answer": "USDA FoodData Central and Open Food Facts are the genuinely free and open options. USDA FoodData Central is US-government data in the public domain (free API key) and is best for authoritative generic-food nutrients; Open Food Facts is crowd-sourced open data with no key, built around barcode lookup. Edamam and Spoonacular are freemium-to-paid rather than free.",
          "url": "https://aifitnessapi.com/alternatives/nutritionix-alternatives#faq-1"
        },
        {
          "question": "Which Nutritionix alternative supports natural-language meal logging?",
          "answer": "Edamam is the closest match — it parses free-text meal descriptions into structured nutrients, much like Nutritionix. USDA FoodData Central and Open Food Facts do not offer natural-language parsing (you build that yourself), and Spoonacular is oriented around recipes and ingredients rather than free-text food logging.",
          "url": "https://aifitnessapi.com/alternatives/nutritionix-alternatives#faq-2"
        },
        {
          "question": "Why is Nutritionix so expensive?",
          "answer": "Nutritionix is a proprietary premium database whose value is US restaurant-menu coverage and natural-language logging. Third-party comparisons cite entry pricing around $1,850/mo for its full UPC and restaurant-menu database, but this figure is volatile and its free-tier terms are often described as ambiguous — verify current pricing and access terms directly with Nutritionix.",
          "url": "https://aifitnessapi.com/alternatives/nutritionix-alternatives#faq-3"
        },
        {
          "question": "What does Nutritionix do that the free alternatives cannot?",
          "answer": "Its two standout strengths are US restaurant-menu coverage and natural-language food logging. USDA FoodData Central and Open Food Facts have neither, and matching Nutritionix usually means combining several sources — for example USDA plus Open Food Facts for data, with Edamam layered on for natural-language parsing.",
          "url": "https://aifitnessapi.com/alternatives/nutritionix-alternatives#faq-4"
        },
        {
          "question": "Which alternative is best for barcode scanning?",
          "answer": "Open Food Facts is barcode-first and free, with millions of packaged products and no API key required, making it a strong fit for a scanner app. Because it is crowd-sourced, coverage and quality vary by product and region, so many teams fall back to USDA FoodData Central for nutrients where a barcode entry is thin.",
          "url": "https://aifitnessapi.com/alternatives/nutritionix-alternatives#faq-5"
        }
      ]
    },
    {
      "question": "ExerciseDB alternatives",
      "answer": "The top alternatives to the RapidAPI ExerciseDB are wger, the open-source exercisedb.dev project, API Ninjas Exercises, and free-exercise-db. Pick by need: wger or exercisedb.dev to self-host and own the data (both AGPL-3.0), free-exercise-db for a public-domain dataset with images and no licensing friction, and API Ninjas if lightweight text metadata is enough. License (AGPL vs public domain) and media (GIF/video vs images vs none) are the real differentiators.",
      "title": "The Best ExerciseDB Alternatives (2026)",
      "url": "https://aifitnessapi.com/alternatives/exercisedb-alternatives",
      "markdown": "https://aifitnessapi.com/alternatives/exercisedb-alternatives.md",
      "cluster": "Alternatives",
      "cluster_url": "https://aifitnessapi.com/alternatives",
      "last_reviewed": "2026-07-09",
      "first_party": false,
      "faqs": [
        {
          "question": "Is exercisedb.dev the same as the ExerciseDB on RapidAPI?",
          "answer": "No. They share a name but are different things. The most-cited 'ExerciseDB' is a commercial listing distributed through RapidAPI, while exercisedb.dev is a separate open-source project (AGPL-3.0) you can self-host. The name overlap is a common source of confusion, so confirm which one a tutorial or SDK is referring to before you integrate.",
          "url": "https://aifitnessapi.com/alternatives/exercisedb-alternatives#faq-1"
        },
        {
          "question": "What is the best free and open ExerciseDB alternative?",
          "answer": "It depends on your license and media needs. free-exercise-db is public domain (the most permissive here) with 800+ exercises as JSON and images, but it is a static dataset, not a live API. wger and the open exercisedb.dev project are free and self-hostable but AGPL-3.0, which is copyleft and carries obligations if you embed them in a closed-source product.",
          "url": "https://aifitnessapi.com/alternatives/exercisedb-alternatives#faq-2"
        },
        {
          "question": "Which ExerciseDB alternative has exercise GIFs or video?",
          "answer": "The open exercisedb.dev project advertises a large catalog with GIFs, images, and video, making it the closest self-hosted match to the RapidAPI version's media. wger and free-exercise-db provide images rather than GIF/video, and API Ninjas Exercises is metadata-only with no media at all. Verify current media availability at the source before relying on it.",
          "url": "https://aifitnessapi.com/alternatives/exercisedb-alternatives#faq-3"
        },
        {
          "question": "Can I self-host exercise data instead of using RapidAPI?",
          "answer": "Yes. wger is a self-hostable open-source platform with a REST API, and the open exercisedb.dev project is a self-hostable API with exercise data and media. Both are AGPL-3.0. free-exercise-db lets you vendor a public-domain JSON dataset and images directly into your app. Self-hosting removes gateway rate limits and pricing exposure but means you host and maintain the data yourself.",
          "url": "https://aifitnessapi.com/alternatives/exercisedb-alternatives#faq-4"
        },
        {
          "question": "Do I need to worry about the AGPL license?",
          "answer": "If you embed AGPL-3.0 code or a modified AGPL service in a product you distribute or offer over a network, the copyleft terms can require you to make source available. wger and exercisedb.dev are AGPL-3.0, so review the obligations for your specific use before shipping. free-exercise-db (public domain) avoids this entirely, and API Ninjas is a hosted service with its own terms. This is not legal advice — verify with counsel.",
          "url": "https://aifitnessapi.com/alternatives/exercisedb-alternatives#faq-5"
        }
      ]
    },
    {
      "question": "kinestex alternatives",
      "answer": "The verifiable alternatives to KinesteX (this site's own product) are Sency (a native no-UI SDK plus a branded UI kit, iOS/Android/React Native/Flutter), QuickPose (an iOS-first MediaPipe/BlazePose wrapper with rep counters and range-of-motion measurement), and building on free pose models — MediaPipe, MoveNet, or Apple Vision — if you want to own the whole stack. Kemtai and Exer AI are named for clinical use and Asensei for connected coaching, but none could be verified from primary sources. Route by your reason to switch: in-process native SDK → Sency or QuickPose; owning the CV layer → the pose models; clinical focus → verify Kemtai directly.",
      "title": "KinesteX Alternatives, From the Team Behind KinesteX (2026)",
      "url": "https://aifitnessapi.com/alternatives/kinestex-alternatives",
      "markdown": "https://aifitnessapi.com/alternatives/kinestex-alternatives.md",
      "cluster": "Alternatives",
      "cluster_url": "https://aifitnessapi.com/alternatives",
      "last_reviewed": "2026-08-02",
      "first_party": true,
      "faqs": [
        {
          "question": "Why would a KinesteX-funded site publish a KinesteX alternatives page?",
          "answer": "Because the alternative is worse: pretending no alternatives exist, which no developer believes. This site is run by the team behind KinesteX and says so in the first line. The page earns its keep by being method-bound — every claim, including claims about KinesteX itself, is limited to what public GitHub repos, package registries, and model documentation actually show, and vendors we could not verify are labeled as unverified rather than described from search snippets.",
          "url": "https://aifitnessapi.com/alternatives/kinestex-alternatives#faq-1"
        },
        {
          "question": "What is the most direct competitor to KinesteX?",
          "answer": "Sency, based on what is publicly verifiable. Its repos document the same two-tier shape — a white-label prebuilt UI kit plus a customizable kit — across iOS, Android, React Native, and Flutter, with assessments and workout plans. The key architectural difference is integration surface: Sency's README describes a native no-UI SDK that runs in your process, while KinesteX's repos describe WebView and iframe wrappers around a hosted experience. Sency has no web target and a proprietary license, and its pricing page was unreachable in our research pass.",
          "url": "https://aifitnessapi.com/alternatives/kinestex-alternatives#faq-2"
        },
        {
          "question": "Which KinesteX alternative can I try without talking to sales?",
          "answer": "From what the repos show, QuickPose is the self-serve option: its README says to get a free SDK key at dev.quickpose.ai, with the caveat that usage limits may apply and keys are tied to your bundle ID. KinesteX's repos direct you to a contact form or email for an API key, and Sency's README links a registration and pricing page whose contents we could not read. The fully gate-free path is Apple Vision or the open pose models, which need no key at all.",
          "url": "https://aifitnessapi.com/alternatives/kinestex-alternatives#faq-3"
        },
        {
          "question": "If I leave KinesteX for raw pose models, what am I signing up to build?",
          "answer": "A pose model gives you per-frame keypoints and nothing else. To match a commercial fitness SDK you build per-exercise form rules and phase detection, rep-counting state machines, mistake-to-feedback content, calibration and framing UX, an exercise library with plans and progression, analytics events, and cross-device robustness across lighting, thermals, and model variants. The models themselves are free and fitness-targeted by Google's own documentation; the exercise intelligence and content are the real product you are taking on.",
          "url": "https://aifitnessapi.com/alternatives/kinestex-alternatives#faq-4"
        },
        {
          "question": "Is Kemtai a verified alternative to KinesteX for physio and rehab?",
          "answer": "It is the name that consistently comes up for physio-first camera exercise tracking, but we could not verify its current offering from primary sources: its site and docs were unreachable in our research pass and it has no public GitHub SDK we could find. That is not evidence against the product — its distribution may simply be private — but it means claims about its features circulating in search results are ones we could not trace to a source. If your product is clinical, contact Kemtai and Exer AI directly and verify first-hand.",
          "url": "https://aifitnessapi.com/alternatives/kinestex-alternatives#faq-5"
        }
      ]
    },
    {
      "question": "does my fitness app need to be hipaa compliant",
      "answer": "Usually no. HIPAA binds only covered entities (providers, health plans, clearinghouses) and their business associates, so a direct-to-consumer fitness app that collects data for its own users generally falls outside it. HIPAA does apply if you build or run the app on behalf of a covered entity under a Business Associate Agreement. But being outside HIPAA is not being unregulated: the FTC Health Breach Notification Rule, GDPR, and state consumer-health laws usually apply instead. This is general guidance, not legal advice, so confirm your status with a qualified professional.",
      "title": "Does My Fitness App Need to Be HIPAA Compliant?",
      "url": "https://aifitnessapi.com/compliance/hipaa-compliance-fitness-app",
      "markdown": "https://aifitnessapi.com/compliance/hipaa-compliance-fitness-app.md",
      "cluster": "Compliance",
      "cluster_url": "https://aifitnessapi.com/compliance",
      "last_reviewed": "2026-07-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Is a consumer fitness app automatically covered by HIPAA because it handles health data?",
          "answer": "No. HIPAA is tied to covered entities and business associates, not to the sensitivity of the data. Per HHS guidance, an app that collects information directly from and for consumers is not likely subject to HIPAA. The same heart-rate reading is PHI only when a covered entity or business associate holds it.",
          "url": "https://aifitnessapi.com/compliance/hipaa-compliance-fitness-app#faq-1"
        },
        {
          "question": "When would my fitness app actually fall under HIPAA?",
          "answer": "Typically when you build or offer the app on behalf of a covered entity, or in B2B2C deployments where a provider or health plan sponsors the app to its patients or members and you sign a Business Associate Agreement to handle PHI for them. The relationship and purpose decide it, not the data type.",
          "url": "https://aifitnessapi.com/compliance/hipaa-compliance-fitness-app#faq-2"
        },
        {
          "question": "If HIPAA doesn't apply, is my app unregulated?",
          "answer": "No. Non-HIPAA health apps still face the FTC Health Breach Notification Rule (updated in 2024 to cover health apps and connected devices), the FTC Act's ban on deceptive practices, GDPR for EU users, state consumer-health laws like Washington's My Health My Data Act, and app-store policies. These often matter more than HIPAA for consumer apps.",
          "url": "https://aifitnessapi.com/compliance/hipaa-compliance-fitness-app#faq-3"
        },
        {
          "question": "Can I advertise my consumer app as HIPAA compliant?",
          "answer": "It is usually the wrong claim for a standalone consumer app and can mislead users, since HIPAA typically does not apply. There is also no official HHS HIPAA certification, so any vendor claiming one is a red flag. Focus on the rules that do apply to you and verify current requirements with a professional.",
          "url": "https://aifitnessapi.com/compliance/hipaa-compliance-fitness-app#faq-4"
        }
      ]
    },
    {
      "question": "gdpr for fitness apps",
      "answer": "If your fitness app has users in the EU, GDPR almost certainly applies, even to a US company, because offering a service to or monitoring EU users brings you into scope. Fitness and wearable metrics are generally treated as special-category health data, so you typically need explicit consent plus a lawful basis and must support user rights like access, portability, and erasure. This is general guidance, not legal advice; how GDPR applies depends on what your app does, so confirm your obligations with a qualified professional.",
      "title": "GDPR for Fitness Apps: What Developers Need to Know",
      "url": "https://aifitnessapi.com/compliance/gdpr-fitness-app",
      "markdown": "https://aifitnessapi.com/compliance/gdpr-fitness-app.md",
      "cluster": "Compliance",
      "cluster_url": "https://aifitnessapi.com/compliance",
      "last_reviewed": "2026-07-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Does GDPR apply to a US fitness app with EU users?",
          "answer": "Generally yes. GDPR's territorial scope (Article 3) reaches non-EU companies that offer goods or services to people in the EU or monitor their behaviour there. A US app that EU users can download and use is offering a service to EU data subjects, so it is in scope. In-scope non-EU controllers usually also need to appoint an EU representative (Article 27), with limited exceptions to verify.",
          "url": "https://aifitnessapi.com/compliance/gdpr-fitness-app#faq-1"
        },
        {
          "question": "Is fitness or wearable data considered health data under GDPR?",
          "answer": "Usually. GDPR Article 9 treats 'data concerning health' as a protected special category, and EU regulators read that broadly. Fitness, wearable, and workout metrics such as heart rate, sleep, and activity are generally treated as health data, which means processing is prohibited unless a specific Article 9 condition applies.",
          "url": "https://aifitnessapi.com/compliance/gdpr-fitness-app#faq-2"
        },
        {
          "question": "Is explicit consent always required for health data?",
          "answer": "Explicit consent is the usual route for a consumer fitness app, but it is not the only one. For special-category health data you generally need both an Article 6 lawful basis and a separate Article 9 condition; explicit consent can satisfy the Article 9 side. Consent must be freely given, specific, informed, unambiguous, and withdrawable. Note that consent may not be valid where there is a power imbalance, such as employer wellness programs. Confirm the right basis for your case.",
          "url": "https://aifitnessapi.com/compliance/gdpr-fitness-app#faq-3"
        },
        {
          "question": "Is an iOS or Android health permission the same as GDPR consent?",
          "answer": "No. A HealthKit authorization sheet or a Health Connect permission grant is a device-level access control that decides whether your app can read those data types. It is not automatically a GDPR lawful basis for what you then do with the data. You typically still need separate, GDPR-valid consent or another lawful basis for your downstream processing.",
          "url": "https://aifitnessapi.com/compliance/gdpr-fitness-app#faq-4"
        },
        {
          "question": "How quickly must I report a data breach under GDPR?",
          "answer": "Under Article 33 you must notify the relevant supervisory authority without undue delay and, where feasible, within 72 hours of becoming aware of a personal data breach, unless it is unlikely to risk people's rights and freedoms. If the risk to individuals is high, you must also notify affected users. Verify the exact procedure for your supervisory authority.",
          "url": "https://aifitnessapi.com/compliance/gdpr-fitness-app#faq-5"
        }
      ]
    },
    {
      "question": "is fitness data phi",
      "answer": "Usually not. PHI is a specific HIPAA term for health information held by a covered entity or its business associate, so most direct-to-consumer fitness data is not PHI. But the same heart-rate or step reading can be GDPR special-category health data for EU users and consumer health data under state laws like Washington MHMDA, so not PHI does not mean unregulated. The label depends on who holds the data and why, not on the data type alone. This is general guidance, not legal advice.",
      "title": "Is Fitness Data PHI? PII, PHI, and Health Data Untangled",
      "url": "https://aifitnessapi.com/compliance/is-fitness-data-phi",
      "markdown": "https://aifitnessapi.com/compliance/is-fitness-data-phi.md",
      "cluster": "Compliance",
      "cluster_url": "https://aifitnessapi.com/compliance",
      "last_reviewed": "2026-07-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Is heart-rate or step data PHI?",
          "answer": "It depends on the context. Held by a health care provider's app or a vendor working for one, it is PHI and HIPAA applies. The identical reading in a standalone consumer fitness app is not PHI, because HIPAA only attaches to covered entities and their business associates. It may still be GDPR health data and state consumer health data, so treat it as sensitive regardless.",
          "url": "https://aifitnessapi.com/compliance/is-fitness-data-phi#faq-1"
        },
        {
          "question": "What is the difference between PII and PHI?",
          "answer": "PII (personally identifiable information) is a broad umbrella for any data that identifies a person, used across US privacy law generally. PHI (Protected Health Information) is a narrower HIPAA term of art: individually identifiable health information held or transmitted by a covered entity or business associate. All PHI is PII, but most PII is not PHI, and health data outside a HIPAA relationship is not PHI at all.",
          "url": "https://aifitnessapi.com/compliance/is-fitness-data-phi#faq-2"
        },
        {
          "question": "If my fitness data is not PHI, is it unregulated?",
          "answer": "No. Non-PHI fitness data is often heavily regulated by other frameworks: GDPR treats it as special-category health data for EU users, and US state laws such as Washington MHMDA, Nevada, and Connecticut treat it as consumer health data. The FTC Health Breach Notification Rule and FTC Act also apply to many consumer health apps. Concluding not PHI equals not regulated is a common and costly mistake.",
          "url": "https://aifitnessapi.com/compliance/is-fitness-data-phi#faq-3"
        },
        {
          "question": "What counts as consumer health data under Washington MHMDA?",
          "answer": "Washington's My Health My Data Act defines consumer health data very broadly: personal information linked or reasonably linkable to a consumer that identifies their past, present, or future physical or mental health status, expressly including bodily functions, vital signs, symptoms, or measurements, and precise location suggesting health-seeking. That sweeps in wearable and workout metrics HIPAA would not touch. Verify current details, as this area is evolving in 2026.",
          "url": "https://aifitnessapi.com/compliance/is-fitness-data-phi#faq-4"
        },
        {
          "question": "How should a fitness app treat this data in practice?",
          "answer": "Treat wearable, workout, biometric, and inferred-health data as sensitive by default, whether or not it is technically PHI. Apply clear consent, data minimization, encryption, access control, and deletion. That posture generally satisfies GDPR and state consumer-health laws even when HIPAA does not apply. Confirm your specific obligations with a qualified professional, since jurisdiction and data flows change what applies.",
          "url": "https://aifitnessapi.com/compliance/is-fitness-data-phi#faq-5"
        }
      ]
    },
    {
      "question": "does the fda regulate fitness apps",
      "answer": "For most fitness and wellness apps the answer is no: step, calorie, sleep, and general-fitness features typically fall under the FDA's general wellness policy, where the agency applies enforcement discretion rather than regulating them as medical devices. What crosses the line is a claim — marketing that your app diagnoses, treats, or cures a disease (for example, detects AFib or diagnoses sleep apnea) can make it Software as a Medical Device and pull it into FDA oversight. General wellness is a policy and guidance posture, not a blanket statutory exemption, and the guidance was refreshed in early 2026, so verify the current text. This is general engineering guidance, not legal advice — confirm your product's pathway with a qualified professional.",
      "title": "Does the FDA Regulate Fitness Apps?",
      "url": "https://aifitnessapi.com/compliance/fda-fitness-app-regulation",
      "markdown": "https://aifitnessapi.com/compliance/fda-fitness-app-regulation.md",
      "cluster": "Compliance",
      "cluster_url": "https://aifitnessapi.com/compliance",
      "last_reviewed": "2026-07-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Does the FDA regulate fitness apps?",
          "answer": "Usually not. Low-risk apps intended for general wellness use — step counting, calorie and sleep tracking, general-fitness coaching, monitoring pulse or oxygen during exercise — typically fall under the FDA's general wellness policy, where the agency applies enforcement discretion rather than regulating them as medical devices. That is a policy posture, not a statutory exemption, and the guidance was refreshed in early 2026, so verify the current text before relying on it.",
          "url": "https://aifitnessapi.com/compliance/fda-fitness-app-regulation#faq-1"
        },
        {
          "question": "What is the difference between general wellness and Software as a Medical Device (SaMD)?",
          "answer": "General wellness covers claims about maintaining or encouraging a general state of health or a healthy activity, with no reference to a specific disease. Software as a Medical Device is software intended for a medical purpose — to diagnose, treat, cure, mitigate, or prevent a disease — which can meet the FDA's device definition and face regulation. To qualify for the general wellness policy a product must meet both prongs of the FDA's test: intended for general wellness use only, and low risk (not invasive, not implanted, no unsafe technology).",
          "url": "https://aifitnessapi.com/compliance/fda-fitness-app-regulation#faq-2"
        },
        {
          "question": "Does calling my app 'for wellness only' keep it out of FDA regulation?",
          "answer": "No. A 'wellness only' disclaimer does not cure a disease claim. The FDA infers intended use from what you actually claim and how you market the app, so if your copy says the app detects, diagnoses, or treats a condition, it can be treated as a device regardless of a disclaimer that says otherwise. Your marketing language is effectively a legal surface — write claims deliberately.",
          "url": "https://aifitnessapi.com/compliance/fda-fitness-app-regulation#faq-3"
        },
        {
          "question": "Does the FDA regulate how my fitness app stores or shares data?",
          "answer": "No. The FDA's concern is the safety and effectiveness of medical claims, not data privacy. Privacy and security obligations come from other sources — the FTC, state consumer-health laws, and GDPR for EU users. Staying within the general wellness policy answers whether you are an FDA device, not whether you are compliant overall; see the HIPAA and 'is fitness data PHI' pages for the data side.",
          "url": "https://aifitnessapi.com/compliance/fda-fitness-app-regulation#faq-4"
        },
        {
          "question": "My app detects AFib or analyzes ECG data — is that a medical device?",
          "answer": "Likely yes. A claim to detect a specific condition such as atrial fibrillation is a disease-detection claim, which generally makes the software a device and may require FDA clearance or authorization (for example, a 510(k) or De Novo pathway). AFib-detection features on consumer wearables have gone through FDA clearance or De Novo in the real world. If you are building a feature like this, plan for a regulatory pathway and verify the specific product route with a specialist rather than assuming a wellness disclaimer covers it.",
          "url": "https://aifitnessapi.com/compliance/fda-fitness-app-regulation#faq-5"
        }
      ]
    },
    {
      "question": "apple app store health data rules",
      "answer": "To ship an iOS health app or use HealthKit, Apple requires a privacy policy in the app and App Store Connect, bans using health data for advertising or data-mining, bans selling it to third parties, and requires in-app account deletion if you offer accounts. These are contractual App Store rules, not law, and don't replace GDPR or state-law obligations. This is general guidance, not legal advice, and Apple renumbers its guidelines often, so verify the current section text.",
      "title": "Apple App Store Health Data Rules: What You Need to Ship a HealthKit App",
      "url": "https://aifitnessapi.com/compliance/app-store-health-data-rules",
      "markdown": "https://aifitnessapi.com/compliance/app-store-health-data-rules.md",
      "cluster": "Compliance",
      "cluster_url": "https://aifitnessapi.com/compliance",
      "last_reviewed": "2026-07-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Do I need a privacy policy to use HealthKit?",
          "answer": "Yes. Under App Review Guideline 5.1.1(i) (verify the current subsection), every app must link a privacy policy in App Store Connect metadata and within the app. It must state what data you collect, how, and every use, and cover retention, deletion, and how users revoke consent. Apps using HealthKit fall squarely under this.",
          "url": "https://aifitnessapi.com/compliance/app-store-health-data-rules#faq-1"
        },
        {
          "question": "Can I use HealthKit data for advertising or analytics?",
          "answer": "No. Data from HealthKit, the Clinical Health Records API, Motion & Fitness, and the MovementDisorder APIs may not be used for marketing, advertising, or use-based data mining, including by any third party you pass it to. This is a hard prohibition in guideline 5.1.2 / 5.1.3 (verify current subsection). Keep health data out of your ad and analytics SDKs.",
          "url": "https://aifitnessapi.com/compliance/app-store-health-data-rules#faq-2"
        },
        {
          "question": "Can I store health data in iCloud?",
          "answer": "Apple's guidelines say you must not store personal health information in iCloud (guideline 5.1.3(ii) as of mid-2026, verify the current text). This rule is easy to miss when designing sync. Confirm the live guideline wording before you architect any cloud storage for health data.",
          "url": "https://aifitnessapi.com/compliance/app-store-health-data-rules#faq-3"
        },
        {
          "question": "Does my app need in-app account deletion?",
          "answer": "If your app supports account creation, yes. Guideline 5.1.1(v) (verify) requires letting users delete their account and associated data from within the app. The deletion has to reach the associated data, not just the login record. Google Play has a similar but distinct requirement.",
          "url": "https://aifitnessapi.com/compliance/app-store-health-data-rules#faq-4"
        },
        {
          "question": "Do Apple's rules make my app HIPAA or GDPR compliant?",
          "answer": "No. Apple's guidelines are contractual App Store rules enforced through app review; passing review does not satisfy HIPAA, GDPR, or state consumer-health laws. A HealthKit permission prompt is an OS access control, not a legal consent. Confirm your separate legal obligations with a qualified professional.",
          "url": "https://aifitnessapi.com/compliance/app-store-health-data-rules#faq-5"
        }
      ]
    },
    {
      "question": "google play health data policy",
      "answer": "If your Android app handles fitness or health data, Google Play requires that you use it only for disclosed, user-facing features and never sell it, transfer it to data brokers, or use it for ads. You also need an in-app prominent disclosure plus consent, a privacy policy, an accurate Data safety form, and account and data deletion paths — with extra rules for data accessed through Health Connect. This is general engineering guidance, not legal advice, and some Play Console policy pages are hard to fetch, so confirm the exact current wording in the official Console.",
      "title": "What does Google Play's health data policy require?",
      "url": "https://aifitnessapi.com/compliance/google-play-health-data-policy",
      "markdown": "https://aifitnessapi.com/compliance/google-play-health-data-policy.md",
      "cluster": "Compliance",
      "cluster_url": "https://aifitnessapi.com/compliance",
      "last_reviewed": "2026-07-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Is Health Connect data treated differently from other data?",
          "answer": "Yes. Data accessed through Health Connect permissions is treated as personal and sensitive user data plus additional Health Connect rules — notably no advertising use and no sale or transfer to third parties. Other health data your app collects directly still falls under Google's broader sensitive-data policy, so the Health Connect rules are not the only ones that apply.",
          "url": "https://aifitnessapi.com/compliance/google-play-health-data-policy#faq-1"
        },
        {
          "question": "Does the Health Connect permission prompt count as user consent?",
          "answer": "No. The permission prompt is an OS-level access control that decides whether your app can read a data type. Google separately requires an in-app prominent disclosure and consent before collecting sensitive data, and a permission grant is not automatically a legal basis such as GDPR consent. Treat them as distinct requirements.",
          "url": "https://aifitnessapi.com/compliance/google-play-health-data-policy#faq-2"
        },
        {
          "question": "What is the Data safety form and how strict is it?",
          "answer": "The Data safety section is mandatory for every Play listing and must accurately state what data you collect, how you use it, and whether you share it. It has to match your actual behavior and your privacy policy — mismatches between your in-app disclosure, privacy policy, and Data safety form are a common rejection and enforcement trigger.",
          "url": "https://aifitnessapi.com/compliance/google-play-health-data-policy#faq-3"
        },
        {
          "question": "What deletion options does Google Play require?",
          "answer": "Apps that offer account creation generally must provide in-app account deletion, an option to request deletion of data without deleting the account, and a web-accessible deletion path, all disclosed in the Data safety form. The exact wording and deadlines have evolved, so verify the current User Data and Data safety policy pages in the Play Console before you rely on specifics.",
          "url": "https://aifitnessapi.com/compliance/google-play-health-data-policy#faq-4"
        },
        {
          "question": "Is Health Connect replacing Google Fit?",
          "answer": "Health Connect is Google's on-device successor as the older Google Fit APIs wind down. New Fit sign-ups reportedly closed in May 2024, and the Fit Android and REST APIs are slated to be supported only until the end of 2026 — verify this at publish time, as the dates have slipped before. Google recommends Health Connect for on-device and mobile use, with a different path for server-side integrations.",
          "url": "https://aifitnessapi.com/compliance/google-play-health-data-policy#faq-5"
        }
      ]
    },
    {
      "question": "how to store health data securely",
      "answer": "Store health data securely by encrypting it in transit (TLS 1.2+/1.3) and at rest (AES-256), managing keys in a KMS or HSM, enforcing least-privilege access, logging access, and collecting as little as possible. No single control makes you 'compliant' — but together these map onto the HIPAA Security Rule safeguards and GDPR Article 32's 'appropriate technical measures.' This is general engineering guidance, not legal advice; verify what applies to your app.",
      "title": "How to Store Health Data Securely",
      "url": "https://aifitnessapi.com/compliance/store-health-data-securely",
      "markdown": "https://aifitnessapi.com/compliance/store-health-data-securely.md",
      "cluster": "Compliance",
      "cluster_url": "https://aifitnessapi.com/compliance",
      "last_reviewed": "2026-07-14",
      "first_party": false,
      "faqs": [
        {
          "question": "What encryption should I use for health data?",
          "answer": "The common baselines are TLS 1.2 or higher (TLS 1.3 recommended) for data in transit and AES-256 for data at rest, including databases, backups, and device storage. These are strong industry norms rather than universal legal mandates — GDPR Article 32 and the current HIPAA Security Rule are risk-based and don't prescribe a specific algorithm — but they are the sensible default. Verify the current requirements for your jurisdiction.",
          "url": "https://aifitnessapi.com/compliance/store-health-data-securely#faq-1"
        },
        {
          "question": "Does encrypting health data make my app HIPAA or GDPR compliant?",
          "answer": "No. Encryption is one important control, not compliance in itself. Both GDPR Article 32 and the HIPAA Security Rule are outcome-based and cover far more than encryption — access control, audit logging, risk analysis, minimization, and organizational measures. Implementing strong encryption helps and can reduce breach-notification burden, but confirm your full obligations with a qualified professional.",
          "url": "https://aifitnessapi.com/compliance/store-health-data-securely#faq-2"
        },
        {
          "question": "Should I store health data on the device or in the cloud?",
          "answer": "It's a trade-off. On-device storage (using iOS Keychain or Android Keystore) keeps data off your servers and shrinks the attack surface, but complicates recovery and sync. Cloud storage centralizes control and audit but concentrates risk. Whichever you choose, avoid insecure local stores like NSUserDefaults, plain SharedPreferences, or unencrypted files. See our on-device vs. cloud guide for the fuller comparison.",
          "url": "https://aifitnessapi.com/compliance/store-health-data-securely#faq-3"
        },
        {
          "question": "How should I manage encryption keys?",
          "answer": "Generate, store, rotate, and destroy keys using a dedicated key management service (KMS) or hardware security module (HSM), ideally with validated modules. Never hardcode keys or secrets in app binaries or source repositories. Envelope encryption — a data key wrapped by a key-encryption key — is a common pattern, and keys should be kept separate from the data they protect.",
          "url": "https://aifitnessapi.com/compliance/store-health-data-securely#faq-4"
        },
        {
          "question": "Why does data minimization matter for security?",
          "answer": "Data you never collect can't be breached, and it stays out of regulatory scope entirely. Applying the 'collect less' principle shrinks both your attack surface and your compliance burden. It pairs with segregating identifiers from health values and using tokenization or pseudonymization so datasets aren't directly identifying on their own.",
          "url": "https://aifitnessapi.com/compliance/store-health-data-securely#faq-5"
        }
      ]
    },
    {
      "question": "user consent for health data",
      "answer": "Valid consent under GDPR must be freely given, specific, informed, and unambiguous — a clear opt-in, never a pre-ticked box or bundled into your terms. Because fitness data is special-category health data, you usually need explicit consent, granular per purpose and as easy to withdraw as to give. The key trap: an iOS HealthKit or Android Health Connect permission is a device access control, not automatically a legal basis for what you then do with the data. This is general guidance, not legal advice, so confirm your obligations with a qualified professional.",
      "title": "How to Get Valid User Consent for Health Data",
      "url": "https://aifitnessapi.com/compliance/health-data-user-consent",
      "markdown": "https://aifitnessapi.com/compliance/health-data-user-consent.md",
      "cluster": "Compliance",
      "cluster_url": "https://aifitnessapi.com/compliance",
      "last_reviewed": "2026-07-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Is an iOS HealthKit or Android Health Connect permission the same as GDPR consent?",
          "answer": "No. An OS permission grant is a device-level access control that decides whether your app can read or write those data types. It is not automatically a GDPR lawful basis for your subsequent processing, storage, or sharing. You typically still need a separate, GDPR-valid consent (or another lawful basis) for what you do with the data.",
          "url": "https://aifitnessapi.com/compliance/health-data-user-consent#faq-1"
        },
        {
          "question": "What makes consent valid under GDPR?",
          "answer": "It must be freely given, specific, informed, and unambiguous — a clear affirmative opt-in, with no pre-ticked boxes, silence, or default-on settings counting as consent. It should be granular (a separate opt-in per purpose) and as easy to withdraw as to give. For health data, which is special-category, the usual route is explicit consent, a higher bar.",
          "url": "https://aifitnessapi.com/compliance/health-data-user-consent#faq-2"
        },
        {
          "question": "Do I need separate consent to sell or share health data?",
          "answer": "Under Washington's My Health My Data Act, yes — consent to collect or share is separate from a distinct, signed authorization to sell consumer health data. Per the statute, that sale authorization is its own signed document, and both seller and purchaser must retain it for six years. Other states have similar-but-different rules, so verify the current landscape.",
          "url": "https://aifitnessapi.com/compliance/health-data-user-consent#faq-3"
        },
        {
          "question": "What consent records do I need to keep?",
          "answer": "GDPR requires you to be able to demonstrate consent, so keep versioned logs of who consented, when, what they were told (the exact wording and version they saw), and how they can withdraw. If you cannot show these, you effectively cannot show valid consent. Treat consent records as part of your data model, not an afterthought.",
          "url": "https://aifitnessapi.com/compliance/health-data-user-consent#faq-4"
        },
        {
          "question": "What about consent for children's health data?",
          "answer": "In the US, COPPA requires verifiable parental consent to collect data from children under 13, usually via an age gate or neutral age-screen. GDPR sets a digital-consent age of 16 that member states may lower to as low as 13, below which parental consent is required. Thresholds vary by jurisdiction, so verify the current numbers for your markets.",
          "url": "https://aifitnessapi.com/compliance/health-data-user-consent#faq-5"
        }
      ]
    },
    {
      "question": "fitness app privacy policy",
      "answer": "If your app collects health or fitness data, you need a privacy policy: both Apple and Google require one, in your store listing and inside the app, and GDPR's transparency rules expect it too. It should cover who you are, what data you collect (health data specifically), why and on what legal basis, who you share it with, transfers, retention, user rights, security, children, and how you handle changes. The critical part is accuracy: it must match what your app actually does and your app-store data labels. This is general guidance, not legal advice, so have a qualified professional review your policy.",
      "title": "What Does a Fitness App Privacy Policy Need to Include?",
      "url": "https://aifitnessapi.com/compliance/health-app-privacy-policy",
      "markdown": "https://aifitnessapi.com/compliance/health-app-privacy-policy.md",
      "cluster": "Compliance",
      "cluster_url": "https://aifitnessapi.com/compliance",
      "last_reviewed": "2026-07-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Do Apple and Google require a privacy policy for a health app?",
          "answer": "Yes. Apple requires a linked privacy policy under its App Store Review Guidelines, and Google requires one for any app handling personal and sensitive user data, which includes health and fitness data. Both expect it in the store listing and accessible inside the app. Verify the current policy text before you submit, since both platforms update their rules.",
          "url": "https://aifitnessapi.com/compliance/health-app-privacy-policy#faq-1"
        },
        {
          "question": "Can I use a privacy policy template for my fitness app?",
          "answer": "You can use one as a starting structure, but not as finished text. A template that misdescribes what your app actually collects, shares, or retains is a liability, because a mismatch between your policy and your real behavior is what triggers app-store rejection and, in the US, FTC deceptive-practices risk. Write the policy from your actual data map and have counsel review it.",
          "url": "https://aifitnessapi.com/compliance/health-app-privacy-policy#faq-2"
        },
        {
          "question": "Does having a privacy policy mean I have valid consent?",
          "answer": "No. A privacy policy is a transparency document, not a consent mechanism. It does not by itself satisfy Google's in-app prominent disclosure and consent requirement or Apple's consent prompts and purpose strings, which are additional steps. An operating-system permission grant is also not the same as legal consent for what you do with the data.",
          "url": "https://aifitnessapi.com/compliance/health-app-privacy-policy#faq-3"
        },
        {
          "question": "Do I need a DPO contact in my privacy policy?",
          "answer": "Only if you are required to appoint a Data Protection Officer. Under GDPR that is generally expected where your core activities involve large-scale processing of special-category data, which a fitness app at scale can meet. If you have appointed one, include their contact. Verify whether the requirement applies to your specific processing.",
          "url": "https://aifitnessapi.com/compliance/health-app-privacy-policy#faq-4"
        },
        {
          "question": "What retention period should my policy state?",
          "answer": "GDPR sets no fixed number. You define, document, and justify a retention period for each data category, or state the criteria you use to decide, then delete or anonymize when the purpose ends. Avoid stating a universal figure; base it on your actual purposes. See the retention and deletion guide for how to set and honor these periods.",
          "url": "https://aifitnessapi.com/compliance/health-app-privacy-policy#faq-5"
        }
      ]
    },
    {
      "question": "health data retention and deletion",
      "answer": "You generally cannot keep health or fitness data longer than you need it: GDPR's storage limitation principle expects a documented retention schedule per data type, and the right to erasure lets users require deletion in defined cases. Apple and Google separately require an in-app account and data deletion path, and any deletion has to reach backups, logs, and third-party processors, not just your main database. This is general engineering guidance, not legal advice; retention periods and how erasure applies depend on your app and jurisdiction, so confirm your obligations with a qualified professional.",
      "title": "Health Data Retention and Deletion: A Developer's Guide",
      "url": "https://aifitnessapi.com/compliance/health-data-retention-deletion",
      "markdown": "https://aifitnessapi.com/compliance/health-data-retention-deletion.md",
      "cluster": "Compliance",
      "cluster_url": "https://aifitnessapi.com/compliance",
      "last_reviewed": "2026-07-14",
      "first_party": false,
      "faqs": [
        {
          "question": "How long can a fitness app keep users' health data?",
          "answer": "There is no universal number. GDPR's storage limitation principle (Article 5(1)(e)) says keep personal data no longer than necessary for the purpose you collected it for, but it sets no fixed periods. You have to define, document, and justify your own retention schedule per data category, then delete or anonymize the data once the purpose ends. Avoid committing to a universal figure and set yours against your actual purposes.",
          "url": "https://aifitnessapi.com/compliance/health-data-retention-deletion#faq-1"
        },
        {
          "question": "Can a user always force me to delete all their data?",
          "answer": "Not always. The right to erasure (Article 17) lets users require deletion in defined situations, such as the data no longer being needed or consent being withdrawn, but it is not absolute. Article 17(3) allows you to retain data despite an erasure request where a lawful basis applies, for example a legal-retention obligation or a legal hold to defend claims. In those cases retain only the minimum data the exception covers, document it, and delete once the reason ends.",
          "url": "https://aifitnessapi.com/compliance/health-data-retention-deletion#faq-2"
        },
        {
          "question": "Do I have to let users delete their account inside the app?",
          "answer": "For the app stores, yes. Apple requires apps that support account creation to offer account and associated-data deletion from within the app. Google Play requires an in-app account deletion path plus an option to delete data without deleting the account, and a web-accessible deletion route disclosed in the Data safety form. These are contractual store rules, distinct from GDPR erasure; verify the current wording as both platforms update it.",
          "url": "https://aifitnessapi.com/compliance/health-data-retention-deletion#faq-3"
        },
        {
          "question": "Does deleting a database record satisfy a deletion request?",
          "answer": "Usually not on its own. Deletion has to propagate to backups, replicas, caches, logs, analytics, and any third-party processors or sub-processors that hold the data. Under GDPR Article 28 you should contractually require processors to delete on your instruction. Backups are a common gap: deletion can lawfully lag a backup cycle if you document how it reconciles and keep backup access restricted in the meantime.",
          "url": "https://aifitnessapi.com/compliance/health-data-retention-deletion#faq-4"
        },
        {
          "question": "Is data minimization the same as retention?",
          "answer": "They are related but distinct. Data minimization (Article 5(1)(c)) is about collecting and keeping less in the first place; storage limitation (Article 5(1)(e)) is about not holding data longer than needed. Together they shrink both your breach surface and your deletion workload, which is why minimizing what you store is one of the highest-leverage steps for sensitive health data.",
          "url": "https://aifitnessapi.com/compliance/health-data-retention-deletion#faq-5"
        }
      ]
    },
    {
      "question": "migrate google fit to health connect",
      "answer": "Google is winding down the Google Fit REST and Android APIs, and the Android successor is Health Connect. The fundamental shift: Google Fit was cloud/REST so a backend could read it server-to-server, but Health Connect is an on-device store with no server endpoint. If you read Fit from your backend, you must re-architect to read on-device in the app and sync to your server yourself, or use an aggregator. This is a real re-integration, not a config swap: new OS permission model, field-by-field data re-mapping, and users must reconnect. Fit reportedly froze new sign-ups in May 2024 and is stated to be supported only through the end of 2026 (verify).",
      "title": "How to migrate from Google Fit to Health Connect",
      "url": "https://aifitnessapi.com/migrate/google-fit-to-health-connect",
      "markdown": "https://aifitnessapi.com/migrate/google-fit-to-health-connect.md",
      "cluster": "Migrations",
      "cluster_url": "https://aifitnessapi.com/migrate",
      "last_reviewed": "2026-07-20",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I just re-point my backend from the Fit REST API to Health Connect?",
          "answer": "No. Health Connect is an on-device store with no server endpoint, so there is no URL for your backend to call. If you read Fit server-to-server, you must re-architect to read on-device inside your Android app and sync to your backend yourself, use the separate cloud Google Health API, or use an aggregator that runs an on-device SDK and forwards normalized data.",
          "url": "https://aifitnessapi.com/migrate/google-fit-to-health-connect#faq-1"
        },
        {
          "question": "When are the Google Fit APIs actually shutting down?",
          "answer": "Google reportedly stopped new sign-ups for the Fit REST and Android APIs on May 1, 2024, and states the APIs are supported only through the end of 2026 before deprecation. The exact shutdown day within 2026 is not published, and Google's dates have moved before, so verify the current timeline in the official migration docs before committing a schedule.",
          "url": "https://aifitnessapi.com/migrate/google-fit-to-health-connect#faq-2"
        },
        {
          "question": "Will my users' Google Fit history transfer to Health Connect?",
          "answer": "Not fully. Health Connect only holds data that is on that device or written by connected apps; it is not a backfill of a user's entire Google Fit cloud history. Reading data older than the default window (documented as roughly 30 days, verify) needs the READ_HEALTH_DATA_HISTORY permission, and deep cloud history may simply not be available on-device. Plan for gaps and tell users.",
          "url": "https://aifitnessapi.com/migrate/google-fit-to-health-connect#faq-3"
        },
        {
          "question": "Do users have to reconnect, or does Fit consent carry over?",
          "answer": "Users must reconnect. There is no silent migration of Google Fit consent to Health Connect; Health Connect uses an OS-level permission model granted per data type, and access tokens and Fit scopes do not carry over. Design a clear in-app re-consent flow, run old and new in parallel, and migrate users in waves rather than forcing a disconnect.",
          "url": "https://aifitnessapi.com/migrate/google-fit-to-health-connect#faq-4"
        },
        {
          "question": "What replaces Google Fit for my iOS users?",
          "answer": "Not Health Connect, which is Android-only. If your iOS app read a user's Google Fit data through the REST API, that path disappears with Fit and there is no on-device Google store on iPhone to inherit it. Your options are Apple HealthKit for on-device data, the separate cloud Google Health API if the read has to happen on your server, or an aggregator that runs an on-device SDK on both platforms and forwards normalized data to your backend. Plan the iOS half as its own migration — it does not reuse the Android work.",
          "url": "https://aifitnessapi.com/migrate/google-fit-to-health-connect#faq-5"
        }
      ]
    },
    {
      "question": "fitbit web api google migration",
      "answer": "As Fitbit and Google accounts consolidate, the legacy Fitbit Web API is being retired in favor of the new Google Health API, a cloud REST API that uses Google OAuth 2.0 with a new console, schema, and response format. Treat it as a real re-integration: the biggest gotcha is that your existing Fitbit tokens almost certainly do not transfer, so every user must re-sign-in with a Google Account and re-grant permissions. This migration is announced and in progress as of 2026, and the specific dates come from vendor and community notices, so verify everything against current Fitbit and Google developer notices before you plan a cutover.",
      "title": "Migrating from the Fitbit Web API to the Google Health API",
      "url": "https://aifitnessapi.com/migrate/fitbit-web-api-to-google-health",
      "markdown": "https://aifitnessapi.com/migrate/fitbit-web-api-to-google-health.md",
      "cluster": "Migrations",
      "cluster_url": "https://aifitnessapi.com/migrate",
      "last_reviewed": "2026-07-20",
      "first_party": false,
      "faqs": [
        {
          "question": "Will my existing Fitbit access and refresh tokens work with the Google Health API?",
          "answer": "Almost certainly not. Because the OAuth provider changes to Google OAuth 2.0, existing Fitbit tokens are reported to be non-portable, and every user must re-sign-in with a Google Account and re-grant permissions. Plan for mandatory re-consent from day one, and do not assume any migration tool moves tokens for you. Verify the current wording in the official Fitbit and Google notices.",
          "url": "https://aifitnessapi.com/migrate/fitbit-web-api-to-google-health#faq-1"
        },
        {
          "question": "When exactly is the legacy Fitbit Web API being shut down?",
          "answer": "The dates are not settled. Vendor and community notices report a side-by-side window running into late September 2026 with the legacy Web API turned down around September 2026, and a requirement to migrate your Fitbit login to a Google Account before roughly mid-May 2026. Treat all of these as provisional and confirm them against current Fitbit and Google developer notices before you schedule a cutover.",
          "url": "https://aifitnessapi.com/migrate/fitbit-web-api-to-google-health#faq-2"
        },
        {
          "question": "Do users need a Google Account to keep their Fitbit connection?",
          "answer": "Reportedly yes. Users on legacy Fitbit-only logins are reported to be unable to use the Google Health API until they consolidate their login into a Google Account. Because this can lock out un-consolidated users, surface the account-migration step clearly in your reconnect messaging. Verify the current gating in the official notices.",
          "url": "https://aifitnessapi.com/migrate/fitbit-web-api-to-google-health#faq-3"
        },
        {
          "question": "Can an aggregator handle this migration for me?",
          "answer": "Potentially. A health-data aggregator that already supports both the legacy Fitbit Web API and the new Google Health API can absorb the OAuth and schema change so you keep a single integration instead of rebuilding. Vendors reported to be preparing for this include Terra, Validic, Thryve/Sahha, Fitabase, and Rook, but coverage and readiness vary, so verify each one's current support before relying on it.",
          "url": "https://aifitnessapi.com/migrate/fitbit-web-api-to-google-health#faq-4"
        },
        {
          "question": "Is the Google Health API the same as Health Connect?",
          "answer": "No. The Google Health API is a cloud REST API (the Fitbit Web API successor) that your backend calls over Google OAuth 2.0. Health Connect is a separate, on-device Android store with an OS-level permission model and no server endpoint. Do not conflate them when planning your architecture.",
          "url": "https://aifitnessapi.com/migrate/fitbit-web-api-to-google-health#faq-5"
        }
      ]
    },
    {
      "question": "add android support healthkit app",
      "answer": "HealthKit is iOS-only and on-device, so there is no cloud API to extend to Android; the Android counterpart is Health Connect, also on-device, and there is no single official cross-platform SDK that speaks both. Adding Android is a real second integration: you either build two native paths behind your own normalization layer or adopt an aggregator that abstracts both. The biggest gotcha is that the platforms are not equivalent, so 'support both' always means a mapping layer for differing data types, units, and permission models, not a flag flip.",
      "title": "Adding Android to a HealthKit app",
      "url": "https://aifitnessapi.com/migrate/add-android-to-healthkit-app",
      "markdown": "https://aifitnessapi.com/migrate/add-android-to-healthkit-app.md",
      "cluster": "Migrations",
      "cluster_url": "https://aifitnessapi.com/migrate",
      "last_reviewed": "2026-07-20",
      "first_party": false,
      "faqs": [
        {
          "question": "Is there an official cross-platform SDK for HealthKit and Health Connect?",
          "answer": "No. There is no first-party Apple or Google product that speaks both. You either build two native integrations with your own normalization layer, or use a third-party aggregator that runs an on-device SDK covering both and forwards normalized data. Community wrappers exist, but verify their maintenance status before depending on one, as they can lag OS changes.",
          "url": "https://aifitnessapi.com/migrate/add-android-to-healthkit-app#faq-1"
        },
        {
          "question": "Can I read HealthKit or Health Connect data from my server?",
          "answer": "No. Both are on-device stores with no server endpoint. You read the data inside the app on the device and sync it to your own backend yourself. This is true for both iOS and Android, so plan an on-device read plus self-sync path either way.",
          "url": "https://aifitnessapi.com/migrate/add-android-to-healthkit-app#faq-2"
        },
        {
          "question": "Do HealthKit data types map one-to-one to Health Connect?",
          "answer": "Core types like steps, distance, heart rate, calories, sleep sessions, weight, and workouts map reasonably, but names, units, granularity, and which types each platform defines can differ. Do not assume field-for-field parity; build an explicit mapping table and verify each data type and unit against the live docs.",
          "url": "https://aifitnessapi.com/migrate/add-android-to-healthkit-app#faq-3"
        },
        {
          "question": "Why does HealthKit return empty data instead of a permission error?",
          "answer": "By design, HealthKit does not tell you a read was denied; it returns empty data instead, so you cannot infer a user's health status from permission state. That means absent data can mean either no permission or no data, and you should handle both cases. Verify the current behavior in Apple's documentation before building logic around it.",
          "url": "https://aifitnessapi.com/migrate/add-android-to-healthkit-app#faq-4"
        },
        {
          "question": "Should I go native on both platforms or use an aggregator?",
          "answer": "Per-platform native gives the most control and no recurring cost, but you build and maintain two integrations, two permission flows, two sync paths, and your own schema. An aggregator gives one integration and one backend contract at the cost of price, coverage limits, and trusting a third party with the data flow. Pick based on your control-versus-maintenance priorities.",
          "url": "https://aifitnessapi.com/migrate/add-android-to-healthkit-app#faq-5"
        }
      ]
    },
    {
      "question": "replace direct integrations with aggregator",
      "answer": "Consolidating several per-vendor integrations (Fitbit, Garmin, Oura, WHOOP) behind one aggregator like Terra, Junction (formerly Vital), Rook, or Spike collapses many auth flows and schemas into one integration and one normalized webhook stream. It is a real re-integration, not a flag flip: you re-map fields, some providers still need your own approved credentials, and every user must re-authorize through the aggregator's connect flow. Run the aggregator in parallel with your existing integrations, back-fill within each provider's cap, and cut over provider-by-provider with a rollback path.",
      "title": "Consolidate wearables: replace direct integrations with one aggregator",
      "url": "https://aifitnessapi.com/migrate/consolidate-wearables-with-aggregator",
      "markdown": "https://aifitnessapi.com/migrate/consolidate-wearables-with-aggregator.md",
      "cluster": "Migrations",
      "cluster_url": "https://aifitnessapi.com/migrate",
      "last_reviewed": "2026-07-20",
      "first_party": false,
      "faqs": [
        {
          "question": "Do users have to reconnect when I move to an aggregator?",
          "answer": "Yes. OAuth grants and refresh tokens are bound to your old per-vendor apps and do not transfer. Every user must re-authorize through the aggregator's connect flow, so plan a re-consent campaign and keep old-path data flowing until each user reconnects.",
          "url": "https://aifitnessapi.com/migrate/consolidate-wearables-with-aggregator#faq-1"
        },
        {
          "question": "If I use one aggregator, do I still need my own developer credentials?",
          "answer": "Often yes. 'One integration' is shorthand: providers such as Garmin, WHOOP, and Fitbit may still require you to register and get approved for your own developer app behind the aggregator, and using your own OAuth app can mean the provider rate-limits you independently. Verify per provider, as of 2026.",
          "url": "https://aifitnessapi.com/migrate/consolidate-wearables-with-aggregator#faq-2"
        },
        {
          "question": "Will the normalized schema drop provider-specific fields?",
          "answer": "It can. A unified schema flattens or drops fields that only exist on one provider. If you depend on a raw provider field, confirm the aggregator exposes a raw or passthrough payload before you decommission the direct integration that returns it. Verify availability per aggregator.",
          "url": "https://aifitnessapi.com/migrate/consolidate-wearables-with-aggregator#faq-3"
        },
        {
          "question": "How far back can I back-fill historical data?",
          "answer": "Back-fill depth is set by each underlying provider, not the aggregator, and it is capped and often permission-gated. Large ranges are delivered asynchronously in chunks. Document the gap for users rather than promising full history, and verify current per-provider caps.",
          "url": "https://aifitnessapi.com/migrate/consolidate-wearables-with-aggregator#faq-4"
        },
        {
          "question": "Should I hard-cut or run both in parallel?",
          "answer": "Run both in parallel. Stand up the aggregator alongside your existing integrations, dual-read and compare for a validation window, migrate users in waves, and cut over provider-by-provider while keeping a rollback path until each cohort is proven.",
          "url": "https://aifitnessapi.com/migrate/consolidate-wearables-with-aggregator#faq-5"
        }
      ]
    },
    {
      "question": "move from aggregator to direct api",
      "answer": "Leaving an aggregator means integrating each provider directly: you register your own developer apps, re-map from the aggregator's normalized schema back to each provider's raw schema, and every user must re-consent onto your own OAuth. The biggest gotcha is that you take back all the maintenance the aggregator absorbed - per-provider auth, token refresh, schema drift, webhooks, and approval renewals - for each provider you bring in-house. It is a real re-integration, so go provider-by-provider, run both paths in parallel, and keep the aggregator as rollback.",
      "title": "Migrate from an aggregator to direct provider integrations",
      "url": "https://aifitnessapi.com/migrate/aggregator-to-direct-integration",
      "markdown": "https://aifitnessapi.com/migrate/aggregator-to-direct-integration.md",
      "cluster": "Migrations",
      "cluster_url": "https://aifitnessapi.com/migrate",
      "last_reviewed": "2026-07-20",
      "first_party": false,
      "faqs": [
        {
          "question": "Do user connections transfer from the aggregator to my direct integration?",
          "answer": "No. OAuth grants and refresh tokens are bound to the aggregator's app and do not transfer to your own app. Every user must re-authorize through your OAuth flow, so plan a reconnect flow and identity reconciliation from day one.",
          "url": "https://aifitnessapi.com/migrate/aggregator-to-direct-integration#faq-1"
        },
        {
          "question": "Which providers require their own approval when I go direct?",
          "answer": "Several gate access behind review even when you integrate directly. As of 2026, Garmin's Health API runs through a partner-program application reviewing your use case and data handling (some premium metrics may carry license fees), and WHOOP and Fitbit have their own app registration and review. Verify each provider's current developer terms and allow weeks of lead time.",
          "url": "https://aifitnessapi.com/migrate/aggregator-to-direct-integration#faq-2"
        },
        {
          "question": "Will I get the raw provider fields the aggregator's normalized schema dropped?",
          "answer": "Often yes - direct access to a provider's raw schema is a common reason to leave. But confirm the provider still exposes that specific field before migrating for it; do not assume a field survives just because the aggregator once flattened or dropped it. Verify per provider.",
          "url": "https://aifitnessapi.com/migrate/aggregator-to-direct-integration#faq-3"
        },
        {
          "question": "How far back can I back-fill history after going direct?",
          "answer": "Back-fill depth is capped by each provider, not by you or the aggregator, and large ranges are often delivered asynchronously. Verify current per-provider limits, and reconcile any gaps against the aggregator path before decommissioning it.",
          "url": "https://aifitnessapi.com/migrate/aggregator-to-direct-integration#faq-4"
        },
        {
          "question": "Is going direct actually cheaper?",
          "answer": "It can be for high-volume providers where per-connection or per-MAU aggregator fees exceed in-house cost, but it is not pure savings. You take back per-provider auth, token refresh, schema drift, webhook handling, and approval renewals. Treat it as a per-provider trade-off and verify current pricing, as of 2026.",
          "url": "https://aifitnessapi.com/migrate/aggregator-to-direct-integration#faq-5"
        }
      ]
    },
    {
      "question": "switch health data aggregator",
      "answer": "Switching aggregators (for example Terra to Junction (formerly Vital), Rook, or Spike) is a real re-integration, not a config swap. Each aggregator has its own normalized schema, connect flow, and webhook signatures, so you re-map fields and rewire your handler. The biggest gotcha: grants and refresh tokens do not transfer, so every user must reconnect. Run both in parallel and migrate in waves.",
      "title": "How to switch from one health data aggregator to another",
      "url": "https://aifitnessapi.com/migrate/between-health-data-aggregators",
      "markdown": "https://aifitnessapi.com/migrate/between-health-data-aggregators.md",
      "cluster": "Migrations",
      "cluster_url": "https://aifitnessapi.com/migrate",
      "last_reviewed": "2026-07-20",
      "first_party": false,
      "faqs": [
        {
          "question": "Do my users have to reconnect when I switch aggregators?",
          "answer": "Yes, in almost all cases. OAuth grants and refresh tokens are bound to the old aggregator's app and do not transfer to the new one, so each user must re-authorize through the new connect flow. Plan a reconnect campaign from the start.",
          "url": "https://aifitnessapi.com/migrate/between-health-data-aggregators#faq-1"
        },
        {
          "question": "Can I just re-point my webhook to the new aggregator?",
          "answer": "No. Aggregators use different webhook signatures and event models (for example Terra's terra-signature HMAC versus another vendor's scheme), so you rewrite your signature verification and handler. It is a real re-integration, not a URL change.",
          "url": "https://aifitnessapi.com/migrate/between-health-data-aggregators#faq-2"
        },
        {
          "question": "Will switching aggregators let me back-fill more history?",
          "answer": "No. Back-fill depth is set by each underlying provider, not by the aggregator you use. Terra documents different per-provider caps, and switching vendors does not raise them. Verify current per-provider limits.",
          "url": "https://aifitnessapi.com/migrate/between-health-data-aggregators#faq-3"
        },
        {
          "question": "Is coverage the same across aggregators?",
          "answer": "Not necessarily. Coverage differs by aggregator and shifts over time, and parity is per-provider and per-field. Confirm the new aggregator supports both every provider and the specific data fields you consume before committing. As of 2026, verify current docs.",
          "url": "https://aifitnessapi.com/migrate/between-health-data-aggregators#faq-4"
        },
        {
          "question": "How long should I run both aggregators in parallel?",
          "answer": "Long enough to migrate users in waves, validate data continuity per cohort, and confirm reconnection rates. Keep the old path live and a rollback available until the new source is proven; do not hard-cut.",
          "url": "https://aifitnessapi.com/migrate/between-health-data-aggregators#faq-5"
        }
      ]
    },
    {
      "question": "migrate polling to webhooks fitness api",
      "answer": "Moving from polling to webhooks means the provider pushes an event when data changes instead of your backend polling on a timer. The biggest gotcha: many providers send a notification with an object id, not the full data, so you still fetch the record. It is a real re-integration - a secured HTTPS endpoint, signature verification, a queue, idempotency, ordering guards, and a fallback poll - not a flag flip. Run polling and webhooks in parallel and keep a low-frequency poll as a permanent safety net.",
      "title": "Migrate from polling to webhooks for a fitness API",
      "url": "https://aifitnessapi.com/migrate/polling-to-webhooks",
      "markdown": "https://aifitnessapi.com/migrate/polling-to-webhooks.md",
      "cluster": "Migrations",
      "cluster_url": "https://aifitnessapi.com/migrate",
      "last_reviewed": "2026-07-20",
      "first_party": false,
      "faqs": [
        {
          "question": "Does the webhook payload contain the full activity data?",
          "answer": "Often not. Many providers send a notification with an object id (Strava webhook events carry object and aspect ids, not the full activity) and you fetch the record afterward. Others, like Terra, can deliver normalized data in the payload but send large historical ranges asynchronously in chunks. Design for both shapes and verify per provider.",
          "url": "https://aifitnessapi.com/migrate/polling-to-webhooks#faq-1"
        },
        {
          "question": "Can I stop polling once webhooks are live?",
          "answer": "Not entirely. Webhooks are best-effort and can be missed during endpoint downtime or dropped deliveries, with no built-in catch-up. Keep a low-frequency reconciliation poll as a permanent fallback and gap back-fill rather than removing polling completely.",
          "url": "https://aifitnessapi.com/migrate/polling-to-webhooks#faq-2"
        },
        {
          "question": "Why do I need idempotency and ordering guards?",
          "answer": "Webhook delivery is at-least-once and not ordered, so the same event can arrive more than once and out of sequence. Dedupe on a unique event id, and use timestamps or version numbers so a stale event does not overwrite newer state.",
          "url": "https://aifitnessapi.com/migrate/polling-to-webhooks#faq-3"
        },
        {
          "question": "How many webhook subscriptions can I create?",
          "answer": "It depends on the provider. Some cap subscriptions per app - Strava is documented as one push subscription per application. Do not hardcode this; verify the current limit in the provider's webhook docs as of 2026.",
          "url": "https://aifitnessapi.com/migrate/polling-to-webhooks#faq-4"
        },
        {
          "question": "Will webhooks lower my rate-limit usage?",
          "answer": "Generally yes, because you stop spending request budget polling for unchanged data and only act when an event fires. Actual limits vary and change - verify current provider numbers rather than relying on any quoted figure.",
          "url": "https://aifitnessapi.com/migrate/polling-to-webhooks#faq-5"
        }
      ]
    },
    {
      "question": "strava api changes 2024 migration",
      "answer": "Strava has tightened its API and Developer Program in changes rolling out from 2024 onward, so a live integration needs to be brought back into compliance rather than left as-is. Re-read the current developer agreement, re-audit every field you store or display, confirm athlete consent shows in your UI, and re-check rate limits and the one-subscription-per-app webhook constraint. The biggest gotcha: routing Strava data through third-party intermediary platforms may no longer be supported, so an aggregator-mediated setup can require a direct rebuild. Treat it as a real re-integration and verify every specific against the current Strava developer agreement and API Policy.",
      "title": "Adapting Your Integration to Strava's API Changes",
      "url": "https://aifitnessapi.com/migrate/adapt-to-strava-api-changes",
      "markdown": "https://aifitnessapi.com/migrate/adapt-to-strava-api-changes.md",
      "cluster": "Migrations",
      "cluster_url": "https://aifitnessapi.com/migrate",
      "last_reviewed": "2026-07-20",
      "first_party": false,
      "faqs": [
        {
          "question": "What changed in Strava's API since 2024?",
          "answer": "At a high level, and rolling out over time: formal developer tiers (Standard and Extended Access), a Developer Program review with display and branding rules, restrictions on routing data through intermediary platforms, athlete-permission requirements, documented rate limits, one webhook subscription per app, and a subscription being required for Standard Tier access. Exact numbers, fees, and dates change often, so verify the current Strava developer agreement and API Policy.",
          "url": "https://aifitnessapi.com/migrate/adapt-to-strava-api-changes#faq-1"
        },
        {
          "question": "Can I still use an aggregator for Strava data?",
          "answer": "Maybe not. Strava has reportedly stopped supporting apps that route its data through third-party intermediary platforms, which can include some aggregator setups. Check whether your aggregator's Strava path still complies under the current terms, and plan a direct integration if it does not. Confirm the current wording before rebuilding.",
          "url": "https://aifitnessapi.com/migrate/adapt-to-strava-api-changes#faq-2"
        },
        {
          "question": "Do I have to reformat or remove data I already store?",
          "answer": "Possibly. How athlete data can be displayed and retained is constrained by the current terms, so a field you store or render today may need to be reformatted or dropped. Audit every Strava field against the live agreement rather than assuming your existing handling still complies.",
          "url": "https://aifitnessapi.com/migrate/adapt-to-strava-api-changes#faq-3"
        },
        {
          "question": "Will my athletes have to reconnect?",
          "answer": "Athlete permission and consent are required and must be visible in your UI. If you change how you collect consent to meet current requirements, plan for athletes to re-authorize rather than assuming existing grants carry over silently.",
          "url": "https://aifitnessapi.com/migrate/adapt-to-strava-api-changes#faq-4"
        },
        {
          "question": "What are the current rate limits and tier caps?",
          "answer": "Strava documents default limits (overall vs non-upload, per-window and per-day) and a limited athlete cap on the Standard tier, but the exact numbers, caps, fees, and effective dates change. Do not build against any specific value from memory; verify the current Strava developer agreement and API Policy.",
          "url": "https://aifitnessapi.com/migrate/adapt-to-strava-api-changes#faq-5"
        }
      ]
    },
    {
      "question": "migrate fitness api without losing users",
      "answer": "Moving a fitness or health integration to a new source is a real re-integration, not a flag flip. The biggest gotcha is that connections do not transfer: OAuth grants and refresh tokens are bound to your old app or aggregator, so every user must re-authorize the new one. Keep users connected by running old and new in parallel, shipping a re-consent flow, migrating in waves, and holding rollback until continuity is proven.",
      "title": "Keep Users Connected During a Fitness API Migration",
      "url": "https://aifitnessapi.com/migrate/keep-users-connected-during-migration",
      "markdown": "https://aifitnessapi.com/migrate/keep-users-connected-during-migration.md",
      "cluster": "Migrations",
      "cluster_url": "https://aifitnessapi.com/migrate",
      "last_reviewed": "2026-07-20",
      "first_party": false,
      "faqs": [
        {
          "question": "Do OAuth tokens transfer to the new integration?",
          "answer": "Almost never. Refresh tokens and provider grants are bound to your old app or aggregator, so the new path needs a fresh user authorization. Plan for mandatory re-consent from day one rather than treating it as cleanup.",
          "url": "https://aifitnessapi.com/migrate/keep-users-connected-during-migration#faq-1"
        },
        {
          "question": "Can I back-fill a user's full history on the new source?",
          "answer": "Usually only partially. How far back you can restore is capped by each underlying provider, not by you or your integration partner, and large ranges are often delivered asynchronously in chunks. As of 2026, verify current per-provider caps and expect a gap somewhere.",
          "url": "https://aifitnessapi.com/migrate/keep-users-connected-during-migration#faq-2"
        },
        {
          "question": "How do I avoid losing users who never reconnect?",
          "answer": "Track per-user connection state (old-connected, reconnected, failed) so reminders target only those who still need to act, and keep the old path live for them until they reconnect. Do not decommission until continuity is confirmed.",
          "url": "https://aifitnessapi.com/migrate/keep-users-connected-during-migration#faq-3"
        },
        {
          "question": "Should I cut everyone over at once?",
          "answer": "No. Migrate in waves with monitoring on both paths, and hold a rollback option until each cohort is validated. A big-bang cutover with no fallback is how continuity fails at scale.",
          "url": "https://aifitnessapi.com/migrate/keep-users-connected-during-migration#faq-4"
        }
      ]
    },
    {
      "question": "migrate off deprecated fitness api",
      "answer": "Migrating off a deprecated fitness or health API is a real re-integration, not a config swap: you adopt a successor with a new data schema and usually a new auth model, and most users must reconnect because tokens do not carry over. The biggest silent gap is historical data, which is provider-capped and often not fully recoverable. Run the successor in parallel with a rollback path, migrate users in waves, and decommission only after the new path is validated. Verify the vendor's current timeline and data-type coverage before you cut over.",
      "title": "Migrate off a deprecated fitness API",
      "url": "https://aifitnessapi.com/migrate/migrate-off-a-deprecated-fitness-api",
      "markdown": "https://aifitnessapi.com/migrate/migrate-off-a-deprecated-fitness-api.md",
      "cluster": "Migrations",
      "cluster_url": "https://aifitnessapi.com/migrate",
      "last_reviewed": "2026-07-20",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I keep my users' existing connections and tokens?",
          "answer": "Generally no. Because the successor changes the OAuth provider/library or moves from OAuth scopes to OS-level permissions, access and refresh tokens do not transfer. Plan for mandatory re-consent from day one; there is no silent migration of consent. Verify the specific move's re-auth requirements.",
          "url": "https://aifitnessapi.com/migrate/migrate-off-a-deprecated-fitness-api#faq-1"
        },
        {
          "question": "Will I get all my historical data on the new API?",
          "answer": "Usually not fully. Back-fill depth is set by each underlying provider, not by you, and on-device successors often gate history behind a dedicated permission and a short default window. Pull what the new source allows, document the gap, and verify each provider's current cap before promising history.",
          "url": "https://aifitnessapi.com/migrate/migrate-off-a-deprecated-fitness-api#faq-2"
        },
        {
          "question": "Do I have to re-architect if the successor is on-device?",
          "answer": "If you previously read data server-to-server and the successor is an on-device store (Health Connect or HealthKit), yes. On-device stores have no cloud endpoint, so you read in the app and sync to your own backend yourself, or use an aggregator that runs an on-device SDK and forwards data. Verify the successor's architecture.",
          "url": "https://aifitnessapi.com/migrate/migrate-off-a-deprecated-fitness-api#faq-3"
        },
        {
          "question": "Can an aggregator remove the need to migrate at all?",
          "answer": "It can shift the burden. An aggregator that already supports both the old and successor APIs can absorb the cutover so you keep one integration. Trade-offs are recurring cost, third-party data-path trust, and coverage limits. Verify the aggregator's current support for your providers before relying on it.",
          "url": "https://aifitnessapi.com/migrate/migrate-off-a-deprecated-fitness-api#faq-4"
        }
      ]
    },
    {
      "question": "fitbit api pricing",
      "answer": "The Fitbit Web API is free to call - there is no documented per-request fee, and developer app registration is free. The costs that actually bite are the approval and OAuth setup effort, your own server and storage infrastructure, and the fact that each user must own a Fitbit device and account. Note that Fitbit is migrating to the Google Health API during 2026 and the successor's pricing model is not clearly public - verify current pricing before you build.",
      "title": "Fitbit API Pricing: What Does It Actually Cost?",
      "url": "https://aifitnessapi.com/pricing/fitbit-api-pricing",
      "markdown": "https://aifitnessapi.com/pricing/fitbit-api-pricing.md",
      "cluster": "Pricing",
      "cluster_url": "https://aifitnessapi.com/pricing",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "Is the Fitbit API free?",
          "answer": "Yes - the Fitbit Web API is free to call. There is no documented per-request fee to access it, and registering a developer app on the Fitbit developer portal costs nothing. 'Free to call' is not the same as 'free to use', though: your end users must own a Fitbit device and hold a Fitbit or Google account, and you pay for your own infrastructure. As of 2026, verify current pricing before you rely on it.",
          "url": "https://aifitnessapi.com/pricing/fitbit-api-pricing#faq-1"
        },
        {
          "question": "What do you actually pay for with a Fitbit integration?",
          "answer": "Not the API calls themselves. You pay in engineering time (developer app approval, OAuth 2.0 setup) and in your own infrastructure - servers, data storage, token refresh, webhook handling, and maintenance. Fitbit does not host your integration. The user-side dependency is that your users must already own a Fitbit.",
          "url": "https://aifitnessapi.com/pricing/fitbit-api-pricing#faq-2"
        },
        {
          "question": "Is there a rate limit on the Fitbit API?",
          "answer": "The Fitbit Web API has historically been reported at 150 requests per hour per consented user, resetting near the top of each hour, with no separate per-call fee. This number may change with the Google Health API migration - verify the current limit on Fitbit's own developer documentation.",
          "url": "https://aifitnessapi.com/pricing/fitbit-api-pricing#faq-3"
        },
        {
          "question": "How does the Google Health API migration affect Fitbit pricing?",
          "answer": "Fitbit is migrating developers to the Google Health API during 2026, with new integrations reportedly targeting it by around end of May 2026 and legacy endpoints scheduled for deprecation around September 30, 2026 - confirm dates on Fitbit and Google's own pages. The successor consumer Google Health API's pricing and quota model is not clearly public yet. Note it is a different product from the enterprise Google Cloud Healthcare API, whose published pricing does not describe the Fitbit replacement. Verify before committing.",
          "url": "https://aifitnessapi.com/pricing/fitbit-api-pricing#faq-4"
        },
        {
          "question": "Is Fitbit Premium the same as paying for the API?",
          "answer": "No. Fitbit Premium is an optional consumer subscription for end users; it is not an API access fee. Do not conflate the two when budgeting - the API itself carries no documented per-call charge.",
          "url": "https://aifitnessapi.com/pricing/fitbit-api-pricing#faq-5"
        }
      ]
    },
    {
      "question": "garmin api pricing",
      "answer": "Garmin does not publish pricing for its developer APIs. Access to the Health API and Activity API runs through the Garmin Connect Developer Program, which is partner-approval-only rather than self-serve, so commercial terms are settled privately in a partnership conversation rather than shown on a price list. The cost that reliably bites is user-side (your users must own a Garmin device) plus your own approval time and infrastructure. Some third-party reports mention a setup fee, but Garmin does not list pricing publicly, so verify any figure directly with Garmin.",
      "title": "Garmin API Pricing: What Does It Actually Cost?",
      "url": "https://aifitnessapi.com/pricing/garmin-api-pricing",
      "markdown": "https://aifitnessapi.com/pricing/garmin-api-pricing.md",
      "cluster": "Pricing",
      "cluster_url": "https://aifitnessapi.com/pricing",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "Is the Garmin API free?",
          "answer": "Unconfirmed. Garmin does not publicly list its developer API terms, so there is no evidence it is free and no confirmation of a fee either. Access is gated behind partner approval, and commercial terms are negotiated in a partner agreement. Verify directly with Garmin rather than assuming it is free or paid.",
          "url": "https://aifitnessapi.com/pricing/garmin-api-pricing#faq-1"
        },
        {
          "question": "Does Garmin charge a setup fee for API access?",
          "answer": "Possibly, but it is unconfirmed. Some third-party integrator guides mention a one-time setup or administrative fee, and some mention separate licensing for certain premium metrics. None of this appears on a Garmin-owned page we could confirm, so do not budget against any circulating number. Get the actual terms from Garmin in writing.",
          "url": "https://aifitnessapi.com/pricing/garmin-api-pricing#faq-2"
        },
        {
          "question": "How do I get pricing for the Garmin API?",
          "answer": "By applying to the Garmin Connect Developer Program and going through partner approval, where Garmin vets your use case, company, and data handling before terms are settled. There is no public price list; pricing comes from a sales or partnership conversation. Confirm the program is currently open before planning around it, as it has reportedly paused new sign-ups at times.",
          "url": "https://aifitnessapi.com/pricing/garmin-api-pricing#faq-3"
        },
        {
          "question": "What does the Garmin API cost my users?",
          "answer": "Your end users must own a Garmin device for their data to exist and flow through the API. That is a one-time hardware purchase; no separate consumer subscription is required for basic Garmin Connect use as of 2026. Verify current terms, since device and account requirements can change.",
          "url": "https://aifitnessapi.com/pricing/garmin-api-pricing#faq-4"
        },
        {
          "question": "Is there a cheaper or more predictable alternative to Garmin's direct API?",
          "answer": "Reaching Garmin data through a health-data aggregator can trade Garmin's private-terms uncertainty and approval gate for a recurring, quotable per-user fee. That is a build-versus-buy decision. See the alternatives and wearable-data-API pages to weigh it, and verify each vendor's current pricing directly.",
          "url": "https://aifitnessapi.com/pricing/garmin-api-pricing#faq-5"
        }
      ]
    },
    {
      "question": "strava api pricing",
      "answer": "The Strava API has no per-call developer fee — you register an app and call it without paying Strava a usage bill. The nuance for 2026: Standard-tier developers now reportedly must hold a paid Strava subscription (reported around $11.99/mo in the US, varies by country) to keep API access, so a membership cost effectively gates Standard access. That developer subscription, plus the 2024-onward display and AI-use restrictions, is the real cost to budget. Verify every figure and date against Strava's current developer agreement and API Policy — the terms changed recently and vary by geography.",
      "title": "Strava API Pricing: What Does It Actually Cost?",
      "url": "https://aifitnessapi.com/pricing/strava-api-pricing",
      "markdown": "https://aifitnessapi.com/pricing/strava-api-pricing.md",
      "cluster": "Pricing",
      "cluster_url": "https://aifitnessapi.com/pricing",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "Is the Strava API free?",
          "answer": "It is free to call — there is no documented per-request fee to access the API. But it is no longer unconditionally free to use: as reported for 2026, Standard-tier developers must hold a paid Strava subscription to keep API access. So there is effectively a membership cost in front of Standard access even though the API calls themselves are not metered. Verify the current requirement on Strava's own developer pages.",
          "url": "https://aifitnessapi.com/pricing/strava-api-pricing#faq-1"
        },
        {
          "question": "How much is the Strava developer subscription?",
          "answer": "It is reported to be the normal Strava membership rather than a separate developer-only fee — cited around $11.99 per month in the US, but the price varies by country. This figure is US-specific and geography-dependent, and the primary announcement could not be machine-verified during research. Treat it as 'as of 2026, verify' and confirm the current price on Strava's own pricing page before budgeting.",
          "url": "https://aifitnessapi.com/pricing/strava-api-pricing#faq-2"
        },
        {
          "question": "Who has to pay — the developer or the end user?",
          "answer": "Keep them separate. The end user needs a Strava account (free or paid) for their data to exist. The new 2026 twist is on the developer side: Standard-tier developers reportedly now also need a paid subscription for API access. New Standard-tier developers were said to need it from June 1, 2026, existing ones a little later, and Extended Access developers reportedly were not affected. Verify which tier and dates apply to you.",
          "url": "https://aifitnessapi.com/pricing/strava-api-pricing#faq-3"
        },
        {
          "question": "Are there Strava API rate limits or usage restrictions?",
          "answer": "Yes. Strava documents per-application rate limits, and a 2024 agreement update reportedly restricts displaying an athlete's data to that same athlete, bans using Strava data to train AI or ML models, and forbids replicating Strava's core functionality. This page does not quote specific rate-limit numbers because they could not be verified from a primary source — check developers.strava.com for current values rather than hardcoding a figure.",
          "url": "https://aifitnessapi.com/pricing/strava-api-pricing#faq-4"
        },
        {
          "question": "Is there a cheaper way to get the same data?",
          "answer": "It depends on your product. If the developer-subscription requirement or the display and AI-use rules conflict with what you are building, a cross-device aggregator (priced per connected user or per monthly active user) or a different first-party API may fit better, each with its own trade-offs. Compare options before committing to Strava's model.",
          "url": "https://aifitnessapi.com/pricing/strava-api-pricing#faq-5"
        }
      ]
    },
    {
      "question": "oura api pricing",
      "answer": "The Oura API is free to call: there is no publicly listed developer or per-request fee, and you register an app and authenticate over OAuth 2.0 for free. The cost that actually bites is user-side: your users must own an Oura Ring, and as of 2026 Gen3 ring users reportedly need an active Oura Membership for their data to flow through the API. Treat the membership rule and any price as 'verify current terms' before you build against them.",
      "title": "Oura API pricing: what it actually costs",
      "url": "https://aifitnessapi.com/pricing/oura-api-pricing",
      "markdown": "https://aifitnessapi.com/pricing/oura-api-pricing.md",
      "cluster": "Pricing",
      "cluster_url": "https://aifitnessapi.com/pricing",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "Is the Oura API free?",
          "answer": "The Oura API is free to call: no developer or per-request fee is publicly listed. You create an app and authenticate over OAuth 2.0 at no cost. The real costs are your own infrastructure and the user-side requirement to own a ring and, for Gen3, hold a membership. Verify current terms with Oura.",
          "url": "https://aifitnessapi.com/pricing/oura-api-pricing#faq-1"
        },
        {
          "question": "Do users need an Oura Membership to use the API?",
          "answer": "As of 2026, Oura's guidance indicates Gen3 Oura Ring users without an active Oura Membership can no longer access their data through the API, while Gen2 users are reportedly unaffected. This is a subscription your users pay, not an API fee. Confirm the current requirement and price on Oura's own pages before relying on it.",
          "url": "https://aifitnessapi.com/pricing/oura-api-pricing#faq-2"
        },
        {
          "question": "What is the difference between a personal-access token and the partner API?",
          "answer": "Oura historically issued Personal Access Tokens (PATs) for single-account use, but PATs have been deprecated in favor of OAuth 2.0 (older tokens may still work during a transition). A new app can connect only a small number of users, reported around 10, until you pass Oura's review for the partner or 'Oura for Organizations' path. Verify the current cap and process.",
          "url": "https://aifitnessapi.com/pricing/oura-api-pricing#faq-3"
        },
        {
          "question": "How much does an Oura Membership cost?",
          "answer": "Oura Membership is a recurring subscription commonly cited at a few dollars a month or roughly seventy dollars a year, with the ring a separate one-time purchase. Prices change and vary, so we do not quote a hard figure here: check Oura's current pricing page to confirm.",
          "url": "https://aifitnessapi.com/pricing/oura-api-pricing#faq-4"
        },
        {
          "question": "Are there commercial or enterprise pricing tiers for the Oura API?",
          "answer": "Beyond the free small-app path, broader or commercial use goes through Oura's review and the 'Oura for Organizations' partner track. Any enterprise or commercial terms are not publicly listed, so plan to verify them directly with Oura.",
          "url": "https://aifitnessapi.com/pricing/oura-api-pricing#faq-5"
        }
      ]
    },
    {
      "question": "whoop api pricing",
      "answer": "The WHOOP API is free to call — there is no documented per-request fee — but developer access is gated by registration on the Developer Platform, and WHOOP requires developers to hold a membership. The cost that actually bites is user-side: WHOOP is subscription hardware, so every end user needs an active WHOOP membership for their data to flow through the API. WHOOP has changed its membership structure recently, so verify current terms before you budget.",
      "title": "WHOOP API Pricing: What Does It Actually Cost?",
      "url": "https://aifitnessapi.com/pricing/whoop-api-pricing",
      "markdown": "https://aifitnessapi.com/pricing/whoop-api-pricing.md",
      "cluster": "Pricing",
      "cluster_url": "https://aifitnessapi.com/pricing",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "Is the WHOOP API free?",
          "answer": "The API is free to call — no documented per-request fee to access the WHOOP Developer Platform. But it is gated: you register on the platform and WHOOP requires developers to hold an active membership and device. Free to call is not the same as free to use, because your users must be paying members for their data to exist.",
          "url": "https://aifitnessapi.com/pricing/whoop-api-pricing#faq-1"
        },
        {
          "question": "What is the real cost of building on WHOOP?",
          "answer": "For the developer it is approval and setup effort plus your own infrastructure (servers, storage, OAuth token refresh, webhooks), not an API fee. The dominant real cost is user-side: WHOOP's subscription-hardware model means every end user pays a recurring WHOOP membership, which limits your addressable users to current subscribers.",
          "url": "https://aifitnessapi.com/pricing/whoop-api-pricing#faq-2"
        },
        {
          "question": "Do I need a WHOOP membership to use the API?",
          "answer": "Reportedly yes. WHOOP requires developers on the Developer Platform to have a WHOOP device and active membership to build an app, and every end user needs an active membership for their data. Confirm the current requirement on WHOOP's own developer docs, as terms change.",
          "url": "https://aifitnessapi.com/pricing/whoop-api-pricing#faq-3"
        },
        {
          "question": "How much is a WHOOP membership?",
          "answer": "WHOOP has restructured its membership and upgrade model recently and drawn press coverage for it, so we do not publish a specific tier price here. A free trial with hardware has been offered at times. Verify the current membership tiers and prices on WHOOP's own pricing page before you rely on any figure.",
          "url": "https://aifitnessapi.com/pricing/whoop-api-pricing#faq-4"
        },
        {
          "question": "Is there a cheaper way to get WHOOP-style data?",
          "answer": "If you only need WHOOP data, calling the API directly is the low-fee path. If you need many wearables, a cross-device aggregator priced per connected user or per MAU can replace several first-party integrations. See the WHOOP API alternatives and the wider fitness API cost breakdown to compare.",
          "url": "https://aifitnessapi.com/pricing/whoop-api-pricing#faq-5"
        }
      ]
    },
    {
      "question": "health data aggregator api pricing",
      "answer": "Unlike most first-party wearable APIs, health-data aggregators are where a recurring API bill actually lands. Terra, Junction (formerly Vital), Rook, and Spike almost all price on active or connected users (per-MAU), usually tiered by user count with an enterprise 'contact sales' top tier, and sometimes a credit or event layer on top. The biggest cost driver is that your bill scales directly with your connected-user base. Specific per-MAU prices are mostly not publicly listed, and several vendor pricing pages could not be verified, so treat the model as reliable and every number as 'as of 2026, verify with the vendor.'",
      "title": "Health data aggregator API pricing: how Terra, Junction, Rook, and Spike charge",
      "url": "https://aifitnessapi.com/pricing/health-data-aggregator-pricing",
      "markdown": "https://aifitnessapi.com/pricing/health-data-aggregator-pricing.md",
      "cluster": "Pricing",
      "cluster_url": "https://aifitnessapi.com/pricing",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "How do health data aggregators charge for API access?",
          "answer": "Most price on active or connected users (per monthly active user, or per-MAU), usually organized into tiers by user count with an enterprise 'contact sales' tier at the top. Some, notably Terra, add a credit or event allowance on top of the user count. You generally pay per connected end user per month rather than per API call. Specific figures are mostly not publicly listed, so verify current pricing with each vendor.",
          "url": "https://aifitnessapi.com/pricing/health-data-aggregator-pricing#faq-1"
        },
        {
          "question": "How much does Terra, Junction, Rook, or Spike cost per user?",
          "answer": "No reliable per-MAU or per-connection dollar figure is publicly listed for any of them, and several of their pricing pages could not be verified during research. Terra is usage-based on active connected users with a credit layer; Junction (formerly Vital) tiers by user count plus enterprise; Rook uses named active-user tiers; Spike markets usage-based pricing. Get a live quote or open the vendor's pricing page before budgeting a number.",
          "url": "https://aifitnessapi.com/pricing/health-data-aggregator-pricing#faq-2"
        },
        {
          "question": "Why pay an aggregator when first-party wearable APIs are free to call?",
          "answer": "It is a build-vs-buy trade. Supporting many wearables directly means a separate integration, OAuth flow, approval, and schema for each provider, plus ongoing maintenance as they change. An aggregator collapses that into one integration and one normalized data stream and charges a recurring per-user fee for it. You are paying to remove per-provider integration and upkeep work, not per API call.",
          "url": "https://aifitnessapi.com/pricing/health-data-aggregator-pricing#faq-3"
        },
        {
          "question": "Is aggregator pricing predictable?",
          "answer": "The per-MAU model is predictable to model, but it scales directly with your user base by design, so a tier that fits at launch is a different number at scale. Credit or event layers can add a second meter for data-heavy integrations, and anything past the self-serve tiers is negotiated through sales. Model the growth curve, not just the launch price, and verify current tiers.",
          "url": "https://aifitnessapi.com/pricing/health-data-aggregator-pricing#faq-4"
        },
        {
          "question": "Does the aggregator fee replace my other costs?",
          "answer": "No. It removes integration labor, not your platform costs. You still pay for your own infrastructure, storage of high-volume wearable history, token and webhook handling, and health-data compliance such as HIPAA or GDPR handling, encryption, and BAAs. Budget the aggregator fee as one layer on top of those, not a replacement for them.",
          "url": "https://aifitnessapi.com/pricing/health-data-aggregator-pricing#faq-5"
        }
      ]
    },
    {
      "question": "nutrition api pricing",
      "answer": "It depends which kind you pick. Commercial food APIs (Nutritionix, Edamam, Spoonacular) are paid, built on freemium or free-tier-then-paid models with an enterprise contact-sales tier. Two options are genuinely free: USDA FoodData Central (public domain) and Open Food Facts (open data) cost nothing to call. The cost that actually bites is often not the sticker price but the licensing and usage restrictions on the cheaper tiers, and the integration work the free datasets push onto you. Pricing changes often and most vendor pricing pages are gated, so treat every specific figure as 'as of 2026, verify current pricing.'",
      "title": "What does a nutrition API cost?",
      "url": "https://aifitnessapi.com/pricing/nutrition-api-pricing",
      "markdown": "https://aifitnessapi.com/pricing/nutrition-api-pricing.md",
      "cluster": "Pricing",
      "cluster_url": "https://aifitnessapi.com/pricing",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "Is there a free nutrition API?",
          "answer": "Yes. USDA FoodData Central is free and public domain (CC0) with a free data.gov API key, and Open Food Facts is free open data (ODbL) with no key needed to read. Both cost nothing to call, but you self-integrate and maintain everything, and Open Food Facts carries attribution and share-alike obligations. These are different from a paid API's free tier, which is limited and can be curtailed. Verify current terms and rate limits.",
          "url": "https://aifitnessapi.com/pricing/nutrition-api-pricing#faq-1"
        },
        {
          "question": "How much does Nutritionix cost?",
          "answer": "Nutritionix uses tiered paid plans with an enterprise contact-sales top tier and annual billing on larger commitments. Reports indicate it curtailed its open free tier and now requires a sales call to upgrade. Specific tier dollar figures are not confirmable on a primary page, so do not rely on any quoted number without checking the live Nutritionix pricing page.",
          "url": "https://aifitnessapi.com/pricing/nutrition-api-pricing#faq-2"
        },
        {
          "question": "How does Spoonacular pricing work?",
          "answer": "Spoonacular uses a freemium points model. Each plan has a daily points quota and every call spends points, with more complex calls costing more. The free plan requires no credit card and hard-caps rather than billing overages, returning HTTP 402 when the daily quota is exhausted and resetting the next day. Paid tiers raise the daily point budget. Verify current point costs and tier prices, as they were not sourced here.",
          "url": "https://aifitnessapi.com/pricing/nutrition-api-pricing#faq-3"
        },
        {
          "question": "Is a free tier the same as a free dataset?",
          "answer": "No, and conflating them is a common budgeting mistake. A paid API's free tier (Edamam Developer, Spoonacular free plan, Nutritionix historically) is limited, funnels you toward paid tiers, and can be reduced or removed at the vendor's discretion. A free/open dataset (USDA FoodData Central, Open Food Facts) is licensed to be free and is far more durable, though it shifts integration work and license obligations onto you.",
          "url": "https://aifitnessapi.com/pricing/nutrition-api-pricing#faq-4"
        },
        {
          "question": "What is the biggest hidden cost of a nutrition API?",
          "answer": "Usually the licensing and usage restrictions, not the monthly fee. Open Food Facts is ODbL with attribution and share-alike duties; Edamam and Nutritionix reportedly restrict calls to end-user-driven requests and prohibit scraping. On the free datasets, the hidden cost is self-integration, normalization, and coverage gaps. Model these against your real request volume and verify each vendor's current terms.",
          "url": "https://aifitnessapi.com/pricing/nutrition-api-pricing#faq-5"
        }
      ]
    },
    {
      "question": "exercise database api pricing",
      "answer": "It depends on which kind you pick. Paid gateways like ExerciseDB (via RapidAPI) and API Ninjas use a freemium, per-request model - a limited free tier, then paid tiers metered by request volume with overage charges. Free and open options like wger, exercisedb.dev, and free-exercise-db cost $0 for the software or data - you pay only your own hosting. The catch on the free side is licensing: two of the three are AGPL copyleft, which matters for closed-source products. Treat every specific quota or price as 'as of 2026 - verify on the live listing.'",
      "title": "Exercise Database API Pricing: What Does It Cost?",
      "url": "https://aifitnessapi.com/pricing/exercise-database-api-pricing",
      "markdown": "https://aifitnessapi.com/pricing/exercise-database-api-pricing.md",
      "cluster": "Pricing",
      "cluster_url": "https://aifitnessapi.com/pricing",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "Is there a free exercise database API?",
          "answer": "Yes, several. wger (AGPL, self-hosted), exercisedb.dev (AGPL, self-hosted), and free-exercise-db (public domain / Unlicense) are genuinely free for the software or data - you pay only your own hosting. Paid gateways like ExerciseDB on RapidAPI and API Ninjas also offer limited free tiers, but those are freemium hooks that lead to paid, metered plans. Note free-exercise-db is a static dataset, not a live API.",
          "url": "https://aifitnessapi.com/pricing/exercise-database-api-pricing#faq-1"
        },
        {
          "question": "How much does ExerciseDB cost?",
          "answer": "ExerciseDB is sold through the RapidAPI marketplace on a freemium, tiered model: a free BASIC tier with a hard monthly request cap, then paid tiers, with overage charged per request above quota. The exact caps and prices are set per-API on the RapidAPI listing and change often - as of 2026, verify on the live RapidAPI page rather than relying on any figure quoted elsewhere.",
          "url": "https://aifitnessapi.com/pricing/exercise-database-api-pricing#faq-2"
        },
        {
          "question": "What is the AGPL licensing implication for exercise APIs?",
          "answer": "wger and exercisedb.dev are licensed under the GNU AGPL, a strong copyleft license with a network-use trigger: running a modified version as a network service can obligate you to release your modifications under the same license. For a closed-source commercial product this is a real architectural and legal consideration. free-exercise-db, by contrast, is public domain (Unlicense) with no obligations. Get any AGPL dependency reviewed before you build on it.",
          "url": "https://aifitnessapi.com/pricing/exercise-database-api-pricing#faq-3"
        },
        {
          "question": "Can I use these exercise APIs for a commercial product?",
          "answer": "It varies by option and is separate from price. API Ninjas' free tier excludes commercial use - you would need a paid tier. The public-domain free-exercise-db has no restrictions. wger and exercisedb.dev are free to use commercially but carry AGPL copyleft obligations if you distribute or run modified versions. Always check the specific license and terms before shipping.",
          "url": "https://aifitnessapi.com/pricing/exercise-database-api-pricing#faq-4"
        },
        {
          "question": "Are the free exercise databases really free?",
          "answer": "The software and data are $0, but self-hosting still costs servers, bandwidth, uptime, and the engineering time to parse, normalize, and keep the dataset updated. And AGPL options (wger, exercisedb.dev) carry copyleft obligations. 'Free' here means no license or data fee - not zero total cost. Verify the current license and terms on each project's own repository.",
          "url": "https://aifitnessapi.com/pricing/exercise-database-api-pricing#faq-5"
        }
      ]
    },
    {
      "question": "are fitness apis free",
      "answer": "Many fitness APIs are free to call - most first-party wearable APIs (Fitbit, Oura, WHOOP) charge no per-request fee, and a few nutrition and exercise datasets are genuinely free and open. But 'free to call' is not 'free to use': aggregators are paid per connected user, Strava and Garmin break the pattern, and the biggest costs (user memberships, approval time, your own infrastructure) sit outside the API sticker. Pricing changed in 2026 and varies by country, so verify current pricing on each provider's own page.",
      "title": "Are Fitness APIs Free? An Honest Overview",
      "url": "https://aifitnessapi.com/pricing/are-fitness-apis-free",
      "markdown": "https://aifitnessapi.com/pricing/are-fitness-apis-free.md",
      "cluster": "Pricing",
      "cluster_url": "https://aifitnessapi.com/pricing",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "Are fitness APIs free?",
          "answer": "Many are free to call - most first-party wearable APIs, including Fitbit, Oura, and WHOOP, charge no per-request fee, and some nutrition and exercise datasets are genuinely free and open. But it is not universal: aggregators like Terra and Junction are paid per connected user, and Strava and Garmin have their own gates. 'Free to call' also is not 'free to use', because your users must own the device and often pay a membership. As of 2026, verify current pricing per provider.",
          "url": "https://aifitnessapi.com/pricing/are-fitness-apis-free#faq-1"
        },
        {
          "question": "Which fitness APIs are genuinely free and open?",
          "answer": "For data you can use at $0, the clearest options are USDA FoodData Central (public domain nutrition data, free API key), Open Food Facts (open food database, no key, with ODbL attribution terms), wger (open-source workout and nutrition API, AGPL, self-host), and free-exercise-db (public-domain exercise dataset). These are truly free but shift integration, hosting, and license-compliance work onto you. Our roundup at /fitness-apis/free-fitness-apis covers them in detail.",
          "url": "https://aifitnessapi.com/pricing/are-fitness-apis-free#faq-2"
        },
        {
          "question": "If the API is free to call, what actually costs money?",
          "answer": "The provider's price tag is usually the smallest number. The real costs are your users owning the device or paying a membership (Oura Membership, WHOOP subscription), the calendar time to pass partner approval (Garmin, Oura partner tier, WHOOP), maintenance as APIs migrate (Fitbit's 2026 move to the Google Health API forces a rebuild), and your own infrastructure - servers, storage of high-volume history, token refresh, and monitoring.",
          "url": "https://aifitnessapi.com/pricing/are-fitness-apis-free#faq-3"
        },
        {
          "question": "Which fitness APIs are not free?",
          "answer": "Cross-device aggregators (Terra, Junction formerly Vital, Rook, Spike) are paid by design, typically per connected user or per monthly active user, tiered, with enterprise contact-sales; specific rates are rarely public - verify. Among first-party APIs, Strava reportedly now requires Standard-tier developers to hold a paid Strava subscription (2026), and Garmin is partner-approval-only with terms not publicly listed. Do not label Garmin free. Commercial nutrition and exercise content APIs (Nutritionix, Edamam, Spoonacular, ExerciseDB) are freemium or tiered.",
          "url": "https://aifitnessapi.com/pricing/are-fitness-apis-free#faq-4"
        },
        {
          "question": "Is a free tier the same as a free and open API?",
          "answer": "No. A freemium free tier is a limited slice of a paid product - it can be capped, curtailed, or removed (Nutritionix reportedly narrowed its open free tier), and it exists to lead into paid plans. A free and open dataset like USDA FoodData Central or free-exercise-db is licensed to be free and used freely, though open licenses (public domain, ODbL, AGPL) carry different obligations. Keep the two distinct when you plan for the long term.",
          "url": "https://aifitnessapi.com/pricing/are-fitness-apis-free#faq-5"
        }
      ]
    },
    {
      "question": "how much does a fitness api cost",
      "answer": "There is no single fitness API price. Cost is driven by which pricing model you land in - free-to-call first-party APIs, per-MAU or per-connection aggregators, tiered freemium content APIs, or free self-host - and by hidden costs that usually dwarf the sticker. The cost that bites most is rarely the API fee itself: it is your own infrastructure, the maintenance time as providers change their terms, and the approval time before you can ship. Every specific figure in this space is volatile, so verify current pricing on the vendor's own page before you budget.",
      "title": "How Much Does a Fitness API Cost?",
      "url": "https://aifitnessapi.com/pricing/how-much-does-a-fitness-api-cost",
      "markdown": "https://aifitnessapi.com/pricing/how-much-does-a-fitness-api-cost.md",
      "cluster": "Pricing",
      "cluster_url": "https://aifitnessapi.com/pricing",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "How much does a fitness API cost?",
          "answer": "It depends entirely on the pricing model. Many first-party wearable APIs are free to call, cross-device aggregators charge a recurring fee per connected user or per monthly active user, and some nutrition and exercise content APIs are freemium or tiered by request volume. Genuinely free open-source and public-dataset options also exist if you self-host. There is no single headline price, and the biggest cost is usually your own infrastructure and maintenance rather than the API fee. As of 2026, verify current pricing directly with each vendor.",
          "url": "https://aifitnessapi.com/pricing/how-much-does-a-fitness-api-cost#faq-1"
        },
        {
          "question": "What actually drives the cost of a fitness API integration?",
          "answer": "Four things dominate: the pricing model of the API itself, your own infrastructure and data-storage costs, the ongoing maintenance labor as providers deprecate or migrate their APIs, and the approval or compliance time before you can ship. Health-data licensing and privacy obligations add further engineering and legal cost. In most real products these hidden costs exceed the quoted API fee - even when that fee is zero.",
          "url": "https://aifitnessapi.com/pricing/how-much-does-a-fitness-api-cost#faq-2"
        },
        {
          "question": "Is it cheaper to build direct integrations or buy an aggregator?",
          "answer": "It is a trade-off, not a fixed answer. Building direct first-party integrations means low or zero API fees but separate engineering work per provider and ongoing maintenance as each one changes. Buying an aggregator means a real recurring per-user fee in exchange for one integration covering many devices and much lower maintenance. Few devices plus engineering time favors building; broad device coverage plus a predictable per-user budget favors buying. Most teams mix both.",
          "url": "https://aifitnessapi.com/pricing/how-much-does-a-fitness-api-cost#faq-3"
        },
        {
          "question": "What are the hidden costs of a fitness API?",
          "answer": "The ones people forget: infrastructure and hosting, storage of high-volume wearable data that grows with your user base, maintenance when a provider changes or migrates its API, approval and time-to-market for partner review, metered-overage surprises on freemium tiers, and licensing or compliance obligations such as attribution, copyleft, or HIPAA and GDPR handling. These recurring costs usually outweigh the API's sticker price.",
          "url": "https://aifitnessapi.com/pricing/how-much-does-a-fitness-api-cost#faq-4"
        },
        {
          "question": "Are any fitness APIs genuinely free?",
          "answer": "Yes, some are free to call with no per-request fee, and a few open-source projects and public datasets are genuinely free to use if you self-host. But free to call is not the same as free to use: you still pay for infrastructure, storage, and maintenance, and open datasets carry licensing obligations ranging from none to copyleft. See the dedicated breakdown of which fitness APIs are actually free before assuming zero cost.",
          "url": "https://aifitnessapi.com/pricing/how-much-does-a-fitness-api-cost#faq-5"
        }
      ]
    },
    {
      "question": "fitness api free tier comparison",
      "answer": "Across the 25 items in this site's own State of Fitness APIs 2026 dataset, free means four different things: free to call with no per-request fee (12 items), a free tier that runs out (5 items), free open-source code or models where your engineering time is the bill, and free data whose licence obligations constrain what you can ship. Those categories behave completely differently over time, so comparing them as one thing is the mistake that wrecks a budget. Of the 12 free-to-call items only five carry no approval gate and no user-side cost, and every one of those five is a dataset or a model rather than a live personal-data feed. This page carries no dollar figures on purpose: prices are volatile, structures are stable, and the structure is what you design against.",
      "title": "Fitness API Free Tiers Compared: What Free Actually Includes",
      "url": "https://aifitnessapi.com/pricing/fitness-api-free-tiers-compared",
      "markdown": "https://aifitnessapi.com/pricing/fitness-api-free-tiers-compared.md",
      "cluster": "Pricing",
      "cluster_url": "https://aifitnessapi.com/pricing",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "What are the four different things vendors mean by free?",
          "answer": "Free to call: no per-request fee documented, with the constraint arriving as an approval, a user-side dependency, or a scope restriction. A free tier that runs out: a real entry point into a paid product, which the vendor can narrow or withdraw. Free code or open models: nothing to obtain, but everything they do not do becomes your engineering bill. Free data with licence obligations: no money changes hands, but attribution, share-alike, or copyleft terms constrain what you can ship. Only the first two look alike on a pricing page.",
          "url": "https://aifitnessapi.com/pricing/fitness-api-free-tiers-compared#faq-1"
        },
        {
          "question": "Which free-to-call fitness APIs carry no approval gate and no user-side cost?",
          "answer": "Five of the twelve free-to-call items in the 2026 dataset have both fields null: Polar Open AccessLink, USDA FoodData Central, MediaPipe Pose Landmarker, TensorFlow MoveNet, and Apple Vision body pose. Note what they have in common — each is a dataset, a model, or a self-serve feed rather than an API returning a named person's health history. Open Food Facts and wger also record no gate, but both carry licence obligations instead. A null field means not documented on our pages, never proof that no catch exists.",
          "url": "https://aifitnessapi.com/pricing/fitness-api-free-tiers-compared#faq-2"
        },
        {
          "question": "Where does each fitness API free tier stop?",
          "answer": "In five different places, and only two of them are a request quota. Strava stops on permitted use, since athlete data may generally only be shown back to that athlete and AI or ML training is prohibited. Edamam stops on request provenance, with terms reportedly restricting calls to end-user-driven requests. ExerciseDB stops on commercial use plus a hard request cap. Nutritionix stops at a Syndigo sales conversation. QuickPose stops above a monthly-active-device threshold. Verify each against the provider's live terms.",
          "url": "https://aifitnessapi.com/pricing/fitness-api-free-tiers-compared#faq-3"
        },
        {
          "question": "Which free-tier fitness APIs restrict commercial use or how you use the data?",
          "answer": "Three of the five, in different ways. The ExerciseDB free tier on RapidAPI is often non-commercial outright. Edamam requires attribution on lower plans and reportedly restricts calls to end-user-driven requests while prohibiting scraping or bulk saving, which rules out pre-fetching a catalogue. Strava permits commercial products but restricts what you may display and prohibits using athlete data to train AI or ML models. Among the free-to-call items, Open Food Facts allows commercial use under ODbL share-alike, and wger's code is AGPL-3.0 copyleft.",
          "url": "https://aifitnessapi.com/pricing/fitness-api-free-tiers-compared#faq-4"
        },
        {
          "question": "Why does this comparison list no dollar figures?",
          "answer": "Because the dataset behind it has none by design, and its methodology states why: prices are volatile, structures are stable. A vendor can reprice twice a year without changing the fact that its API sits behind a partner review or that its data only exists for people who already bought hardware. There is a practical reason too — serious tiers in this market are contact-sales, and most figures circulating in third-party posts were stale on publication. Structure is what you design against; price is what you negotiate later.",
          "url": "https://aifitnessapi.com/pricing/fitness-api-free-tiers-compared#faq-5"
        }
      ]
    },
    {
      "question": "oura vs whoop api",
      "answer": "Pick the Oura API when your app is built on sleep architecture, HRV, and nightly body-temperature deviation from users who often own their ring outright; pick the WHOOP API when you want a Recovery-and-strain framing from a base where the hardware is a subscription, so every active user is a paying member with full data. Both are cloud REST APIs on OAuth 2.0 with scoped tokens and webhooks. The biggest developer differences: Oura's Personal Access Tokens were deprecated around December 2025 (verify), full Oura Gen3+ data needs a membership so completeness varies, and WHOOP uses rotating refresh tokens that can trip up multi-worker backends.",
      "title": "Oura vs WHOOP: Which API for Your App?",
      "url": "https://aifitnessapi.com/compare/oura-vs-whoop",
      "markdown": "https://aifitnessapi.com/compare/oura-vs-whoop.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "What data does the Oura API expose that WHOOP does not?",
          "answer": "Oura's API v2 centers on sleep with stages, HRV, respiratory rate, a Readiness Score with named contributors, and nightly body-temperature deviation from the user's personal baseline. WHOOP reports skin temperature for 4.0 members but frames the day around a Recovery percentage and daily strain rather than a readiness-contributor breakdown. Verify the current metric lists and which are gated to specific bands in each provider's docs.",
          "url": "https://aifitnessapi.com/compare/oura-vs-whoop#faq-1"
        },
        {
          "question": "Do PATs still work for the Oura API?",
          "answer": "Personal Access Tokens were deprecated around December 2025, so new PATs can no longer be created and new integrations must use OAuth 2.0 Authorization Code flow with scoped Bearer tokens. Whether existing PATs still function is worth confirming directly, and the exact deprecation date should be verified in Oura's authentication docs before you rely on it.",
          "url": "https://aifitnessapi.com/compare/oura-vs-whoop#faq-2"
        },
        {
          "question": "Does every WHOOP user have full API data, unlike Oura?",
          "answer": "Effectively yes for active WHOOP members: WHOOP's hardware is sold as a subscription, so every active user is a paying member and data completeness is reliable. Oura is different — a user needs a ring, and full Gen3+ readiness and insights require an Oura membership, so a ring owner without an active subscription can return thinner data. Design for that variance if you integrate Oura.",
          "url": "https://aifitnessapi.com/compare/oura-vs-whoop#faq-3"
        },
        {
          "question": "Do Oura and WHOOP both support webhooks?",
          "answer": "Yes. Oura offers webhook subscriptions per data_type (sleep, readiness, activity, workout, and more) with create, update, and delete events. WHOOP offers v2 webhooks such as sleep.updated, recovery.updated, and workout.updated or deleted; note that v1 webhooks have been removed, so build against v2. Verify current event names and payloads in each provider's webhook docs.",
          "url": "https://aifitnessapi.com/compare/oura-vs-whoop#faq-4"
        },
        {
          "question": "Should I integrate Oura and WHOOP directly or use an aggregator?",
          "answer": "Integrate directly when you need only one or two sources and want the deepest native fields and control. If you plan to support many wearables at once, a health-data aggregator lets you code one integration instead of maintaining separate OAuth flows and webhook handlers per provider. See our wearable data APIs overview to weigh the trade-off, and verify each aggregator's coverage and pricing model.",
          "url": "https://aifitnessapi.com/compare/oura-vs-whoop#faq-5"
        }
      ]
    },
    {
      "question": "fitbit vs apple watch api",
      "answer": "Pick Fitbit if you want backend-first, cross-platform access - it is a cloud Web API your servers call with OAuth 2.0, without the user's phone present. Pick Apple Watch via HealthKit if you are building an iOS-native app for users already in Apple Health. The single biggest developer difference: Fitbit is a cloud API, while Apple Watch has no cloud endpoint at all - its data lives on-device in HealthKit, so you must ship a native iOS app and sync it yourself. As of 2026, Fitbit's Web API is migrating to the Google Health API - verify current dates.",
      "title": "Fitbit vs Apple Watch: Which for Your App?",
      "url": "https://aifitnessapi.com/compare/fitbit-vs-apple-watch",
      "markdown": "https://aifitnessapi.com/compare/fitbit-vs-apple-watch.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "Does Apple Watch have a cloud API like Fitbit?",
          "answer": "No. There is no Apple server endpoint for Apple Watch data. HealthKit is an on-device framework - the data lives in an encrypted store on the user's iPhone and Apple runs no cloud service that aggregates it. To use Apple Watch data you must ship a native iOS app, have the user grant HealthKit permission, read locally, and sync to your own backend. Fitbit, by contrast, is a server-to-server cloud Web API your backend can call directly. As of 2026, verify against the official docs.",
          "url": "https://aifitnessapi.com/compare/fitbit-vs-apple-watch#faq-1"
        },
        {
          "question": "Can my backend pull Apple Watch data without the user's phone?",
          "answer": "No. Because HealthKit is on-device and iOS-only, reads happen inside your native app on the user's device with their active involvement; you cannot pull server-side without it. Fitbit is the opposite - once a user consents via OAuth, your backend can pull their data cross-platform without the phone in-hand. This is the core architectural reason to choose one over the other.",
          "url": "https://aifitnessapi.com/compare/fitbit-vs-apple-watch#faq-2"
        },
        {
          "question": "What data does each expose to developers?",
          "answer": "Fitbit's cloud API covers steps/activity, heart rate including HRV, sleep with stages, SpO2, cardio fitness (a VO2-max estimate), Active Zone Minutes, body/weight, and food/water, with intraday time series for some metrics. Apple Watch via HealthKit exposes workouts with the associated heart-rate stream, active calories, GPS where the workout supports it, and duration, plus the broad Health data types the user has stored. As of 2026, verify exact fields and granularity.",
          "url": "https://aifitnessapi.com/compare/fitbit-vs-apple-watch#faq-3"
        },
        {
          "question": "Is the Fitbit API changing in 2026?",
          "answer": "Yes - as of 2026 the Fitbit Web API is being migrated to the Google Health API (health.googleapis.com, Google OAuth). Reported timelines have the two running side-by-side with the legacy Fitbit Web API sunsetting around end of September 2026, and existing Fitbit OAuth tokens do not transfer, so users must re-consent via Google OAuth. These dates are actively changing - verify them on Fitbit's and Google's own developer pages before you build.",
          "url": "https://aifitnessapi.com/compare/fitbit-vs-apple-watch#faq-4"
        },
        {
          "question": "Which should I choose for a cross-platform app?",
          "answer": "Fitbit, because it is a real cloud API your backend can call regardless of the user's OS once they consent. Apple Watch via HealthKit is iOS-only and on-device, so it cannot serve Android users or a phone-less server pipeline. If you need both ecosystems from one integration, neither first-party path alone covers it - a cross-device aggregator normalizes Fitbit's cloud API and HealthKit's on-device SDK behind one interface.",
          "url": "https://aifitnessapi.com/compare/fitbit-vs-apple-watch#faq-5"
        }
      ]
    },
    {
      "question": "strava vs garmin api",
      "answer": "Pick the Strava API when you want fast, self-serve OAuth access to activities, routes, and its signature segment and social data across many device brands; pick Garmin's developer program when you need first-party device metrics like Body Battery, VO2 max, HRV, and all-day health and you can clear partner approval. Both are activity- and GPS-centric cloud APIs, but Strava is self-serve while Garmin's full server-side access is partner-approval-only with terms that are not public. The other decider is recent change: Strava tightened its program in 2024 and, as of 2026, reportedly moved standard access behind a paid subscription and restricts using its data to train AI or ML models (verify), while Garmin has reportedly paused new-partner sign-ups.",
      "title": "Strava vs Garmin: Which API for Your App?",
      "url": "https://aifitnessapi.com/compare/strava-vs-garmin-connect",
      "markdown": "https://aifitnessapi.com/compare/strava-vs-garmin-connect.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "Is the Strava API free to use?",
          "answer": "Strava's API was historically free and self-serve via OAuth 2.0. As of 2026, multiple outlets report that standard-tier access now requires an active paid Strava subscription, but the exact fee, effective date, and tier structure are reported inconsistently across sources. Treat it as verify-flagged and confirm current terms on Strava's developer program pages before you rely on it.",
          "url": "https://aifitnessapi.com/compare/strava-vs-garmin-connect#faq-1"
        },
        {
          "question": "Can I sign up for Garmin's developer program directly?",
          "answer": "Garmin's full server-side access is partner-approval-only rather than a self-serve credential, and its program terms are not public. As of 2026, new-partner sign-ups are reportedly paused with no announced re-open date, though existing partners are said to be unaffected (verify). There is no confirmed developer fee, so do not assume one. Confirm you can get approved before designing around Garmin's data.",
          "url": "https://aifitnessapi.com/compare/strava-vs-garmin-connect#faq-2"
        },
        {
          "question": "Can I use Strava data to train an AI or ML model?",
          "answer": "As of 2026, Strava's developer rules reportedly ban using its data to train AI or ML models, along with display restrictions on how data is shown to the authorizing user. This is directly relevant if you are building an AI fitness product. Verify the current wording in Strava's developer agreement, since these policies changed in 2024 and may change again.",
          "url": "https://aifitnessapi.com/compare/strava-vs-garmin-connect#faq-3"
        },
        {
          "question": "Which has richer health metrics, Strava or Garmin?",
          "answer": "Garmin exposes deeper first-party device metrics: its Health API covers heart rate, HRV, sleep, steps, stress, Body Battery, VO2 max, and respiration, and its Activity API covers 100+ activity types with GPS and session detail. Strava's strength is its social layer — segments, segment efforts, and cross-brand activity aggregation — rather than owned-device physiology.",
          "url": "https://aifitnessapi.com/compare/strava-vs-garmin-connect#faq-4"
        },
        {
          "question": "Do end users need to buy anything to share their data?",
          "answer": "For Strava, a user just needs a Strava account, into which they can sync activities from many device brands. For Garmin, the user needs a Garmin device, bought outright, with no recurring membership required for data to flow. The bigger cost question sits on the developer side: Strava's reported subscription requirement versus Garmin's private partner terms.",
          "url": "https://aifitnessapi.com/compare/strava-vs-garmin-connect#faq-5"
        }
      ]
    },
    {
      "question": "fitbit vs oura api",
      "answer": "Pick the Fitbit API when you want broad mainstream coverage, a large install base, and high-frequency intraday time series; pick the Oura API when your app centers on sleep architecture, readiness, HRV, and body-temperature trends. Both are cloud REST APIs behind OAuth 2.0, so you pull server-side without the user's phone in hand. The biggest developer difference is breadth versus depth plus the user requirement: a Fitbit device with a large base, versus an Oura ring plus a membership for full data. Two roadmap items to verify: Fitbit is migrating to the Google Health API (legacy Web API sunset targeted ~Sept 2026), and Oura deprecated Personal Access Tokens ~Dec 2025 in favor of OAuth.",
      "title": "Fitbit vs Oura API: Which for Your App?",
      "url": "https://aifitnessapi.com/compare/fitbit-vs-oura",
      "markdown": "https://aifitnessapi.com/compare/fitbit-vs-oura.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the main difference between the Fitbit and Oura APIs?",
          "answer": "Breadth versus depth. Fitbit exposes a broad mainstream set (steps, heart rate and HRV, sleep with stages, SpO2, VO2-max estimate, Active Zone Minutes, body and nutrition) plus intraday time series. Oura is narrower but deeper on recovery: sleep architecture, a readiness score, HRV, and nightly body-temperature deviation. Both are cloud REST APIs using OAuth 2.0.",
          "url": "https://aifitnessapi.com/compare/fitbit-vs-oura#faq-1"
        },
        {
          "question": "Does a user need a paid membership to get Oura data through the API?",
          "answer": "The user needs an Oura ring, and full Gen3+ data requires an Oura membership, so not every ring owner returns complete data. Fitbit only requires the user own a Fitbit device, though some insights may sit behind Fitbit Premium. Verify which specific fields are gated for each before building.",
          "url": "https://aifitnessapi.com/compare/fitbit-vs-oura#faq-2"
        },
        {
          "question": "Is the Fitbit Web API being replaced?",
          "answer": "The legacy Fitbit Web API is migrating to the Google Health API on Google OAuth 2.0, with the legacy API sunset reportedly targeted around September 2026, as of 2026. Existing Fitbit OAuth tokens do not transfer, so users re-consent. Verify the current dates in the migration docs before you build.",
          "url": "https://aifitnessapi.com/compare/fitbit-vs-oura#faq-3"
        },
        {
          "question": "Can I still use a Personal Access Token with the Oura API?",
          "answer": "Oura reportedly deprecated Personal Access Tokens around December 2025, so new integrations must use OAuth 2.0 Authorization Code with scoped Bearer tokens, as of 2026. Verify the exact deprecation date and whether existing tokens still function in Oura's authentication docs.",
          "url": "https://aifitnessapi.com/compare/fitbit-vs-oura#faq-4"
        },
        {
          "question": "Which API is better for intraday, high-frequency data?",
          "answer": "Fitbit is the stronger option for intraday time series, exposing high-granularity data for heart rate, activity, SpO2, and breathing rate, though intraday access for other users is granted case-by-case on the Client/Server app types. Oura's API is framed around daily summaries and nightly metrics rather than the same intraday granularity.",
          "url": "https://aifitnessapi.com/compare/fitbit-vs-oura#faq-5"
        }
      ]
    },
    {
      "question": "whoop vs garmin api",
      "answer": "Pick WHOOP when you want recovery and strain framing from guaranteed-subscribed users reachable through a clean self-serve OAuth API. Pick Garmin when you need the broadest owned-device metric set, like Body Battery, VO2 max, and all-day health, and you can clear partner approval. The single biggest developer difference is the access model: WHOOP is self-serve OAuth 2.0 you can start building against, while Garmin's Health API is partner-approval-only with terms that are not public. Both return data only for consenting users, not as a bulk feed.",
      "title": "WHOOP vs Garmin: Which for Your App?",
      "url": "https://aifitnessapi.com/compare/whoop-vs-garmin",
      "markdown": "https://aifitnessapi.com/compare/whoop-vs-garmin.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "How do developers access WHOOP vs Garmin data?",
          "answer": "WHOOP offers a documented OAuth 2.0 Authorization Code flow with scoped tokens and v2 webhooks you can wire up yourself, so it is effectively self-serve to start. Garmin's Health API is partner-approval-only: full server-side health-data push requires acceptance into its Connect Developer Program, and the program terms are not public. Reports as of 2026 suggest new-partner sign-ups may be paused, so verify onboarding status before designing around Garmin.",
          "url": "https://aifitnessapi.com/compare/whoop-vs-garmin#faq-1"
        },
        {
          "question": "Does the end user pay for WHOOP or Garmin?",
          "answer": "The models differ. WHOOP hardware is sold as a subscription, so every active WHOOP user is a paying member and per-user data completeness stays reliably high. A Garmin device is a one-time purchase the user owns outright, with no recurring membership required for the data to flow. Do not assume a specific WHOOP membership price here, and note there is no confirmed Garmin developer fee; verify both cost specifics before relying on them.",
          "url": "https://aifitnessapi.com/compare/whoop-vs-garmin#faq-2"
        },
        {
          "question": "Which exposes more health metrics, WHOOP or Garmin?",
          "answer": "Garmin is broader. Its Health and Activity APIs span 100+ activity types, GPS, HRV, sleep, Body Battery, stress, VO2 max, respiration, and all-day summaries. WHOOP is tighter and recovery-focused: Recovery percentage, daily strain, sleep stages, workouts, and body measurement, with SpO2 and skin temperature for 4.0 members. Verify the current metric lists and which sensors are gated to which WHOOP band in each provider's docs.",
          "url": "https://aifitnessapi.com/compare/whoop-vs-garmin#faq-3"
        },
        {
          "question": "Is there a Garmin API fee?",
          "answer": "No Garmin developer fee is confirmed, and the Connect Developer Program terms are not public, so we do not quote one. Access is gated by partner approval rather than a published price. Treat any specific figure you see elsewhere as unverified and confirm current terms directly with Garmin.",
          "url": "https://aifitnessapi.com/compare/whoop-vs-garmin#faq-4"
        },
        {
          "question": "Which should I pick for a recovery coaching app?",
          "answer": "For recovery or strain coaching, WHOOP is usually the better fit: its data model is built around Recovery percentage and daily strain, the OAuth flow is self-serve so you can start quickly, and the subscription hardware model means users are reliably paying members with complete data. Choose Garmin instead if you specifically need its broader owned-device metrics and can clear partner approval.",
          "url": "https://aifitnessapi.com/compare/whoop-vs-garmin#faq-5"
        }
      ]
    },
    {
      "question": "terra vs rook",
      "answer": "Terra and ROOK both give you one integration that returns normalized data from many wearables and health apps. Pick Terra for the broadest marketed provider catalog and a mature signed-webhook push pipeline with global reach. Pick ROOK if you are mobile-SDK-first, targeting Latin America, or want a bundled health score and a reported active-user tier pricing model. The biggest developer difference is delivery and reach: Terra emphasizes webhook push across the widest source list, while ROOK ships native Android/iOS SDKs for on-device sources plus regional focus. Provider counts and pricing here are vendor or third-party claims as of 2026, so verify against official docs.",
      "title": "Terra vs ROOK: Which Aggregator API for Your App?",
      "url": "https://aifitnessapi.com/compare/terra-vs-rook",
      "markdown": "https://aifitnessapi.com/compare/terra-vs-rook.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "Do Terra and ROOK both give one integration for many devices?",
          "answer": "Yes. Both are single-integration aggregators: you integrate once and receive normalized data from many providers such as Garmin, Fitbit, Apple Health, Oura and WHOOP. Terra markets a larger catalog ('500+' as of 2026, verify) while ROOK markets '400+' sources (verify). The choice is about delivery model, mobile-SDK need and region, not whether the data is reachable.",
          "url": "https://aifitnessapi.com/compare/terra-vs-rook#faq-1"
        },
        {
          "question": "How do their normalization models differ?",
          "answer": "Terra exposes standardized endpoints and data models across all sources so you code once. ROOK classifies sources into two extraction methods: direct API integrations for centralized cloud providers and SDK-based integrations for on-device stores like Apple Health and Health Connect, and it also bundles a proprietary health score. Verify the current schema details in each vendor's docs.",
          "url": "https://aifitnessapi.com/compare/terra-vs-rook#faq-2"
        },
        {
          "question": "What are Terra and ROOK pricing models?",
          "answer": "Neither publishes a fully confirmed self-serve pricing table at last check. Terra's pricing was not publicly listed and reads as sales-led/tiered. ROOK is reported to use a tiered active-user model, but its official pricing page returned a 403 to automated fetch, so specific tiers and per-user figures circulating online are unconfirmed. Do not budget against them; verify directly. A quoted ~$0.50-$2 per connected user per month is a third-party category estimate, not ROOK's published rate.",
          "url": "https://aifitnessapi.com/compare/terra-vs-rook#faq-3"
        },
        {
          "question": "Is ROOK better than Terra for Latin America?",
          "answer": "ROOK is explicitly positioned for Latin America, letting regional teams build without importing or manufacturing devices. If LatAm is your primary market, that positioning is a point in ROOK's favor as of 2026 (verify it still holds). Terra's scope is global, so for worldwide reach with the widest catalog it remains a strong option.",
          "url": "https://aifitnessapi.com/compare/terra-vs-rook#faq-4"
        },
        {
          "question": "Which should I pick for a mobile app versus a backend service?",
          "answer": "For a mobile-native app that relies on phone-resident data like Apple Health or Health Connect, ROOK's native Android/iOS SDKs handle the on-device extraction and are the easier lean. For a backend-first, server-side product that wants normalized data pushed via signed webhooks across the broadest source list, Terra fits well. Verify webhook signing and SDK details in each vendor's docs before committing.",
          "url": "https://aifitnessapi.com/compare/terra-vs-rook#faq-5"
        }
      ]
    },
    {
      "question": "terra vs spike health",
      "answer": "Terra and Spike Health are both single-integration health-data aggregators, so the choice comes down to data reach. Pick Terra if you need broad consumer-wearable and fitness-app aggregation with a clean, normalized signed-webhook push feed. Lean Spike if your build is clinical- or medical-adjacent and needs IoT sensors, lab systems, and EMR/EHR data alongside wearables, plus AI add-ons like health-data interpretation, food-photo nutrition extraction, or an MCP server. Neither vendor publicly lists pricing, and Spike's own device-count claims vary, so treat every number and capability as 'as of 2026, verify.'",
      "title": "Terra vs Spike Health: Which Aggregator for Your App?",
      "url": "https://aifitnessapi.com/compare/terra-vs-spike",
      "markdown": "https://aifitnessapi.com/compare/terra-vs-spike.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "What's the core difference between Terra and Spike Health?",
          "answer": "Both are single-integration aggregators that return normalized data from many sources, so you code once. The difference is reach: Terra centers on consumer wearables and fitness apps with a mature normalized push feed, while Spike also markets IoT sensors, lab systems, and EMR/EHR data plus AI add-ons. Terra suits broad wearable aggregation; Spike suits clinical/medical-adjacent builds. Verify current coverage and features against each vendor's docs.",
          "url": "https://aifitnessapi.com/compare/terra-vs-spike#faq-1"
        },
        {
          "question": "How much do Terra and Spike cost?",
          "answer": "No per-MAU or per-connection dollar figure is publicly confirmed for either vendor, and aggregator pricing pages often can't be read externally. Treat both as sales-led, likely tiered or usage-based models with an enterprise 'contact sales' top tier. Plan around the model, not a number, and get a live quote before budgeting. See the health-data aggregator pricing breakdown for how this category charges.",
          "url": "https://aifitnessapi.com/compare/terra-vs-spike#faq-2"
        },
        {
          "question": "Does Spike really support 500+ devices?",
          "answer": "Spike markets a large device catalog, but its own materials cite inconsistent figures (for example '500+' on one page and '200+' on another), so don't treat any single count as fact. Terra similarly markets '500+' providers. Both numbers are vendor marketing as of 2026 — verify the current supported-source list in each vendor's official documentation before relying on coverage claims.",
          "url": "https://aifitnessapi.com/compare/terra-vs-spike#faq-3"
        },
        {
          "question": "Which is better for a clinical or medical app?",
          "answer": "Lean Spike for clinical or medical-adjacent builds. It markets a single API spanning wearables plus IoT sensors, lab systems, and EMR/EHR data, with lab-report data and clinical/LOINC framing cited, plus a generative-AI interpretation SDK and an MCP server. Verify LOINC support, MCP, and food-photo extraction are production-ready as of 2026 before designing around them.",
          "url": "https://aifitnessapi.com/compare/terra-vs-spike#faq-4"
        },
        {
          "question": "Do Terra and Spike offer webhooks?",
          "answer": "Terra streams normalized data and lifecycle events via signed HTTP POST to a developer-configured 'Destination' endpoint, giving near-real-time push after a user authorizes rather than polling. Spike offers one standardized API and manages provider updates; confirm its webhook signing and payload format in Spike's docs. Verify current webhook behavior for both before building an event-driven pipeline.",
          "url": "https://aifitnessapi.com/compare/terra-vs-spike#faq-5"
        }
      ]
    },
    {
      "question": "nutritionix vs edamam",
      "answer": "Pick Nutritionix if your app centers on US branded and restaurant/chain foods with plain-text meal logging, and pick Edamam if you need recipe and ingredient-list nutrition analysis backed by a generic-food database with a self-serve free plan. Both parse free text into nutrients, but Nutritionix leans into food-service coverage while Edamam splits into three separate APIs, each with its own credentials. The biggest developer difference is access: Nutritionix is freemium-to-paid with enterprise via contact-sales, while Edamam is self-serve tiered freemium signed up per API. Verify current pricing and coverage on each vendor's pages before committing.",
      "title": "Nutritionix vs Edamam: Which Nutrition API to Use?",
      "url": "https://aifitnessapi.com/compare/nutritionix-vs-edamam",
      "markdown": "https://aifitnessapi.com/compare/nutritionix-vs-edamam.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the main difference between Nutritionix and Edamam?",
          "answer": "Nutritionix is strongest on US branded/packaged and restaurant/chain foods with natural-language meal logging. Edamam splits into three APIs (Food Database, Nutrition Analysis, Recipe Search) and is built for recipe and ingredient-list analysis backed by a generic-food database. Verify coverage claims as of 2026.",
          "url": "https://aifitnessapi.com/compare/nutritionix-vs-edamam#faq-1"
        },
        {
          "question": "Which has better natural-language food logging?",
          "answer": "Both parse free text, but for different jobs. Nutritionix's natural-language endpoint is tuned toward logging restaurant and food-service meals like '1 cup rice, 2 eggs'. Edamam's Nutrition Analysis API is built to parse ingredient lists and full recipes into detailed nutrition. Match the parser to your input.",
          "url": "https://aifitnessapi.com/compare/nutritionix-vs-edamam#faq-2"
        },
        {
          "question": "How do Nutritionix and Edamam pricing models compare?",
          "answer": "Nutritionix is freemium to paid, with a free/attribution tier and higher quota-based tiers gated through a Syndigo sales contact. Edamam is self-serve tiered freemium with a free application plan plus paid monthly tiers chosen per API. Neither vendor's specific tier prices are confirmed here; third-party figures conflict, so verify official pricing.",
          "url": "https://aifitnessapi.com/compare/nutritionix-vs-edamam#faq-3"
        },
        {
          "question": "Do Edamam's three APIs share one API key?",
          "answer": "No. Edamam's Food Database, Nutrition Analysis, and Recipe Search APIs each use their own app_id/app_key pair, and credentials do not carry across the three. A build that touches food lookup and recipe search means managing multiple credential sets. Verify the current registration flow in Edamam's docs.",
          "url": "https://aifitnessapi.com/compare/nutritionix-vs-edamam#faq-4"
        },
        {
          "question": "Which is better for barcode and packaged-food coverage?",
          "answer": "Both reach packaged/UPC items. Nutritionix is strongest on US branded and restaurant/chain foods, while Edamam's Food Database API pairs generic foods with packaged/UPC items. Choose based on whether US food-service depth or generic-plus-UPC breadth matters more for your users. Verify current coverage as of 2026.",
          "url": "https://aifitnessapi.com/compare/nutritionix-vs-edamam#faq-5"
        }
      ]
    },
    {
      "question": "edamam vs spoonacular",
      "answer": "Pick Edamam when precise nutrition analysis of arbitrary ingredient lists and recipes is your core need, and pick Spoonacular when you want an all-in-one API for recipe discovery, meal-plan generation, grocery products, and nutrition behind one key. The biggest developer difference is shape and cost model: Edamam is three separate nutrition APIs, each with its own credentials, on tiered freemium plans; Spoonacular is a single API metered by a daily points budget that every call draws down. Tier prices, point costs, and coverage counts shift often, so verify current figures on each vendor's own pages.",
      "title": "Edamam vs Spoonacular: Which Nutrition API?",
      "url": "https://aifitnessapi.com/compare/edamam-vs-spoonacular",
      "markdown": "https://aifitnessapi.com/compare/edamam-vs-spoonacular.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the main difference between Edamam and Spoonacular?",
          "answer": "Data focus and structure. Edamam is nutrition-first: a Food Database API, a Nutrition Analysis API that parses free-text ingredients and recipes into detailed nutrients, and a Recipe Search API, offered as three separate products each with its own app_id and app_key. Spoonacular is recipe-first and all-in-one: recipe search, meal-plan generation, grocery products, menu items, and nutrition behind a single API and key. Pick Edamam for precise nutrition analysis, Spoonacular for recipe and meal-planning breadth.",
          "url": "https://aifitnessapi.com/compare/edamam-vs-spoonacular#faq-1"
        },
        {
          "question": "How does Spoonacular's pricing model work?",
          "answer": "Spoonacular uses a freemium points model rather than a per-call price list. Each plan grants a daily quota of points, and every request spends points - documented as roughly 1 point per request plus about 0.01 point per result returned, endpoint-dependent. On the free plan, once the daily points quota is exhausted the API returns HTTP 402 until it resets, and paid tiers raise the daily quota. Do not treat any dollar figure as fixed; as of 2026, verify current point costs and tier prices on Spoonacular's official pricing page.",
          "url": "https://aifitnessapi.com/compare/edamam-vs-spoonacular#faq-2"
        },
        {
          "question": "How is Edamam's pricing structured?",
          "answer": "Edamam uses tiered freemium plans selected per API at registration - a free application plan plus paid monthly tiers. Because the Food Database, Nutrition Analysis, and Recipe Search APIs are separate products with separate credentials, you choose a plan for each one you use rather than a single combined plan. Third-party dollar figures for Edamam tiers conflict badly, so as of 2026, verify current tier prices and limits on Edamam's official pricing page.",
          "url": "https://aifitnessapi.com/compare/edamam-vs-spoonacular#faq-3"
        },
        {
          "question": "Can I use one set of credentials across Edamam's APIs?",
          "answer": "No. Edamam's Food Database API, Nutrition Analysis API, and Recipe Search API each have their own app_id and app_key pair, and the credentials are not interchangeable across the three. A build that needs food lookup, nutrition analysis, and recipe search manages three credential pairs and three plans. This is a real integration detail to plan for; verify current terms in Edamam's developer docs.",
          "url": "https://aifitnessapi.com/compare/edamam-vs-spoonacular#faq-4"
        },
        {
          "question": "Which should I choose for a recipe and meal-planning app?",
          "answer": "For recipe discovery plus meal-plan generation plus grocery and product data behind one key, Spoonacular is the more natural fit, since it consolidates those into a single all-in-one API. If your core need is instead precise nutrition analysis of arbitrary ingredient lists or user-submitted recipes, Edamam's Nutrition Analysis API is the stronger anchor. Our nutrition APIs overview weighs the wider category.",
          "url": "https://aifitnessapi.com/compare/edamam-vs-spoonacular#faq-5"
        }
      ]
    },
    {
      "question": "exercisedb vs wger",
      "answer": "Pick ExerciseDB when you want a media-rich, ready-to-call hosted API with GIF and video and you will pay a per-request gateway; pick wger when you want full data ownership, no per-call fees, and are comfortable self-hosting and complying with its licenses. The biggest developer difference is the delivery model: ExerciseDB is most commonly a paid, RapidAPI-hosted gateway billed per request, while wger is open-source software you run yourself. Note the name ambiguity - 'ExerciseDB' is both the RapidAPI product and the separate AGPL-3.0 exercisedb.dev project - and treat every count and price as 'as of 2026, verify.'",
      "title": "ExerciseDB vs wger: Which Exercise API for Your App?",
      "url": "https://aifitnessapi.com/compare/exercisedb-vs-wger",
      "markdown": "https://aifitnessapi.com/compare/exercisedb-vs-wger.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-07-23",
      "first_party": false,
      "faqs": [
        {
          "question": "Are ExerciseDB and exercisedb.dev the same thing?",
          "answer": "They share a name but are not the same. The ExerciseDB commonly used via the RapidAPI marketplace is a paid, hosted gateway governed by RapidAPI and vendor commercial terms. The exercisedb.dev / GitHub exercisedb/exercisedb-api project is open-source under AGPL-3.0 with direct-access and self-host options. Which one you integrate changes both the cost and the licensing, so confirm the exact path you sign up for.",
          "url": "https://aifitnessapi.com/compare/exercisedb-vs-wger#faq-1"
        },
        {
          "question": "Is wger really free?",
          "answer": "The software and data carry no license or usage fee: wger's code is AGPL-3.0-or-later and its exercise/ingredient data is Creative Commons (verify the exact variant). But self-hosting still costs servers, bandwidth, uptime, and engineering time to run and update it, and the AGPL code carries copyleft obligations. 'Free' here means no per-call fee, not zero total cost.",
          "url": "https://aifitnessapi.com/compare/exercisedb-vs-wger#faq-2"
        },
        {
          "question": "Does the AGPL license affect my closed-source app?",
          "answer": "It can if you self-host and modify the code. AGPL-3.0 has a network clause: modifying AGPL-covered code and letting users interact with it over a network can obligate you to release your modified source under AGPL. Merely calling a hosted API over HTTP does not by itself make your app a derivative work. A hosted or commercially licensed API path sidesteps this; self-hosting AGPL code warrants legal review. This is general guidance, not legal advice.",
          "url": "https://aifitnessapi.com/compare/exercisedb-vs-wger#faq-3"
        },
        {
          "question": "Which has more exercises and media, ExerciseDB or wger?",
          "answer": "ExerciseDB markets a much larger catalog - vendor claims cite '11,000+' exercises plus large GIF, video and image libraries - while third-party sources cite roughly 520 curated exercises for wger with lighter, community-contributed media. Treat all of these counts as vendor or third-party claims to re-verify against each project's primary source as of 2026.",
          "url": "https://aifitnessapi.com/compare/exercisedb-vs-wger#faq-4"
        },
        {
          "question": "What does it actually take to run wger yourself?",
          "answer": "More than a first deploy, though that is the easy part - the documented path is Docker Compose, and there is a hosted demo instance at wger.de for evaluation rather than production. Running it yourself means you own the hosting bill, upgrades, backups, and uptime for a service your app now depends on, plus whatever auth and rate limiting you put in front of the REST API. That ongoing ops load is the real trade for no per-call fee and full ownership of the data.",
          "url": "https://aifitnessapi.com/compare/exercisedb-vs-wger#faq-5"
        }
      ]
    },
    {
      "question": "kinestex vs sency",
      "answer": "KinesteX (this site's own product) and Sency are both AI motion tracking SDKs for fitness apps, and the honest difference is architectural, not better-versus-worse: KinesteX embeds a hosted camera experience via WebView/iframe with prebuilt workout content, views, and a content API across iOS, Android, React Native, Flutter, and the web, while Sency's SMKit is a native no-UI SDK (plus a branded UI kit) for iOS, Android, React Native, and Flutter, where you own the camera preview and UI. Pick KinesteX if you need a web surface or want content and gamified experiences shipped in the box; pick Sency if you need native rendering and full UI control with no embedded web experience. Pricing could not be verified for either vendor, and no accuracy claim on either side has been independently benchmarked, so test both against your own movements before committing.",
      "title": "KinesteX vs Sency: Which Motion Tracking SDK?",
      "url": "https://aifitnessapi.com/compare/kinestex-vs-sency",
      "markdown": "https://aifitnessapi.com/compare/kinestex-vs-sency.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-08-02",
      "first_party": true,
      "faqs": [
        {
          "question": "Is KinesteX a native SDK like Sency's SMKit?",
          "answer": "No, and this is the core difference. KinesteX's public repos describe its SDKs as WebView and iframe wrappers that embed a hosted camera workout experience, communicating via postMessage events plus a content REST API. Sency's README describes its core SMKit as a native no-UI SDK where the developer owns the camera preview and UI in the Custom Kit. Neither shape is wrong — a hosted experience ships faster with content included, while a native SDK gives you full rendering control.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-sency#faq-1"
        },
        {
          "question": "Does Sency support web or JavaScript apps?",
          "answer": "Not per its own public documentation: Sency's platform table in the smkit-sdk README lists iOS, Android, React Native, and Flutter, and marks JavaScript and Unity as NA. KinesteX publishes HTML/JS and PWA iframe integrations for browser-based products. If your product includes a web surface, that gap currently decides the comparison on its own — but re-check Sency's repos before ruling it out, since platform tables change.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-sency#faq-2"
        },
        {
          "question": "How much do KinesteX and Sency cost?",
          "answer": "We could not verify pricing for either vendor, and this page will not guess. KinesteX's repos contain no self-serve pricing; access goes through a contact form and API key. Sency's README links to a pricing and registration page, but its contents could not be read from our research environment, so we cannot say what the terms are. Budget for a direct conversation with both vendors.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-sency#faq-3"
        },
        {
          "question": "Are KinesteX or Sency open source?",
          "answer": "Neither product is open source, though the repo licensing differs. Several KinesteX wrapper repos (Swift, React Native, HTML-JS) carry an Apache-2.0 LICENSE, but the hosted experience behind them is a commercial, API-key-gated service, and some repos have no LICENSE file. Sency's repo LICENSE is its own proprietary Terms of Use. In both cases you are buying a commercial service; the public repos are integration code, not the product.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-sency#faq-4"
        },
        {
          "question": "Which is more accurate, KinesteX or Sency?",
          "answer": "Unknown, and be wary of anyone who answers confidently — including us, since KinesteX funds this site. KinesteX's own README claims its models consistently exceed 90% accuracy, which is a first-party marketing line, not an independent benchmark. Sency publishes no comparable figure in its public repos. No independent accuracy comparison of the two exists that we could verify, so run both SDKs on your actual exercises, devices, and lighting conditions before deciding.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-sency#faq-5"
        }
      ]
    },
    {
      "question": "kinestex vs quickpose",
      "answer": "These are not the same product wearing different logos. QuickPose is an iOS-first developer toolkit wrapping MediaPipe/BlazePose — pose estimation, skeleton tracking, and rep counting as native building blocks inside your own app and UI. KinesteX (this site's own product) is a cross-platform embedded coaching product: its iOS, Android, Flutter, React Native, and web SDKs are wrappers that load a hosted camera workout experience in a WebView or iframe, plus a content API. Lean QuickPose for an iOS-only product where you build the experience yourself; lean KinesteX to ship a white-label workout experience across every platform at once. Neither publishes verifiable pricing, and everything on this page traces to their public GitHub repos as of 2026-08-02.",
      "title": "KinesteX vs QuickPose: Decide by How Much You Want to Build",
      "url": "https://aifitnessapi.com/compare/kinestex-vs-quickpose",
      "markdown": "https://aifitnessapi.com/compare/kinestex-vs-quickpose.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-08-02",
      "first_party": true,
      "faqs": [
        {
          "question": "Are KinesteX and QuickPose direct competitors?",
          "answer": "Only partially. They meet at camera-based exercise tracking, but they sell different layers: QuickPose provides pose estimation, skeleton tracking, and exercise counters as native iOS building blocks with no workout content or prebuilt coaching UI in its repos, while KinesteX embeds a complete hosted coaching experience — content, plans, leaderboards, assessments — behind a WebView or iframe on five platforms. A team choosing between them is really choosing how much product to build versus configure.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-quickpose#faq-1"
        },
        {
          "question": "Is QuickPose open source?",
          "answer": "The repository code is Apache-2.0 licensed, but the product is not fully open source: the SDK requires a key, and the README states exactly that you can \"Get your free SDK key on https://dev.quickpose.ai, usage limits may apply. SDK Keys are linked to your bundle ID.\" So treat it as openly licensed wrapper code around a keyed SDK with usage limits, and verify the current limits with QuickPose before shipping.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-quickpose#faq-2"
        },
        {
          "question": "Does KinesteX process video on-device?",
          "answer": "Its SDK READMEs say the platform \"ensures data security with optional edge processing (no cloud transmission)\" — and the word optional matters. From the public repos alone you cannot conclude that processing is unconditionally on-device; the sourced architecture is a native wrapper embedding a hosted web experience, and the Android integration requires the INTERNET permission. If on-device processing is a compliance requirement for you, confirm the specific configuration with KinesteX directly.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-quickpose#faq-3"
        },
        {
          "question": "Can I use QuickPose on Android or React Native?",
          "answer": "Repos exist for both — quickpose-android-sdk (Kotlin, updated 2026-07-23) and quickpose-react-native-pose-estimation — so the platforms are not ignored. But the detailed README, the iOS 14.0+ requirement, the feature list, and the demo apps we could verify all sit on the iOS side, which is also where the SDK's 324 stars are. Inspect the Android and React Native repos yourself before assuming feature parity with the flagship iOS SDK.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-quickpose#faq-4"
        },
        {
          "question": "What do KinesteX and QuickPose cost?",
          "answer": "Neither cost is publicly verifiable. QuickPose's repos say only that a free SDK key is available with possible usage limits — no tiers or prices appear anywhere in them. KinesteX's repos route access through a contact form (\"To get demo access and your api key, please fill out a form on our website\") with no self-serve pricing found. Both vendors' websites were unreachable in our research pass, so get current numbers from each vendor directly and treat any third-party figure as unverified.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-quickpose#faq-5"
        }
      ]
    },
    {
      "question": "kinestex vs mediapipe",
      "answer": "These two are not peers, and that is the real answer: MediaPipe is a free, Apache-2.0 pose model that outputs 33 landmarks per frame and nothing else, while KinesteX (this site's own product) is a commercial SDK selling the application layer above the keypoints — rep counting, mistake feedback, workout content, and a WebView-embedded cross-platform experience, per its public repos. Build on MediaPipe when motion analysis is your core product and you have the team to own rep logic, content, and per-platform camera pipelines at zero per-user vendor cost. Buy KinesteX when time-to-market, content breadth, and one integration across five platforms matter more than owning the stack. KinesteX pricing is not public in its repos — get it from the vendor before you commit.",
      "title": "KinesteX vs MediaPipe: Which Layer Do You Want to Own?",
      "url": "https://aifitnessapi.com/compare/kinestex-vs-mediapipe",
      "markdown": "https://aifitnessapi.com/compare/kinestex-vs-mediapipe.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-08-02",
      "first_party": true,
      "faqs": [
        {
          "question": "Does MediaPipe include rep counting or form feedback?",
          "answer": "No. MediaPipe Pose Landmarker outputs 33 landmarks per frame — coordinates, visibility, and presence — and nothing more. Google's model card lists fitness and repetition counting as an intended application domain, but the counting state machines, per-exercise form rules, mistake feedback, and exercise content are all yours to build. That gap between keypoints and a working fitness feature is the entire substance of the KinesteX vs MediaPipe question.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-mediapipe#faq-1"
        },
        {
          "question": "Is KinesteX a native SDK or a WebView wrapper?",
          "answer": "Per its own public repositories, every KinesteX SDK — Swift, Kotlin, React Native, Flutter, and web — is a thin wrapper that embeds a hosted web experience via WKWebView, Android WebView, react-native-webview, or an iframe, communicating through postMessage events, with internet permission required. That is not a criticism; it is how one vendor implementation serves five platforms at once. But you are integrating an embedded experience, not an in-process inference library, and you should weigh that against MediaPipe's in-process, offline-capable model.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-mediapipe#faq-2"
        },
        {
          "question": "How much does KinesteX cost compared to free MediaPipe?",
          "answer": "MediaPipe's framework and pose models are Apache-2.0 and cost nothing; you pay in engineering time. KinesteX is commercial — an API key is required and its repos point to a contact form for demo access — but no public pricing appears anywhere in its repositories as of August 2026, so we cannot quote a number and will not guess one. Price the decision as free plus substantial build effort (quarters, in our estimate) versus a vendor fee you must obtain directly from KinesteX in writing.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-mediapipe#faq-3"
        },
        {
          "question": "Is KinesteX built on top of MediaPipe?",
          "answer": "We could not verify what pose model runs inside KinesteX's hosted experience; its public repositories do not document the underlying model, so do not assume either way. For this decision it barely matters: what KinesteX sells is the interpretation, content, and cross-platform layer above the keypoints, and what MediaPipe gives you free is the keypoints. The comparison is between layers of the stack, not between two pose models.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-mediapipe#faq-4"
        },
        {
          "question": "Can I start with KinesteX and migrate to my own MediaPipe pipeline later?",
          "answer": "Yes in principle, and it is a sane de-risking path: ship on the vendor layer while you validate the product, then bring tracking in-house if motion analysis becomes your core IP. Plan for a real rewrite rather than a swap, though — KinesteX hands you interpreted events from an embedded experience, while a MediaPipe pipeline means owning camera plumbing, rep logic, and content yourself, so little integration code transfers. The reverse move, from an in-house pipeline to a vendor SDK, is usually the easier migration.",
          "url": "https://aifitnessapi.com/compare/kinestex-vs-mediapipe#faq-5"
        }
      ]
    },
    {
      "question": "apple watch vs whoop api",
      "answer": "Pick Apple Watch when your product is an iOS or watchOS app: Apple documents HealthKit as a store the user's own device holds locally, so you read it inside an app you ship and sync it to your backend yourself, with no vendor account, no quota, and no approval queue for the data. Pick WHOOP when your backend needs to reach a consenting user on any platform without their phone in hand, using OAuth 2.0 with scoped tokens and v2 webhooks that push sleep, recovery, and workout events to you. These are opposite architectures rather than competing products: Apple gives you sensor-level access and no counterparty but iOS-only reach, an App Store review, and a sync you build; WHOOP gives you server-side reach and event push but a paid-membership dependency on both the developer and every end user, plus an app-approval cap of roughly 10 members. As of 2026, verify both sides against the current docs.",
      "title": "Apple Watch vs WHOOP: Which for Your App?",
      "url": "https://aifitnessapi.com/compare/apple-watch-vs-whoop",
      "markdown": "https://aifitnessapi.com/compare/apple-watch-vs-whoop.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-08-11",
      "first_party": false,
      "faqs": [
        {
          "question": "Do I need to build a watchOS app to use Apple Watch data?",
          "answer": "Not always. An iPhone app alone can read what the watch has already written into HealthKit, since Apple describes HealthKit as a central repository shared across iPhone and Apple Watch. You need your own watchOS app when you want to act during the activity — Apple documents HKWorkoutSession as fine-tuning the watch's sensors for the chosen activity and generating high-frequency heart rate samples, which is what live coaching or in-workout haptics require. Either way you are shipping an app, which is the structural difference from WHOOP's server-to-server API.",
          "url": "https://aifitnessapi.com/compare/apple-watch-vs-whoop#faq-1"
        },
        {
          "question": "How does HealthKit background delivery compare with WHOOP webhooks?",
          "answer": "They point in opposite directions. WHOOP pushes v2 webhook events for sleep, recovery, and workouts straight to an endpoint you control, so your backend learns about new data without asking. On Apple, nothing is pushed to your servers: your app observes the local store with HKObserverQuery and enableBackgroundDelivery, then forwards data itself, and Apple documents system limits including an hourly maximum frequency for some types and, on watchOS, four updates per hour shared with background refresh. Verify the current limits in Apple's docs.",
          "url": "https://aifitnessapi.com/compare/apple-watch-vs-whoop#faq-2"
        },
        {
          "question": "Which is harder to clear, App Review or WHOOP app approval?",
          "answer": "They gate different things, so budget for both rather than ranking them. WHOOP's cap is on users: an unapproved app is limited to roughly 10 WHOOP members until it is submitted and granted access, so the gate blocks scale rather than development (verify current terms). Apple's gate is on distribution: nothing reaches users until the app passes App Review, and Apple's own HealthKit setup guidance warns that App Review may reject apps that enable capabilities they do not actually use. Apple's gate is earlier; WHOOP's is the one that stops growth.",
          "url": "https://aifitnessapi.com/compare/apple-watch-vs-whoop#faq-3"
        },
        {
          "question": "What does each option cost the person wearing the device?",
          "answer": "An Apple Watch is a one-time hardware purchase, and no recurring payment to Apple is required for your app to read the data the watch records. WHOOP sells the hardware as a recurring membership, so every end user of your integration is an ongoing subscriber and their data only flows while that membership is active. No figure is printed here because WHOOP has restructured its membership recently — confirm the current terms on WHOOP's own pricing page before you model your addressable market.",
          "url": "https://aifitnessapi.com/compare/apple-watch-vs-whoop#faq-4"
        },
        {
          "question": "Should I support Apple Watch and WHOOP at the same time?",
          "answer": "You can, but understand that it is two unrelated builds rather than two API clients: an on-device HealthKit reader inside a native app plus a server-side OAuth and webhook consumer that shares no code, no auth model, and no data-freshness behaviour with it. Teams that want both, plus other wearables, usually reach for a cross-device aggregator that normalizes the on-device and cloud sources behind one interface. Weigh that against maintaining both integrations yourself.",
          "url": "https://aifitnessapi.com/compare/apple-watch-vs-whoop#faq-5"
        }
      ]
    },
    {
      "question": "apple watch vs garmin api",
      "answer": "Pick Apple Watch when you can ship an iOS or watchOS app: Apple documents HealthKit as a repository the user's own device stores locally, so you read it inside your app with no vendor account, no credential to rotate and no approval queue for the data itself. Pick Garmin when your backend must receive data server-side without the user present, through the Connect Developer Program's Health and Activity APIs, which push summaries to callback URLs you register instead of letting you poll. The catch is getting in: Garmin's program is partner-approval-only and, as of 2026, new sign-ups are reportedly on hold with the public request form removed and no published re-open date. Unusually for this category, the user-cost axis is a tie here, since both are one-time hardware purchases with no membership required for the data to flow; the real split is that Apple gates distribution through App Review while Garmin gates access itself, and that gate may currently be shut. Verify both against current docs.",
      "title": "Apple Watch vs Garmin: Which Should You Build On?",
      "url": "https://aifitnessapi.com/compare/apple-watch-vs-garmin",
      "markdown": "https://aifitnessapi.com/compare/apple-watch-vs-garmin.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I read Garmin data through Apple HealthKit instead of Garmin's API?",
          "answer": "Sometimes, and it is a genuine workaround while the Garmin program is gated. HealthKit is a shared repository, so if a user's Garmin data has synced into Apple Health on their iPhone, your app can read it on-device without any Garmin credential. It is not equivalent to the partner API: you get only what reached that one user's store, only on iOS, and only while your app stays installed and permitted. Garmin activities that re-sync into Strava, and user-uploaded FIT files, are the other indirect routes.",
          "url": "https://aifitnessapi.com/compare/apple-watch-vs-garmin#faq-1"
        },
        {
          "question": "Does building for Apple Watch need any vendor approval the way Garmin does?",
          "answer": "Both have a gate, but they block different things. Apple gates distribution: you need a paid Apple Developer account to enable the HealthKit capability, and nothing reaches users until the app passes App Review, which scrutinizes whether your usage-description strings are honest and whether you actually use the data you request. Garmin gates access itself, through a manual partner-level review with no self-serve key, and as of 2026 new sign-ups are reportedly on hold. Apple's gate you can always eventually clear; Garmin's you may not be able to enter at all right now.",
          "url": "https://aifitnessapi.com/compare/apple-watch-vs-garmin#faq-2"
        },
        {
          "question": "Which reaches my backend sooner, a Garmin push callback or a HealthKit sync?",
          "answer": "Garmin, structurally. Once a user's device syncs, Garmin POSTs to callback URLs you registered per summary type, either as a Ping notification carrying a callbackURL you then fetch or as a Push with the full JSON inline. On Apple nothing is pushed to your servers at all: your app observes the local store with HKObserverQuery and enableBackgroundDelivery and forwards the data itself, subject to system limits that Apple documents as an hourly maximum for some types and four updates per hour on watchOS shared with background refresh. Verify the current limits in Apple's docs.",
          "url": "https://aifitnessapi.com/compare/apple-watch-vs-garmin#faq-3"
        },
        {
          "question": "Do Apple Watch and Garmin owners pay a recurring fee for their data?",
          "answer": "No on both sides, which makes this pair unusual. An Apple Watch and iPhone are one-time hardware purchases and no recurring payment to Apple is required for your app to read what the watch records. A Garmin device is likewise bought outright, with no separate consumer subscription required for basic Garmin Connect use as of 2026 (verify current terms). The recurring-cost question in this comparison lands on the developer side instead, where Garmin's commercial terms are private and Apple charges no API fee at all.",
          "url": "https://aifitnessapi.com/compare/apple-watch-vs-garmin#faq-4"
        },
        {
          "question": "Should I support both Apple Watch and Garmin in a single app?",
          "answer": "You can, but budget for two unrelated builds rather than two API clients. One is an on-device HealthKit reader inside a native iOS app with its own sync code; the other is a server-side OAuth 2.0 PKCE consumer with registered webhook callbacks, sharing no auth model, no delivery behaviour and no code with the first. Garmin also has to approve you before the second exists. Teams that want both, plus other wearables, usually reach for a health-data aggregator that already holds its own Garmin partnership and normalizes the on-device and cloud sources behind one interface.",
          "url": "https://aifitnessapi.com/compare/apple-watch-vs-garmin#faq-5"
        }
      ]
    },
    {
      "question": "rook vs spike health data api",
      "answer": "Both Rook and Spike are single-integration health-data aggregators, so the decision is about reach and how you learn the price. Pick Rook when your product is mobile-first and you need a cost you can model today: its native Android and iOS SDKs pull Apple Health and Health Connect through the OS permission model across a stated 400-plus sources, and its pricing is usage-based with named tiers by active-user ceiling. Pick Spike when your build needs to reach past the wrist into IoT and medical devices, EMRs and lab tests, and you will accept a sales conversation plus a dedicated implementation engineer from the sandbox stage in exchange. State the gaps plainly: Rook's official pricing page could not be verified and no per-user figure was sourced, while Spike's specific tiers and figures were not retrievable at all and its own materials cite inconsistent device counts. As of 2026, verify both directly.",
      "title": "Rook vs Spike: Which Health-Data API Fits Your Build?",
      "url": "https://aifitnessapi.com/compare/rook-vs-spike",
      "markdown": "https://aifitnessapi.com/compare/rook-vs-spike.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "How do Rook and Spike differ on pricing transparency?",
          "answer": "In shape, not in candour. Rook prices usage-based, pay only for what you use, with named tiers by active-user ceiling, which at least gives you a model you can sanity-check against a growth curve. Spike is tiered and sales-assisted with no durable itemized public figures, so treat it as contact-sales. Neither publishes a confirmed per-user rate: Rook's official pricing page could not be verified, and Spike's specific tiers and figures were not retrievable. Get live quotes rather than budgeting against any circulating number.",
          "url": "https://aifitnessapi.com/compare/rook-vs-spike#faq-1"
        },
        {
          "question": "Does Rook reach lab, EMR, or IoT sources the way Spike markets?",
          "answer": "No, and this is the clearest split between them. Rook's coverage is wearables and health apps — activity, sleep, heart rate, body, and glucose or CGM across a stated 400-plus sources. Spike positions itself as a Health 360-degree API spanning consumer wearables plus IoT and medical devices, EMRs, and lab tests, with an AI and analytics layer on top. If labs, EMR data, or medical IoT are on your roadmap, Rook means adding a second vendor later. Verify the current source lists in each vendor's docs.",
          "url": "https://aifitnessapi.com/compare/rook-vs-spike#faq-2"
        },
        {
          "question": "Which handles on-device Apple Health and Health Connect extraction better, Rook or Spike?",
          "answer": "Rook, on the available evidence. Its native Android and iOS SDKs integrate directly with Health Connect and Apple Health using the OS permission model, and it organizes its catalogue around the distinction between direct-API cloud providers and SDK-based on-device stores, so the mobile layer is architectural rather than incidental. Spike markets Apple HealthKit among its supported sources, but confirm its on-device SDK details and webhook signing in Spike's own docs before assuming parity.",
          "url": "https://aifitnessapi.com/compare/rook-vs-spike#faq-3"
        },
        {
          "question": "Will I need my own provider credentials with Rook or Spike?",
          "answer": "Probably, for at least some providers, and it applies across this category rather than to one vendor. For several popular sources — commonly Garmin, WHOOP, Strava, Dexcom, and Samsung Health — you must still register your own developer or partner credentials even though the aggregator brokers everything else. Rook is documented as requiring this for several providers; verify which of your target sources are affected on each vendor's live integrations page, because it is real onboarding time either way.",
          "url": "https://aifitnessapi.com/compare/rook-vs-spike#faq-4"
        },
        {
          "question": "Is Spike being a newer, smaller company a risk next to Rook?",
          "answer": "It is a factor to weigh rather than a disqualifier. Spike is described as a newer, smaller company than Terra or Vital/Junction, it publishes the least of the mainstream aggregators, and its own materials cite inconsistent device counts, for example 500-plus on one page and 200-plus on another. Against that, every organization gets a dedicated implementation engineer from the sandbox stage, which is unusual hands-on support. Confirm that its marketed AI interpretation, food-photo extraction, and MCP capabilities are production-ready before designing around them.",
          "url": "https://aifitnessapi.com/compare/rook-vs-spike#faq-5"
        }
      ]
    },
    {
      "question": "usda fooddata central vs open food facts",
      "answer": "Pick USDA FoodData Central when you need authoritative US nutrient reference values you can absorb into a closed-source product, because it is public domain under CC0 and imposes no obligations at all; pick Open Food Facts when your core interaction is scanning a barcode on a packaged product anywhere in the world, and accept that its ODbL licence requires attribution and can force you to release a derived database as open data. Both are genuinely free rather than free tiers, so cost is not the deciding axis here — licence philosophy and coverage centre are. Neither offers natural-language meal parsing, so the logging layer is yours to build either way. Verify rate limits and the exact licence variants before you merge either dataset into anything you intend to keep private.",
      "title": "USDA FoodData Central vs Open Food Facts: Which Free Food Data?",
      "url": "https://aifitnessapi.com/compare/usda-fooddata-central-vs-open-food-facts",
      "markdown": "https://aifitnessapi.com/compare/usda-fooddata-central-vs-open-food-facts.md",
      "cluster": "Comparisons",
      "cluster_url": "https://aifitnessapi.com/compare",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Which of these two free food databases does barcode lookup?",
          "answer": "Open Food Facts. Barcode lookup is its core call, returning ingredients, nutrition facts, Nutri-Score, allergens, labels, categories, and images for a product code, globally and with no API key. USDA FoodData Central includes GTIN/UPC fields in its Branded Foods dataset, but it is oriented around its own food IDs and is not a consumer barcode-lookup product. If scanning a packet is your primary interaction, Open Food Facts is the one that makes the feature exist on day one.",
          "url": "https://aifitnessapi.com/compare/usda-fooddata-central-vs-open-food-facts#faq-1"
        },
        {
          "question": "Does the ODbL share-alike obligation force me to open my own food catalogue?",
          "answer": "It can. Open Food Facts is licensed under the ODbL, and the share-alike term means a derived database that combines its data with yours may have to be released as open data, with attribution required either way. Commercial use itself is explicitly permitted, and the obligation attaches to the database rather than the application around it. Where a merged catalogue sits on that line is a question for counsel, not a comparison table. This is general guidance, not legal advice.",
          "url": "https://aifitnessapi.com/compare/usda-fooddata-central-vs-open-food-facts#faq-2"
        },
        {
          "question": "Can I safely combine USDA FoodData Central and Open Food Facts in one product?",
          "answer": "Yes, and most food apps end up doing exactly that, but keep the two in separate stores. USDA data is public domain under CC0, so anything you derive from it stays yours with no strings. Open Food Facts data carries ODbL attribution and share-alike, so keep it attributed and unmerged, queried live or cached as its own dataset, rather than folded into a proprietary master catalogue. Deciding this on day one costs nothing; retrofitting it later is a schema migration.",
          "url": "https://aifitnessapi.com/compare/usda-fooddata-central-vs-open-food-facts#faq-3"
        },
        {
          "question": "Why does Open Food Facts require a custom User-Agent header?",
          "answer": "Open Food Facts issues no API keys for read access, so the User-Agent string identifying your app is how the project attributes traffic and contacts you if your calls cause a problem. Sending a generic library default is the most common reason an integration gets treated as anonymous scraping. The project has said it intends to keep the API free and add no keys, so the header is the whole of your identity on the wire. Verify the current header format in the project's documentation.",
          "url": "https://aifitnessapi.com/compare/usda-fooddata-central-vs-open-food-facts#faq-4"
        },
        {
          "question": "How hard is USDA FoodData Central rate limited?",
          "answer": "It is metered per API key at a modest rate, reported around 1,000 requests per hour as of 2026 — verify the current figure, since it changes. That is comfortable for a server-side integration with caching and uncomfortable for anything that proxies every user keystroke straight through. The usual pattern is to mirror or cache the datasets you actually use rather than calling live. Signup is a free data.gov key, and a shared DEMO_KEY exists for first exploration only.",
          "url": "https://aifitnessapi.com/compare/usda-fooddata-central-vs-open-food-facts#faq-5"
        }
      ]
    },
    {
      "question": "heart rate api",
      "answer": "Heart rate is a measured signal, read on consumer devices from a PPG optical sensor (chest straps use electrical ECG-style sensing). You get it into an app from on-device stores (Apple HealthKit `HKQuantityTypeIdentifierHeartRate`, Android Health Connect `HeartRateRecord`), from nearly every wearable cloud API (Fitbit, Garmin, Oura, WHOOP, Strava), or from an aggregator that normalizes all of them. HR itself is measured and wellness-grade, not an ECG or diagnostic; resting and walking-average HR are derived aggregates. Best pick: on-device or a chest strap for live in-workout HR, and cloud OAuth or an aggregator for all-day and resting HR across many devices.",
      "title": "Heart Rate API: How to Get Heart-Rate Data Into Your App",
      "url": "https://aifitnessapi.com/data/heart-rate-api",
      "markdown": "https://aifitnessapi.com/data/heart-rate-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Is heart rate from a wearable measured or estimated?",
          "answer": "Heart rate itself is measured, not modeled. Most consumer devices read it optically with a PPG sensor (green or infrared LEDs at the wrist or finger); chest straps use electrical, ECG-style sensing. What varies is accuracy under conditions: optical PPG degrades with motion, cold, tattoos, and poor fit, so accuracy depends on the device and situation. Resting and walking-average heart rate are derived aggregates computed from measured samples, not live readings. It is a wellness signal, not a clinical diagnostic.",
          "url": "https://aifitnessapi.com/data/heart-rate-api#faq-1"
        },
        {
          "question": "How do I get real-time heart rate into an app?",
          "answer": "For live, in-workout HR, read on-device through a HealthKit workout session on iOS or Android Health Connect, or connect directly to a chest strap over the Bluetooth Low Energy Heart Rate Profile. Cloud wearable APIs (Fitbit, Garmin, Oura, WHOOP, Strava) are too latent for hard real-time because their data only lands after the user's device syncs to the vendor cloud. Verify current on-device session behavior in each platform's docs.",
          "url": "https://aifitnessapi.com/data/heart-rate-api#faq-2"
        },
        {
          "question": "Which data types expose heart rate on HealthKit and Health Connect?",
          "answer": "On Apple HealthKit, general samples come from `HKQuantityTypeIdentifierHeartRate`, with `HKQuantityTypeIdentifierRestingHeartRate`, `walkingHeartRateAverage`, and `heartRateRecoveryOneMinute` for derived values, plus the beat-to-beat `HKDataTypeIdentifierHeartbeatSeries`. On Android Health Connect, use `HeartRateRecord`, a series of BPM samples. Both are on-device reads that need per-type user permission and have no cloud pull. Confirm exact identifiers in each platform's live data dictionary.",
          "url": "https://aifitnessapi.com/data/heart-rate-api#faq-3"
        },
        {
          "question": "Can I get all-day and resting heart rate from Strava?",
          "answer": "No. Strava exposes heart rate only as a per-workout activity stream in BPM, not resting or continuous all-day HR. For resting HR and continuous intraday data across devices, use per-vendor cloud OAuth (Fitbit, Garmin, Oura, WHOOP) or an aggregator that normalizes them. Note that resting HR is a once-daily derived aggregate, not a value you can poll live. Verify each provider's current fields and scopes.",
          "url": "https://aifitnessapi.com/data/heart-rate-api#faq-4"
        },
        {
          "question": "Should I use an aggregator or integrate each wearable directly?",
          "answer": "Integrate directly when you support one or two sources or need on-device, low-latency reads; that keeps the data path simple. Use an aggregator such as Terra, Junction, or Rook when you want all-day and resting HR from many wearables behind one normalized schema and webhooks, so you avoid building and maintaining a separate OAuth integration per vendor. Verify each aggregator's current source list and normalized fields in its own docs.",
          "url": "https://aifitnessapi.com/data/heart-rate-api#faq-5"
        }
      ]
    },
    {
      "question": "hrv api",
      "answer": "HRV is a measured metric from the timing between heartbeats. You read it on-device (Apple HealthKit stores SDNN via HKQuantityTypeIdentifierHeartRateVariabilitySDNN; Android Health Connect gives RMSSD via HeartRateVariabilityRmssdRecord) or from cloud wearable APIs (Oura, WHOOP, Garmin, Fitbit) after sync. It reflects parasympathetic activity, so treat it as a wellness signal, not a stress or recovery measurement. Best pick: Oura or WHOOP for ready-made recovery scoring, Health Connect for a raw RMSSD trend on Android, a chest strap for real-time.",
      "title": "HRV API: How to Get Heart Rate Variability Data",
      "url": "https://aifitnessapi.com/data/hrv-api",
      "markdown": "https://aifitnessapi.com/data/hrv-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Is HRV measured or estimated?",
          "answer": "The HRV value itself is measured from real beat-to-beat interval timing. What is not a direct measurement is the interpretation: RMSSD reflects parasympathetic (vagal) influence on heart rate, so it is a wellness signal, not a readout of stress, recovery, or nervous-system health. Recovery and readiness scores built on HRV are proprietary vendor models.",
          "url": "https://aifitnessapi.com/data/hrv-api#faq-1"
        },
        {
          "question": "What is the difference between RMSSD and SDNN in HRV APIs?",
          "answer": "They are two different statistics computed from the same interbeat intervals and are not directly comparable. Apple HealthKit stores SDNN; Android Health Connect, Fitbit, and most other sources report RMSSD. Always label which one you store and never mix them in a single trend.",
          "url": "https://aifitnessapi.com/data/hrv-api#faq-2"
        },
        {
          "question": "Can I get HRV from a phone without a wearable?",
          "answer": "No. HRV needs a device that captures beat-to-beat intervals, so it requires a wearable (ring, watch, band) or a chest strap. A phone alone cannot produce it. Verify each provider's device coverage in its live data dictionary, as coverage changes.",
          "url": "https://aifitnessapi.com/data/hrv-api#faq-3"
        },
        {
          "question": "Why do Oura and WHOOP HRV values differ from a morning app reading?",
          "answer": "Most consumer platforms compute HRV over a nocturnal/overnight window for comparability, while some apps use a guided morning spot reading. The two windows are not interchangeable, and absolute HRV varies a lot between people, so HRV is meant for within-person trends. Surface which window each reading came from.",
          "url": "https://aifitnessapi.com/data/hrv-api#faq-4"
        },
        {
          "question": "Which API is best for HRV?",
          "answer": "For recovery or readiness scoring out of the box, Oura or WHOOP, which bake nightly HRV into their models. For a raw RMSSD trend on Android, Health Connect. On iOS, HealthKit (SDNN). For real-time biofeedback, a chest strap's RR intervals over BLE. To combine many brands, an aggregator like Terra or Junction.",
          "url": "https://aifitnessapi.com/data/hrv-api#faq-5"
        }
      ]
    },
    {
      "question": "vo2 max api",
      "answer": "You get VO2 max by reading an on-device store (Apple HealthKit HKQuantityTypeIdentifierVO2Max, Android Health Connect Vo2MaxRecord) or by pulling a cloud wearable API (Garmin User Metrics, Fitbit's Cardio Fitness Score, Oura) over OAuth 2.0. Be honest that consumer VO2 max is estimated, not lab-measured: it is modeled from heart-rate response versus pace or power plus demographics, so it is a fitness-trend signal, not a clinical value. Not every provider exposes it and coverage is device-dependent. Best pick: HealthKit for Apple apps, Garmin or Fitbit for a cross-device trend, and an aggregator when you mix brands.",
      "title": "VO2 Max API: How to Get VO2 Max Data",
      "url": "https://aifitnessapi.com/data/vo2-max-api",
      "markdown": "https://aifitnessapi.com/data/vo2-max-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Is VO2 max from a watch accurate?",
          "answer": "Consumer VO2 max is an estimate, not a lab measurement, so treat it as a fitness-trend signal rather than a precise value. Accuracy varies with device, fitness level, and activity type, and the estimate often only refreshes after qualifying outdoor activities with heart rate and pace or GPS. There is no single accuracy percentage to quote; verify each provider's method in its data dictionary.",
          "url": "https://aifitnessapi.com/data/vo2-max-api#faq-1"
        },
        {
          "question": "Which APIs expose VO2 max data?",
          "answer": "Apple HealthKit exposes HKQuantityTypeIdentifierVO2Max on-device, Android Health Connect exposes Vo2MaxRecord, and cloud wearable APIs include Garmin (User Metrics), Fitbit (Cardio Fitness Score), and Oura. WHOOP has not historically been a headline field, and Strava has no VO2 max field. Not all providers expose it and coverage is device-dependent, so verify per provider as of 2026.",
          "url": "https://aifitnessapi.com/data/vo2-max-api#faq-2"
        },
        {
          "question": "Is consumer VO2 max measured or estimated?",
          "answer": "Estimated on every consumer device. True VO2 max comes from a lab graded-exercise test with a metabolic cart. Watches and rings model it from your heart-rate response relative to pace or power during activity plus profile data like age, weight, and sex. Health Connect's Vo2MaxRecord even carries a measurementMethod field distinguishing estimated from metabolic-cart values.",
          "url": "https://aifitnessapi.com/data/vo2-max-api#faq-3"
        },
        {
          "question": "Can I compare VO2 max across Garmin, Fitbit, and Apple?",
          "answer": "Not directly. Vendors label it differently (VO2 max, Cardio Fitness Score, Cardio Fitness) and use different estimation models, so the same person can get different numbers on different devices. Use it as a within-person trend, and normalize through an aggregator if you need one consistent field across brands.",
          "url": "https://aifitnessapi.com/data/vo2-max-api#faq-4"
        },
        {
          "question": "How do I read VO2 max in an iOS or Android app?",
          "answer": "On iOS, request permission and read HKQuantityTypeIdentifierVO2Max from HealthKit on-device; there is no Apple cloud pull. On Android, read Vo2MaxRecord from Health Connect with the granted permission. Both are permissioned on-device reads, so verify the current type and field names in Apple's and Google's data dictionaries before you build.",
          "url": "https://aifitnessapi.com/data/vo2-max-api#faq-5"
        }
      ]
    },
    {
      "question": "blood oxygen spo2 api",
      "answer": "Blood oxygen (SpO2) is measured by optical pulse oximetry on wrist wearables and finger rings, but on consumer devices it is a general-wellness signal, not an FDA-cleared diagnostic. You can read it from on-device stores (HealthKit oxygenSaturation, Health Connect OxygenSaturationRecord) or cloud wearable APIs (Fitbit, Garmin, Oura, WHOOP), most of which report an overnight trend rather than continuous daytime readings. Best pick: Oura, Fitbit, or Garmin for overnight trends; HealthKit for an on-demand iOS spot check, subject to Apple Watch US availability caveats.",
      "title": "Blood Oxygen (SpO2) API: How to Get SpO2 Data",
      "url": "https://aifitnessapi.com/data/blood-oxygen-api",
      "markdown": "https://aifitnessapi.com/data/blood-oxygen-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Is consumer SpO2 data a medical measurement?",
          "answer": "No. SpO2 is genuinely measured by an optical sensor, but consumer wearables and rings are marketed as general fitness and wellness devices that are not intended for medical use and are not FDA-cleared diagnostics. Do not treat their SpO2 data as a substitute for a medical pulse oximeter or as a way to detect or monitor disease.",
          "url": "https://aifitnessapi.com/data/blood-oxygen-api#faq-1"
        },
        {
          "question": "Which platform data types expose blood oxygen?",
          "answer": "On iOS, Apple HealthKit exposes HKQuantityTypeIdentifierOxygenSaturation as an on-device permissioned read. On Android, Health Connect exposes OxygenSaturationRecord (a single reading). Cloud wearable APIs use OAuth: Oura returns daily_spo2, and Fitbit, Garmin, and WHOOP expose their own SpO2 fields. Verify exact field names and scopes in each provider's current data dictionary.",
          "url": "https://aifitnessapi.com/data/blood-oxygen-api#faq-2"
        },
        {
          "question": "Can I get an Apple Watch blood oxygen reading in the US?",
          "answer": "It depends and is unsettled. Apple Watch's Blood Oxygen feature was disabled on new US units after a 2023 ITC order, then restored around August 2025 via a reworked flow that computes the reading on the paired iPhone, with litigation ongoing into late 2025. As of 2026, availability differs by model, region, and OS version, so do not assume the HealthKit oxygenSaturation type is populated. Verify current US availability.",
          "url": "https://aifitnessapi.com/data/blood-oxygen-api#faq-3"
        },
        {
          "question": "Do wearables give continuous SpO2 or just overnight readings?",
          "answer": "Both modes exist, but they differ by source. On-demand spot readings require the user to initiate and hold still; overnight or background sampling produces a trend. Many providers report only an overnight average or oxygen variation rather than continuous daytime SpO2, so confirm which mode a given source returns before building around it.",
          "url": "https://aifitnessapi.com/data/blood-oxygen-api#faq-4"
        },
        {
          "question": "What is the easiest way to read SpO2 across many devices?",
          "answer": "Use an aggregator such as Terra, Junction, or Rook, which normalize SpO2 across providers behind one schema and webhooks where the underlying source supplies it. This avoids building a separate OAuth integration for each wearable, though coverage still depends on what each device and vendor expose.",
          "url": "https://aifitnessapi.com/data/blood-oxygen-api#faq-5"
        }
      ]
    },
    {
      "question": "sleep tracking api",
      "answer": "Sleep data comes from devices worn overnight (Oura, WHOOP, Fitbit, Garmin, Apple Watch) via on-device stores (HealthKit's HKCategoryTypeIdentifierSleepAnalysis, Health Connect's SleepSessionRecord) or cloud OAuth APIs. Duration is measured reasonably well, but sleep stages are estimated from motion and heart rate and each vendor labels them differently. Best pick: Oura or WHOOP for rich staging plus readiness, or an aggregator to reconcile several brands.",
      "title": "Sleep Tracking API: How to Get Sleep Data Into Your App",
      "url": "https://aifitnessapi.com/data/sleep-tracking-api",
      "markdown": "https://aifitnessapi.com/data/sleep-tracking-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Are sleep stages from a wearable accurate?",
          "answer": "Sleep stages (light, deep, REM, awake) are estimated from movement, heart rate, HRV, and respiration, not from EEG, so they are modeled rather than measured. Duration and time in bed are more reliable. Consumer stages are a wellness signal, not a clinical or diagnostic tool, and accuracy varies by device and person. Verify each provider's method in its data dictionary.",
          "url": "https://aifitnessapi.com/data/sleep-tracking-api#faq-1"
        },
        {
          "question": "Can I get sleep data from a phone without a wearable?",
          "answer": "Typically not reliably. Phones alone usually do not produce trustworthy staged sleep, so phone-only sleep should be treated as coarse. Reliable sleep data comes from a wrist wearable or ring worn overnight, such as Oura, WHOOP, Fitbit, Garmin, or Apple Watch. Confirm which device generated any record before using it.",
          "url": "https://aifitnessapi.com/data/sleep-tracking-api#faq-2"
        },
        {
          "question": "Why do sleep stages differ between Oura, WHOOP, and Apple?",
          "answer": "Vendors use different stage taxonomies. Apple uses Core, Deep, REM, and Awake; others use Light, Deep, REM; WHOOP uses Light, REM, and Slow-Wave (Deep). Definitions of in-bed versus asleep also vary. If you merge sources you must map stages explicitly and cannot assume a 1:1 match. Verify each provider's stage enum before combining data.",
          "url": "https://aifitnessapi.com/data/sleep-tracking-api#faq-3"
        },
        {
          "question": "How do I access sleep data on iOS and Android?",
          "answer": "On iOS, read HealthKit's HKCategoryTypeIdentifierSleepAnalysis on-device with the user's permission. On Android, read Health Connect's SleepSessionRecord, also on-device. Neither is a cloud API. For server-side access across users, use cloud OAuth wearable APIs (Oura, WHOOP, Fitbit, Garmin) or an aggregator. Verify current field names and scopes.",
          "url": "https://aifitnessapi.com/data/sleep-tracking-api#faq-4"
        },
        {
          "question": "Can sleep tracking APIs diagnose sleep disorders?",
          "answer": "No. Consumer sleep data is a general wellness signal, not a medical diagnostic. Stages are estimates validated only imperfectly against clinical polysomnography, so they should not be used to diagnose sleep apnea or other disorders. Frame the data as wellness insight and direct users to a clinician for any medical concern.",
          "url": "https://aifitnessapi.com/data/sleep-tracking-api#faq-5"
        }
      ]
    },
    {
      "question": "step counting api",
      "answer": "Step counts are widely available because the phone itself can count them - no wearable needed. You get them from an on-device store (Apple HealthKit's stepCount, iOS Core Motion CMPedometer, or Android Health Connect's StepsRecord) or from a cloud wearable API (Garmin, Fitbit, Samsung Health) after the device syncs. Steps are counted, but algorithmically from motion sensors, so treat them as a close estimate rather than exact. Best pick: read the on-device platform store so you inherit the OS's own de-duplication - which matters because a phone plus a paired watch will otherwise double-count.",
      "title": "Step Counting API: How to Get Step Data",
      "url": "https://aifitnessapi.com/data/step-counting-api",
      "markdown": "https://aifitnessapi.com/data/step-counting-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Can a phone count steps without a wearable?",
          "answer": "Yes. Step counting is one of the few fitness metrics fully available from a phone alone - its accelerometer feeds a pedometer. On iOS you can read stored counts via HealthKit (HKQuantityTypeIdentifier.stepCount) or live data via Core Motion's CMPedometer; on Android you read Health Connect's StepsRecord. A wearable only adds coverage for times the phone is not carried. As of 2026, verify exact fields in each platform's data dictionary.",
          "url": "https://aifitnessapi.com/data/step-counting-api#faq-1"
        },
        {
          "question": "Why do my step counts look doubled?",
          "answer": "Because a phone and a paired watch both log steps, so naively summing every source roughly doubles the total. Use the platform's de-duplication instead: on Android, use Health Connect's aggregate() (for example StepsRecord.COUNT_TOTAL) rather than summing raw readRecords(); on iOS, query HealthKit statistics, which de-duplicate across sources. Read the aggregated total the OS provides rather than stitching sources together yourself.",
          "url": "https://aifitnessapi.com/data/step-counting-api#faq-2"
        },
        {
          "question": "Are step counts measured or estimated?",
          "answer": "They are counted, but algorithmically - motion-sensor pattern recognition interpreting accelerometer data, not a sensor that registers each literal foot-fall. Treat step counts as a close algorithmic estimate, not ground truth, and do not rely on an exact accuracy figure; accuracy varies by device, gait, and where the device is carried. It is wellness-grade activity data, not a clinical measurement.",
          "url": "https://aifitnessapi.com/data/step-counting-api#faq-3"
        },
        {
          "question": "Did Health Connect change how steps are attributed in 2026?",
          "answer": "There is a reported 2026 change to on-device step attribution in Health Connect - legacy readings attributed to the \"android\" package versus a newer device Synthetic Package Name - which affects how you filter or de-duplicate by DataOrigin. Confirm the current Health Connect steps guidance before shipping any de-duplication logic, as this behavior is volatile; verify in the official docs.",
          "url": "https://aifitnessapi.com/data/step-counting-api#faq-4"
        },
        {
          "question": "Which source should I use for step data?",
          "answer": "For the widest reach with least friction, read the on-device platform store (HealthKit on iOS, Health Connect on Android) so you inherit the OS's multi-source de-duplication. Use Core Motion's CMPedometer for live counts on iOS. Use a cloud wearable API (Garmin, Fitbit, Samsung Health) when your backend needs data without the user's phone present, or an aggregator to normalize many brands at once.",
          "url": "https://aifitnessapi.com/data/step-counting-api#faq-5"
        }
      ]
    },
    {
      "question": "workout detection api",
      "answer": "A workout detection API gets you recorded workout sessions with start time, end time, and activity type. You read them on-device (Apple HealthKit HKWorkout on iOS, Android Health Connect ExerciseSessionRecord on Android) or from a cloud activity API (Strava, Garmin, Fitbit) after the device syncs. Some vendors auto-detect activity (Fitbit SmartTrack) while others expect a manual start; duration is measured but activity type is inferred. Best pick: for automatic capture, a wearable that auto-detects; to read what the user already logged, the on-device store.",
      "title": "Workout Detection API: Get Recorded Workout Sessions",
      "url": "https://aifitnessapi.com/data/workout-detection-api",
      "markdown": "https://aifitnessapi.com/data/workout-detection-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Which providers auto-detect workouts vs. require a manual start?",
          "answer": "Fitbit SmartTrack auto-recognizes select activities after sustained movement and logs them with no manual start, while Apple Watch generally relies on the user starting and stopping a workout. Garmin and Strava records reflect whatever the device or app captured, and auto-start varies by device and setting. Which activity types are auto-detected changes, so verify each vendor's current docs rather than hardcoding a list.",
          "url": "https://aifitnessapi.com/data/workout-detection-api#faq-1"
        },
        {
          "question": "How do I read workout sessions on iOS and Android?",
          "answer": "On iOS, read Apple HealthKit's HKWorkout on-device with per-type permission; each session carries an activity type plus fields like totalEnergyBurned. On Android, read Health Connect's ExerciseSessionRecord (start time, end time, session type), with optional ExerciseSegment and ExerciseLap sub-intervals. Both are on-device stores, so there is no cloud pull and no post-sync latency.",
          "url": "https://aifitnessapi.com/data/workout-detection-api#faq-2"
        },
        {
          "question": "Is a detected workout type accurate?",
          "answer": "The session's duration is measured, but the activity type and session boundaries are algorithmically inferred, especially for auto-detected workouts, so treat the type as a model's guess rather than certain. Any derived calories or effort are estimates that differ across devices. Do not present a detected activity type as fact, and do not publish accuracy percentages.",
          "url": "https://aifitnessapi.com/data/workout-detection-api#faq-3"
        },
        {
          "question": "Is this the same as AI camera-based rep counting?",
          "answer": "No. This page covers recorded workout sessions from HealthKit, Health Connect, Strava, and Garmin. AI camera-based rep or exercise detection classifies movement from a video or pose feed in real time and is a separate capability, covered under AI workout tracking APIs.",
          "url": "https://aifitnessapi.com/data/workout-detection-api#faq-4"
        },
        {
          "question": "How do I merge workouts from different sources?",
          "answer": "Activity-type taxonomies differ across HealthKit, Health Connect, Strava, and Garmin, so their type enums are not a 1:1 mapping. If you combine sources, map the taxonomies explicitly instead of assuming equivalence, and confirm each enum in the provider's data dictionary. An aggregator like Terra, Junction, or Rook can normalize workouts across brands for you.",
          "url": "https://aifitnessapi.com/data/workout-detection-api#faq-5"
        }
      ]
    },
    {
      "question": "gps activity route api",
      "answer": "GPS route data comes from an on-device store (Apple HealthKit HKWorkoutRoute on iOS, Android Health Connect ExerciseRoute on Android) or a cloud activity API (Strava streams, Garmin Activity API) after the device syncs. The coordinates are measured by the device's GPS/GNSS but are noisy, so filter low-accuracy samples and never quote a positional-accuracy figure. Best pick: on-device routes (HKWorkoutRoute / ExerciseRoute) to show a user their own route; Garmin's Activity API for server-side pulls across users; Strava only after confirming its display and data-combination restrictions.",
      "title": "GPS Activity API: How to Get Route Data from Workouts",
      "url": "https://aifitnessapi.com/data/gps-activity-api",
      "markdown": "https://aifitnessapi.com/data/gps-activity-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Is GPS route data measured or estimated?",
          "answer": "The coordinates are measured by the device's GNSS/GPS receiver, not modeled. But the measurement is noisy: it drifts near buildings or tree cover and is subject to vendor smoothing, which is why Health Connect advises filtering low-accuracy samples before writing a route. Any distance or pace derived from the route is a computation over those imperfect points, so figures can differ slightly between apps. Never publish a positional-accuracy number; accuracy varies by device and conditions.",
          "url": "https://aifitnessapi.com/data/gps-activity-api#faq-1"
        },
        {
          "question": "Can I get GPS route data from a phone without a wearable?",
          "answer": "Yes. A phone has GPS, so it can record a route on its own, and a GPS-capable watch or bike computer can too. A non-GPS wearable relies on the connected phone's location. On-device recording needs the OS location permission, and Google recommends a foreground service when capturing a route on Android.",
          "url": "https://aifitnessapi.com/data/gps-activity-api#faq-2"
        },
        {
          "question": "What are Strava's API restrictions for route data?",
          "answer": "Strava enforces rate limits and has been tightening access; for example the Explore Segments endpoint is documented as moving to an approved Extended Access tier per the Strava changelog. Its API Agreement also restricts how Strava data may be displayed and combined with other providers' data, which can block common designs like merging Strava routes with other sources onto one map. These terms change, so verify the current Strava API Agreement before you build.",
          "url": "https://aifitnessapi.com/data/gps-activity-api#faq-3"
        },
        {
          "question": "Which API is best for GPS route data?",
          "answer": "To show a user their own route, the on-device path is least restrictive: HKWorkoutRoute on iOS, ExerciseRoute on Android. To pull routes server-side across many users, Garmin's Activity API is straightforward because it delivers standard .FIT, GPX, and .TCX files. Use Strava only after confirming its display and data-combination restrictions fit your product. To combine many brands, an aggregator like Terra, Junction, or Rook normalizes routes, but you inherit each provider's terms.",
          "url": "https://aifitnessapi.com/data/gps-activity-api#faq-4"
        },
        {
          "question": "How do HealthKit and Health Connect expose route data?",
          "answer": "On iOS, HealthKit stores a route as HKWorkoutRoute attached to a workout; you read it with HKWorkoutRouteQuery and build it with HKWorkoutRouteBuilder. On Android, Health Connect exposes ExerciseRoute, a sequence of ExerciseRoute.Location points tied to an exercise session rather than an independent record. Both are on-device reads that require the OS location permission. Verify exact field names in each platform's data dictionary.",
          "url": "https://aifitnessapi.com/data/gps-activity-api#faq-5"
        }
      ]
    },
    {
      "question": "calorie tracking api",
      "answer": "Calorie tracking is two different problems. Calories burned is a modeled estimate, not a measurement: read it on-device (Apple HealthKit activeEnergyBurned and basalEnergyBurned; Android Health Connect ActiveCaloriesBurnedRecord and TotalCaloriesBurnedRecord) or from cloud wearable APIs after sync. Calories consumed never comes from a wearable and needs a dedicated nutrition API such as Nutritionix or Edamam. Best pick: read the on-device energy types for burn and pair a nutrition API for intake. Both burn figures are estimates that differ across devices.",
      "title": "Calorie Tracking API: How to Get Calorie Data",
      "url": "https://aifitnessapi.com/data/calorie-tracking-api",
      "markdown": "https://aifitnessapi.com/data/calorie-tracking-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Are calories burned measured or estimated?",
          "answer": "Estimated. Calories burned is a model derived from heart rate, motion, activity type, and your profile (age, weight, sex) via a proprietary per-vendor algorithm, so the same workout yields different numbers on different devices. Basal or resting energy is a formula-based baseline, not a live measurement. Present it as a wellness estimate, never as a precise readout.",
          "url": "https://aifitnessapi.com/data/calorie-tracking-api#faq-1"
        },
        {
          "question": "How do I get calories consumed from a fitness API?",
          "answer": "You do not get intake from a wearable or phone sensor, because nothing measures what a person eats. Calories consumed comes from food logging against a nutrition database, which means a dedicated nutrition API such as Nutritionix or Edamam. On-device stores (HealthKit dietaryEnergyConsumed, Health Connect NutritionRecord) can hold intake a user already logged, but the nutrition facts still come from the database.",
          "url": "https://aifitnessapi.com/data/calorie-tracking-api#faq-2"
        },
        {
          "question": "What is the difference between active and total calories?",
          "answer": "Active energy is exercise/movement calories only; total energy includes basal (resting) energy on top. On HealthKit, activeEnergyBurned and basalEnergyBurned are separate types you sum yourself. On Health Connect, TotalCaloriesBurnedRecord already includes basal while ActiveCaloriesBurnedRecord does not, so mixing them double-counts. Verify how each source populates these before adding anything up.",
          "url": "https://aifitnessapi.com/data/calorie-tracking-api#faq-3"
        },
        {
          "question": "Why do calorie counts differ between my devices?",
          "answer": "Because they are estimates, not measurements. Each vendor uses a different proprietary model over heart rate, motion, and user profile, so an Apple Watch, a Garmin, and a Fitbit can report different calories for the same activity. Do not treat any single figure as ground truth, and avoid publishing accuracy percentages, as none are reliably sourced.",
          "url": "https://aifitnessapi.com/data/calorie-tracking-api#faq-4"
        },
        {
          "question": "Which API is best for calorie tracking?",
          "answer": "For calories burned with the widest coverage, read the on-device platform energy types (active plus basal on HealthKit, active plus total on Health Connect); use a wearable vendor API or an aggregator when you need it server-side. For calories consumed, use a dedicated nutrition API like Nutritionix or Edamam, since a wearable API will never give you intake.",
          "url": "https://aifitnessapi.com/data/calorie-tracking-api#faq-5"
        }
      ]
    },
    {
      "question": "body composition api",
      "answer": "Body composition (weight, body fat %, BMI, lean mass) mostly does not come from wearables. A wrist band or watch cannot measure body fat or lean mass; those need a smart scale (bioimpedance) or manual entry, and BMI is computed from weight and height. You read the results on-device (Apple HealthKit bodyMass, bodyFatPercentage, bodyMassIndex, leanBodyMass; Android Health Connect WeightRecord, BodyFatRecord) or from a scale vendor's cloud API like Withings or Garmin via OAuth. Best pick: integrate a smart scale such as Withings for a full breakdown, or read whatever a paired scale wrote into HealthKit or Health Connect for a hardware-agnostic path. Weight measured, BMI computed, body fat and lean mass estimated.",
      "title": "Body Composition API: Weight, Body Fat, and Lean Mass Data",
      "url": "https://aifitnessapi.com/data/body-composition-api",
      "markdown": "https://aifitnessapi.com/data/body-composition-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Can a fitness watch or band measure body fat?",
          "answer": "No. A typical wrist wearable does not measure body fat, lean mass, or BMI. Those come from a smart scale using bioelectrical impedance, a body scanner, or the user entering values manually. This is the sharpest case in health data where a phone or watch alone cannot produce the metric.",
          "url": "https://aifitnessapi.com/data/body-composition-api#faq-1"
        },
        {
          "question": "Is body fat percentage from a smart scale accurate?",
          "answer": "It is an estimate, not a lab measurement. Consumer scales use bioelectrical impedance analysis (BIA), which infers fat versus fat-free mass from electrical resistance. BIA is sensitive to hydration, recent food or exercise, time of day, and electrode placement. DEXA and hydrostatic weighing are the reference methods. Treat scale body fat as a wellness signal and track trends under consistent conditions rather than any single reading.",
          "url": "https://aifitnessapi.com/data/body-composition-api#faq-2"
        },
        {
          "question": "How do I get weight and body fat data from HealthKit and Health Connect?",
          "answer": "Apple HealthKit exposes bodyMass, bodyFatPercentage, bodyMassIndex, and leanBodyMass as on-device quantity types you read with per-type permission. Android Health Connect exposes WeightRecord and BodyFatRecord, plus related body records, read with per-record permission. Both are on-device only, so you read whatever a paired scale app or the user wrote; there is no cloud pull. Verify exact record and field names in each platform's live data dictionary.",
          "url": "https://aifitnessapi.com/data/body-composition-api#faq-3"
        },
        {
          "question": "Is BMI measured or calculated?",
          "answer": "BMI is calculated, not measured. It is weight divided by height squared, so it is only as good as the weight and height behind it. HealthKit exposes it as bodyMassIndex, but treat it as a derived value rather than a sensor reading.",
          "url": "https://aifitnessapi.com/data/body-composition-api#faq-4"
        },
        {
          "question": "Which API is best for body composition?",
          "answer": "For a full breakdown of fat, muscle, water, and bone, integrate a smart-scale source; Withings is the common pick for a rich bioimpedance field set. For a hardware-agnostic path, read what a paired scale wrote into HealthKit or Health Connect. If you only need weight and BMI, the on-device store plus manual entry is enough. To combine many scale brands, use an aggregator like Terra or Junction. Verify current fields and units in each provider's docs.",
          "url": "https://aifitnessapi.com/data/body-composition-api#faq-5"
        }
      ]
    },
    {
      "question": "menstrual cycle api",
      "answer": "Menstrual cycle data is almost entirely user-logged rather than sensor-measured, so the real question is where the log lives and who may read it. On iOS you read Apple HealthKit's Reproductive Health category types - HKCategoryTypeIdentifierMenstrualFlow plus cervicalMucusQuality, ovulationTestResult, intermenstrualBleeding and others - and on Android you read Health Connect's Cycle Tracking records such as MenstruationFlowRecord, MenstruationPeriodRecord, CervicalMucusRecord and OvulationTestRecord. Cloud coverage is thin: among the sources documented on our pages, only Terra normalizes a menstruation datatype, so verify any other vendor directly. Best pick: the on-device platform stores, keeping the log on the device wherever the feature allows, because this category carries privacy stakes ordinary fitness metrics do not.",
      "title": "Menstrual Cycle API: How to Get Cycle Tracking Data",
      "url": "https://aifitnessapi.com/data/menstrual-cycle-api",
      "markdown": "https://aifitnessapi.com/data/menstrual-cycle-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Which Health Connect records cover menstrual cycle tracking?",
          "answer": "Health Connect groups them under Cycle Tracking: MenstruationFlowRecord (instantaneous, with a flow field taking FLOW_LIGHT, FLOW_MEDIUM, FLOW_HEAVY or FLOW_UNKNOWN), MenstruationPeriodRecord (an interval with startTime and endTime), CervicalMucusRecord, IntermenstrualBleedingRecord, OvulationTestRecord, SexualActivityRecord, and BasalBodyTemperatureRecord. The two menstruation records share one permission pair, android.permission.health.READ_MENSTRUATION and WRITE_MENSTRUATION, while the others have their own. Verify the current record and permission list in Google's data types reference before you build.",
          "url": "https://aifitnessapi.com/data/menstrual-cycle-api#faq-1"
        },
        {
          "question": "Does Apple HealthKit predict ovulation, or only store what was logged?",
          "answer": "HealthKit stores samples; the prediction lives in Apple's Cycle Tracking feature, not in a type you read. Apple documents that Cycle Tracking uses sleeping wrist temperature data to provide a retrospective estimate of when someone likely ovulated, combined with heart rate and logged cycle data. That is an estimate made after the fact, not a forecast, and the appleSleepingWristTemperature type is read-only, so you can request permission to read it but cannot write samples. Anything your app renders as a future fertile window is your own model's prediction and should be labelled as one.",
          "url": "https://aifitnessapi.com/data/menstrual-cycle-api#faq-2"
        },
        {
          "question": "Can a wearable detect a period automatically, or must the user log it?",
          "answer": "Flow, spotting, cervical mucus quality, ovulation test results, and sexual activity are all logged by the person or written by another app; there is no sensor that detects them. The genuinely sensor-derived signals are adjacent, not equivalent: overnight wrist temperature, basal body temperature, and resting heart rate are inputs a cycle model consumes rather than the cycle itself. Design your empty states around a log that may simply not exist yet.",
          "url": "https://aifitnessapi.com/data/menstrual-cycle-api#faq-3"
        },
        {
          "question": "What extra privacy obligations come with period-tracking data?",
          "answer": "Treat it as the most exposed category in consumer health. Google's Health Connect guidance is to request only the permissions and data types that support the specific user-facing features you offer, and to justify each one, with period tracking listed as a declarable health feature in the Play Console. Apple's HealthKit rules prohibit using the data for advertising, disclosing it to a third party without express permission (and even then only to a party that also provides a health or fitness service), and selling it to advertising platforms, data brokers, or information resellers, and require a privacy policy. Keep the log on-device where the feature allows, and make deletion real. This is engineering guidance, not legal advice.",
          "url": "https://aifitnessapi.com/data/menstrual-cycle-api#faq-4"
        },
        {
          "question": "Which wearable cloud APIs return menstrual cycle data?",
          "answer": "Fewer than you would expect. Among the sources documented on our pages, Terra is the one that normalizes cycle data, with a menstruation payload type and a /v2/menstruation REST endpoint. Menstrual cycle data is not documented on our pages for Fitbit, Garmin, Oura, or WHOOP, nor for the Junction, Rook, or Spike aggregators, so verify with each vendor rather than assuming coverage. Oura's nightly temperature deviation is described on our pages as a useful input to cycle features, which is not the same as an API datatype for the cycle itself.",
          "url": "https://aifitnessapi.com/data/menstrual-cycle-api#faq-5"
        }
      ]
    },
    {
      "question": "blood glucose api",
      "answer": "Blood glucose reaches your app second-hand: a fingerstick meter or a continuous glucose monitor measures it and its companion app writes it into the platform store, which you then read on-device via Apple HealthKit's HKQuantityTypeIdentifierBloodGlucose or Android Health Connect's BloodGlucoseRecord. The value is genuinely measured, but not all glucose is the same measurement - Health Connect requires a specimenSource field distinguishing interstitial fluid from capillary blood, plasma, serum, tears, or whole blood. The two traps that bite hardest are units, since samples may be in mg/dL or mmol/L by region, and meal context, which Health Connect makes mandatory and Apple exposes only as optional metadata. Best pick: the on-device stores for a single platform, or an aggregator such as Terra, Rook, or Spike server-side - and keep the framing wellness, not medical guidance.",
      "title": "Blood Glucose API: How to Get Glucose Data Into Your App",
      "url": "https://aifitnessapi.com/data/blood-glucose-api",
      "markdown": "https://aifitnessapi.com/data/blood-glucose-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Where does blood glucose data in HealthKit and Health Connect come from?",
          "answer": "Almost never from a fitness wearable. It comes from a fingerstick meter or a continuous glucose monitor, hardware sold and regulated as a medical device, whose companion app writes the reading into the platform store. Users can also type values in by hand. Manual entries, meter uploads, and CGM streams all land in the same data type, so if the distinction matters to your feature, inspect the sample's source rather than assuming a device produced it.",
          "url": "https://aifitnessapi.com/data/blood-glucose-api#faq-1"
        },
        {
          "question": "What units do blood glucose samples use, and how do I avoid a unit mix-up?",
          "answer": "Apple documents that blood glucose samples may be measured in mg/dL (milligrams per deciliter) or mmol/L (millimoles per liter) depending on the region, and that the Health app lets users pick their preferred units for display and manual entry. Read that preference with preferredUnits(for:completion:) rather than assuming one, and Apple advises alerting the user if your connected meter uses different units. Always store the unit alongside the value. This trap produces plausible wrong numbers rather than empty results, which is what makes it dangerous.",
          "url": "https://aifitnessapi.com/data/blood-glucose-api#faq-2"
        },
        {
          "question": "Can I read continuous glucose monitor data through a fitness API?",
          "answer": "Usually indirectly. On a phone you read whatever the CGM's companion app wrote into HealthKit or Health Connect. Server-side, our pages document Terra as normalizing CGM and glucose, Rook as covering glucose and CGM across a stated 400-plus sources, and Spike as marketing Dexcom among its providers. Note that several popular providers, Dexcom among them, commonly require you to register your own developer or partner credentials regardless of which aggregator you use. Going direct to a CGM manufacturer is a partner relationship with its own approval process.",
          "url": "https://aifitnessapi.com/data/blood-glucose-api#faq-3"
        },
        {
          "question": "Is a glucose reading measured or estimated?",
          "answer": "Measured, not modeled - but glucose names several different measurements that are not interchangeable. Health Connect makes this explicit with a mandatory specimenSource field carrying constants for interstitial fluid, capillary blood, plasma, serum, tears, whole blood, and unknown. A continuous monitor sampling interstitial fluid and a fingerstick meter sampling capillary blood are measuring different compartments with different devices, so do not merge them into one unlabelled trend line. Apple's type has no equivalent required field, so on iOS that context usually has to come from the source app and metadata.",
          "url": "https://aifitnessapi.com/data/blood-glucose-api#faq-4"
        },
        {
          "question": "What must a wellness app avoid claiming about glucose readings?",
          "answer": "Do not compute or display dosing suggestions, do not frame alerts as clinical instructions, and do not describe your app as monitoring or managing diabetes. Glucose data typically originates from a regulated medical device and is used by people managing a chronic condition, but that does not make a general-wellness app a clinical tool, and presenting it as one moves you toward software-as-a-medical-device territory. Treat that line as a deliberate product decision made with counsel rather than something you drift across through copywriting. This is not legal or medical advice.",
          "url": "https://aifitnessapi.com/data/blood-glucose-api#faq-5"
        }
      ]
    },
    {
      "question": "blood pressure api",
      "answer": "Blood pressure reaches an app through the two on-device stores, not through a wearable feed. Apple HealthKit splits it into the quantity types bloodPressureSystolic and bloodPressureDiastolic and asks you to combine them into a single correlation, HKCorrelationTypeIdentifier.bloodPressure. Android Health Connect uses one BloodPressureRecord in the Vitals category, where systolic, diastolic, bodyPosition, and measurementLocation are all mandatory fields. It is a real measurement, but the instrument is a cuff outside your app: both platforms also expose a write permission, so a stored value may have come from a monitor's companion app or from a person typing. Our pages document no consumer wearable that measures blood pressure, so verify any device claim against that vendor's own documentation and regulatory record.",
      "title": "Blood Pressure API: How to Read BP Data In Your App",
      "url": "https://aifitnessapi.com/data/blood-pressure-api",
      "markdown": "https://aifitnessapi.com/data/blood-pressure-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Which platform data types store a blood pressure reading?",
          "answer": "Apple HealthKit uses two quantity sample types, HKQuantityTypeIdentifier.bloodPressureSystolic and HKQuantityTypeIdentifier.bloodPressureDiastolic, both documented from iOS 8.0 and watchOS 2.0, both using pressure units and measuring discrete values. Android Health Connect uses a single BloodPressureRecord in the Vitals category, an instantaneous record in the Pressure unit, gated on android.permission.health.READ_BLOOD_PRESSURE. Re-check both references in the live docs before you build, since identifiers and permission strings change.",
          "url": "https://aifitnessapi.com/data/blood-pressure-api#faq-1"
        },
        {
          "question": "Why does HealthKit want systolic and diastolic combined into a correlation?",
          "answer": "Because on iOS the two halves are separate sample types, and only the correlation ties them together as one reading. Apple documents HKCorrelationTypeIdentifier.bloodPressure as a correlation sample that combines a systolic sample and a diastolic sample into a single blood pressure reading, and its discussion notes say to combine them when recording. If you save them as two unrelated samples, anything reading them back has to guess at pairing by timestamp, which is a heuristic rather than a guarantee.",
          "url": "https://aifitnessapi.com/data/blood-pressure-api#faq-2"
        },
        {
          "question": "Does Health Connect require body position and cuff site for BP?",
          "answer": "Yes. BloodPressureRecord lists systolic, diastolic, bodyPosition, measurementLocation, metadata, and time as mandatory fields. The constants are explicit, covering standing, sitting, lying down, reclining, and unknown positions, and left or right wrist versus left or right upper arm for location. Treat those as part of the reading rather than optional notes: a normalization layer that flattens BP to two integers and a timestamp discards fields the platform itself considers required.",
          "url": "https://aifitnessapi.com/data/blood-pressure-api#faq-3"
        },
        {
          "question": "Can a smartwatch send blood pressure into my app without a cuff?",
          "answer": "Our pages document no consumer wrist wearable that measures blood pressure, so this is a claim to verify with the vendor rather than assume. What the platforms guarantee is only that some app wrote a value: both HealthKit and Health Connect expose a write permission alongside the read permission, so a stored reading may have come from a monitor's companion app or from a person typing a number in. Inspect the record metadata for provenance before you plot anything.",
          "url": "https://aifitnessapi.com/data/blood-pressure-api#faq-4"
        },
        {
          "question": "Why do Health Connect blood pressure writes throw an exception?",
          "answer": "The record validates ranges and throws IllegalArgumentException when a value falls outside them. Health Connect documents systolic as valid from 20-200 mmHg, or 20-300 mmHg for SDK extension 17 or higher, and diastolic as 10-180 mmHg, or 10-300 mmHg for SDK extension 17 or higher. Because the bounds depend on the SDK extension level, the same payload can be accepted on one device and rejected on another, so handle the failure rather than assuming clamping.",
          "url": "https://aifitnessapi.com/data/blood-pressure-api#faq-5"
        }
      ]
    },
    {
      "question": "respiratory rate api",
      "answer": "Respiratory rate is exposed as a bare number on both mobile platforms. Apple HealthKit defines HKQuantityTypeIdentifier.respiratoryRate as discrete samples in count over time units, and states that the system records them automatically on Apple Watch. Android Health Connect defines RespiratoryRateRecord in the Vitals category with only rate, time, and metadata, where rate is breaths per minute with a valid range of 0 to 1000. Neither type carries a method or provenance field, so the store cannot tell you whether a value came from a wearable algorithm, a medical device, or someone typing. On our pages, Oura returns respiratory rate inside its sleep payload and Fitbit documents a respiratory_rate OAuth scope; other vendors are not documented here, so verify them.",
      "title": "Respiratory Rate API: How to Get Breathing-Rate Data",
      "url": "https://aifitnessapi.com/data/respiratory-rate-api",
      "markdown": "https://aifitnessapi.com/data/respiratory-rate-api.md",
      "cluster": "Health Data",
      "cluster_url": "https://aifitnessapi.com/data",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "What unit does respiratory rate use on HealthKit versus Health Connect?",
          "answer": "Health Connect fixes it: RespiratoryRateRecord exposes rate as a Double documented as respiratory rate in breaths per minute, with a valid range of 0 to 1000. Apple leaves it open: HKQuantityTypeIdentifier.respiratoryRate uses count over time units, so you choose the HKUnit on read and on write. Normalizing between the two platforms without pinning the unit on the iOS side is a quiet factor-of-sixty bug, so store the unit alongside every value.",
          "url": "https://aifitnessapi.com/data/respiratory-rate-api#faq-1"
        },
        {
          "question": "Does the API tell me how a breathing-rate value was produced?",
          "answer": "No. Neither platform type carries a method or source field. Health Connect's record holds only rate, time, and metadata, and Apple's is a bare quantity sample, so the same record could hold a wearable's derived value, a reading from a dedicated device, or a number a person typed. Compare Vo2MaxRecord, which does carry a measurementMethod field. The only provenance available is the record metadata, so name the source in your UI rather than presenting the figure as a platform fact.",
          "url": "https://aifitnessapi.com/data/respiratory-rate-api#faq-2"
        },
        {
          "question": "Can Health Connect compute a nightly average respiratory rate?",
          "answer": "Not for you. The Health Connect data types page lists aggregate metrics for several vitals, such as systolic and diastolic averages for blood pressure and BPM averages for resting heart rate, but lists none for RespiratoryRateRecord. The record is also an instantaneous type, so there is no built-in nightly value at all. If you want an overnight average, read the individual records and compute it yourself, and be able to say which samples went into it.",
          "url": "https://aifitnessapi.com/data/respiratory-rate-api#faq-3"
        },
        {
          "question": "Which wearable APIs return a breathing rate field?",
          "answer": "On our pages, Oura API v2 returns respiratory rate as part of its sleep payload alongside sleep stages and HRV, and Fitbit's documented OAuth scope list includes respiratory_rate. Apple HealthKit covers the metric among its data types. WHOOP, Garmin, and Strava are not documented on our pages for this metric, so verify them in each vendor's live data dictionary. Where the value lives in a sleep object, availability depends on the user sleeping with the device on.",
          "url": "https://aifitnessapi.com/data/respiratory-rate-api#faq-4"
        },
        {
          "question": "Does an Apple Watch record breathing rate on its own?",
          "answer": "Apple's documentation for the respiratory rate quantity type states that the system automatically records samples on Apple Watch. Your app does not trigger a measurement and cannot request one; you ask for read authorization and see whatever has already been recorded. The docs do not state which sensor signal the value is derived from, so treat it as a within-person wellness trend and avoid comparing values across brands as if they were the same measurement.",
          "url": "https://aifitnessapi.com/data/respiratory-rate-api#faq-5"
        }
      ]
    },
    {
      "question": "pose estimation models compared",
      "answer": "For a single-user on-device fitness app, MediaPipe/BlazePose (33 keypoints, with monocular 3D world landmarks) is the usual starting point. MoveNet (17 keypoints) gives a speed-vs-accuracy dial for lightweight 2D tracking (Lightning for speed, Thunder for accuracy), while YOLO-pose and OpenPose handle multi-person scenes. The decisive trade-off is single-person on-device (private, cheap, simpler) vs multi-person (heavier, with real licensing strings). Check the license first: OpenPose is non-commercial and Ultralytics YOLO is AGPL-3.0.",
      "title": "Pose Estimation Models Compared: MediaPipe, MoveNet, YOLO and More",
      "url": "https://aifitnessapi.com/motion/pose-estimation-models-compared",
      "markdown": "https://aifitnessapi.com/motion/pose-estimation-models-compared.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "How many keypoints does each model detect?",
          "answer": "MediaPipe/BlazePose predicts 33 body landmarks, a superset of the 17 COCO keypoints that adds face, hand, and foot points. MoveNet, YOLO-pose, and PoseNet each use the 17 COCO keypoints. OpenPose uses configurable keypoint sets such as COCO-18 or BODY_25, so verify the current config for your build. Keypoint counts are stable, but any speed or accuracy number is device-dependent and should be verified on your own hardware.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-models-compared#faq-1"
        },
        {
          "question": "Which model should I use for a single-user fitness app?",
          "answer": "For a single user on-device, MediaPipe/BlazePose is the common default: its 33 landmarks and monocular 3D world landmarks suit joint-angle and form work on a normal phone. If you only need lightweight 2D and want a speed dial, MoveNet works well (Lightning for speed, Thunder for accuracy). Avoid PoseNet for new builds since it is deprecated in favor of MoveNet and BlazePose.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-models-compared#faq-2"
        },
        {
          "question": "Are these pose models free to use commercially?",
          "answer": "Not all of them. MediaPipe/BlazePose, MoveNet, and PoseNet are Apache-2.0, the most permissive here, though you should still verify terms for any bundled model assets. Ultralytics YOLO is AGPL-3.0, a strong copyleft license that can require you to release your own source unless you buy its Enterprise License. OpenPose is a non-commercial academic license and needs a separate agreement for commercial use. Confirm current terms and consult counsel before shipping.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-models-compared#faq-3"
        },
        {
          "question": "Which of these models output 3D landmarks?",
          "answer": "Among the common on-device options, only MediaPipe/BlazePose: alongside its 2D image-coordinate landmarks it returns 3D world landmarks in meters, hip-relative and inferred from a single camera. MoveNet and PoseNet return 2D keypoints only, and YOLO-pose stores an extra visibility value per point rather than depth. OpenPose has configurable keypoint sets but is a heavy, GPU-oriented multi-person system rather than an on-device 3D source. Treat monocular depth as a lower-confidence axis than x and y — it is estimated, not measured — and validate it on real users before building a feature on it.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-models-compared#faq-4"
        },
        {
          "question": "Which models handle multiple people at once?",
          "answer": "YOLO-pose detects multiple people and their keypoints in one pass, and OpenPose is a bottom-up multi-person system. MediaPipe/BlazePose and MoveNet are single-person oriented (MoveNet has a multipose variant to verify in your pipeline). Multi-person also needs a separate cross-frame tracking layer to keep identities stable, and remember YOLO is AGPL-3.0 and OpenPose is non-commercial.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-models-compared#faq-5"
        },
        {
          "question": "Should I pick MoveNet or MediaPipe for a fitness app?",
          "answer": "They sit at different points on the same trade-off. MediaPipe Pose (BlazePose) returns 33 keypoints including monocular 3D world landmarks, which helps for form feedback where joint angles in space matter. MoveNet returns the 17 COCO keypoints in 2D, with Lightning tuned for speed and Thunder for accuracy, and is a common choice when rep counting on modest hardware is the job. Both run on-device on a normal phone camera. Our recommendation: choose by what you compute downstream — 3D landmarks and more joints favor MediaPipe, minimal latency on old devices favors MoveNet Lightning — and verify current performance on your own target hardware rather than trusting anyone's benchmark.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-models-compared#faq-6"
        }
      ]
    },
    {
      "question": "2d vs 3d pose estimation",
      "answer": "2D pose estimation returns each keypoint as an (x, y) position in the image; 3D adds a depth axis (z) so joints sit in space. A normal RGB camera can output both, but its 3D depth is estimated from a single view (monocular), not measured, so it is less reliable than a multi-camera rig or depth sensor and weakest on occluded, out-of-plane, and extremity joints. Default to 2D for well-framed, in-plane form checks; add monocular 3D only when the movement leaves the camera plane, and treat depth as a lower-confidence axis you smooth and verify.",
      "title": "2D vs 3D Pose Estimation for Fitness Apps",
      "url": "https://aifitnessapi.com/motion/2d-vs-3d-pose-estimation",
      "markdown": "https://aifitnessapi.com/motion/2d-vs-3d-pose-estimation.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Do I need a depth camera or LiDAR for 3D pose?",
          "answer": "No. A normal RGB phone camera is enough for both 2D pose and monocular 3D world landmarks — models like BlazePose infer depth from a single view, so no depth sensor or LiDAR is required. A dedicated depth sensor or multi-camera rig only becomes worthwhile for high-accuracy biomechanics, at the cost of hardware and setup. For most consumer fitness apps, the plain camera is the right target because it maximizes device reach.",
          "url": "https://aifitnessapi.com/motion/2d-vs-3d-pose-estimation#faq-1"
        },
        {
          "question": "How reliable is monocular 3D depth?",
          "answer": "Less reliable than the x and y axes, and less reliable than multi-camera or depth-sensor 3D. Predicting true depth from one image is inherently hard, so monocular z is an estimate — hip-relative rather than absolute distance to the camera. It degrades most on occluded joints (which have no measurable depth), on extremities like wrists and ankles, and on angles that project into the depth axis. Treat it as a lower-confidence signal, smooth it over time, and validate on your own footage rather than trusting a published number.",
          "url": "https://aifitnessapi.com/motion/2d-vs-3d-pose-estimation#faq-2"
        },
        {
          "question": "When is 2D enough and when do I need 3D?",
          "answer": "2D is enough when the joint angle you measure stays in the camera plane — for example an elbow angle filmed side-on or a knee angle filmed from the side. It is cheaper and less noisy on the axis you can actually measure. Use 3D when the movement goes out of the plane: rotation toward or away from the camera, the depth of a lunge or squat, or a twist, where you need orientation that holds up as the viewing angle changes. Many fitness angle checks work fine in 2D, so add 3D only where you need it.",
          "url": "https://aifitnessapi.com/motion/2d-vs-3d-pose-estimation#faq-3"
        },
        {
          "question": "Is 3D form feedback accurate enough for injury or medical advice?",
          "answer": "No. Camera-based form feedback, whether 2D or monocular 3D, is a coaching aid, not medical or physical-therapy advice. Monocular depth error, occlusion, lighting, and clothing all introduce mistakes, so it cannot judge pain, injury history, or individual biomechanics. Keep the framing as general guidance and point users to a qualified professional for pain or injury. Any accuracy or depth-error figure you find should be verified on your own hardware and users, as of 2026.",
          "url": "https://aifitnessapi.com/motion/2d-vs-3d-pose-estimation#faq-4"
        }
      ]
    },
    {
      "question": "pose estimation accuracy",
      "answer": "Pose estimation accuracy is not one number. It is a set of metrics measured on a specific dataset: PCK and OKS for 2D keypoints, MPJPE for 3D joints. Real-world accuracy is driven down by lighting, occlusion, camera angle, distance, loose clothing, fast motion, and multiple people, and it is recovered with per-keypoint confidence gating and temporal smoothing like the One-Euro filter. The key takeaway: a leaderboard score is not your app's accuracy, so the only number that matters is the one you measure on your own footage.",
      "title": "Pose Estimation Accuracy: What It Means and What Drives It",
      "url": "https://aifitnessapi.com/motion/pose-estimation-accuracy",
      "markdown": "https://aifitnessapi.com/motion/pose-estimation-accuracy.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "What do PCK, OKS, and MPJPE measure?",
          "answer": "PCK (Percentage of Correct Keypoints) is the fraction of 2D keypoints within a distance threshold of ground truth, with the PCKh variant normalizing by head size. OKS (Object Keypoint Similarity) is the COCO 2D metric that scales each keypoint's error by person size and a per-keypoint constant. MPJPE (Mean Per Joint Position Error) is the 3D metric, the mean distance in millimeters between predicted and true joints. Higher PCK and OKS are better; lower MPJPE is better. Treat any published figure as dataset- and version-dependent and verify it against the original benchmark.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-accuracy#faq-1"
        },
        {
          "question": "What degrades pose estimation accuracy the most?",
          "answer": "Low or backlit lighting, occlusion of joints behind the body or objects, extreme camera angles, too much distance from the camera, loose or baggy clothing, and fast motion (motion blur) all reduce accuracy. Multiple people in frame add association errors. Extremities like wrists and ankles are typically less reliable than the torso and hips. Benchmark scores are collected under favorable lab conditions, so real-world accuracy is generally lower than a published number suggests.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-accuracy#faq-2"
        },
        {
          "question": "How do confidence and visibility scores help?",
          "answer": "Pose models emit a per-keypoint confidence or visibility score (some, like BlazePose, add a presence score) that indicates how sure the model is about each joint. Gate your logic on these: drop or down-weight low-visibility keypoints before you compute a joint angle or count a rep, rather than trusting a coordinate the model itself is uncertain about. It is the cheapest accuracy win available, costing only a threshold check.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-accuracy#faq-3"
        },
        {
          "question": "What is the One-Euro filter and why is it used?",
          "answer": "The One-Euro filter is a low-pass filter with an adaptive cutoff used to reduce frame-to-frame jitter in real-time pose tracking. It filters aggressively at low speed to steady static holds and relaxes at high speed to avoid adding lag during fast movement, tuned with two parameters (minCutoff and beta). Apply it to keypoints before deriving angles or reps. Kalman filters and learned refiners like SmoothNet are alternatives, but One-Euro is a common low-cost default.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-accuracy#faq-4"
        },
        {
          "question": "How do I evaluate accuracy for my own app?",
          "answer": "Do not trust a leaderboard score alone. Record footage that matches production (your camera, your users' lighting, distances, angles, clothing, and exercises) and measure there. Match the metric to your feature: PCK or OKS for 2D angle and rep work, MPJPE for depth-dependent 3D. Also measure jitter (keypoint variance on a static hold) and end-to-end latency, not just static accuracy, and validate visibility gating and smoothing across the full pipeline. Never present a lab figure as your app's real-world accuracy.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-accuracy#faq-5"
        }
      ]
    },
    {
      "question": "multi person pose tracking",
      "answer": "Multi-person pose tracking estimates several people's skeletons in one frame and keeps each identity stable across frames. Two paradigms exist: top-down detects each person then runs pose per box (accurate per person, but cost grows with the number of people), and bottom-up finds all keypoints then groups them (cost stays roughly constant, but grouping is harder and less accurate). Most fitness apps are single-user, where single-person models like MediaPipe or MoveNet are simpler and more accurate. Pick multi-person (YOLO-pose top-down or OpenPose bottom-up, plus a cross-frame tracking layer) only for group classes, gyms, or two-person sessions.",
      "title": "Multi-Person Pose Tracking: Top-Down vs Bottom-Up",
      "url": "https://aifitnessapi.com/motion/multi-person-pose-tracking",
      "markdown": "https://aifitnessapi.com/motion/multi-person-pose-tracking.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the difference between top-down and bottom-up pose estimation?",
          "answer": "Top-down first detects each person, then runs a pose model on each cropped box, so per-person accuracy is generally higher but inference cost grows with the number of people. Bottom-up detects all keypoints in the image at once and then groups them into individuals, so cost stays roughly constant regardless of crowd size, but the grouping step is harder and accuracy is typically lower. Verify the trade-off on your own scene and hardware.",
          "url": "https://aifitnessapi.com/motion/multi-person-pose-tracking#faq-1"
        },
        {
          "question": "Does my fitness app need multi-person pose tracking?",
          "answer": "Usually not. Most fitness apps are single-user, with one person in front of one camera, and single-person models such as MediaPipe/BlazePose or MoveNet are simpler, cheaper, and more accurate for that case. You need multi-person tracking only when several people are in frame at once, such as group classes, gyms, team or two-person sessions, or overhead studio cameras.",
          "url": "https://aifitnessapi.com/motion/multi-person-pose-tracking#faq-2"
        },
        {
          "question": "Which models support multi-person pose?",
          "answer": "OpenPose is the classic bottom-up multi-person system using Part Affinity Fields to group keypoints. YOLO-pose (Ultralytics) is detection-driven, producing person boxes and keypoints in one pass (top-down style). MediaPipe/BlazePose, MoveNet, and PoseNet are single-person oriented; MoveNet has a multipose variant, but verify current support in your pipeline before relying on it.",
          "url": "https://aifitnessapi.com/motion/multi-person-pose-tracking#faq-3"
        },
        {
          "question": "How are people tracked across frames?",
          "answer": "Per-frame pose estimation does not by itself keep identities stable, so multi-person work adds a separate tracking layer that associates the same person from frame to frame, using approaches like box/IoU tracking, ByteTrack-style trackers, or pose-based association. Track IDs can be lost or swapped when people occlude each other or cross paths, so verify how your tracker behaves on your camera angle and crowd density.",
          "url": "https://aifitnessapi.com/motion/multi-person-pose-tracking#faq-4"
        },
        {
          "question": "Are there licensing concerns with multi-person models?",
          "answer": "Yes, and they are a real decision point. OpenPose ships under a non-commercial/academic research license, so commercial use requires a separate license. Ultralytics YOLO (including YOLO-pose) is AGPL-3.0, a strong copyleft license, with a paid Enterprise License to bypass AGPL. Verify current license terms before shipping a commercial product.",
          "url": "https://aifitnessapi.com/motion/multi-person-pose-tracking#faq-5"
        }
      ]
    },
    {
      "question": "on device vs cloud pose estimation",
      "answer": "The choice is where the pose model runs: on the phone or on a server. For consumer fitness, on-device is almost always the right default - toolkits like ML Kit Pose, MediaPipe/BlazePose, TensorFlow Lite/LiteRT, and Core ML or Vision run inference locally, so it is private, works offline, has no network round-trip, and costs nothing per frame. Cloud lets you run a heavier or custom model with results consistent across every device, but you pay in latency, bandwidth, per-frame cost, and the privacy weight of streaming raw workout video. Pick on-device for real-time coaching and privacy; reach for cloud only when a model will not fit on the phone or you need identical output across many devices.",
      "title": "On-Device vs Cloud Pose Estimation: Which to Choose",
      "url": "https://aifitnessapi.com/motion/on-device-vs-cloud-pose-estimation",
      "markdown": "https://aifitnessapi.com/motion/on-device-vs-cloud-pose-estimation.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Is on-device or cloud pose estimation better for a fitness app?",
          "answer": "For most consumer fitness apps, on-device is the better default. Running the model on the phone with a toolkit like ML Kit Pose, MediaPipe/BlazePose, LiteRT, or Core ML and Vision gives you real-time responsiveness with no network round-trip, offline use in a poor-signal gym, video that never leaves the device, and no per-frame server cost. Cloud is worth it mainly when a model is too heavy or custom to run on the phone, or you need identical results across a huge range of devices - and you can accept the latency, cost, and video-handling compliance burden. Verify latency and pricing with your own provider and hardware.",
          "url": "https://aifitnessapi.com/motion/on-device-vs-cloud-pose-estimation#faq-1"
        },
        {
          "question": "Why is streaming workout video to a server a privacy concern?",
          "answer": "A workout video is raw footage of a person's body, face, and home - sensitive personal and biometric data, not a neutral rep count. When you transmit frames to a server, identifying traits like facial features ride along in every frame. That can trigger compliance regimes such as the EU's GDPR and US biometric laws like Illinois BIPA, which govern retention, consent, and cross-border transfer. Treat the specific figures and rules as verify and consult counsel. The strongest privacy posture is keeping inference on-device so frames never leave the phone.",
          "url": "https://aifitnessapi.com/motion/on-device-vs-cloud-pose-estimation#faq-2"
        },
        {
          "question": "Can I keep video private but still use a server?",
          "answer": "Yes, with a hybrid architecture. Run pose detection on the edge device, then transmit only the text-based landmark coordinates - not the raw video - to your server for analytics or logging. Keeping the frames local while sending anonymized landmark streams preserves most of the privacy benefit of on-device while still giving you server-side aggregation. This privacy-by-design pattern avoids exposing the sensitive footage that streaming full video would.",
          "url": "https://aifitnessapi.com/motion/on-device-vs-cloud-pose-estimation#faq-3"
        },
        {
          "question": "Does cloud pose estimation cost more than on-device?",
          "answer": "Generally yes, in a recurring way. On-device inference runs on hardware the user already owns, so there is no per-frame server bill. Cloud pose inference typically needs GPU infrastructure running at frame rate, which is a recurring per-frame or per-minute cost, plus bandwidth for streaming frames. Exact pricing is vendor-, region-, and model-specific, so verify it with your provider rather than relying on a fixed figure. Cloud does not remove work - it moves it to infrastructure you run and pay for.",
          "url": "https://aifitnessapi.com/motion/on-device-vs-cloud-pose-estimation#faq-4"
        },
        {
          "question": "Does on-device pose estimation work on older phones?",
          "answer": "It can, but performance depends on the device. Phones with a strong GPU or neural accelerator run pose models smoothly, while older or low-end devices may run a heavy model slowly. The usual fix is to target a mobile-optimized model and, where needed, a lighter variant or a lower frame rate. A normal RGB camera is enough - no depth sensor or LiDAR is required. Verify frame rate on your actual target hardware, since it varies widely across devices.",
          "url": "https://aifitnessapi.com/motion/on-device-vs-cloud-pose-estimation#faq-5"
        }
      ]
    },
    {
      "question": "real time pose estimation",
      "answer": "Real-time pose estimation means the pipeline keeps up with the live camera stream so feedback feels immediate. It is a budget problem: a frame-rate and latency target balanced against model size, battery, and thermals. The central lever is model size vs speed. Pick a smaller, faster model (MoveNet Lightning or a fast SDK mode) for live rep counting and low-end devices; pick a larger, more accurate one (MoveNet Thunder or an accurate mode) for detailed form scoring where you can process fewer frames. Treat every fps and latency figure as device-dependent and verify on your target hardware.",
      "title": "Real-Time Pose Estimation: Frame Rate, Latency, and Model Trade-offs",
      "url": "https://aifitnessapi.com/motion/real-time-pose-estimation",
      "markdown": "https://aifitnessapi.com/motion/real-time-pose-estimation.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "What frame rate do I need for real-time pose estimation?",
          "answer": "Smooth, interactive tracking is commonly framed around 30 fps, but usable coaching can work at lower rates, so treat any single number as a target rather than a hard requirement. Your achievable frame rate depends on the device, the accelerator, the input resolution, and the model, and older or budget phones may fall short of a vendor's modern-device claim. Measure it on your lowest-end target device rather than trusting a headline figure.",
          "url": "https://aifitnessapi.com/motion/real-time-pose-estimation#faq-1"
        },
        {
          "question": "Should I use MoveNet Lightning or Thunder?",
          "answer": "Lightning is tuned for speed with a smaller model and lower input resolution, so it suits live rep counting, real-time overlays, and low-end devices. Thunder is larger and more accurate, which fits detailed form scoring or post-session review where you can afford more compute or process fewer frames. The positioning is documented but the exact fps is device-dependent, so verify on your target hardware before committing.",
          "url": "https://aifitnessapi.com/motion/real-time-pose-estimation#faq-2"
        },
        {
          "question": "What should I do if inference can't keep up with the camera?",
          "answer": "Drop frames rather than queue them. If you queue frames the model can't process in time, feedback drifts further and further behind the user's real movement, whereas skipping stale frames keeps tracking anchored to the present. You can also downscale the input resolution, switch to a lighter model, or run inference on the GPU or NPU instead of the CPU to free up budget.",
          "url": "https://aifitnessapi.com/motion/real-time-pose-estimation#faq-3"
        },
        {
          "question": "Why is temporal smoothing needed?",
          "answer": "Per-frame pose estimation jitters, so the keypoints wobble even when the subject holds still, and raw keypoints are too noisy to derive clean joint angles or rep counts. A temporal filter such as the One Euro filter removes that jitter cheaply, using an adaptive cutoff that limits lag when the subject moves fast. Smooth the keypoints first, then derive angles and reps, but tune the filter per exercise because over-smoothing makes tracking feel sluggish.",
          "url": "https://aifitnessapi.com/motion/real-time-pose-estimation#faq-4"
        },
        {
          "question": "Does continuous pose estimation drain the battery?",
          "answer": "Yes. A continuous camera plus continuous inference is a sustained load that drains battery and heats the device over a full workout, and a hot device can throttle and quietly lower your frame rate mid-session. Hardware acceleration on the GPU or NPU runs inference faster and uses less energy per frame than the CPU, and a lighter model, lower resolution, or processing fewer frames all reduce the draw. Test for thermal throttling over a realistic session length, not a short demo.",
          "url": "https://aifitnessapi.com/motion/real-time-pose-estimation#faq-5"
        }
      ]
    },
    {
      "question": "pose estimation hardware requirements",
      "answer": "A normal RGB smartphone camera is enough for both 2D pose and monocular (single-camera) 3D pose - no depth sensor or LiDAR is required. What matters is hardware acceleration: a GPU or NPU/Neural Engine keeps inference fast and battery-friendly, while older and low-end devices with weaker chips run slower and may need a lighter model, lower resolution, or frame dropping. Lighting and full-body framing affect accuracy as much as silicon does. Best pick for reach: target the RGB camera plus a GPU delegate so mid-range and older phones work, and opt into NPU/Neural Engine for headroom where it exists. Going cloud instead adds a server GPU as a recurring cost.",
      "title": "Pose Estimation Hardware Requirements: What You Actually Need",
      "url": "https://aifitnessapi.com/motion/pose-estimation-hardware-requirements",
      "markdown": "https://aifitnessapi.com/motion/pose-estimation-hardware-requirements.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Do I need a depth camera or LiDAR for pose estimation?",
          "answer": "No. A normal RGB smartphone camera is enough for 2D pose and for monocular (single-camera) 3D pose - both run from a single RGB frame. Depth hardware is optional and only marginally improves 3D accuracy, and requiring it shrinks the range of devices you can support. Even Apple's 3D body-pose request works from RGB and does not require a LiDAR Scanner, using depth only if the device exposes it (verify current behavior in the docs). For 2D fitness use, skip depth hardware.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-hardware-requirements#faq-1"
        },
        {
          "question": "Does pose estimation need a GPU or a special AI chip?",
          "answer": "It runs faster and uses less battery with one, but it is not strictly required. Hardware acceleration - a mobile GPU, or an NPU/Neural Engine - speeds inference and cuts energy per frame versus CPU. Apple's Core ML auto-dispatches to the Neural Engine, then GPU, then CPU; Android uses the LiteRT GPU delegate (present on nearly every phone) or an NPU delegate on supported chips. On devices without acceleration you can still run pose estimation, just at lower frame rates - use a lighter model to compensate.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-hardware-requirements#faq-2"
        },
        {
          "question": "Will pose estimation work on older or low-end phones?",
          "answer": "Often yes, but expect lower frame rates. Older and budget devices lack an NPU and have weaker GPUs and CPUs, so heavier models can drop below a smooth live rate. The fix is to ship a lighter model, lower the input resolution, or drop frames rather than queue them so tracking stays current. If broad device reach matters, design for the RGB-camera-plus-GPU-delegate baseline and treat NPU acceleration as a bonus, not a requirement. Always verify on the oldest device you promise to support.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-hardware-requirements#faq-3"
        },
        {
          "question": "What hardware do I need to run pose estimation in the cloud?",
          "answer": "Server-side pose inference typically needs GPU hardware to run heavier models at frame rate, which is a recurring per-frame or per-minute cost that on-device inference avoids. Cloud makes sense when you need a heavier or custom model that will not fit on a phone, or identical results across a huge device range - and you can accept the added latency, bandwidth, and the privacy burden of streaming video. For most consumer fitness apps, on-device inference on the phone is cheaper and more private.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-hardware-requirements#faq-4"
        },
        {
          "question": "Do lighting and camera position affect the hardware I need?",
          "answer": "They affect accuracy more than they change the hardware, but they matter a lot. Accuracy degrades in low light, backlight, and harsh shadows, and with cluttered backgrounds, occlusion, or oblique camera angles - the exercised joints must be in frame and unoccluded. Lab accuracy assumes good lighting, a plain background, and one visible person, so real rooms perform worse. No amount of GPU power fixes a poorly lit or badly framed shot, so plan for good conditions and verify with real users.",
          "url": "https://aifitnessapi.com/motion/pose-estimation-hardware-requirements#faq-5"
        }
      ]
    },
    {
      "question": "how does rep counting work",
      "answer": "Rep counting reduces a pose to one signal over time — usually a joint angle like the elbow (shoulder-elbow-wrist) for a curl — and counts a rep each time that signal completes a full up-down cycle. Two approaches dominate: peak/valley detection on the angle trajectory, or a finite state machine that models up/down phases with thresholds. The key to not double-counting jitter is hysteresis: separate entry thresholds for the up and down phases so noise near one boundary cannot re-fire. A state machine with hysteresis, run on a smoothed signal, is the robust default; pure peak detection is simpler but needs smoothing and a minimum-amplitude gate.",
      "title": "How Rep Counting Works: The Algorithm Explained",
      "url": "https://aifitnessapi.com/motion/how-rep-counting-works",
      "markdown": "https://aifitnessapi.com/motion/how-rep-counting-works.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "What signal does a rep counter actually track?",
          "answer": "It reduces the pose to one number that oscillates once per rep. Most commonly that is a joint angle from three keypoints (elbow angle for a curl, knee or hip angle for a squat), because an angle is invariant to where the person stands or how far they are from the camera. Some movements use a keypoint position instead (wrist height, hip height), but positions need normalization first. Everything after that is signal processing on that one curve.",
          "url": "https://aifitnessapi.com/motion/how-rep-counting-works#faq-1"
        },
        {
          "question": "What is hysteresis and why does it stop double-counting?",
          "answer": "Hysteresis means using two different thresholds with a gap between them instead of one. To count a rep you must cross a low threshold into the down phase and then travel all the way past a separate high threshold into the up phase. With a single threshold, noisy keypoints hovering right at that value would flip the state back and forth and count several reps for one. The gap forces the signal to make a full, deliberate swing before it can count again.",
          "url": "https://aifitnessapi.com/motion/how-rep-counting-works#faq-2"
        },
        {
          "question": "How do you handle noise and false reps?",
          "answer": "Smooth the keypoints or the derived angle before any detection (a One Euro filter is a common low-cost choice), use hysteresis rather than a single threshold, and gate on minimum amplitude and minimum time so twitches and partial motions do not count. Also gate on the model's per-keypoint confidence or visibility and skip frames where the joints you depend on are occluded. Naive peak detection on a raw signal is the main source of miscounts.",
          "url": "https://aifitnessapi.com/motion/how-rep-counting-works#faq-3"
        },
        {
          "question": "Do I need a depth camera to count reps?",
          "answer": "No. A normal RGB phone camera is enough. Rep counting tracks 2D joint angles that stay in the camera plane, so no depth sensor or LiDAR is required. What matters more is orientation and framing: keep the measured joints in frame and roughly in the camera plane, since an angle projecting toward or away from the camera relies on estimated depth and is the least reliable.",
          "url": "https://aifitnessapi.com/motion/how-rep-counting-works#faq-4"
        },
        {
          "question": "How accurate is camera-based rep counting?",
          "answer": "It varies by exercise, dataset, and the user's form, so there is no single number to quote. Partial reps, very fast reps, occlusion, and oblique camera angles all cause miscounts, and thresholds often need per-user calibration. Treat any accuracy figure you see as attributed and hedged, and verify it on your own exercises and hardware rather than trusting a lab result. Rep counting also is not form judgment and is not medical advice.",
          "url": "https://aifitnessapi.com/motion/how-rep-counting-works#faq-5"
        }
      ]
    },
    {
      "question": "how does form feedback work",
      "answer": "Camera-based form feedback computes the angle at a joint from three tracked keypoints, watches that angle across a rep to capture range of motion, and compares it against a reference or target. When the user drifts outside a tolerance band, the app cues which way to correct. It runs from an ordinary phone camera with no depth sensor, but the pose underneath is a monocular estimate, so it is a coaching aid, not medical or physical-therapy advice.",
      "title": "How Camera-Based Form Feedback Works",
      "url": "https://aifitnessapi.com/motion/how-form-feedback-works",
      "markdown": "https://aifitnessapi.com/motion/how-form-feedback-works.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "How does a form checker actually measure my form?",
          "answer": "It takes three keypoints that meet at a joint (for a squat, hip, knee, and ankle), computes the angle between the two limb segments, and tracks that angle across the rep to capture range of motion. It then compares your angle to a reference or target and flags the deviation if it exceeds a tolerance band, cueing which direction to move.",
          "url": "https://aifitnessapi.com/motion/how-form-feedback-works#faq-1"
        },
        {
          "question": "Do I need a depth camera or special sensor for form feedback?",
          "answer": "No. A normal RGB phone camera is enough to track keypoints and compute joint angles. No LiDAR or depth sensor is required. The catch is that a single camera estimates depth rather than measuring it, so angles that rotate toward or away from the lens are the least reliable part of the signal.",
          "url": "https://aifitnessapi.com/motion/how-form-feedback-works#faq-2"
        },
        {
          "question": "Can I use camera form feedback for injury rehab or physical therapy?",
          "answer": "Treat it only as general coaching, never as medical or physical-therapy advice. Monocular pose estimation is not accurate enough for clinically relevant measurement, and it cannot judge pain, injury history, or individual biomechanics. For anyone in pain or recovering from an injury, the responsible step is to consult a clinician or physical therapist rather than trust an angle from a camera.",
          "url": "https://aifitnessapi.com/motion/how-form-feedback-works#faq-3"
        },
        {
          "question": "Why does form feedback get worse from some camera angles?",
          "answer": "Any joint angle that projects toward or away from the camera falls into the depth axis, which is exactly where a single-camera estimate is weakest. Occluded joints hidden behind the body also produce bad angles. The fix is usually to re-orient the camera so the measured angle stays in the camera plane and the joints stay visible, rather than trusting depth.",
          "url": "https://aifitnessapi.com/motion/how-form-feedback-works#faq-4"
        },
        {
          "question": "How accurate is camera-based form feedback?",
          "answer": "Good enough for gross-movement coaching, not for degree-level or clinical claims. Accuracy depends on lighting, clothing, camera angle, occlusion, and the exercise, and published lab numbers assume ideal conditions real users rarely match. As of 2026, verify any accuracy or tolerance figure on your own cameras and users rather than trusting a headline value.",
          "url": "https://aifitnessapi.com/motion/how-form-feedback-works#faq-5"
        }
      ]
    },
    {
      "question": "build vs buy motion tracking",
      "answer": "Building your own AI motion pipeline means picking a pose model, integrating it natively per platform, and writing all the rep-counting, form-scoring, and exercise-library logic yourself, since keypoints are only coordinates. Buying a motion-tracking SDK bundles pose plus pre-built fitness logic, vendor-maintained, so you ship faster at a recurring per-user cost and with less control. Build when camera-based tracking is your core differentiator and you have CV/ML staff; buy when time-to-market and cross-platform maintenance matter more. Most teams go hybrid: adopt an on-device pose model, build the coaching layer on top.",
      "title": "Build vs Buy: AI Motion Tracking",
      "url": "https://aifitnessapi.com/motion/build-vs-buy-ai-motion-tracking",
      "markdown": "https://aifitnessapi.com/motion/build-vs-buy-ai-motion-tracking.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-07-24",
      "first_party": false,
      "faqs": [
        {
          "question": "Isn't the hard part just picking a pose model?",
          "answer": "No. Choosing MediaPipe, MoveNet, or Apple Vision is the easy first step. The real, ongoing work is everything after the keypoints arrive: native per-platform integration, rep-counting and form-scoring logic, an exercise library, accuracy tuning, and maintenance as models and devices change. Keypoints are just coordinates; the interpretation layer is yours to build.",
          "url": "https://aifitnessapi.com/motion/build-vs-buy-ai-motion-tracking#faq-1"
        },
        {
          "question": "When does building your own pipeline make sense?",
          "answer": "Build when camera-based motion tracking is your core differentiator, you have computer-vision/ML engineers, you need offline use and zero per-user license cost at scale, or you require a custom exercise set no vendor covers, and you can fund ongoing accuracy tuning and per-platform maintenance. If tracking is a supporting feature rather than the product, buying usually wins.",
          "url": "https://aifitnessapi.com/motion/build-vs-buy-ai-motion-tracking#faq-2"
        },
        {
          "question": "What does buying a motion-tracking SDK cost?",
          "answer": "A recurring per-user or per-device fee, plus less control over the underlying model and its roadmap. Free tiers and paid plans both exist, but pricing changes often, so verify current figures with each vendor rather than treating any quoted price as permanent. In exchange you skip model upkeep and get a maintained, cross-platform pipeline.",
          "url": "https://aifitnessapi.com/motion/build-vs-buy-ai-motion-tracking#faq-3"
        },
        {
          "question": "Can I mix building and buying?",
          "answer": "Yes, and most teams do. The common hybrid is to adopt an on-device pose model or SDK for detection, then build your own rep, form, and coaching logic on top where you want to stand out. You get maintained pose detection without giving up control of the experience that differentiates your app.",
          "url": "https://aifitnessapi.com/motion/build-vs-buy-ai-motion-tracking#faq-4"
        },
        {
          "question": "Do I need a depth camera either way?",
          "answer": "No. A normal RGB phone camera is enough for both 2D and monocular 3D pose, whether you build or buy. Monocular 3D depth is estimated rather than measured, so it is less reliable for occluded or extremity joints. Form feedback from a single camera is a coaching aid, not medical or physical-therapy advice.",
          "url": "https://aifitnessapi.com/motion/build-vs-buy-ai-motion-tracking#faq-5"
        }
      ]
    },
    {
      "question": "movenet vs mediapipe",
      "answer": "Decide by what you compute from the keypoints, not by benchmark screenshots. MediaPipe/BlazePose outputs 33 landmarks plus estimated 3D world landmarks, which is what joint-angle form feedback needs; MoveNet outputs 17 COCO keypoints in 2D, with the Lightning variant tuned for minimal latency, which is all a rep counter on modest hardware needs. MoveNet MultiPose is the only verified multi-person option in this pair. Both are Apache-2.0, both are effectively frozen, and every published speed number is a vendor claim you must re-measure on your own devices.",
      "title": "MediaPipe vs MoveNet: Decide by What You Compute Downstream",
      "url": "https://aifitnessapi.com/motion/mediapipe-vs-movenet",
      "markdown": "https://aifitnessapi.com/motion/mediapipe-vs-movenet.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-08-02",
      "first_party": false,
      "faqs": [
        {
          "question": "Does MoveNet output any 3D or depth information?",
          "answer": "No. MoveNet's model card documents 17 COCO keypoints as 2D normalized coordinates with a confidence score per keypoint, and nothing else. MediaPipe/BlazePose outputs a z value per landmark plus world landmarks documented in meters with the origin between the hips, though that depth is estimated from a single camera, not measured. If your downstream math needs joint angles in space, this one difference decides the comparison.",
          "url": "https://aifitnessapi.com/motion/mediapipe-vs-movenet#faq-1"
        },
        {
          "question": "Can MediaPipe Pose track multiple people like MoveNet MultiPose?",
          "answer": "The BlazePose GHUM model card states it tracks only one person when multiple are on scene, while MoveNet MultiPose Lightning is documented to detect up to 6 people simultaneously in real time. Whether the newer MediaPipe Tasks Pose Landmarker API adds a multi-pose option is something we could not verify against Google's live docs in our latest research pass, so check those docs before assuming it. For a verified multi-person answer within this pair, MoveNet MultiPose is it.",
          "url": "https://aifitnessapi.com/motion/mediapipe-vs-movenet#faq-2"
        },
        {
          "question": "Is MoveNet still maintained in 2026?",
          "answer": "It looks stable and frozen rather than actively developed. The last commit touching pose-detection in the tensorflow/tfjs-models repo was May 2024 and was a documentation typo fix, the model cards date to 2021, and tfhub.dev links have redirected to Kaggle Models since November 2023. MediaPipe's pose .task files are in a similar state: the download URLs work, but the served files were last modified in April 2023. Neither is abandoned; neither shows signs of new work.",
          "url": "https://aifitnessapi.com/motion/mediapipe-vs-movenet#faq-3"
        },
        {
          "question": "Which is actually faster, MediaPipe Lite or MoveNet Lightning?",
          "answer": "No published number answers that honestly. BlazePose's card reports FPS on a Pixel 3 via TFLite, while MoveNet's card reports milliseconds in a desktop Chrome browser via TF.js, so the two sets of numbers do not cross-compare on hardware, runtime, or metric. Both are positioned by their vendors as real-time on-device models. The only comparison that counts is running both on your actual target devices at your actual input resolution.",
          "url": "https://aifitnessapi.com/motion/mediapipe-vs-movenet#faq-4"
        },
        {
          "question": "Are MediaPipe's world landmarks accurate in real meters?",
          "answer": "Treat them as scaled estimates, not measurements. Google documents world landmarks as real-world 3D coordinates in meters with the origin at the center between the hips, but the model card also says the z coordinate is not metric but up to scale, and it explicitly lists applications requiring metric accurate depth as out of scope. They are good enough to compute joint angles that survive a change of viewpoint; they are not good enough to measure distances or heights.",
          "url": "https://aifitnessapi.com/motion/mediapipe-vs-movenet#faq-5"
        }
      ]
    },
    {
      "question": "pose landmarker lite vs full vs heavy",
      "answer": "MediaPipe Pose Landmarker ships as three .task bundles - lite, full, and heavy - that share the same 33-landmark output and API, so the variant is a swappable config value, not an architecture decision. What differs is the size-speed-accuracy trade: Google's model card positions lite as the only variant near real-time on a modest CPU, heavy as the most accurate at a fraction of the frame rate, with full in between. Start with full for form feedback and lite for live rep counting, then verify on your own hardware - the published numbers come from a 2021 model card measured on a Pixel 3.",
      "title": "MediaPipe Pose Landmarker Models: Lite vs Full vs Heavy",
      "url": "https://aifitnessapi.com/motion/mediapipe-pose-landmarker-models",
      "markdown": "https://aifitnessapi.com/motion/mediapipe-pose-landmarker-models.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-08-02",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I swap Pose Landmarker variants without changing code?",
          "answer": "Mostly yes, and that is the point of the family. All three variants emit the same 33 landmarks with the same per-landmark values (x, y, z, visibility, presence), the same normalized and world coordinate spaces, and the same optional segmentation mask, so your indices, angle math, and rep logic carry over unchanged - you swap the .task file path and keep the code. What does change is timing: a slower variant shifts your frame budget, so re-test frame dropping, smoothing, and any latency-sensitive thresholds after a swap even though nothing else breaks.",
          "url": "https://aifitnessapi.com/motion/mediapipe-pose-landmarker-models#faq-1"
        },
        {
          "question": "What does the /latest/ segment in the Pose Landmarker model URL mean?",
          "answer": "It is the version slot in the download path on Google's mediapipe-models storage bucket - a pointer to the newest published build rather than a frozen artifact. When we checked all three URLs in August 2026 they returned HTTP 200 and the served files were last modified in late April 2023, so latest has been stable for years, but nothing guarantees it stays that way. For a production app, download the file once, pin it, and serve it from your own storage instead of hotlinking latest, so a silent model update cannot change landmark behavior under you.",
          "url": "https://aifitnessapi.com/motion/mediapipe-pose-landmarker-models#faq-2"
        },
        {
          "question": "Why is the pose_landmarker .task file bigger than the model size in the model card?",
          "answer": "The model card's figures - 3 MB lite, 6 MB full, 26 MB heavy - describe the landmark models alone, while the .task downloads are bundles that served at roughly 5.5, 9.0, and 29.2 MiB when we checked. MediaPipe describes the pipeline as a two-step detector-plus-landmarker design, so the bundle packages more than the landmark model by itself, though the exact bundle contents are not documented in the sources we verified. Budget your app's download size against the served .task figures, not the card's model sizes.",
          "url": "https://aifitnessapi.com/motion/mediapipe-pose-landmarker-models#faq-3"
        },
        {
          "question": "What does float16 mean in the Pose Landmarker download path?",
          "answer": "It is the precision segment of the path - it names the numeric precision of the bundled model weights, in this case half-precision floating point. The float16 build is what Google's own sample download scripts fetch for all three variants. We have not verified whether builds at other precisions are published for Pose Landmarker, so if you need a different one, check the current MediaPipe documentation rather than guessing at a URL.",
          "url": "https://aifitnessapi.com/motion/mediapipe-pose-landmarker-models#faq-4"
        },
        {
          "question": "Does pose_landmarker_heavy add extra landmarks or multi-person tracking?",
          "answer": "No. Heavy outputs the same 33 landmarks as lite and full, and the model card states the model tracks only one person on scene if multiple are present, with multiple people explicitly out of scope. What heavy buys is accuracy - the model card reports 94.2 percent PDJ versus 91.8 for full and 87.0 for lite - at a steep speed cost, around 4 FPS on a Pixel 3 CPU in the card's 2021 measurements. If you need multi-person tracking, this family is the wrong starting point regardless of variant.",
          "url": "https://aifitnessapi.com/motion/mediapipe-pose-landmarker-models#faq-5"
        }
      ]
    },
    {
      "question": "apple vision framework body pose",
      "answer": "Apple's Vision framework gives you two body pose requests with no model file to ship: VNDetectHumanBodyPoseRequest (2D, 19 named joints, iOS 14+) and VNDetectHumanBodyPose3DRequest (3D, 17 named joints with camera-relative positions and a metric body-height estimate, iOS 17+). Choose Vision for an iOS-only app that wants zero model bytes, OS-maintained inference, and built-in offline video via VNVideoProcessor; choose a bundled model like MediaPipe or MoveNet when an Android sibling app exists or you need to pin a model version for regression testing. The catch to weigh honestly: Apple publishes no model card and no accuracy numbers, so any accuracy claim about Vision is unverifiable — measure it on your own footage, not from a spec sheet.",
      "title": "Apple Vision Framework Body Pose: The Native iOS Option",
      "url": "https://aifitnessapi.com/motion/apple-vision-body-pose",
      "markdown": "https://aifitnessapi.com/motion/apple-vision-body-pose.md",
      "cluster": "AI Motion",
      "cluster_url": "https://aifitnessapi.com/motion",
      "last_reviewed": "2026-08-02",
      "first_party": false,
      "faqs": [
        {
          "question": "Why do Apple's 2D and 3D body pose requests return different joint counts?",
          "answer": "They use different skeletons. VNDetectHumanBodyPoseRequest exposes 19 named joint constants including face detail (nose, eyes, ears) plus neck, shoulders, elbows, wrists, root, hips, knees, and ankles. VNDetectHumanBodyPose3DRequest exposes 17 named joints that drop the eyes and ears in favor of structural points: topHead, centerHead, centerShoulder, spine, and root, plus the arm and leg joints. Neither includes hand or foot detail, so code written against one skeleton does not map one-to-one onto the other.",
          "url": "https://aifitnessapi.com/motion/apple-vision-body-pose#faq-1"
        },
        {
          "question": "Does Apple publish a model card or accuracy numbers for Vision body pose?",
          "answer": "No. Apple's documentation is an API reference: it contains no model card, no accuracy figures, no evaluation dataset, no distance-from-camera guidance, and no stated intended use cases. That contrasts with MediaPipe BlazePose and MoveNet, whose model cards publish accuracy numbers and working-distance limits. The only published figures naming Apple Vision come from Google's own MediaPipe comparison table, which is a competitor's benchmark and should be treated with that caveat. If you need a citable accuracy basis, measure Vision yourself on labeled footage.",
          "url": "https://aifitnessapi.com/motion/apple-vision-body-pose#faq-2"
        },
        {
          "question": "What OS versions do the Vision body pose requests require?",
          "answer": "Apple documents VNDetectHumanBodyPoseRequest (2D) as available from iOS 14.0, iPadOS 14.0, macOS 11.0, Mac Catalyst 14.0, tvOS 14.0, and visionOS 1.0. VNDetectHumanBodyPose3DRequest (3D) requires iOS 17.0, iPadOS 17.0, macOS 14.0, Mac Catalyst 17.0, tvOS 17.0, or visionOS 1.0. VNVideoProcessor for offline video matches the 2D floor at iOS 14.0 and macOS 11.0. The three-version gap between the 2D and 3D floors matters if your feature depends on 3D output.",
          "url": "https://aifitnessapi.com/motion/apple-vision-body-pose#faq-3"
        },
        {
          "question": "Can Vision run body pose on recorded video instead of a live camera?",
          "answer": "Yes. VNVideoProcessor is Apple's documented object for offline analysis of video content: create it with init(url:) pointing at a video asset, attach requests with addRequest(_:processingOptions:), and run analyze(_:) over a time range, with cancel() to stop. The older analyze(with:) and VNVideoProcessingOption are deprecated. This is useful for fitness work because a library of recorded workout clips becomes a pose regression suite that needs no capture session or physical device camera.",
          "url": "https://aifitnessapi.com/motion/apple-vision-body-pose#faq-4"
        },
        {
          "question": "Should a cross-platform fitness app use Apple Vision for pose estimation?",
          "answer": "Usually not as its only pose layer. Vision runs on Apple platforms only, so an Android sibling app needs a second implementation with a different skeleton, different coordinates, and different failure modes, all validated separately. Cross-platform teams therefore usually bundle one model, such as MediaPipe Pose Landmarker or MoveNet, and run the same artifact on both platforms. Vision still earns a place in an iOS-only product, or as a deliberate per-platform choice made with eyes open about maintaining two pipelines.",
          "url": "https://aifitnessapi.com/motion/apple-vision-body-pose#faq-5"
        }
      ]
    },
    {
      "question": "ai workout plan generator",
      "answer": "You can generate a workout plan with an LLM, but the implementations that hold up do not let the model invent the plan. Filter your own exercise catalogue down to a candidate set with ordinary database queries, let the model select and sequence from that set, return it as schema-constrained JSON, and validate every row server-side against your own rules before a user sees it. Keep the arithmetic — sets, reps, load progression, weekly volume caps, equipment substitution — in deterministic code, because that is the part users notice when it is wrong. And screen the intake for red flags with a cheap deterministic gate first: for some answers the correct output is not a plan at all.",
      "title": "AI Workout Plan Generation: How to Build One That Ships",
      "url": "https://aifitnessapi.com/ai/ai-workout-plan-generation",
      "markdown": "https://aifitnessapi.com/ai/ai-workout-plan-generation.md",
      "cluster": "AI Features",
      "cluster_url": "https://aifitnessapi.com/ai",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I just ask an LLM to write the workout plan?",
          "answer": "You can, and the demo will look convincing. The problem is what comes back: exercise names that may not exist in your catalogue, invented progression, and constraints stated in prose that the model treats as suggestions rather than hard limits. For a shipped feature, retrieve a candidate set from your own database first, have the model select and sequence from it, and validate the result server-side. The model is doing selection, not authorship.",
          "url": "https://aifitnessapi.com/ai/ai-workout-plan-generation#faq-1"
        },
        {
          "question": "What should the model return instead of a finished plan?",
          "answer": "Identifiers and intent, not content. Have it return exercise IDs drawn from a candidate set you supplied, a rep-scheme category picked from a fixed enum, and an ordering — then let your own code expand that into sets, reps, load and rest. The model is doing selection and sequencing, which it is good at; your code is doing arithmetic and progression, which it is not. The practical test is whether a wrong answer from the model can survive your validator. If it can only hand back an ID from a list you gave it, an invented exercise cannot reach the user.",
          "url": "https://aifitnessapi.com/ai/ai-workout-plan-generation#faq-2"
        },
        {
          "question": "Should the LLM decide sets, reps and weights?",
          "answer": "Have it propose intent, not numbers. Let it pick a rep-scheme category (strength, hypertrophy, endurance, timed) from a fixed enum, then let deterministic code turn that into actual sets, reps, rest and load using the user's logged history. Models are unreliable at arithmetic and progression, and load math is exactly what a user notices when it drifts. Published expert evaluations of AI-generated resistance-training programmes broadly characterise the output as safe but generic with weak progression and individualisation, though we could not read the primary papers from this environment, so treat that as a direction rather than a measurement.",
          "url": "https://aifitnessapi.com/ai/ai-workout-plan-generation#faq-3"
        },
        {
          "question": "Where in the pipeline does the safety gate run?",
          "answer": "Before generation, not after. Screen the intake and any free-text the user typed with a deterministic check first, decide which path the user is on, and only then call the model — with the path as an input it cannot override. Screening after generation means you have already spent the tokens and still have to throw the plan away, and it tempts you into patching an unsafe plan rather than refusing to build one. Note that some conditions call for a constrained, conservative path rather than a refusal; declining to give a pregnant user a walking programme is its own kind of harm.",
          "url": "https://aifitnessapi.com/ai/ai-workout-plan-generation#faq-4"
        },
        {
          "question": "How do I regenerate next week's plan without contradicting last week's?",
          "answer": "Pass the relevant history as structured facts, not as prose, and make continuity a rule rather than a hope. Your code should decide what progresses and by how much, based on what the user actually logged, and hand the model the resulting targets. If you instead ask the model to remember what it prescribed and build on it, you get drift: the load moves in the wrong direction, an exercise silently disappears, or a movement the user cannot do reappears. Continuity across weeks is state, and state belongs in your database.",
          "url": "https://aifitnessapi.com/ai/ai-workout-plan-generation#faq-5"
        }
      ]
    },
    {
      "question": "ai food logging api",
      "answer": "The reliable pattern for AI food logging is resolution, not generation: the model turns \"two eggs and a slice of rye\" or a photo of a plate into a food identity plus a quantity, and your server looks the macros up in a vetted food database. Never persist a nutrition number the model emitted — that single rule removes a whole class of arithmetic error and makes every entry auditable and editable. Text logging is mostly an entity-resolution problem and works well; photo logging is much harder, because portion size is driven by counting discrete items and provider documentation is explicit that counting small objects is only approximate. Design correction as the primary interaction rather than an error path, and log every correction delta as your evaluation set.",
      "title": "AI Food Logging: Text and Photo Nutrition Entry That Actually Works",
      "url": "https://aifitnessapi.com/ai/ai-nutrition-logging",
      "markdown": "https://aifitnessapi.com/ai/ai-nutrition-logging.md",
      "cluster": "AI Features",
      "cluster_url": "https://aifitnessapi.com/ai",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Should the model return calories and macros directly?",
          "answer": "No. Have it return a food query string, a quantity, and a unit, then resolve that to a row in your food database and compute the macros server-side from the row. Calories per 100 g of a known food is a database lookup, not a judgement call, so asking a model to regenerate it introduces error into something that had none. It also gives you a stable food ID for trends, favourites and re-logging, and a named row the user can swap when the guess is wrong. A useful test: if your schema has a calories field in it, the design is wrong.",
          "url": "https://aifitnessapi.com/ai/ai-nutrition-logging#faq-1"
        },
        {
          "question": "How accurate is photo calorie estimation?",
          "answer": "Not accurate enough to present as a precise number, and no honest figure applies across the board. Published evaluations of photo-based calorie estimation exist and report meaningful error, but we could not verify their figures first-hand and do not quote them here. The provider's own vision documentation states that counting is approximate and may be imprecise with large numbers of small objects, and count is what drives portion size for discrete foods. The realistic frame is that nobody estimates calories accurately from a photograph, including dietitians. The product question is whether it is consistent and convenient enough to beat the user logging nothing at all.",
          "url": "https://aifitnessapi.com/ai/ai-nutrition-logging#faq-2"
        },
        {
          "question": "Do I need a vector database to log \"two eggs and a slice of rye\"?",
          "answer": "Not on its own. Extraction into quantity, unit and a search string is a small structured-output call. Resolution is then a search problem over your food catalogue, and food catalogues are large, messy and user-generated, which makes hybrid lexical plus vector search a legitimate fit, unlike a small structured exercise table. Start with lexical search plus a curated alias table, re-ranked by the user's own recent logs and favourites, and add embeddings for the long tail where brand and dish names do not lexically match any row.",
          "url": "https://aifitnessapi.com/ai/ai-nutrition-logging#faq-3"
        },
        {
          "question": "Why did photo logging get worse after I added client-side image compression?",
          "answer": "Because you probably added a second or third lossy pass. Provider vision documentation states that image compression artifacts are detrimental to model performance, particularly across multiple compression passes, and a phone camera has already handed you a lossy JPEG before your client touches it. Downsample once from the highest-quality frame you have, straight to your target size, and prefer reducing resolution over reducing JPEG quality. Send the model the clean asset rather than a display thumbnail. It is also worth choosing a fixed target size on purpose, since image token cost is a direct function of pixel dimensions.",
          "url": "https://aifitnessapi.com/ai/ai-nutrition-logging#faq-4"
        },
        {
          "question": "What should I measure to know whether the feature is working?",
          "answer": "Log the model's proposed food ID and portion, the version the user finally committed, and which candidate they picked if they swapped. That gives you top-1 and top-5 resolution accuracy graded deterministically against your catalogue, plus portion error. Track signed portion error, not just absolute error: an absolute-error metric will completely hide a directional bias, and under-counting is the bias worth testing for in your own data. Segment edit rate by food class, since discrete countable items are where the small-object counting weakness shows up first.",
          "url": "https://aifitnessapi.com/ai/ai-nutrition-logging#faq-5"
        }
      ]
    },
    {
      "question": "personalize app with wearable data ai",
      "answer": "The pattern that actually ships is narrate my structured data: your backend computes the averages, personal baselines and deltas, and the language model only writes prose about numbers it was handed. Do that rather than pasting raw time-series into the prompt and asking the model to find the trend, which is where the arithmetic quietly goes wrong and where the token bill grows. The hard constraint is not technical: sending a user's health profile to a third-party LLM API is exactly what Apple's App Store Review Guideline 5.1.2(i) covers, so you must clearly disclose it and get explicit permission before the first call. Whatever the model writes is your app's output, not the vendor's, and it is not medical advice.",
      "title": "Personalizing Your App With a User's Own Wearable Data",
      "url": "https://aifitnessapi.com/ai/personalize-with-wearable-data",
      "markdown": "https://aifitnessapi.com/ai/personalize-with-wearable-data.md",
      "cluster": "AI Features",
      "cluster_url": "https://aifitnessapi.com/ai",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Should I send raw heart-rate or HRV samples to the LLM?",
          "answer": "Generally no. Serializing days of samples into a prompt asks the model to do aggregation and arithmetic, which is the part models are least reliable at and the part users cannot verify, and it makes the prompt scale with your sampling frequency. Compute window averages, a personal baseline, the delta and a trend label in code, and send only those finished values. If you need the model to fetch data on demand for an open-ended chat surface, expose a tool that returns your own precomputed summary rather than raw rows, and validate the arguments server-side.",
          "url": "https://aifitnessapi.com/ai/personalize-with-wearable-data#faq-1"
        },
        {
          "question": "Do I need the user's permission to send their health data to an LLM API?",
          "answer": "For iOS, Apple's App Store Review Guideline 5.1.2(i) says you must clearly disclose where personal data will be shared with third parties, including with third-party AI, and obtain explicit permission before doing so. A health profile going to an external model API is that. Note also that Apple has no generative-AI-specific guideline; LLM features are governed by the general user-generated-content, physical-harm and medical rules plus 5.1.2(i). Separately, most health apps find they need a no-retention and no-training contract term with the model vendor before legal will approve the feature at all.",
          "url": "https://aifitnessapi.com/ai/personalize-with-wearable-data#faq-2"
        },
        {
          "question": "How do I stop the model inventing numbers about the user?",
          "answer": "Two layers. In the prompt, state that the model may only reference values present in the supplied payload, must not compute new ones, and must not estimate anything absent. Then check the output in code: extract every number the model emitted and confirm each one appears in what you sent, falling back to a deterministic template on a mismatch rather than re-prompting. This reduces risk but does not eliminate it. It catches fabricated figures; it does not catch bad advice attached to correct figures.",
          "url": "https://aifitnessapi.com/ai/personalize-with-wearable-data#faq-3"
        },
        {
          "question": "What should the app do when the user's wearable data has gaps?",
          "answer": "Handle it explicitly rather than papering over it. Do not silently impute missing days and label the result the same as measured data. Carry a coverage field in the payload (days with data out of days in the window) and gate on it: below your threshold, skip the model call entirely and render a deterministic not-enough-data state, which is cheaper and cannot hallucinate. When you do generate, send absent metrics as an explicit unknown with a reason rather than omitting the key, and tell the model to mention the gap. Users find a partial picture that admits it is partial more trustworthy than confident prose built on three nights of data.",
          "url": "https://aifitnessapi.com/ai/personalize-with-wearable-data#faq-4"
        },
        {
          "question": "Can the model interpret a user's HRV or recovery trend for them?",
          "answer": "It can describe it. Be careful about letting it explain it. Describing a below-baseline week and suggesting a lighter training block is general wellness framing; suggesting the user may be ill, or naming a condition, is a disease-adjacent inference with a recommended action, and that is a different kind of claim about your product's intended purpose. Also set a minimum effect size in code before the feature says anything at all, since wearable metrics carry real measurement error and narrating noise as a trend is false precision no matter who wrote the sentence. None of this is medical advice, and a disclaimer is not a liability shield.",
          "url": "https://aifitnessapi.com/ai/personalize-with-wearable-data#faq-5"
        }
      ]
    },
    {
      "question": "rag exercise database llm",
      "answer": "Grounding means the model may only return identifiers from a candidate set you supplied, so an invented exercise cannot survive validation. For a few-thousand-row exercise catalogue you usually do not need a vector database: the real constraints are categorical (equipment, muscle group, difficulty, contraindications), which makes them SQL WHERE clauses rather than similarity gradients. Filter in the database, enumerate the survivors into the prompt, have the model pick IDs, and reject anything outside that set server-side. Save embedding retrieval for large messy corpora like a food database, and remember that a valid schema still proves nothing about whether the plan is safe.",
      "title": "Grounding an LLM in Your Exercise Database",
      "url": "https://aifitnessapi.com/ai/ground-llm-in-exercise-database",
      "markdown": "https://aifitnessapi.com/ai/ground-llm-in-exercise-database.md",
      "cluster": "AI Features",
      "cluster_url": "https://aifitnessapi.com/ai",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Do I need a vector database to ground an LLM in my exercise catalogue?",
          "answer": "Usually not. Vector search exists to solve semantic retrieval over large unstructured corpora. An exercise catalogue is typically low thousands of clean, structured, well-labelled rows, and the constraints in a workout request are categorical: available equipment, target muscle group, difficulty band, excluded contraindications. Those are WHERE clauses, and a similarity search answers them badly because 'no barbell' is a boolean, not a gradient. Filter in SQL, put the surviving candidates in the prompt, and let the model select from them. Embeddings earn their keep when the corpus is large, messy and user-generated, which describes a food database far more than an exercise table.",
          "url": "https://aifitnessapi.com/ai/ground-llm-in-exercise-database#faq-1"
        },
        {
          "question": "How do I stop the model inventing exercises that are not in my database?",
          "answer": "Do not try to make it unlikely, make it impossible to persist. Restrict the model to returning an exercise_id, supply the exact candidate set, and check every returned ID against that set on your server before anything is written. An ID that is not in the set is rejected outright rather than repaired, because a miss usually signals an upstream problem. Prompt-level techniques help, and provider guidance recommends explicitly restricting the model to supplied source material and letting it say it does not know, but those reduce likelihood. Set membership is a decidable check, which is a different kind of guarantee.",
          "url": "https://aifitnessapi.com/ai/ground-llm-in-exercise-database#faq-2"
        },
        {
          "question": "Can a JSON schema enforce sensible sets and reps?",
          "answer": "No. Structured output guarantees the response is valid JSON matching your schema, but the schema layer does not support numeric constraints such as minimum, maximum and multipleOf, nor string length limits or most array constraints. That means you cannot enforce 'reps between 1 and 30' or 'at most 10 sets' at the decoding layer. SDK helpers strip those constraints from the wire schema and re-validate after generation, which is the pattern to copy: check ranges, duplicates, weekly volume ceilings and session duration server-side. Schema validity is not physiological sensibility, and neither one makes a plan safe for a given user.",
          "url": "https://aifitnessapi.com/ai/ground-llm-in-exercise-database#faq-3"
        },
        {
          "question": "Should the exercise IDs go in a schema enum or in the prompt?",
          "answer": "A schema enum is the most direct way to say 'pick only from this list', and enums are supported. The practical catch is that compiled grammars are cached and invalidated when the schema structure changes, so a per-user filtered enum is a distinct schema for every distinct user filter and pays cold compilation each time. In most apps a stable schema with exercise_id typed as a plain string, the filtered candidates supplied in the prompt, and a server-side set check gives the same guarantee without churning the schema on every request. Also check the stop reason first, since a refusal or a max_tokens truncation can produce output that does not match your schema at all.",
          "url": "https://aifitnessapi.com/ai/ground-llm-in-exercise-database#faq-4"
        },
        {
          "question": "Does the same approach work for a food database?",
          "answer": "The grounding contract does, the retriever does not. Food catalogues are large, user-generated and lexically messy, so users type brand and dish names that match no row exactly, and hybrid lexical plus vector retrieval genuinely earns its complexity there. What stays the same is that retrieval should resolve to a food_id and a quantity in a canonical unit, with every macro recomputed server-side from the catalogue row. MyFitnessPal's Meal Scan and Voice Log are publicly described as resolving input to entries in an existing verified food database rather than generating nutrition numbers. Never persist macro values a model emitted.",
          "url": "https://aifitnessapi.com/ai/ground-llm-in-exercise-database#faq-5"
        }
      ]
    },
    {
      "question": "ai fitness coach system prompt",
      "answer": "A fitness coach system prompt should set scope, tone, output format, and which numbers the model is allowed to repeat. It is not a safety control: models abandon correct positions under sustained user pressure, so an instruction to refuse unsafe requests will hold on turn one and get negotiated away later in the conversation. Enforce hard limits with a deterministic gate that runs before the model and that the user cannot argue with, and use the prompt for everything else. Put the stable bulk of the prompt first so it can be cached, and the user's context after it.",
      "title": "Writing the System Prompt for an AI Fitness Coach",
      "url": "https://aifitnessapi.com/ai/ai-fitness-coach-prompts",
      "markdown": "https://aifitnessapi.com/ai/ai-fitness-coach-prompts.md",
      "cluster": "AI Features",
      "cluster_url": "https://aifitnessapi.com/ai",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "What should actually go in an AI fitness coach system prompt?",
          "answer": "Six things: the role and scope of the assistant, an explicit list of what it may do, an explicit list of what it may not do, how to use the supplied user context (including which fields it has been given), the tone you want, and the output shape. Keep it stable across users so it can sit in a cached prefix, and put the user's profile, today's readiness data and the current question after it. What should not go in it is anything you would describe to a regulator or a reviewer as your safety mechanism.",
          "url": "https://aifitnessapi.com/ai/ai-fitness-coach-prompts#faq-1"
        },
        {
          "question": "Where should the cache breakpoint go in a coaching prompt?",
          "answer": "After the parts that never change and before the parts that change every turn. In practice that means the role and scope definition, the output contract, and any long reference material sit at the top and stay byte-identical between calls; the user's profile, retrieved context and conversation history come after. Anything that varies per user or per turn, placed early, invalidates everything below it. Order the prompt by volatility, cheapest-to-change last.",
          "url": "https://aifitnessapi.com/ai/ai-fitness-coach-prompts#faq-2"
        },
        {
          "question": "Why is \"you are a certified personal trainer\" a bad first line?",
          "answer": "Because it invites the model to behave like something holding a credential — asserting rather than hedging, prescribing rather than suggesting, and reaching for clinical register. It also creates a claim problem, since the assistant will then tell users it is certified, which is not true and which you would have to substantiate. Describe the function instead, for example \"the in-app coaching assistant for this app\", state plainly that it is software with no certification or clinical training, and put the register you want in a separate tone section.",
          "url": "https://aifitnessapi.com/ai/ai-fitness-coach-prompts#faq-3"
        },
        {
          "question": "How do I tell the model which fields it has been given?",
          "answer": "Enumerate them explicitly and say what to do when one is missing. A prompt that hands over a blob of user context without naming its fields invites the model to fill gaps with plausible values. Name each field you are supplying, state that these are the only user facts it has, and instruct it to say it does not know rather than estimate. Then verify on the way out — if the response contains a number you never supplied and your code did not compute, that is a bug to catch in the response handler, not a wording problem to fix in the prompt.",
          "url": "https://aifitnessapi.com/ai/ai-fitness-coach-prompts#faq-4"
        },
        {
          "question": "Does prompt caching change how I order the prompt?",
          "answer": "Yes. Caching is a prefix match over tools, then system, then messages, and any byte change inside the prefix invalidates everything after it. So the stable material — role, scope, refusal behaviour, tone, output format, tool and schema definitions — goes first, and the user profile, current readiness numbers and the question go after the breakpoint. Interpolating today's date, a session ID or the user's name into the system prompt is the usual reason a team sees no cache hits. Verify with the usage fields on the response instead of assuming, and note there is a minimum cacheable prefix length below which caching silently does nothing.",
          "url": "https://aifitnessapi.com/ai/ai-fitness-coach-prompts#faq-5"
        }
      ]
    },
    {
      "question": "ai vs rule based fitness app",
      "answer": "Most good AI fitness features are a rules engine wearing a language interface. Give ordinary code every job that has a single correct answer — progression schemes, set and rep math, volume caps, deload timing, equipment substitution, heart-rate zone arithmetic — because deterministic logic is testable, reproducible, effectively free per call, and cannot hallucinate. Give the language model the genuinely open-ended jobs: understanding what the user typed, explaining why the plan looks the way it does, adapting tone, and handling \"I tweaked my shoulder, swap today's session\". The safest and most common first ship is a model that narrates numbers your engine already computed, not one that computes anything.",
      "title": "AI vs Rules-Based Coaching: Where a Language Model Actually Helps",
      "url": "https://aifitnessapi.com/ai/ai-vs-rules-based-coaching",
      "markdown": "https://aifitnessapi.com/ai/ai-vs-rules-based-coaching.md",
      "cluster": "AI Features",
      "cluster_url": "https://aifitnessapi.com/ai",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Should an LLM generate the workout plan, or should I just write the progression logic?",
          "answer": "Write the progression logic. Load progression, set and rep math, volume caps and deload timing are pure functions of data you already store, so they have one correct answer, they are cheap to unit test, they cost nothing per call, and they produce the same result twice. A model handed those jobs converts something with zero error into something with non-zero error for no product benefit. Where a model does help on plan generation is selection and sequencing: pre-filter your catalogue in code, hand the model the surviving candidates, and let it choose and order them. Then validate everything it returns server-side against the original filter.",
          "url": "https://aifitnessapi.com/ai/ai-vs-rules-based-coaching#faq-1"
        },
        {
          "question": "Can I ship an AI coach without a rules engine underneath?",
          "answer": "You can, but you are then trusting a language model with the parts of the product that have correct answers — progression, volume, load math, equipment substitution — and those are exactly the parts users notice when they drift. The rules engine is not the legacy thing the AI replaces; it is the thing that makes the AI safe to expose. Teams that ship the language layer first usually end up building the rules engine anyway, after the first round of users reports plans that contradict themselves week to week.",
          "url": "https://aifitnessapi.com/ai/ai-vs-rules-based-coaching#faq-2"
        },
        {
          "question": "Do I have to rewrite my rules engine to add an AI coach?",
          "answer": "No, and you should not. The migration is additive. First expose the engine's output as structured data, then ship narration — the model explains numbers your engine produced and writes nothing back. Next add read-only question answering through tools that call endpoints you already have. Then, if you need write behaviour, have the model emit an intent rather than a result: a tool call like swap_exercise with an exercise ID and a slot, which your existing engine validates and applies with its normal rules. The engine stays the source of truth, and a feature flag that disables the language layer leaves you with exactly the app you had before.",
          "url": "https://aifitnessapi.com/ai/ai-vs-rules-based-coaching#faq-3"
        },
        {
          "question": "Which AI fitness features are lowest risk to ship first?",
          "answer": "Features that narrate structured data you already computed. Your engine produces the session, the recap, the weekly volume; the model turns those into readable prose. Publicly announced examples of this shape include Strava's Athlete Intelligence, Oura's Advisor and WHOOP Coach, where the numbers already exist and the model's job is legibility. There is little the model can get factually wrong that the user cannot see, because the user is looking at the same data. Resolving unstructured input to a catalogue row (a spoken meal matched to a verified food database entry, as MyFitnessPal describes for Voice Log and Meal Scan) is the next tier. Free estimation, where the model emits the number itself, is the riskiest, because nothing downstream can check the answer.",
          "url": "https://aifitnessapi.com/ai/ai-vs-rules-based-coaching#faq-4"
        },
        {
          "question": "Is a rules-based fitness app less capable than an AI one?",
          "answer": "For anything with a correct answer, it is more capable, because it is right every time and you can prove it. Personalized and algorithmic are not the same thing as generative AI, and a good deal of what gets marketed as AI coaching is deterministic logic underneath. The honest positioning is that rules give you correctness and a language model gives you an interface: the ability to accept whatever the user types, explain the plan in their terms, adapt tone, and handle awkward one-offs like an aggravated shoulder. Both, layered correctly, beats either alone. And whatever the architecture, output about exercise or nutrition is not medical advice, and the app publisher, not the model vendor, owns what the app tells a user.",
          "url": "https://aifitnessapi.com/ai/ai-vs-rules-based-coaching#faq-5"
        }
      ]
    },
    {
      "question": "how to evaluate ai fitness feature",
      "answer": "No public benchmark exists for AI fitness coaching, so you have to build your own evaluation: a golden set of realistic user inputs, frozen before you ship, and a grader that runs without you. Use three layers - deterministic assertions that check every exercise ID against your catalogue and every plan against the user's equipment, injuries and volume caps; LLM-as-judge for subjective qualities like tone and clarity; and review by someone actually qualified in exercise programming. Build the deterministic layer first, because it is nearly free to run and covers most of the ways the feature can be wrong. Keep safety red-teaming as a separate ship-blocking suite with multi-turn cases, since a guardrail that holds on turn 1 and is negotiated away by turn 6 has not held.",
      "title": "How to Evaluate an AI Fitness Feature",
      "url": "https://aifitnessapi.com/ai/evaluating-ai-fitness-features",
      "markdown": "https://aifitnessapi.com/ai/evaluating-ai-fitness-features.md",
      "cluster": "AI Features",
      "cluster_url": "https://aifitnessapi.com/ai",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "How do I write tests for output that is different every time?",
          "answer": "You assert properties of the output rather than equality against a fixed string, because prose has no equality check and the model will rephrase. Useful properties fall into four groups: structural (it parses, it matches the schema, every exercise ID resolves to a catalogue row), invariant (it contains no exercise from the user's contraindication list, it includes a professional-consultation prompt when the input carried a risk signal), statistical across the whole set (pass rate by category, mean signed error, refusal rate on the safety suite), and semantic via an LLM judge for things like coherence. Version the prompt, schema, catalogue snapshot and model ID together, because a catalogue edit can regress plan quality with no code change.",
          "url": "https://aifitnessapi.com/ai/evaluating-ai-fitness-features#faq-1"
        },
        {
          "question": "Is there a standard benchmark for AI fitness coaching quality?",
          "answer": "Not that we could find. Our research located no public benchmark, leaderboard or published methodology specific to evaluating AI fitness coaching or workout-plan generation, and if one exists we did not find it. That means you set your own thresholds and write down why you chose them. Published expert evaluations of chatbot-generated resistance-training programmes do exist and have characterised output as safe but generic, with persistent weaknesses in individualisation and progression. We could not read the primary papers from this environment, so treat that as a direction to look for in your own review pass rather than a measurement.",
          "url": "https://aifitnessapi.com/ai/evaluating-ai-fitness-features#faq-2"
        },
        {
          "question": "Do I need LLM-as-judge, or is plain code enough?",
          "answer": "Start with plain code, and add a judge only for what code cannot reach. If you generate plans by selecting from a vetted catalogue, most correctness questions are lookups: does the ID exist, does the exercise match the user's equipment, is the weekly volume under the cap, is the session inside the time budget. Those are deterministic, fast and free to run in CI. Reserve LLM-as-judge for subjective properties like tone, beginner comprehensibility and whether the response appropriately deferred to a professional. Use a different model for judging than for generating where you can, and validate the judge against human labels before trusting its scores.",
          "url": "https://aifitnessapi.com/ai/evaluating-ai-fitness-features#faq-3"
        },
        {
          "question": "How many test cases do I need, and how much does a run cost?",
          "answer": "Provider guidance on eval design recommends prioritising volume of automatically-graded cases over a small number of hand-crafted ones, so a couple of hundred realistic profiles beats twenty perfect ones. Cost is arithmetic you can do yourself: cases multiplied by (input tokens plus output tokens) multiplied by the rate. As a hypothetical, 300 cases at roughly 4,000 input and 800 output tokens each is 1.2M input and 240K output tokens; at the published rates for claude-opus-5 ($5.00 per million input, $25.00 per million output as of mid-2026, verify current pricing) that is about $12 per run. Evals are non-interactive, so the asynchronous batch API applies, documented at a 50% cost reduction versus standard requests.",
          "url": "https://aifitnessapi.com/ai/evaluating-ai-fitness-features#faq-4"
        },
        {
          "question": "Does an app store actually require adversarial testing?",
          "answer": "Google Play's AI-Generated Content policy tells developers to test across user scenarios and to safeguard against prompts that could manipulate a generative feature into producing harmful output, which is an expectation of adversarial testing, and it separately requires an in-app way for users to report or flag offensive AI output without leaving the app. Play policies are named rather than numbered and the wording changes, so verify the current text before you rely on it. Apple has no generative-AI-specific guideline; LLM output is governed by the general user-generated-content, physical-harm and medical rules, plus the requirement to disclose and get explicit permission before sharing personal data with third-party AI. Passing your own suite is risk reduction, not compliance.",
          "url": "https://aifitnessapi.com/ai/evaluating-ai-fitness-features#faq-5"
        }
      ]
    },
    {
      "question": "llm safety fitness advice guardrails",
      "answer": "Put a deterministic gate in front of the model, not inside it. Cheap rules read the accumulated conversation state on every turn, decide whether this is a hard stop, a clinician referral or a constrained generation, and only then does the model write anything — failing closed when the gate is unsure. The failure that catches teams out is sycophancy: a guardrail that fires on turn one and gets negotiated away by turn six has not worked, so re-evaluate against the whole conversation rather than the latest message. And constrain rather than refuse, because refusing a pregnant user a walking programme is itself a harm.",
      "title": "Guardrails for an LLM That Gives Fitness Advice",
      "url": "https://aifitnessapi.com/ai/llm-safety-fitness-advice",
      "markdown": "https://aifitnessapi.com/ai/llm-safety-fitness-advice.md",
      "cluster": "AI Features",
      "cluster_url": "https://aifitnessapi.com/ai",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I just put the safety rules in the system prompt?",
          "answer": "Not on their own. A model asked to police itself in the same call where it is trying to be helpful is subject to sycophancy — the well-attested pattern where models abandon a correct position under sustained user pressure. A safety instruction competing against a determined user across several turns is not a control. Detect the risk signal with a deterministic gate the user cannot argue with, run it before the generation call, and if you also want a model-based policy check, run it as a separate call with a single job.",
          "url": "https://aifitnessapi.com/ai/llm-safety-fitness-advice#faq-1"
        },
        {
          "question": "What should an LLM fitness coach do if a user mentions chest pain?",
          "answer": "Our engineering judgement is a hard stop with emergency guidance, no workout generated and no continuation of the coaching thread — the same for fainting or near-fainting, unexplained shortness of breath, new or worsening palpitations, one-sided weakness or facial droop, and sudden severe headache. This is not a published standard and we could not find one for consumer fitness LLMs, so have a clinician review your own trigger list before you ship it.",
          "url": "https://aifitnessapi.com/ai/llm-safety-fitness-advice#faq-2"
        },
        {
          "question": "Should I block pregnant users or users with heart conditions from AI-generated workouts?",
          "answer": "Constrain, do not refuse. Refusing a pregnant user a walking programme is itself a harm, and the populations most likely to trip a risk signal are often the ones with the most to gain from appropriate movement. The safer pattern is a conservative vetted-template path with an explicit clinician-consultation prompt and no free generation or numeric prescriptions. Build that constrained path first, so that failing closed costs the user very little.",
          "url": "https://aifitnessapi.com/ai/llm-safety-fitness-advice#faq-3"
        },
        {
          "question": "Does a 'not medical advice' disclaimer protect me legally?",
          "answer": "No. It is an app-store expectation and good practice — Apple's Guideline 1.4.1 says apps should remind users to check with a doctor in addition to using the app and before making medical decisions — but it is not a liability shield, it does not satisfy any regulator, and it does not make an unsafe answer safe. Whether providers of AI fitness coaching owe users a legal duty of care is genuinely unsettled: we found no case law, statute or regulator statement either way.",
          "url": "https://aifitnessapi.com/ai/llm-safety-fitness-advice#faq-4"
        },
        {
          "question": "Does Apple have a generative AI guideline I need to follow?",
          "answer": "No. The App Store Review Guidelines text contains no occurrence of 'generative' or 'machine learning', and chatbots appear only in Guideline 4.7 as permitted non-embedded software. LLM output is governed by the general rules: 1.2 on user-generated content, 1.4 on physical harm, 1.4.1 on medical apps, and above all 5.1.2(i), which requires you to clearly disclose where personal data will be shared with third parties, including third-party AI, and obtain explicit permission first. Google Play separately names an AI-Generated Content policy requiring in-app reporting of offensive AI output; verify its current wording yourself.",
          "url": "https://aifitnessapi.com/ai/llm-safety-fitness-advice#faq-5"
        }
      ]
    },
    {
      "question": "which llm for fitness app",
      "answer": "Pick a model per job, not per app, and expect to use more than one. Open-ended plan generation and multi-turn coaching want a frontier model where reasoning and instruction-following matter; high-volume mechanical work like intent classification, schema extraction and safety pre-screens wants a small fast model; anything user-facing should stream, because perceived latency beats raw quality there. The constraint that usually decides it is not benchmark scores but whether the vendor will contract for no retention and no training on user health data, in a region you can defend, so check that before you compare outputs.",
      "title": "Choosing an LLM for a Fitness App: Pick by Job, Not by Leaderboard",
      "url": "https://aifitnessapi.com/ai/choosing-an-llm-for-fitness-apps",
      "markdown": "https://aifitnessapi.com/ai/choosing-an-llm-for-fitness-apps.md",
      "cluster": "AI Features",
      "cluster_url": "https://aifitnessapi.com/ai",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Which LLM is best for generating workout plans?",
          "answer": "Use a frontier-tier model for open-ended plan generation, because instruction-following and constraint retention are what fail visibly on weaker models: the plan drifts outside the equipment filter or forgets a stated injury. We do not publish head-to-head model benchmarks because we have no dated, cited numbers we could verify, and we found no industry-standard benchmark for AI workout-plan quality. Build a golden set of a few hundred profiles with a code-based grader that checks every returned exercise ID against your catalogue and the original filter, then run two or three candidate models against it. Whichever model you pick, validate the output server-side; no model is safe to give medical advice.",
          "url": "https://aifitnessapi.com/ai/choosing-an-llm-for-fitness-apps#faq-1"
        },
        {
          "question": "Should I use one model or several?",
          "answer": "Usually several. A frontier model for open-ended generation and multi-turn coaching, and a small fast model for the high-volume mechanical calls (intent classification, routing, extracting a food entry into a schema, safety pre-screens) is the common split, since those calls have tiny outputs and run on every message. One caveat that catches teams out: prompt caches are model-scoped, so switching models mid-conversation invalidates the cache for that thread. Keep the main conversation on one model and spawn a separate cheap call for the sub-task instead of re-routing the main thread.",
          "url": "https://aifitnessapi.com/ai/choosing-an-llm-for-fitness-apps#faq-2"
        },
        {
          "question": "How much does an LLM feature cost per user?",
          "answer": "We will not give you a per-user figure, because it depends entirely on your token counts. Cost is dominated by how many tokens you send and receive, not by which vendor you chose. Do the arithmetic yourself: tokens in times the input rate, plus tokens out times the output rate, times calls per user per month. As an illustration with invented numbers, 1,000 input and 200 output tokens on Claude Opus 5 at $5.00 and $25.00 per million tokens is $0.005 plus $0.005, so about a cent a turn. Measure your real prompt size with a token-counting endpoint rather than guessing, and verify current pricing in the provider's docs.",
          "url": "https://aifitnessapi.com/ai/choosing-an-llm-for-fitness-apps#faq-3"
        },
        {
          "question": "Can I self-host an open-weight model instead of calling an API?",
          "answer": "Yes, and it is the right call when user data genuinely must not leave your infrastructure, since that becomes a fact about your topology rather than a promise in a contract. The honest trade-off is that you take on the serving cost (GPU capacity you pay for regardless of load, an inference stack to keep patched, and the on-call) and a quality gap on exactly the open-ended reasoning jobs where quality mattered most. A hybrid often works better than an all-or-nothing choice: self-host the high-volume mechanical tier and keep open-ended coaching on a hosted model under a no-retention contract.",
          "url": "https://aifitnessapi.com/ai/choosing-an-llm-for-fitness-apps#faq-4"
        },
        {
          "question": "What should I check before signing with a model vendor?",
          "answer": "For a health-adjacent app, these routinely outrank benchmark scores: whether the vendor will contract in writing for no retention and no training on prompts containing user health data; where requests are processed and whether you can pin data residency to a region; and whether you can buy through a channel your company can actually contract with, since rates and terms differ between a first-party API and a cloud marketplace. Separately, Apple's Guideline 5.1.2(i) requires you to clearly disclose where personal data is shared with third parties, including third-party AI, and obtain explicit permission first. This is not legal advice; check current wording yourself.",
          "url": "https://aifitnessapi.com/ai/choosing-an-llm-for-fitness-apps#faq-5"
        }
      ]
    },
    {
      "question": "how much does an ai fitness feature cost",
      "answer": "There is no useful industry per-user number, because the cost is entirely a function of your feature's shape: (tokens in + tokens out) times the per-token rate, times calls per user per period, times users. Input tokens are usually the surprise, because your system prompt, safety rules, tool schemas and retrieved context get re-sent on every single turn, and in a chat coach the conversation history is re-sent too. That makes weekly plan generation and an always-on chat coach completely different businesses even though both are one API call at a time. Measure your own prompt with a token-counting endpoint and do this arithmetic before you design the feature, not after you ship it, because the per-user figure has to fit inside your subscription margin.",
      "title": "What Does an AI Fitness Feature Cost to Run?",
      "url": "https://aifitnessapi.com/ai/ai-fitness-app-cost",
      "markdown": "https://aifitnessapi.com/ai/ai-fitness-app-cost.md",
      "cluster": "AI Features",
      "cluster_url": "https://aifitnessapi.com/ai",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "How much does it cost to add an AI coach to a fitness app?",
          "answer": "Anyone who gives you a single number for this is guessing. The honest answer is a formula: (input tokens + output tokens priced separately) times calls per user per period, times your user count. What decides the answer is feature shape, not vendor choice. Generating one plan per user per week is a handful of calls a month with a bounded prompt. An always-on chat coach is dozens of calls per session with a prompt that grows on every turn, and can plausibly land an order of magnitude higher per user. Work it out with your own measured token counts before you commit to the feature.",
          "url": "https://aifitnessapi.com/ai/ai-fitness-app-cost#faq-1"
        },
        {
          "question": "Why are my input tokens so much higher than I expected?",
          "answer": "Because the API is stateless. Every request re-sends the entire system prompt, your tool and schema definitions, any retrieved catalogue context, the user profile, and in a conversation the full message history. Nothing persists between calls on the provider's side. So a 4,000-token system prompt is not paid once, it is paid on every turn. In a chat feature the history term is the one that compounds: turn 20 sends everything from turns 1 to 19 again, so the cumulative input tokens across a session grow with roughly the square of the turn count.",
          "url": "https://aifitnessapi.com/ai/ai-fitness-app-cost#faq-2"
        },
        {
          "question": "What is the single biggest lever for reducing LLM cost?",
          "answer": "Sending fewer tokens. Concretely, in rough order of impact: filter your catalogue in the database before enumerating candidates into the prompt, cap max output tokens and prompt for brevity because output is billed at a higher rate than input, cache the stable prompt prefix so repeated persona and safety text is not reprocessed at full rate, move anything non-interactive to the batch API, route mechanical calls such as intent classification to a smaller model, and replace verbatim conversation history with a rolling summary. Answering deterministic questions from your own database with no model call at all beats all of them.",
          "url": "https://aifitnessapi.com/ai/ai-fitness-app-cost#faq-3"
        },
        {
          "question": "Does photo food logging cost more than text food logging?",
          "answer": "Yes, materially. Images are billed as visual tokens, and the provider documents the count as ceil(width / 28) times ceil(height / 28), capped by a per-model limit above which the image is downscaled. Their worked examples give a 200 by 200 image as 64 tokens and a 1000 by 1000 image as 1296 tokens. A typed meal description is a few dozen tokens. Since you control the upload resolution client-side, you control this cost exactly; uploading a full-resolution camera image when a roughly 1000-pixel long edge would do is pure waste, and higher-resolution tiers can consume several times the visual tokens for the same picture.",
          "url": "https://aifitnessapi.com/ai/ai-fitness-app-cost#faq-4"
        },
        {
          "question": "Can I cut cost by summarising or truncating conversation history?",
          "answer": "You can, and it is one of the most effective levers, but it has a safety consequence you must test for. If a user disclosed a knee injury, a pregnancy, or a medication on turn 2 and your compaction drops it by turn 15, the model can cheerfully recommend something contraindicated with no idea it ever knew better. Persist safety-relevant facts as structured profile fields that are always injected, rather than trusting them to survive inside summarised prose, and add a regression test that checks whether a stated constraint still holds after a long conversation.",
          "url": "https://aifitnessapi.com/ai/ai-fitness-app-cost#faq-5"
        }
      ]
    },
    {
      "question": "llm structured output json schema workout plan",
      "answer": "Treat the response schema as the contract between a probabilistic model and a deterministic engine: declare exactly the fields your engine consumes, use closed enums for every vocabulary that has one, and leave out anything your code recomputes. Constrained decoding guarantees the output parses and matches the shape; it guarantees nothing about whether the identifiers exist, the loads sit inside your caps, or the week adds up, so server-side validation stays non-negotiable. Keep exercise IDs as plain strings in one stable schema with the candidate set in the prompt rather than enumerating them per user, because a per-request schema pays cold grammar compilation on every call. Version the schema like any persisted format, retry once with the specific validation errors as data, and do not constrain coaching prose at all.",
      "title": "Structured Output for Workout Plans: Constraining What the Model Returns",
      "url": "https://aifitnessapi.com/ai/structured-output-for-workout-plans",
      "markdown": "https://aifitnessapi.com/ai/structured-output-for-workout-plans.md",
      "cluster": "AI Features",
      "cluster_url": "https://aifitnessapi.com/ai",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Why not have the model write the plan as text and parse it afterwards?",
          "answer": "Because the format drifts and a wrong parse looks like a right one. Rep and rest notation changes between calls, parenthetical caveats appear, units switch, and your regex accumulates special cases that fail hardest on the users whose requests are unusual. The outcome you should fear is not an exception but a capture group that matched the wrong span and returned a plausible number nobody questions. Extracting structure with a second model call does not fix it either: you pay twice, and you get clean structure wrapped around whatever the first call invented.",
          "url": "https://aifitnessapi.com/ai/structured-output-for-workout-plans#faq-1"
        },
        {
          "question": "Constrained decoding already guarantees my schema. What is left to check on the server?",
          "answer": "Everything that is not shape. Three categories in particular. Referential integrity: each returned identifier must exist in your catalogue and still be inside the candidate set you supplied for that request, since a schema-valid string can point at nothing. Numeric bounds: minimum, maximum and array-length constraints are widely unsupported at the decoding layer, and client libraries that accept them typically strip them from the wire schema and re-check after generation, so assume the bounds are yours to enforce. And cross-row invariants such as weekly sets per muscle group, duplicate movements inside one session, or estimated duration against a time budget, which no per-field constraint can see.",
          "url": "https://aifitnessapi.com/ai/structured-output-for-workout-plans#faq-2"
        },
        {
          "question": "Should the exercise identifier be a schema enum built from the candidate set?",
          "answer": "In our judgement no, even though it would make an invented exercise impossible to emit. Constrained decoding compiles a grammar from your schema and caches that compilation against the schema's structure, so a per-user enum is a distinct structure for every distinct filter and every request pays cold compilation. Keep the identifier a plain string in one stable schema, list the candidates in the prompt, and enforce membership yourself: the guarantee is identical and only the enforcement point moves. Reserve enums for vocabularies that are the same in every request, such as block type or training intent. This inverts if your candidate sets ever collapse to a small number of fixed variants.",
          "url": "https://aifitnessapi.com/ai/structured-output-for-workout-plans#faq-3"
        },
        {
          "question": "What should happen when the response is cut off partway through the JSON?",
          "answer": "Treat it as a failure even when the fragment happens to parse. Check the response's termination reason before you parse anything, because a budget-exhausted stop and a clean finish are indistinguishable once you are looking only at the text, and a lenient parser will hand you a plan that is silently missing its last block. The durable fix is to make the response smaller rather than to keep raising the output budget: generate one session per call instead of a week, drop the free-text rationale from the structured call, and shorten enum member names. Repeated truncation on the same shape is a sign the schema is doing work the prompt should be doing.",
          "url": "https://aifitnessapi.com/ai/structured-output-for-workout-plans#faq-4"
        },
        {
          "question": "How do I change the plan schema without breaking plans I have already stored?",
          "answer": "Version it and migrate it like any other persisted format, because stored plans outlive the schema that produced them. Stamp a schema version on every generated plan, have readers accept the current version and its predecessors, and have writers emit only the current one. Additive changes such as a new optional field or a new enum member are cheap; removals and renames need a backfill or a compatibility shim. Stamp the prompt version, the catalogue snapshot and the model alongside it, since a schema edit and a catalogue edit can each move output quality with no application code change and a regression is unattributable without all four.",
          "url": "https://aifitnessapi.com/ai/structured-output-for-workout-plans#faq-5"
        }
      ]
    },
    {
      "question": "how to sync only new health data since last sync",
      "answer": "Use the platform's own change cursor to detect what moved, and treat the result as a list of days that are now wrong rather than a list of values to add up. On iOS that is an HKQueryAnchor, which is an opaque position in the store's change log and not a timestamp; on Android it is a Health Connect changes token, which Google documents as expiring within 30 days of going unused. The constraint driving the whole design is that health data is retro-edited: sleep gets revised after further processing, watches backfill late, users correct old workouts, and Apple's own condenser rewrites months-old records. So mark the affected days dirty and recompute them from raw data, rather than incrementing a running total that no timestamp watermark can ever repair.",
      "title": "Incremental Sync: Reading Only What Changed Since Last Time",
      "url": "https://aifitnessapi.com/architecture/incremental-sync",
      "markdown": "https://aifitnessapi.com/architecture/incremental-sync.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Why can't I just filter health samples by a last-synced timestamp?",
          "answer": "Because a watermark is a filter over a time column, and both candidate columns fail. If you filter on event time (the sample's start date), you miss every retro-edit and late arrival, which on health platforms is normal traffic rather than an edge case: Apple documents that samples carry arbitrary caller-supplied dates back to a platform floor, that users can edit their data outside your app at any time, and that HealthKit itself condenses and rewrites months-old workout data. If instead you filter on a modification time, you may catch revisions where the provider exposes such a field, but you still get no deletion signal at all, because a deleted record is simply absent from the response and absence is indistinguishable from being outside your window. A change cursor exists specifically to express deletions and re-surfaced history, which a timestamp cannot.",
          "url": "https://aifitnessapi.com/architecture/incremental-sync#faq-1"
        },
        {
          "question": "Is an expired Health Connect changes token thrown as an exception I can catch?",
          "answer": "No. Google surfaces it as a boolean flag on the response, changesTokenExpired, and the official codelab pattern is for your own code to raise an error from that flag. If you wrote only a try/catch, an expired token passes through as a successful sync that happens to return nothing, which is the worst possible failure shape. Google documents that an unused token expires within 30 days and publishes a ranked recovery ladder: most ideal is to read and dedupe all data from your last-read timestamp or the last 30 days, and least ideal is to read the last 30 days without deduping, which the docs say results in duplicate data shown to users. Note that the constants TOKEN_EXPIRED and TOKEN_INVALID appear in Google's Android 13 to 14 migration documentation as platform-migration signals; the response flag is what your normal sync loop should check.",
          "url": "https://aifitnessapi.com/architecture/incremental-sync#faq-2"
        },
        {
          "question": "Does an HKQueryAnchor still work after the user reinstalls my app?",
          "answer": "Apple does not document this either way. What Apple documents is only how to persist an anchor: HKQueryAnchor adopts NSSecureCoding, so you can archive it and reload it on the next launch. There is no published statement about validity across app reinstall, device restore, or migration to a new device, and developers report both anchors that compare unequal after a round trip through NSKeyedArchiver and persisted anchors that caused a query to return the entire store again. Design accordingly: assume a nil anchor and a full replay are normal states, and make your ingest idempotent on the sample UUID so that a replay is a no-op rather than a doubling. Backing the anchor up server-side is cheap and may save you a replay, but it cannot be the thing correctness depends on.",
          "url": "https://aifitnessapi.com/architecture/incremental-sync#faq-3"
        },
        {
          "question": "Should I add up the samples an anchored query returns to get a daily total?",
          "answer": "No, and this is the mistake that survives adopting a proper cursor. Three reasons. A replay after an anchor reset would double the total. Raw samples are not merged across sources: an Apple Frameworks Engineer states that with a plain sample query you must select between overlapping samples yourself and are unlikely to match HealthKit's merge algorithm, so summing a phone's and a watch's samples double-counts the overlap. And sample identity churns without the numbers changing, because HealthKit's condensing deletes originals and writes series samples. Apple's own recommended shape from WWDC20 is to look at the dates of the returned samples, run a statistics collection query for those days, and send those recomputed statistics onward. The cursor is a change detector, not a data channel.",
          "url": "https://aifitnessapi.com/architecture/incremental-sync#faq-4"
        },
        {
          "question": "How do I know which day a deleted sample belonged to?",
          "answer": "Only from an index you built yourself at ingest time, because neither platform tells you. Apple's HKDeletedObject exposes just a uuid and metadata: no type, no dates, no value. Health Connect's DeletionChange carries only the record id and deliberately omits the record type for privacy reasons. So you must persist a mapping from the platform identifier to the record's type, dates and value when you first read it, or a deletion is unactionable. On Android the alternative is to keep one changes token per data type, which Google recommends anyway so that one revoked permission does not break the whole batch. Two further traps on iOS: a date-range predicate on the anchored query filters the deleted objects as well as the samples, and Apple documents that deleted-object records are temporary and may be purged at any time to free space.",
          "url": "https://aifitnessapi.com/architecture/incremental-sync#faq-5"
        }
      ]
    },
    {
      "question": "backfill years of wearable data rate limit",
      "answer": "Design a multi-year first sync as a resumable job, not a loop: order it newest-first so the app is useful within seconds of connecting, chunk it by civil-date window, and commit a checkpoint after every chunk so a crash costs you one window instead of the whole history. The binding constraint is that the quota is per consented user, so you cannot buy your way out of it with more workers, and on Health Connect Google publishes no numbers at all. Spend a deliberate share of that budget and reserve the rest for live sync, rather than letting the backfill starve today's data to complete 2019.",
      "title": "Backfilling Years of Wearable Data Without Hitting Rate Limits",
      "url": "https://aifitnessapi.com/architecture/historical-backfill",
      "markdown": "https://aifitnessapi.com/architecture/historical-backfill.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "How far back can I backfill Health Connect data, and what stops me at 30 days?",
          "answer": "Google documents that by default any app can read Health Connect data for up to 30 days prior to when any permission was first granted. To go further back you request PERMISSION_READ_HEALTH_DATA_HISTORY on androidx.health.connect.client.permission.HealthPermission. Without it, an attempt to read records older than 30 days results in an error rather than an empty page, so your worker has to treat that as a permanent wall and not retry it on a backoff schedule. There is a version split worth knowing: on Android 14 and higher there is no historical limit on an app reading its own data, and the 30-day limit applies to other data; on Android 13 and lower it applies to any data.",
          "url": "https://aifitnessapi.com/architecture/historical-backfill#faq-1"
        },
        {
          "question": "What happens to a user's backfilled history when they reinstall my app?",
          "answer": "On Android the readable window resets. Google documents that deleting the app revokes all permissions including the history permission, and that on reinstall and re-grant the same default restrictions apply from the new date. Their worked example: delete on May 10 2023, reinstall and grant on May 15 2023, and the earliest readable date becomes April 15 2023. Anything between those dates that you never read is unrecoverable from the device. Your server copy is the only mitigation, which is a strong argument for backfilling early and completely rather than lazily. On iOS, Apple documents nothing about anchor validity across reinstall or device restore, so make writes idempotent on record identity and treat a full replay as a no-op.",
          "url": "https://aifitnessapi.com/architecture/historical-backfill#faq-2"
        },
        {
          "question": "Should the backfill and the incremental sync share a worker?",
          "answer": "No, and on Health Connect that is close to a correctness requirement rather than a preference. Changes tokens expire after 30 days if unused, so a slow multi-year backfill running ahead of the delta stream in one sequential queue can outlive the token that was supposed to cover the same period. Acquire and persist the changes token before the backfill claims its first chunk, and run the delta stream in parallel. The same separation matters for quota: reserve a fixed share of the per-user allowance for live sync before the backfill worker is allowed to claim anything, or the import makes today's data stale in order to complete a year nobody is looking at.",
          "url": "https://aifitnessapi.com/architecture/historical-backfill#faq-3"
        },
        {
          "question": "What rate should I tune a Health Connect backfill loop to?",
          "answer": "There is no number to tune to. Google documents that rate limits exist and publishes only the categories: a periodic limit and a daily limit on API calls for reads and changelogs, plus memory limits on bulk and single insertions for writes. Limits vary by operation and by foreground versus background, and background rate limiting is documented as stricter than foreground. So build an adaptive loop rather than a fixed-rate one: page with pageToken, catch the IllegalStateException that Google's own read sample treats as the quota signal, back off exponentially, and resume from the same pageToken. The default pageSize is 1000, and Google's own guidance when iterating pages is to be careful to avoid rate-limiting concerns.",
          "url": "https://aifitnessapi.com/architecture/historical-backfill#faq-4"
        },
        {
          "question": "Why do users see wrong personal records and streaks while a backfill is running?",
          "answer": "Because a partial history is a complete history as far as your PR logic is concerned. If you have imported the last 30 days and you compute a best-ever 5K from that, the app will confidently congratulate someone on a time their real history contradicts, and they will remember the number long after the import finishes. Suppress streaks, personal records, best-ever markers and trend badges until the range they depend on is actually covered, label charts with the earliest date imported so far, and render not-yet-imported, not-permitted-to-read and genuinely-no-activity as three distinct empty states rather than as a zero.",
          "url": "https://aifitnessapi.com/architecture/historical-backfill#faq-5"
        }
      ]
    },
    {
      "question": "healthkit background delivery not firing",
      "answer": "Treat every background wake as an opportunistic hint, never as a delivery guarantee. Apple documents only an upper bound on HealthKit background delivery (at most once per period, hourly-capped for step count on iOS) and a shutdown after three unacknowledged deliveries, while Health Connect has no new-data callback at all. That single constraint drives the design: pair each wake with a foreground reconciliation on the next app open and a server-side staleness check that marks a user's data unknown rather than zero. Do that, rather than running a nightly job that assumes last night's wake fired.",
      "title": "Background Sync That Does Not Depend on the Phone Waking Up",
      "url": "https://aifitnessapi.com/architecture/background-sync",
      "markdown": "https://aifitnessapi.com/architecture/background-sync.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Does force-quitting an iOS app stop HealthKit background delivery?",
          "answer": "It is very widely repeated and probably true, but it is not documented. We found no statement on developer.apple.com, in documentation or in an Apple-staff forum reply, confirming it for HealthKit specifically. Treat it as expected but unconfirmed rather than as Apple's position, and design so it does not matter: if a force quit does stop delivery, a foreground reconciliation on the next app open recovers everything, which is the same mechanism you need for a phone that was simply switched off.",
          "url": "https://aifitnessapi.com/architecture/background-sync#faq-1"
        },
        {
          "question": "What happens if my observer query does not call its completion handler?",
          "answer": "Apple documents that HealthKit retries using a backoff algorithm, and that if your app fails to respond three times HealthKit assumes it cannot receive data and stops sending background updates. An Apple DTS engineer has confirmed on the developer forums that this shutdown is as-designed behaviour. That makes the completion handler the heartbeat that keeps the channel alive rather than optional bookkeeping, so call it on every code path, including the error branch and every early return.",
          "url": "https://aifitnessapi.com/architecture/background-sync#faq-2"
        },
        {
          "question": "Why does requesting immediate background delivery for step count change nothing on iOS?",
          "answer": "Apple documents that some sample types have a maximum frequency of hourly and that the system enforces this frequency transparently, naming step count on iOS as the example. Requesting immediate is not an error, it is inert. Plan step pipelines around hourly at best, and remember that the frequency parameter is documented as a maximum, so hourly does not promise one wake every hour either.",
          "url": "https://aifitnessapi.com/architecture/background-sync#faq-3"
        },
        {
          "question": "Can Health Connect notify my app when new health data arrives?",
          "answer": "No. Google documents that your app cannot get notified of new data, and instead tells you to check at two points: each time your app becomes active in the foreground, using lifecycle events, and periodically while it remains in the foreground. The background read permission lets you read while backgrounded, but it does not schedule your process and does not guarantee a read completes; Google documents that access may be interrupted at any point and that you should continue the next time the app is opened.",
          "url": "https://aifitnessapi.com/architecture/background-sync#faq-4"
        },
        {
          "question": "Why do my background HealthKit reads fail while the phone is locked?",
          "answer": "Apple documents that the device encrypts the HealthKit store when the user locks it, so your app may not be able to read from the store while running in the background. The concrete error is errorDatabaseInaccessible. Writes still succeed and are cached until unlock. Treat that error as retryable rather than as an absence of data, still call the completion handler, and re-run the anchored query once the device is unlocked.",
          "url": "https://aifitnessapi.com/architecture/background-sync#faq-5"
        }
      ]
    },
    {
      "question": "health api webhook idempotency duplicate events",
      "answer": "Give the delivery and the effect separate idempotency layers: dedupe the POST on (provider, delivery_id), and make the resulting write a versioned replace on (user_id, provider, metric, local_date, source_id). The constraint driving this is that most fitness webhooks are thin change pointers rather than data, so the handler's real job is to enqueue a fetch — and a handler slow enough to do that fetch inline is what triggers the provider retries that manufacture your duplicates. Replace the day, never increment it, and order on the provider's version rather than on arrival time.",
      "title": "Webhook ingestion for health data: making at-least-once delivery safe",
      "url": "https://aifitnessapi.com/architecture/webhook-ingestion",
      "markdown": "https://aifitnessapi.com/architecture/webhook-ingestion.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Should I dedupe on the webhook event ID or on the day the event points at?",
          "answer": "Both, at different layers. Dedupe the delivery on the provider's event ID so a retried POST does no work twice. Separately, make the effect a replace-by-natural-key write on user, provider, metric, civil date and source, gated on a version. Event-ID dedupe alone still lets an incrementing write double a total, and natural-key dedupe alone cannot tell a retry apart from a genuine re-notification.",
          "url": "https://aifitnessapi.com/architecture/webhook-ingestion#faq-1"
        },
        {
          "question": "A provider sent eleven webhooks for the same day's steps. Is that a bug on their side?",
          "answer": "No, that is normal. Health providers re-notify the same day repeatedly as it fills in: the morning walk, the lunchtime sync, the watch catching up at 22:40. Each is a real update with its own event ID. The bug is on your side if you treat the eleventh as an increment, or if you suppress it with INSERT ON CONFLICT DO NOTHING, which pins the day to its first partial morning value and freezes the user's step count.",
          "url": "https://aifitnessapi.com/architecture/webhook-ingestion#faq-2"
        },
        {
          "question": "Does Health Connect send a webhook when a user's steps change?",
          "answer": "No. Google documents that your app cannot get notified of new data on Health Connect, so there is no push mechanism to subscribe to. You check on foreground lifecycle events and periodically while foregrounded. This also means nobody can resell you Android health webhooks as a cloud service: what a vendor can offer is your own app's sync forwarded to your server, which has your app's reliability characteristics rather than a cloud provider's.",
          "url": "https://aifitnessapi.com/architecture/webhook-ingestion#faq-3"
        },
        {
          "question": "How long should I keep webhook delivery IDs before purging the idempotency table?",
          "answer": "At least as long as the provider's maximum retry horizon, which you should read off their documentation rather than guess. There is a health-specific catch: that table is keyed by user and holds raw provider payloads, so it is a copy of health data and belongs on your erasure inventory. An idempotency table that outlives a user-deletion purge will accept a late delivery and re-materialize the user you were obliged to erase.",
          "url": "https://aifitnessapi.com/architecture/webhook-ingestion#faq-4"
        },
        {
          "question": "If two webhooks for the same user arrive out of order, which one should win?",
          "answer": "The one with the higher provider version or modified timestamp, never the one that arrived later. Out-of-order arrival is normal because a phone that was offline flushes a backlog while live events keep coming, and some providers deliver backfilled history through the same webhook channel. Resolving on arrival time overwrites a fresh value with a stale one. If the provider supplies no version field, compare on sample end time then ingest time, and record on the row that the ordering was inferred.",
          "url": "https://aifitnessapi.com/architecture/webhook-ingestion#faq-5"
        }
      ]
    },
    {
      "question": "map users to wearable provider accounts multiple devices",
      "answer": "Model three entities, not one: the person in your product, the grant you hold from a provider, and the source that produced each sample. The constraint that forces the split is that health data is attributed at the source level, not the account level, so the mapping is many-to-many in both directions. Put a connection table between users and provider accounts rather than hanging an access token and a provider user id off your users row. The version without it cannot represent one human with two Fitbit accounts, a household sharing a scale, or a merge, and the merge is where it silently doubles someone's step and calorie history.",
      "title": "Mapping Users to Wearable Provider Accounts and Devices",
      "url": "https://aifitnessapi.com/architecture/identity-and-account-linking",
      "markdown": "https://aifitnessapi.com/architecture/identity-and-account-linking.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Can one person connect two Fitbit accounts at the same time?",
          "answer": "Only if your schema has somewhere to put the second one. It happens for real reasons: a work wellness account alongside a personal one, or an account created before a signup the user forgot about. Model it as two provider_account rows and two connection rows under the same user. The important follow-on is that the two accounts are not duplicates of each other, they are two honest sources measuring the same person, so your aggregation has to pick a source per interval using a per-user, per-metric priority rather than summing them. Summing is how you get a 34,000-step day.",
          "url": "https://aifitnessapi.com/architecture/identity-and-account-linking#faq-1"
        },
        {
          "question": "What happens when two of my accounts that share one wearable login get merged?",
          "answer": "That collision is the test your model either passes or fails. With a connection table you repoint the link rows and the samples never move, because they were attributed to a connection and a source rather than to a user. The unique constraint on user plus provider account then collides, and correct handling is to keep one connection and drop the duplicate link, keeping the earlier connected_at and the earlier history floor. Nothing doubles, because the samples were only ever stored once against a single provider account. With provider fields flattened onto the user row you end up with two full copies of the same history under one person, and every daily total for that user is permanently wrong.",
          "url": "https://aifitnessapi.com/architecture/identity-and-account-linking#faq-2"
        },
        {
          "question": "How do I tell an expired access token apart from a grant the user revoked?",
          "answer": "Do not decide from the resource call. A 401 on a data request means the access token needs refreshing, and that is an internal state your code fixes silently with backoff. Only a failed refresh, with the provider's explicit invalid-grant response, means the user revoked and only the user can fix it. Collapsing the two puts a reconnect banner in front of people whose connection was fine, which trains them to ignore the banner that matters. On Android the granularity is different again: Health Connect permissions are per data type, and Google recommends separate change tokens per type so one revoked permission does not take the others down, so a single state column on the connection is not enough there.",
          "url": "https://aifitnessapi.com/architecture/identity-and-account-linking#faq-3"
        },
        {
          "question": "How do I keep a shared smart scale from mixing two people's weights?",
          "answer": "Recognize that the provider account is a container for measurements, not a person, and that your connection row says nothing about whose body produced a reading. Handle it at the sample level. If the provider supplies a per-measurement subject or profile hint, give it its own column instead of flattening it into the connection. Where no such hint exists, our position is that body-composition samples from a shared-capable source should not be auto-accepted into a trend line: gate them behind an explicit confirmation from the user or behind a rate-of-change bound. Any specific bound is engineering judgement, not a clinical threshold, and should be reviewed by someone with a physiology background before it ships.",
          "url": "https://aifitnessapi.com/architecture/identity-and-account-linking#faq-4"
        },
        {
          "question": "Should unlinking a wearable also delete the data already synced?",
          "answer": "Those are two different requests and the states should answer them differently. A user pressing Disconnect means stop, not erase. What unlinking must do is reach upstream: stop ingest, delete the provider-side webhook subscription, and call the provider's revocation endpoint, because a deleted row with a live grant means the provider keeps pushing and your ingest path recreates the user you thought was gone. There is also a health-specific reason not to hard-delete on unlink. Google documents that deleting your app revokes Health Connect permissions including the history permission, and that a reinstall and re-grant resets the default window to 30 days before the new grant date, so data you drop on unlink may be data you can never fetch again.",
          "url": "https://aifitnessapi.com/architecture/identity-and-account-linking#faq-5"
        }
      ]
    },
    {
      "question": "healthkit duplicate steps multiple sources",
      "answer": "Do not assume the platform deduplicates for you. HealthKit merges overlapping sources only inside statistics-query results and only for quantity types, and Health Connect dedupes only Activity and Sleep, only through the Aggregate API, using a priority order that only the end user can change. So ask the platform for the merged figure where it can give you one, and build your own resolution everywhere else: workouts, cross-provider totals, and every non-Activity type on Android. The algorithm that works is interval-wise rather than device-wise. Rank sources per user per metric, cut the day at every sample boundary, let the highest-priority source covering each sub-interval win, and never sum per-source totals.",
      "title": "Deduplicating Health Data From Multiple Sources",
      "url": "https://aifitnessapi.com/architecture/deduplicate-health-data",
      "markdown": "https://aifitnessapi.com/architecture/deduplicate-health-data.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Does HealthKit automatically remove duplicate steps from iPhone and Apple Watch?",
          "answer": "Not for the samples you read. HealthKit merges overlapping sources only inside statistics-query results, meaning HKStatisticsQuery and HKStatisticsCollectionQuery, and only for quantity types. A plain sample query or an anchored object query returns every writer's raw overlapping samples with no merging at all. An Apple Frameworks Engineer stated on the developer forums that an app using the non-statistics queries has to select between overlapping samples itself and is unlikely to match HealthKit's merge algorithm correctly, and Apple has never published that algorithm. The practical rule is to ask for daily quantity totals through a statistics collection query rather than summing samples yourself. There is one other documented dedupe mechanism, the sync identifier plus sync version pair, but that only affects samples your own app writes, so it does nothing about first-party iPhone or Watch step samples.",
          "url": "https://aifitnessapi.com/architecture/deduplicate-health-data#faq-1"
        },
        {
          "question": "Why did an Android user's step total change after they reordered apps in Health Connect settings?",
          "answer": "Because Health Connect's deduplication lives in the Aggregate API and uses a priority list only the end user can change. Google documents that only the Activity and Sleep data types are deduped, that the totals shown are the values after that dedupe has been performed, and that only end users can alter these priority lists. No change event fires when the ordering moves, and we found no documented API for reading the current ordering, so the same user, the same day and the same device can produce a different aggregate with no underlying data change at all. If your product needs a number it can reproduce, aggregate per DataOrigin using dataOriginFilter and perform your own merge instead of relying on the bare aggregate.",
          "url": "https://aifitnessapi.com/architecture/deduplicate-health-data#faq-2"
        },
        {
          "question": "How do you resolve two workouts that partially overlap rather than exactly duplicate each other?",
          "answer": "Cut the timeline at every start and end instant across all candidate samples, which gives you atomic sub-intervals over which the set of covering samples is constant. For each sub-interval take the sample from the highest-priority source that covers it, attribute that sample's value pro rata to the sub-interval length, and sum the result. This keeps periods that only one source covered, which a per-day winner rule would throw away, and removes periods that two sources both covered, which a naive sum would count twice. It matters most for workouts specifically, because HealthKit statistics queries are documented as quantity-only, so duplicate workout records get no framework help whatsoever and the resolution is entirely yours to build.",
          "url": "https://aifitnessapi.com/architecture/deduplicate-health-data#faq-3"
        },
        {
          "question": "Should you pick one winning device per day or resolve source conflicts per interval?",
          "answer": "Per interval. Picking a winning device for the whole day deletes every period the winner did not record, which is a common real case: the watch was on the charger, the user showered, the phone stayed in a bag during a gym session. Apple's own WWDC20 walkthrough describes a statistics query excluding 900 duplicated iPhone steps while adding 1,100 iPhone steps from a day the Watch was left at home, which is interval-wise behaviour rather than device-wise. Any rule phrased as the watch always winning contradicts that example and has no Apple source behind it. Rank sources per user and per metric rather than globally, because a chest strap is the best heart-rate source a user owns and a nonexistent step source.",
          "url": "https://aifitnessapi.com/architecture/deduplicate-health-data#faq-4"
        },
        {
          "question": "Why do on-device Android steps suddenly appear under a package name I have never seen?",
          "answer": "Google documents that starting with the June 2026 update, steps counted natively by Health Connect are attributed to a Synthetic Package Name, a value beginning com.android.healthconnect.phone followed by a long hex string. Previously those built-in steps carried the package name android, and historical data recorded before the change keeps android forever, so one physical phone legitimately appears under two source values across that boundary. Synthetic package names are device-specific and scoped per application, so different apps on the same device see different values for the same source. Google states you must not hardcode them and should resolve them at runtime with getCurrentDeviceDataSource. Any server-side allow-list keyed on step package names is therefore wrong, and your source-priority table needs an alias concept so one device does not end up competing against itself.",
          "url": "https://aifitnessapi.com/architecture/deduplicate-health-data#faq-5"
        }
      ]
    },
    {
      "question": "normalize wearable data across providers",
      "answer": "Store the measurement definition beside every value, not just the metric name. Units and field names are mechanical; the layer that breaks you is that Apple HealthKit stores HRV as SDNN while Android Health Connect stores RMSSD, and those are different measurements with no conversion between them. So a canonical record carries provenance — source app, device, measurement definition, recording method and read path — as first-class columns. Do that, not a single normalized hrv column that silently mixes incompatible measures.",
      "title": "Normalizing wearable data across providers",
      "url": "https://aifitnessapi.com/architecture/normalize-wearable-data",
      "markdown": "https://aifitnessapi.com/architecture/normalize-wearable-data.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I convert SDNN into RMSSD so HRV lines up across platforms?",
          "answer": "No. They are two different statistics computed from the same interbeat intervals, and there is no constant that converts one into the other. Apple HealthKit stores SDNN; Android Health Connect stores RMSSD. Keep them as separate measurements with separate names, chart them separately, and never let a baseline or trend span both.",
          "url": "https://aifitnessapi.com/architecture/normalize-wearable-data#faq-1"
        },
        {
          "question": "What provenance columns does a canonical health record actually need?",
          "answer": "Beyond the value and unit: the measurement definition (not just the metric family), the source app and its version, the device manufacturer and model, the recording method, the read path that produced the number, the zone offset plus where that offset came from, and a pointer to the untouched provider payload with the adapter version that parsed it. Every one of those that can be absent needs an explicit unknown value rather than a default.",
          "url": "https://aifitnessapi.com/architecture/normalize-wearable-data#faq-2"
        },
        {
          "question": "Should manually entered health data be stored in the same table as device samples?",
          "answer": "Same table is fine; same treatment is not. Health Connect models recording method as a required field with separate constants for automatically recorded, actively recorded and manual entry, and HealthKit has a user-entered flag that the writing app sets. Carry that flag into storage and branch on it: manual entries need a differently shaped plausibility envelope, should be excludable from scoring and baselines, and an implausible manual value should prompt the user to confirm rather than page your on-call.",
          "url": "https://aifitnessapi.com/architecture/normalize-wearable-data#faq-3"
        },
        {
          "question": "Why is a source package name or bundle identifier not a stable way to identify a wearable source?",
          "answer": "Google documents that from the June 2026 update, steps tracked natively by Health Connect are attributed to a Synthetic Package Name that is device-specific and scoped per application, must not be hardcoded, and is resolved at runtime. Step data recorded before that keeps the package name android. So one physical phone appears under two different source identifiers across the cutover, and the values cannot be enumerated in a server-side mapping table.",
          "url": "https://aifitnessapi.com/architecture/normalize-wearable-data#faq-4"
        },
        {
          "question": "Does buying an aggregator remove the normalization problem?",
          "answer": "It removes the tedious half and often that is the right trade, because maintaining unit tables and field maps across many providers is real work that does not differentiate your product. It does not remove the semantic and measurement-definition layers, and it can hide them: check whether each record carries its source measurement definition, its recording method and device, and whether you can also retrieve the untouched provider payload. If a single field can be fed by both an SDNN and an RMSSD source with no discriminator, that field cannot support a trend line.",
          "url": "https://aifitnessapi.com/architecture/normalize-wearable-data#faq-5"
        }
      ]
    },
    {
      "question": "fitness app daily totals timezone local midnight",
      "answer": "Store three things on every sample: the UTC instant, the UTC offset in effect at that instant, and the civil local date you compute from the two at ingest. The constraint driving it is that a daily total is a calendar question, not a time-range question - UTC alone throws away information you cannot recover, and local time alone is ambiguous on the autumn DST transition and impossible on the spring one. Then decide deliberately whose midnight defines the day; our default is the zone in effect at each sample's own timestamp. Write the local date as a real indexed column and group on it, rather than converting on read.",
      "title": "Timezones and Day Boundaries: Whose Midnight Defines the Day?",
      "url": "https://aifitnessapi.com/architecture/timezones-and-day-boundaries",
      "markdown": "https://aifitnessapi.com/architecture/timezones-and-day-boundaries.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Should daily totals use the timezone the user is in now, or the one they were in when the data was recorded?",
          "answer": "The one they were in at the time, in our judgement. That gives the user the day they actually lived through, and it is the only option that is stable: re-bucketing history against the user's current zone means a previously reported daily total changes with no data change at all, and once you have rewritten a year of days against a zone the user was not in, the original assignment is gone. Note that this is also the default you get by accident if you do not store the offset - both mobile platforms fall back to the device's current or default zone when the offset is absent. The one legitimate alternative is a fixed home or profile zone, which suits coaching products where a week is a training block anchored to home life. What is not acceptable is not choosing, because then different endpoints in your own API will quietly implement different rules.",
          "url": "https://aifitnessapi.com/architecture/timezones-and-day-boundaries#faq-1"
        },
        {
          "question": "How long is a day when the clocks change, and what does that do to a step goal or a streak?",
          "answer": "In a zone that observes daylight saving, one civil day a year is 23 hours long and one is 25. In America/New_York in 2026, 8 March runs from 05:00Z to 04:00Z the next day, which is 23 hours; 1 November runs from 04:00Z to 05:00Z the next day, which is 25 hours. A step goal is stated per day but achieved at a per-hour rate, so those two days are genuinely about four percent harder and easier than every other day. That is a fact about the calendar, not a bug. The bug is a streak evaluator that asks whether less than 24 hours have elapsed since the last qualifying day, because on the 25-hour day two genuinely consecutive days are more than 24 hours apart and the streak breaks. Streaks must be successor arithmetic over civil dates. Durations must come from instants. Never mix the two.",
          "url": "https://aifitnessapi.com/architecture/timezones-and-day-boundaries#faq-2"
        },
        {
          "question": "Does HealthKit tell me what timezone a sample was recorded in?",
          "answer": "Not reliably. HKSample carries startDate and endDate as Date values, which are absolute instants with no calendar or zone attached. There is an optional metadata key, HKMetadataKeyTimeZone, that takes an NSTimeZone-compatible name string, but Apple documents it as writer-supplied and only recommends it, specifically for sleep samples. Apple does not document whether first-party iPhone and Watch step samples populate it, so do not build a design that depends on the answer. The practical approach is to capture the device's current zone identifier on the client when you read the batch, ship it up alongside the samples, and record in your schema that it was device-reported rather than observed at the moment of the activity. Health Connect is better here - zone offset is required on write - but its offsets can also be back-filled from the device default zone, so they are a hint rather than provenance.",
          "url": "https://aifitnessapi.com/architecture/timezones-and-day-boundaries#faq-3"
        },
        {
          "question": "Why does a daily rollup built on a UTC time bucket give the wrong number for users outside UTC?",
          "answer": "Because a time bucket over a timestamp-with-time-zone column aligns to UTC, which Timescale's own documentation states explicitly. A one-day bucket is therefore a UTC day, so for a user in UTC+9 the total labelled today covers 09:00 local to 09:00 the next morning, and nine hours of their day land under yesterday. Nothing errors, no samples are lost, and the number is plausible enough that it survives review - which is why this survives to production and gets caught by a user rather than a test. The fix is not to convert on read, which forces every daily query to carry the user's zone history and gives up the index. Write the civil local date as a real column at ingest from the instant plus the offset, and key the rollup on that date.",
          "url": "https://aifitnessapi.com/architecture/timezones-and-day-boundaries#faq-4"
        },
        {
          "question": "What breaks when a provider returns a bare date string instead of a timestamp?",
          "answer": "Two things. First, the instant is unrecoverable: a date with no offset cannot be converted back into a point in time, so any code that turns it into a timestamp is inventing data. Second, and worse, that date was computed by the provider in whatever timezone it holds in the user's profile, which you cannot see and the user probably set once and forgot. Joining a date-keyed daily summary against instant-keyed samples runs cleanly, returns plausible rows, and is silently wrong for exactly the users whose real zone differs from the provider's assumption - a small, invisible, travel-weighted slice of your users. Treat a provider's bare date as a label, never as a timestamp: store it separately for reconciliation, and route every join through your own civil date, computed by your own rule, from data that actually carries an offset.",
          "url": "https://aifitnessapi.com/architecture/timezones-and-day-boundaries#faq-5"
        }
      ]
    },
    {
      "question": "missing days step data fill gaps health app",
      "answer": "Store absence as absence: model every user-metric-day cell as measured-with-a-value or unknown-with-a-reason, and never write a zero you did not observe. The constraint driving it is that \"the user did nothing\" and \"we have no data\" are different facts about a person, and both mobile platforms hand you the second one disguised as the first. Apple documents that a denied read permission is indistinguishable from an empty store, and Google documents a default 30-day read-history window beyond which older data is absent rather than zero. Do carry a status column and a coverage count into your daily rollup; do not zero-fill, and do not interpolate.",
      "title": "Missing Data and Gaps in Health Metrics",
      "url": "https://aifitnessapi.com/architecture/missing-data-and-gaps",
      "markdown": "https://aifitnessapi.com/architecture/missing-data-and-gaps.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Should a day with no step data be stored as zero?",
          "answer": "No. Store it as unknown, with a reason code. A zero is only legitimate when you have evidence that some source was present and reporting during that day, which is what a coverage count gives you. Zero-filling looks harmless until the derived numbers land: a seven-day average silently divides by seven instead of by the five days you actually have, trend lines slope downward through injected zeros, and streaks reset on days the user did not miss. Those are the failures users notice and complain about, and once the zeros are written you cannot tell them apart from real rest days ever again.",
          "url": "https://aifitnessapi.com/architecture/missing-data-and-gaps#faq-1"
        },
        {
          "question": "Can I tell whether a user denied HealthKit read access or simply has no data?",
          "answer": "No, and Apple documents this as deliberate. Apple states that your app cannot determine whether the user granted permission to read data, and that if permission is not given it simply appears as if there is no data of that type in the store. The one positive signal available is getEarliestAuthorizedSampleDate, which Apple describes as the only authorization state your app can positively identify, because limited access returns a date while both full access and denied access return nothing at all. Practical consequence: name the reason code honestly as something like not-authorized-or-no-data rather than pretending your pipeline can split the two, and treat a long implausible run of emptiness as a cue to prompt the user to check permissions.",
          "url": "https://aifitnessapi.com/architecture/missing-data-and-gaps#faq-2"
        },
        {
          "question": "Is it ever acceptable to interpolate missing health data?",
          "answer": "Only at render time, in code with no write path, and never as an input to anything derived. The reason interpolation is worse for health data than for most domains is that the gaps are not missing at random and the reason for the gap correlates with the value: people stop wearing trackers when they are ill, travelling, or having a bad week, which are exactly the periods whose real values differ most from their neighbours. Interpolating there does not produce a noisy estimate, it produces a confidently normal week that did not happen. A stored interpolated value is also indistinguishable from a measurement within about two hops, so it contaminates baselines, training-load models and any summary text you generate. A dashed connector on a body-weight chart is a defensible display choice; a stored daily weight is not.",
          "url": "https://aifitnessapi.com/architecture/missing-data-and-gaps#faq-3"
        },
        {
          "question": "Why does Health Connect show nothing before a certain date?",
          "answer": "Because of the default history window, not because the user was inactive. Google documents that by default an app can read Health Connect data for up to 30 days prior to when any permission was first granted, and that reading records older than that without the read-health-data-history permission results in an error. Two details catch people out. The window is anchored to first grant and resets on reinstall, so a returning user develops a fresh hole in a history you may already hold from their previous install. And the rule differs by OS version: on Android 14 and higher there is no historical limit on an app reading its own data with a 30-day limit on other data, while on Android 13 and lower the limit applies to any data. Label everything past the boundary as outside-history-window, and never let a re-sync overwrite data you already have with that state.",
          "url": "https://aifitnessapi.com/architecture/missing-data-and-gaps#faq-4"
        },
        {
          "question": "Should a missing day break a user's streak?",
          "answer": "No. A day you have no data for should suspend the streak, not break it, and the copy should say so. Telling someone we do not have data for Tuesday is a recoverable message; telling them they broke a 90-day streak because their phone was off is not, and they will not give you the benefit of the doubt. The same gating applies to personal bests, best-ever badges and trend arrows, which should stay suppressed while a historical backfill is still running, because a partial history produces a wrong personal record that the user sees and remembers. Gate every one of these on your coverage count rather than on whether a row exists.",
          "url": "https://aifitnessapi.com/architecture/missing-data-and-gaps#faq-5"
        }
      ]
    },
    {
      "question": "database schema for storing heart rate time series app",
      "answer": "Store raw samples immutably in one table and make every daily figure a recomputable function of them, rather than a counter you increment at ingest. The constraint driving that is that health samples are not append-only: they arrive late, users edit them months later, and Apple documents that HealthKit itself re-condenses workouts at least a few months old and deletes the originals. So a rollup over yesterday can become wrong after yesterday has passed, and only a recompute can fix it. Do keep raw plus a rollup keyed on the civil date with a dirty-day queue; do not maintain an incremental counter you can never prove correct.",
      "title": "How Should You Store Health Time-Series Data?",
      "url": "https://aifitnessapi.com/architecture/time-series-storage",
      "markdown": "https://aifitnessapi.com/architecture/time-series-storage.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "How long can plain Postgres handle wearable sample data before I need a time-series database?",
          "answer": "Longer than most teams assume. PostgreSQL's own documentation gives a rule of thumb that the size of the table should exceed the physical memory of the database server before partitioning is even worthwhile, and a specialised time-series engine is a step beyond that. Work out rows as users times samples per user per day times days of history, multiply by your measured row width, and compare. The deeper argument is that the hard part of health storage is not write throughput, it is identity and correction. Time-series databases are optimised for append-only infrastructure monitoring; health data is low-volume per user, multi-source and mutable, so adopting one early buys a solution to a problem you do not have and pays for it with a weaker correction story.",
          "url": "https://aifitnessapi.com/architecture/time-series-storage#faq-1"
        },
        {
          "question": "Why can a unique index not stop duplicate samples in a time-partitioned table?",
          "answer": "PostgreSQL documents that to create a unique or primary key constraint on a partitioned table, the constraint's columns must include all of the partition key columns. If you partition by sample time, your uniqueness constraint on the provider's identifier has to be provider plus external id plus start time, not provider plus external id alone. So when a retro-edit moves a workout from 23:50 to 00:10, the new row crosses a partition boundary, satisfies the constraint, and lands as a second row that is a duplicate in every sense except the one the index checks. There is no database-level fix. On ingest you need an application step that finds an existing row with the same external id at a different time and tombstones it before writing the new one.",
          "url": "https://aifitnessapi.com/architecture/time-series-storage#faq-2"
        },
        {
          "question": "Should a user's daily step total be a stored counter or recomputed from raw samples?",
          "answer": "Recomputed. A counter cannot be proved correct: a webhook retry, a full replay after a client lost its sync cursor, or a platform re-condense all add again, and nothing in your system can tell you afterwards whether the number is right. If the rollup is a pure function of the raw rows for one user, metric, day and source, then answering a user who says their Tuesday is wrong means recomputing one cell and comparing. This is also the shape Apple recommends for server sync: the anchored query tells you which days changed and a statistics query tells you what those days now total. Never sum the anchored query's samples into a running total yourself.",
          "url": "https://aifitnessapi.com/architecture/time-series-storage#faq-3"
        },
        {
          "question": "Can I delete raw health samples once the daily rollups are computed?",
          "answer": "Usually not, and the reason is recompute rather than sentiment. The rollup is only trustworthy because it can be regenerated from raw, so deleting raw converts a verifiable number into one you simply have to believe. It also makes metric versioning impossible for that period: when version two of your calorie or sleep-efficiency formula ships, you cannot apply it to history you no longer hold. So your recompute reach sets your raw retention floor. That collides with data minimisation and does not resolve cleanly. Either keep raw for as long as your stated policy allows and version-stamp the frozen older rollups so a chart can say which formula produced them, or keep raw longer and justify it in the retention policy.",
          "url": "https://aifitnessapi.com/architecture/time-series-storage#faq-4"
        },
        {
          "question": "Why is a TimescaleDB continuous aggregate wrong after a user edits last month's data?",
          "answer": "Continuous aggregates are built around an invalidation threshold that the documentation describes as deliberately lagging behind the point in time where data changes are common, and refresh policies exclude the current bucket because it is incomplete and gets a lot of writes. That design assumes edits cluster near now, which health data violates routinely: users edit weeks-old entries and Apple documents HealthKit re-condensing workouts at least a few months old. The repair tool is refresh_continuous_aggregate with force set to true, which the docs warn can be very expensive, so treat it as a routine job rather than an emergency. Note also the documented caveat that it is not guaranteed all buckets will be updated, and that a continuous aggregate on a timestamp with time zone column aligns to UTC, so its daily bucket is a UTC day, not the user's.",
          "url": "https://aifitnessapi.com/architecture/time-series-storage#faq-5"
        }
      ]
    },
    {
      "question": "offline first workout logging sync conflict",
      "answer": "Carry two conflict strategies, not one, and branch between them on the provenance flag both mobile health platforms already give you. For device-sourced samples the device is authoritative, so the question is dedupe — a stable external id plus a monotonic version — not conflict. For records a person typed, last-write-wins is usually wrong: it silently deletes a set or a meal the user deliberately entered, and no fitness app has a merge-conflict UI to tell them. Model user-entered workout data as an append-only event log with client-generated IDs, so two offline devices produce a union of events rather than a fight over one row.",
      "title": "Resolving Sync Conflicts in an Offline-First Workout Log",
      "url": "https://aifitnessapi.com/architecture/offline-first-conflict-resolution",
      "markdown": "https://aifitnessapi.com/architecture/offline-first-conflict-resolution.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Is last-write-wins good enough for sets and reps logged offline?",
          "answer": "Usually not, and the reason is that it fails silently. Last-write-wins imposes a total order on operations that were not ordered and then discards everything except the maximum, so a set the user actually performed can disappear with no error, no retry and no alert. It is also whole-record when the edits were field-level: a watch appending set 3 and a phone correcting the weight on set 1 touch nothing in common, yet one of them still loses. Reserve last-write-wins for fields where a later value genuinely supersedes an earlier one and losing the earlier costs nothing, such as a display name or a units preference. A logged set is not one of those.",
          "url": "https://aifitnessapi.com/architecture/offline-first-conflict-resolution#faq-1"
        },
        {
          "question": "Why is conflict resolution different for device samples than for data the user types?",
          "answer": "Because there is no semantic disagreement in a measurement. When a watch reports a heart rate, the device is authoritative and the only question is whether you have already stored that measurement, which is a deduplication question answered with a stable external identifier plus a monotonic version. Apple documents this as HKMetadataKeySyncIdentifier with HKMetadataKeySyncVersion, and Health Connect as clientRecordId with clientRecordVersion. A set the user typed is a claim about what they did, so two devices can hold two legitimate, different claims and you have to merge intentions rather than pick a version. Both platforms encode the distinction in the schema, through Health Connect's recording method constants and Apple's HKMetadataKeyWasUserEntered, and the mistake is dropping that flag at the adapter boundary because a sample is a sample.",
          "url": "https://aifitnessapi.com/architecture/offline-first-conflict-resolution#faq-2"
        },
        {
          "question": "How should an offline workout record get an ID before the server has seen it?",
          "answer": "Generate a UUID on the client at the moment the record is created, and treat it as the record's real identity for the rest of its life. Without it the client cannot reference the record in a later edit, cannot recognise its own retried flush as a duplicate, and cannot show the user a stable row. The same identifier then doubles as your sync idempotency key, so a flush that times out and retries is a no-op instead of a second set. It also travels into the platforms: Apple documents HKMetadataKeyExternalUUID for adding your own unique ID to an object's metadata, and Health Connect's clientRecordId is described as an optional unique ID your app supplies to reference records in your own datastore.",
          "url": "https://aifitnessapi.com/architecture/offline-first-conflict-resolution#faq-3"
        },
        {
          "question": "Do I need CRDTs for a fitness app, or is an append-only event log enough?",
          "answer": "For one user logging their own sets and meals, an event log is our default and CRDTs are usually more machinery than the problem needs. The entities are small, bounded and single-user, which is the case where folding immutable events gets you most of a CRDT's benefit for a fraction of its cost. CRDTs bring a library dependency, a different data model, metadata that inflates payloads, and semantics you have to live with such as interleaved concurrent inserts and an add-wins versus remove-wins choice. Where we would reach for one is a genuinely concurrent multi-writer object, such as a coach and a client editing the same training plan. Vector clocks sit awkwardly in between: they buy you detection of concurrency, not resolution, and in a two-device system you can get the same detection by recording on each event the last event that device had already applied.",
          "url": "https://aifitnessapi.com/architecture/offline-first-conflict-resolution#faq-4"
        },
        {
          "question": "When should a sync conflict be shown to the user instead of resolved automatically?",
          "answer": "Only when both branches contain deliberate human input that cannot coexist: two different weights on the same set, an edit racing a delete, or the same meal logged twice with different portions. Never surface a device-sample conflict, because the user cannot arbitrate whether their watch or their phone counted a flight of stairs better and asking implies they should be able to. Do not interrupt the session with a modal either; flag the record and offer a short review list in the post-session summary. Default to keeping more rather than less, since a duplicate set costs one tap to remove while a deleted personal record costs a support ticket and trust in the log. The same treatment fits an implausible manual entry, such as a hundred-thousand-step day that is almost certainly an extra zero: ask the user to confirm it rather than raising a pipeline alert to yourself.",
          "url": "https://aifitnessapi.com/architecture/offline-first-conflict-resolution#faq-5"
        }
      ]
    },
    {
      "question": "recalculate derived metrics after algorithm change backfill",
      "answer": "A derived health metric is not a number, it is a function you ran over raw samples with a specific formula version, day boundary and source-resolution policy, and every one of those inputs keeps moving after the fact. Store only the output and you can neither explain the number nor reproduce it. So stamp the formula version onto every derived row, keep the raw samples that fed it, and run recompute as a checkpointed background job with the same budgeting as backfill. Recompute deliberately and announce it; silently rewriting last year's calorie or readiness numbers is the version users actually notice.",
      "title": "Versioning Derived Metrics and Recomputing Health History",
      "url": "https://aifitnessapi.com/architecture/metric-versioning-and-recompute",
      "markdown": "https://aifitnessapi.com/architecture/metric-versioning-and-recompute.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "If we improve our calorie formula, does last year's number change?",
          "answer": "Both answers are defensible and the choice is a product decision, not an engineering one. Recomputing everything gives you a series that is internally consistent end to end, so year-over-year comparisons compare like with like, at the cost of moving numbers your users remember. Versioning forward from today preserves history exactly as the user saw it, at the cost of a discontinuity in the chart and any comparison across the boundary quietly comparing two different functions. What is not defensible is doing either one silently. A useful heuristic per metric: if the value is a record of something the user achieved, such as a workout distance or a personal best, lean toward preserving it; if it is an estimate of how they were, such as a readiness or recovery score, lean toward recomputing, because a series containing two generations of a scoring model is not really a series.",
          "url": "https://aifitnessapi.com/architecture/metric-versioning-and-recompute#faq-1"
        },
        {
          "question": "What do we store next to a derived health metric so we can reproduce it later?",
          "answer": "At minimum: the formula id and version that produced the value, the source-resolution policy used, the civil date and the instant window the value covers, a digest of the contributing sample ids and versions, and the timestamp it was computed at. Keep the version and the source policy in separate columns, because they change independently and the source policy is frequently the one that actually moved the number. Also make the value column nullable and treat null as unknown rather than zero, since on Apple's platform a denied read is documented as indistinguishable from no data and an empty interval returns nil rather than zero. Finally, keep a small formula registry table mapping each version to a one-sentence human description of what changed, because an integer in a column tells nobody anything eighteen months later.",
          "url": "https://aifitnessapi.com/architecture/metric-versioning-and-recompute#faq-2"
        },
        {
          "question": "What are the two triggers that make a derived health metric stale?",
          "answer": "Dirty inputs and a formula change, and they should not share a policy. Dirty inputs are late-arriving, retro-edited or deleted samples that invalidate specific user, metric and day cells; the blast radius is one user and a handful of days, and handling should be automatic with no human in the loop. A formula change invalidates every value ever produced by the previous version across every user and all history for that metric; it should be a deliberate, announced, reversible migration and never a side effect of a deploy. The dirty-input feed comes straight out of incremental sync: an anchored query or a change token tells you which days changed, and you then recompute what those days now total rather than adding the new samples to a running counter.",
          "url": "https://aifitnessapi.com/architecture/metric-versioning-and-recompute#faq-3"
        },
        {
          "question": "Does updating a user's body weight mean recomputing their calorie history?",
          "answer": "It is the question people forget to ask, and yes for most calorie models. Any metric that consumes a profile field such as body weight, age or max heart rate has an input that can change with no health sample changing at all, so a user correcting a weight they entered wrong invalidates every estimate you ever produced for them. That makes it the same product dilemma as a formula change, except it arrives one user at a time and is easy to ship by accident. Decide the policy explicitly, and if you do recompute, treat the profile field as a versioned input to the function so that the resulting values are still explainable afterwards.",
          "url": "https://aifitnessapi.com/architecture/metric-versioning-and-recompute#faq-4"
        },
        {
          "question": "Is every part of a health history recomputable if we kept the raw samples?",
          "answer": "No, and you should know exactly which ranges are not. Retention policies and erasure requests can remove raw data you would need, which means your own published retention schedule is a hard ceiling on how far back a formula fix can reach. Re-pulling from the source is not a general fallback either: Apple documents that deleted-object records are temporary and may be purged at any time and that condensing old workouts deletes the original samples, and Health Connect grants only 30 days of history by default without the history read permission, a window anchored to first permission grant that resets on reinstall. And some inputs were never observable by you at all, such as the user-controlled Health Connect priority list that decides an aggregate figure. Keep a per-user, per-metric recomputable-from date as a recorded fact, and where you cannot recompute, label the boundary rather than drawing one continuous line across two definitions.",
          "url": "https://aifitnessapi.com/architecture/metric-versioning-and-recompute#faq-5"
        }
      ]
    },
    {
      "question": "monitor health data pipeline anomaly detection",
      "answer": "Treat ingestion as a monitored system with its own SLOs, and define every check per provider rather than globally. The constraint driving that is cadence: Apple delivers when the app opens or a background wake fires, Health Connect never pushes at all, a ring syncs when it is charged, so one global freshness alarm is either always firing or never firing. Measure the fraction of a provider's active users whose newest sample is older than N hours, not the time of the last row inserted, because one active user keeps a global metric green while the rest of the cohort has gone dark. Alert on the absence and the shape of data, not on exceptions, because a health pipeline's dominant failure mode is silence.",
      "title": "Monitoring a Health Data Pipeline for Silent Failures",
      "url": "https://aifitnessapi.com/architecture/data-quality-monitoring",
      "markdown": "https://aifitnessapi.com/architecture/data-quality-monitoring.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "How do I detect that a provider silently changed units on a field?",
          "answer": "Distribution monitoring, because type validation catches none of it. A kilojoule-for-kilocalorie swap, metres becoming feet, or seconds becoming milliseconds all keep the declared type and deserialise cleanly, so nothing errors anywhere in your system. Compute per-provider, per-metric statistics daily, at minimum the median, the p99, the null rate and the distinct-value set for enums, and alert on step changes. A kJ-for-kcal swap is roughly a 4.18x shift in the median appearing within one day across every user of one provider, which is trivially visible in that series. As a cheap early warning, also hash the sorted set of key paths in each provider's payload daily and diff it, so a new upstream key surfaces before it reaches a field you read.",
          "url": "https://aifitnessapi.com/architecture/data-quality-monitoring#faq-1"
        },
        {
          "question": "Should a single 100,000-step day trigger an alert?",
          "answer": "No, and treating it as one detector is the mistake. A 100,000-step day is usually not a sensor error at all: it is a manual entry with an extra zero, a unit confusion, or double counting from two sources that both covered the same hours, and the remedy differs for each. That is why provenance has to survive into the monitoring layer, using HealthKit's user-entered metadata key or Health Connect's recording method. A manual entry at an implausible magnitude should surface to the user as a confirmation prompt, since it is their typo. A device-recorded sample at the same magnitude is your bug. In both cases alert on the rate of out-of-range values per provider per day, never on individual rows, because genuine physiological outliers exist and a zero-tolerance bound fires constantly.",
          "url": "https://aifitnessapi.com/architecture/data-quality-monitoring#faq-2"
        },
        {
          "question": "Why can't one freshness threshold cover every wearable provider?",
          "answer": "Because the providers have structurally different sync cadences. Apple's data reaches your server when the user opens the app or a background wake happens, and Apple documents only an upper bound on background delivery, never a minimum rate, plus a shutdown after three unacknowledged deliveries. Google documents that Health Connect cannot notify your app of new data at all, so the client polls while it is in the foreground. A ring syncs when it is charged, a watch when it is near a phone. A single threshold across that mixture is either always firing or never firing. Set two thresholds, a warn and an error, per provider, derived from that provider's own observed inter-sync gap distribution over a normal month.",
          "url": "https://aifitnessapi.com/architecture/data-quality-monitoring#faq-3"
        },
        {
          "question": "Is it worth reconciling my daily totals against the platform's own aggregate?",
          "answer": "Yes, but as a drift detector rather than a correctness target, because you will not match and should not try to. Apple's statistics queries merge across sources while a plain sample query does not, and an Apple Frameworks Engineer has said publicly that third parties are unlikely to reproduce the merge algorithm correctly. Health Connect deduplicates only Activity and Sleep, only through the Aggregate API, and the ordering comes from a priority list only the end user can change and your backend cannot read. So track the distribution of the delta per provider per day and alert when that distribution moves. A steady small spread that jumps overnight means a dedupe regression or a newly connected source you are summing instead of merging, which is the bug that doubles a step count on someone's home screen.",
          "url": "https://aifitnessapi.com/architecture/data-quality-monitoring#faq-4"
        },
        {
          "question": "How do I notice one provider going dark when total ingest volume looks normal?",
          "answer": "You cannot, from an aggregate chart, and that is the point of splitting every signal by provider. If one provider represents eight percent of your volume, its total disappearance is smaller than the normal weekly seasonality in health data, where weekends genuinely differ from weekdays, so it never crosses a global band. Split freshness and volume by provider and, for volume, compare against the same weekday in the prior few weeks rather than against yesterday. Segment by metric too, since the common real failure is partial: steps keep flowing while sleep stops after a scope change in a re-consent flow. Also chart new connections per provider, because a broken OAuth redirect stops all new links for one provider while existing users mask it entirely.",
          "url": "https://aifitnessapi.com/architecture/data-quality-monitoring#faq-5"
        }
      ]
    },
    {
      "question": "implement delete user health data across backend",
      "answer": "Model deletion as a tombstone plus a checkpointed, per-store purge job driven by a checked-in registry of stores, not as a cascade of DELETE statements and not as a script someone runs. The constraint is that a health record never lives in one place: it lives in raw samples, every rollup and continuous aggregate derived from them, caches, queues, dead-letter queues, logs that captured a provider payload, analytics, search indexes, embeddings, backups you cannot surgically edit, and an upstream OAuth grant that will refill all of it tomorrow. Revoke the provider grant first and purge second, because the reverse ordering leaves a window in which a webhook re-creates the user you just deleted. Export is the same traversal in reverse, and an export that omits derived rollups omits the only numbers the user ever actually saw.",
      "title": "Deleting and Exporting a User's Health Data",
      "url": "https://aifitnessapi.com/architecture/data-deletion-and-export",
      "markdown": "https://aifitnessapi.com/architecture/data-deletion-and-export.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "If I delete a user's rows but leave their wearable OAuth grant active, what happens?",
          "answer": "You start collecting them again. Wearable backends push: the provider does not know you deleted anything, it knows there is a live grant and a registered callback. The next webhook hits an ingest path whose job is to create records, and if that path upserts on a provider user id it does not recognise, it will recreate the account. Backfill makes it worse, because some providers deliver historical data asynchronously through the same callback as live data, so a request made weeks earlier can land in the middle of your purge. Revocation is therefore the first step of deletion, not cleanup afterwards: revoke the token, delete the webhook subscription, record the result per provider, and treat a failed revocation as an incomplete purge task rather than a warning.",
          "url": "https://aifitnessapi.com/architecture/data-deletion-and-export#faq-1"
        },
        {
          "question": "Can I surgically delete one user out of my database backups?",
          "answer": "Realistically no, and a design that claims to is either rewriting backups, which destroys their value as a recovery point, or quietly lying. The defensible answer has three parts. First, a documented and bounded retention window for every backup class, including snapshots, the point-in-time recovery window, WAL archives and warehouse copies, with the stated commitment that erasure completes when the last backup containing the user ages out. Second, a tombstone list stored outside the backups that outlives them, containing only the internal user id and hashed provider account identifiers. Third, deletion-on-restore as a mandatory first step of any restore runbook, re-applying every tombstone recorded since the snapshot was taken. That third step is the one that fails, because restores are rare, so it has to be exercised in the restore drill.",
          "url": "https://aifitnessapi.com/architecture/data-deletion-and-export#faq-2"
        },
        {
          "question": "A user unlinks one wearable but keeps their account. What has to change beyond deleting that provider's rows?",
          "answer": "Every merged number derived from that source. A daily total is a resolution across overlapping sources rather than a sum of one, so removing a source gives every affected user, metric and local-date cell a different correct value. The operation is a recompute, not a delete. If you already maintain a dirty-day queue for late-arriving and retro-edited data, partial deletion is nearly free: mark every day the disconnected source touched as dirty and let the existing recompute path run. If you store incremented counters as the user-facing number instead, there is no correct operation available at all, because you cannot subtract a contribution from a number you never decomposed. Streaks, personal records and best-ever badges must be recomputed in the same pass, or the user keeps a record set by data you no longer hold.",
          "url": "https://aifitnessapi.com/architecture/data-deletion-and-export#faq-3"
        },
        {
          "question": "Does a health data export have to include derived metrics like daily rollups and computed scores?",
          "answer": "In our judgement yes, and this is where most exports fall down. Nobody makes a decision from a heart-rate sample at 07:42:13; they act on the daily rollup, the weekly trend, the sleep-stage breakdown and whatever readiness-style score the app showed them. Those are personal data derived from the user's data and they are the only part that corresponds to something the user actually saw, so an export of bare timestamp and value pairs is technically defensible and practically useless. Ship the rollups tagged with the calculation version that produced them so exports taken months apart are comparable, carry provenance per sample including source device and the manual-entry flag, and carry time as three fields: the instant, the offset in effect at that instant, and the civil local date you bucketed on.",
          "url": "https://aifitnessapi.com/architecture/data-deletion-and-export#faq-4"
        },
        {
          "question": "How do I stop a deleted user reappearing from a queue or a dead-letter queue?",
          "answer": "Write a positive tombstone rather than relying on the absence of a row, and check it at consume time. A missing user row is exactly what an upsert-on-unknown-id ingest path treats as a signal to create the account, so the marker has to be an explicit deleted flag that reads, exports, coaching and ingest all fail closed against. Then drain or filter in-flight messages and purge the dead-letter queue, which is the one routinely missed. Most DLQs are unpurgeable by user because they store only the raw provider payload, so store user id, provider and the affected time range alongside the payload from the start. Finally, alarm on webhook deliveries and writes arriving for tombstoned users: that counter is your resurrection detector and the only instrument that finds the queue you forgot.",
          "url": "https://aifitnessapi.com/architecture/data-deletion-and-export#faq-5"
        }
      ]
    },
    {
      "question": "cache fitness api responses health data",
      "answer": "Cache what is not about a person as freely as you like: provider metadata, exercise catalogue rows and media are effectively immutable and belong in a long-lived shared tier. A user's settled days are cacheable only under an eviction driven by the event that says they moved, and the current day's totals — plus streaks, goals and anything that fires a notification — should be recomputed rather than served warm. Two properties make this different from ordinary API caching: health data is retro-edited, so a day you considered final can change tonight, and the day a value belongs to is a civil-calendar question, so a cached today is wrong the moment the user crosses their own midnight. Key every entry per user and per civil date, use expiry only as a backstop behind event-driven invalidation, and put your caches on the erasure inventory, because a cache is storage.",
      "title": "Caching Fitness API Responses Without Serving Stale Health Data",
      "url": "https://aifitnessapi.com/architecture/caching-fitness-api-responses",
      "markdown": "https://aifitnessapi.com/architecture/caching-fitness-api-responses.md",
      "cluster": "Architecture",
      "cluster_url": "https://aifitnessapi.com/architecture",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Which parts of a health API response are actually safe to cache for a long time?",
          "answer": "The parts that are not about a person. Exercise catalogue rows, demo media, unit conversion tables and a provider's capability metadata change on your deploy cadence rather than on the user's, so they take a long lifetime and a shared cache keyed by content version. A user's settled historical days sit in a middle tier: cacheable, but only with an eviction driven by the event that says the day moved. The current day's totals, streak state and anything a goal or notification reads should not be treated as cacheable at all in the authoritative sense, because the harm from a stale value there is a wrong nudge or a goal that reads as unmet after the user already hit it.",
          "url": "https://aifitnessapi.com/architecture/caching-fitness-api-responses#faq-1"
        },
        {
          "question": "Should invalidation be driven by expiry times or by provider events?",
          "answer": "By events, with expiry kept only as a backstop. A time-to-live is a guess about how long a value stays true, made before you know anything about the value, and for health data it is simultaneously too long for a user actively wearing a device and pointlessly short for one whose watch has been in a drawer for months. A provider webhook is already a change pointer, which makes it a ready-made invalidation signal: the same code path that marks a day dirty should enqueue the eviction. Where no push channel exists you invalidate on sync completion instead, which means your cache freshness cannot be better than your sync freshness — worth stating explicitly rather than implying a guarantee with a five-minute expiry.",
          "url": "https://aifitnessapi.com/architecture/caching-fitness-api-responses#faq-2"
        },
        {
          "question": "Can a cache be my answer to a provider's rate limit?",
          "answer": "It stretches the quota, but it is not the strategy, and three other things matter more than the hit rate. Coalesce concurrent misses so four widgets opening the same dashboard cost one upstream call rather than four, because the burst is what trips the limit. Cache the rejection as well as the success, keyed to the same user and resource for the reset interval, or you will spend the whole window generating fresh rejections. And jitter expiry per user, since a fixed refresh cadence makes every miss arrive in a wave. Read each provider's own published quota rather than assuming they resemble each other.",
          "url": "https://aifitnessapi.com/architecture/caching-fitness-api-responses#faq-3"
        },
        {
          "question": "What goes wrong with a cached daily total when the user crosses midnight?",
          "answer": "It stops being an answer to the question that was asked. A total cached under a key meaning today does not decay gracefully; at local midnight it becomes yesterday's number wearing today's label. Key on the civil date computed from the instant and the offset in effect at that instant, resolve today to a date in the request handler before the lookup rather than inside the cache layer, and cap the lifetime of any current-day entry at the time remaining until that user's next local midnight. Compute that next midnight as a calendar operation rather than by adding twenty-four hours, because two days a year are twenty-three and twenty-five hours long, and a user who flies east gets a short day for the same reason.",
          "url": "https://aifitnessapi.com/architecture/caching-fitness-api-responses#faq-4"
        },
        {
          "question": "Does a purge of a user's health data have to reach the cache?",
          "answer": "Yes, and the cache is one of the stores most often left off the list, because it is filed under performance rather than under data. A cached response carrying health values is a copy of health data with its own location, its own access controls and its own retention behaviour, so it belongs on the erasure inventory by name and with an owner, alongside the databases. Two practical consequences: give every entry an absolute maximum lifetime even where you invalidate on events, so an orphaned key cannot outlive the retention window you published, and log cache keys rather than cached values, since the key is a reference while the payload is the health record itself.",
          "url": "https://aifitnessapi.com/architecture/caching-fitness-api-responses#faq-5"
        }
      ]
    },
    {
      "question": "how to test healthkit integration",
      "answer": "The assertion worth writing is about your arithmetic, not Apple's framework: given a fixture set of overlapping iPhone and Watch samples, your daily total must not be their sum. Apple ships no HealthKit test double: no fake store, no test mode, no way to seed ordinary samples into the Simulator. So define a narrow protocol seam yourself and keep the deduplication, timezone and rollup logic behind it as pure functions that need no store at all. Keep XCUITest for two or three end-to-end paths, and test the empty result as a first-class path rather than an error, because HealthKit hides read authorization and a denied read is indistinguishable from no data.",
      "title": "How to Test a HealthKit Integration",
      "url": "https://aifitnessapi.com/test/healthkit-integration",
      "markdown": "https://aifitnessapi.com/test/healthkit-integration.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Is HKHealthStore final, and does that stop you injecting a fake?",
          "answer": "No on both counts. Apple declares it as class HKHealthStore with no final keyword, and documents no prohibition on subclassing it, so the widely repeated claim that Apple made it unsubclassable is simply wrong. Apple does say you should not subclass HKQuantitySample, adding the phrase like many HealthKit classes, but that is a different class on a different page and it is not a statement about the store. What is true is that Apple ships no test double of any kind: no fake store, no test mode, no injectable simulated store. Subclassing is available and still a bad idea on merit, because a subclass runs the real initializer and holds the real connection to the health daemon, and because every read flows through execute, which delivers results through a callback the query itself owns, so overriding it commits you to hand-synthesising the completion contract of every query subclass you use. Define a narrow protocol of your own instead, for the design reason rather than the folklore one: you want to own the interface your assertions are written against.",
          "url": "https://aifitnessapi.com/test/healthkit-integration#faq-1"
        },
        {
          "question": "Should the protocol seam return HKQuantitySample or your own sample type?",
          "answer": "Your own type, and the reason is concrete rather than stylistic. Apple's public initializers for HKQuantitySample take type, quantity, start and end, plus optional device and metadata, so the sample objects themselves are easy to build as fixtures with no store involved. But none of those initializers takes a source or a source revision, because HealthKit populates provenance itself. Source is exactly what a source-priority deduplication keys on, so a fixture constructed in a unit test cannot express the most important input to the logic you are trying to prove. Map HealthKit objects into your own struct inside the adapter, carry the source bundle identifier as a plain string, and let every dedupe, timezone and rollup test construct that struct directly. A useful placement rule follows from this: put the seam where the last HealthKit type disappears from your call graph, and push that point as early as you can.",
          "url": "https://aifitnessapi.com/test/healthkit-integration#faq-2"
        },
        {
          "question": "Can you seed ordinary step samples into the iOS Simulator for a test run?",
          "answer": "Not with any Apple tool. Apple's only documented simulator sample data is clinical health records, supplied as three sample accounts you add by hand through the Health app, and Apple states plainly that you cannot create your own samples of that type. For ordinary quantity samples such as steps, heart rate or active energy, Apple documents no seeding mechanism, no simctl subcommand and no fixture format. Two routes remain. Your test target can write the samples itself with the health store's save method and read them back, which exercises the real store, the real query and your real adapter, but attributes every sample to your own bundle identifier so source priority stays untested. Or you drive the Health app's own data-entry UI from a UI test, which is what the third-party XCTHealthKit framework automates.",
          "url": "https://aifitnessapi.com/test/healthkit-integration#faq-3"
        },
        {
          "question": "Which HealthKit paths are worth an end-to-end XCUITest?",
          "answer": "Our recommendation is three, and a hard stop after them. First run with authorization granted, where the app moves from empty state to data. First run with the read denied, where the app must show an empty state and persist no zero. And a sample written by a different app appearing in yours after a foreground refresh. The denial case is the one that justifies the whole layer, because it is the only place the read-authorization opacity is observable end to end: behind a protocol seam, a denial and a genuinely empty day are the same input. Everything else, meaning every deduplication, timezone and rollup case, runs deterministically behind the seam and should not be paid for in UI-test flakiness. Apple gives you XCUIProtectedResource.health with resetAuthorizationStatus to make the authorization runs repeatable, and that is the only first-party test affordance in this area.",
          "url": "https://aifitnessapi.com/test/healthkit-integration#faq-4"
        },
        {
          "question": "Why must an empty HealthKit read be a first-class test case rather than an error?",
          "answer": "Because Apple hides read-authorization state deliberately, so a denied read and a type with no samples both come back as an empty array with no error, and your code cannot tell them apart. The authorizationStatus call reports the sharing side, meaning writing, truthfully and tells you nothing usable about reading. Since the cause is unknowable, the assertions have to be about behaviour instead: an empty result renders an empty state rather than a zero or an error banner, no zero rows are persisted for empty days, and nothing on the read path branches on authorizationStatus. The middle one matters most in the long run. A stored zero is a claim that the user did nothing, whereas a missing row correctly says you do not know, and a backfill arriving months later has to be able to tell those apart before it decides what it is allowed to overwrite.",
          "url": "https://aifitnessapi.com/test/healthkit-integration#faq-5"
        }
      ]
    },
    {
      "question": "health connect test data",
      "answer": "Insert records into FakeHealthConnectClient, read them back with a page size of 2, and assert every record arrives exactly once — pagination, change tokens, permission checks and thrown exceptions are what the library genuinely proves. The constraint is that androidx.health.connect:connect-testing is still 1.0.0-alpha03, released April 9 2025, ships no fake-data generation API, and stubs aggregation rather than computing it, so a daily-total assertion made through the fake only re-reads the number you handed it. Move the arithmetic into your own pure function and test that against records instead. Use the Toolbox by hand on a device for exploration, never in CI, and write your own generators for the ugly multi-source fixtures.",
      "title": "Test Data for Health Connect: Fakes, the Toolbox, and the Generators You Write",
      "url": "https://aifitnessapi.com/test/health-connect-test-data",
      "markdown": "https://aifitnessapi.com/test/health-connect-test-data.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Does FakeHealthConnectClient compute aggregates from the records I insert?",
          "answer": "No. Google documents that aggregation calls have no fake implementations and use stubs you program instead, accessed through the overrides property. The fake does no arithmetic over inserted records, so a test that inserts a week of steps, calls aggregate, and asserts on the total is asserting on the AggregationResult it programmed a moment earlier. That test cannot fail, which is worse than having no test, because a coverage report counts it as protection. Put the bucketing and summing in your own pure function that takes records and returns totals, test that directly, and reserve the stub for checking how your UI renders a known value and for making calls throw.",
          "url": "https://aifitnessapi.com/test/health-connect-test-data#faq-1"
        },
        {
          "question": "Which version of the Health Connect testing library is current, and is it still being developed?",
          "answer": "As of 2026-07-30 the latest published version is 1.0.0-alpha03, released April 9 2025. The AndroidX release notes list exactly three releases: alpha01 on September 4 2024, alpha02 on February 26 2025, and alpha03 on April 9 2025, with nothing after. Over the same period the runtime client kept moving and is stable at 1.1.0 with 1.2.0-alpha04 in alpha. The docs page also opens with a note that the library is in alpha and future versions might include breaking changes. Use it, but do not plan around new capabilities arriving.",
          "url": "https://aifitnessapi.com/test/health-connect-test-data#faq-2"
        },
        {
          "question": "Can I drive the Health Connect Toolbox from a CI script to seed data?",
          "answer": "Not in any documented way. The only scriptable step is installing the APK with adb after extracting it from the downloaded ZIP. Every other interaction Google documents is a tap sequence through the app: insert a health record, pick a category, pick a type, enter a value, save. There is no documented CLI, intent, broadcast, content provider or instrumentation surface. Google does not state that the tool is manual only, and it does not state the opposite either; reading it as a manual exploration tool is the only conclusion the documentation supports. Its real value is that it is a peer app writing into the on-device store, which is the one way to test cross-app attribution.",
          "url": "https://aifitnessapi.com/test/health-connect-test-data#faq-3"
        },
        {
          "question": "Do I have to complete Google's recommended Health Connect test cases before shipping?",
          "answer": "Google frames them as recommendations: the page says you are responsible for testing your applications and that Health Connect recommends a list of test cases designed to conform with best practices and user experience guidelines. There are ten numbered cases and thirteen sections, since 02 and 04 subdivide, each with explicit pass and fail conditions, which makes them a decent manual release checklist. The page says nothing about Google Play in either direction — we searched its full text on 2026-07-30 for Play, approv and mandat and every hit was navigation chrome. So do not treat a completed checklist as a review artifact, and do not assume anyone has exempted you from anything. The separate and genuinely mandatory item is declaring read or write access for the data types your app uses.",
          "url": "https://aifitnessapi.com/test/health-connect-test-data#faq-4"
        },
        {
          "question": "How do I test what happens when a user revokes a Health Connect permission mid-sync?",
          "answer": "Construct FakePermissionController with grantAll set to false, pass it into FakeHealthConnectClient as the permissionController, and assert on what your sync does when the client throws SecurityException. Google's own caution says you should have tests verifying correct behaviour when the client throws it, because users can revoke permissions at any time. The behaviour worth asserting is that you keep the last known value and mark the range unknown rather than rendering a zero, since a zero step count is a claim about the user's day rather than an absence of data. One limit checked on 2026-07-30: grantAll is the only constructor parameter the documentation demonstrates, so verify against the current API reference before assuming a per-permission grant or revoke call exists.",
          "url": "https://aifitnessapi.com/test/health-connect-test-data#faq-5"
        }
      ]
    },
    {
      "question": "mock wearable data for testing",
      "answer": "Your fixtures have to be ugly enough that idempotence, coverage and preserved absence can actually fail — clean synthetic data cannot fail any of them, which is why a green suite coexists with a Saturday that reads double. The constraint is that no platform will build those fixtures for you. Google documents that the Health Connect testing library ships no fake-data generation API and stubs aggregation rather than computing it, and Apple ships no HealthKit test double at all, so the generator is yours. Write a seeded generator that emits overlaps, clock skew, retro-edits, gaps, DST days and denied reads, and take the magnitudes from your own production data rather than from anyone's published ranges.",
      "title": "Mock Wearable Data That Is Ugly Enough to Find Bugs",
      "url": "https://aifitnessapi.com/test/mock-wearable-data",
      "markdown": "https://aifitnessapi.com/test/mock-wearable-data.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Should a fixture generator draw a new random seed on every CI run?",
          "answer": "No. Pin the seeds in source and add new ones rather than rotating them. A generator that reseeds itself each run will eventually produce a shape that breaks your rollup on a Tuesday morning, and nobody will be able to reproduce it. The failure gets labelled flaky, the case gets skipped, and within a quarter the whole suite is deleted. A pinned seed makes every failure reproduce from two values you can paste into a bug report: the case identifier and the seed. Use a small deterministic generator such as xorshift32 rather than the platform random function, so the same seed yields the same bytes across runtimes, language ports and CI images.",
          "url": "https://aifitnessapi.com/test/mock-wearable-data#faq-1"
        },
        {
          "question": "Why won't you publish typical ranges or distributions for synthetic wearable data?",
          "answer": "Because we have not measured them, and an invented range does not stay on the page it was invented on. It becomes the tolerance in somebody's assertion, and from then on the test is measuring a plausible-sounding sentence instead of a population. What a fixture actually needs from us is structure: how many sources overlap, in what arrival order, with what gaps, offsets, edits and permission states. Those are transferable. Magnitudes are not, because they describe your users and not ours. Take a window of real payloads from your own production system, strip identifiers, and read the distribution off that.",
          "url": "https://aifitnessapi.com/test/mock-wearable-data#faq-2"
        },
        {
          "question": "What does a two-minute device clock skew break that a clean fixture never will?",
          "answer": "Three things. Any duplicate matcher that treats an identical start instant and value as the same sample stops matching, so the same walk is stored twice under two sources. Any interval resolver that assumes source boundaries align leaves slivers of double-counted time at every transition between sources. And a sample recorded near midnight can land on the wrong calendar day, which moves it into a different daily total and can break a streak. Skew also drifts and resets when a device syncs its clock, so a fixture with one fixed offset is not enough; vary it per seed.",
          "url": "https://aifitnessapi.com/test/mock-wearable-data#faq-3"
        },
        {
          "question": "Is it safe to keep scrubbed real user payloads as test fixtures?",
          "answer": "Treat them as production data, because that is what they are. Fixtures get committed to repositories, echoed into CI logs, and pasted into issue trackers, and a scrubbed health payload is still a health payload. Our recommendation is to split the two things you want from real data: sample the structure freely, since field presence, arrival order, overlaps and null patterns carry no personal information once identifiers are gone, and sample the magnitudes statistically rather than copying rows. Where you do keep raw captures, keep them under the same handling and retention rules as your production store rather than in the test directory.",
          "url": "https://aifitnessapi.com/test/mock-wearable-data#faq-4"
        },
        {
          "question": "Where do new fixture cases come from once the obvious ones are written?",
          "answer": "From incidents, not from imagination. Every case worth having exists because something like it happened to someone, which means you cannot derive the list from your schema, and a generator written by the same person who wrote the ingest adapter will encode that adapter's assumptions and agree with it forever. The loop that works is a capture path: when reconciliation produces an implausible day, persist the raw payload window that produced it, scrub it, and promote it to a named case with its own seed. It is deliberately manual, because a human has to decide that a captured day is interesting enough to keep.",
          "url": "https://aifitnessapi.com/test/mock-wearable-data#faq-5"
        }
      ]
    },
    {
      "question": "test healthkit background delivery",
      "answer": "The assertion worth writing is that your wake handler never advances its cursor on a failed read and produces the same result when the same wake arrives twice, expressed as a total function over samples, an error and a stored cursor. Apple documents that background server queries are not supported on the Simulator, so no hosted CI run can prove the delivery itself ever happens. Test that handler exhaustively and alert on silence, rather than writing an integration test that pretends CI woke your app up.",
      "title": "Testing Background Sync: Three Tests, and Only One Is Real",
      "url": "https://aifitnessapi.com/test/background-sync",
      "markdown": "https://aifitnessapi.com/test/background-sync.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Why does HealthKit background delivery never fire during a CI run?",
          "answer": "Because hosted CI runners give you simulators, and Apple states on both the enableBackgroundDelivery method page and the HKObserverQuery page that background server queries are not supported on the Simulator and that you should test background queries on a device. There is no workaround. Any CI test that appears to cover background delivery is testing something else, and it will be read by reviewers as coverage that does not exist.",
          "url": "https://aifitnessapi.com/test/background-sync#faq-1"
        },
        {
          "question": "What should a unit test for an HKObserverQuery handler actually assert?",
          "answer": "Five things, all of which are decisions rather than side effects. A failed read advances no cursor and marks a retry. The same delivery replayed a second time persists nothing new. A sample spanning local midnight marks the correct two days, including through a daylight-saving transition. An empty delivery produces no dirty days and no zero. A batch that is only partly persisted advances the cursor no further than the last durable record. Model the handler as a total function returning one comparable outcome value and each of these is a one-line assertion.",
          "url": "https://aifitnessapi.com/test/background-sync#faq-2"
        },
        {
          "question": "Does WorkManagerTestInitHelper prove my background job will run on a real phone?",
          "answer": "No, and it is important to say why. Google documents that Doze does not let JobScheduler run and that WorkManager uses JobScheduler internally, so WorkManager tasks do not run. The work-testing library exists to remove exactly that nondeterminism: SynchronousExecutor and TestDriver let you fire the trigger the operating system was going to withhold. The resulting test proves your worker logic and constraint wiring and cannot fail for the reason production fails. Forcing Doze from adb with dumpsys deviceidle force-idle is the closer approximation.",
          "url": "https://aifitnessapi.com/test/background-sync#faq-3"
        },
        {
          "question": "How often should we do the manual on-device background delivery run?",
          "answer": "Our recommendation is to trigger it on events rather than on a calendar: a new iOS major version, any change to the background-delivery entitlement or to where observer queries are registered, and any rewrite of the wake handler. Run it on an unplugged physical device with the debugger detached, write a sample from another source, and assert on your server rather than on the device. Record the device, OS version and date in the pull request, because the result is one engineer's observation and not a regression gate.",
          "url": "https://aifitnessapi.com/test/background-sync#faq-4"
        },
        {
          "question": "Why can I not assert that a background wake arrived within a time limit?",
          "answer": "Because there is no documented number to assert against. Apple documents the frequency parameter as a maximum, at most one wake per period, and publishes no minimum rate or latency figure for iOS observer wakes; Google publishes no scheduling guarantee for deferred work. Any deadline in your test suite is a number you invented, and it will flake. Keep timing out of assertions and move it to the server-side freshness threshold, where the number is an explicit product decision about how stale is too stale.",
          "url": "https://aifitnessapi.com/test/background-sync#faq-5"
        }
      ]
    },
    {
      "question": "how to test oauth integration third party api",
      "answer": "Write four assertions against recorded fixtures. A 401 triggers exactly one refresh and one retry; a rotated refresh token is persisted before anything else runs; an invalid_grant flips the connection to revoked rather than retrying forever; a user-initiated disconnect leaves no usable token behind. RFC 7009 shapes all of it: a revocation endpoint returns 200 even for a token that was never valid, so assert consequences — including the one nobody writes, which is that a day with no samples because the grant was dead is not a day with zero steps. Drive the suite from fixtures rather than pointing CI at a live provider account you will eventually get locked out of.",
      "title": "Testing an OAuth Integration: The Token Lifecycle, Not the Login Screen",
      "url": "https://aifitnessapi.com/test/oauth-flows",
      "markdown": "https://aifitnessapi.com/test/oauth-flows.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Should my CI pipeline ever call a real provider's token endpoint?",
          "answer": "No, and the reason is stronger than flakiness. Under refresh token rotation a refresh is destructive and non-idempotent, so a CI run that refreshes a shared staging account invalidates the refresh token every other run and every developer laptop is holding. Add parallel jobs and you get a replay, which the OAuth Security Best Current Practice describes as triggering the authorization server's breach detection and revoking the active token. Your build then fails for a reason that has nothing to do with the commit. Run the suite on fixtures, and keep the one real refresh in a scheduled job outside the build.",
          "url": "https://aifitnessapi.com/test/oauth-flows#faq-1"
        },
        {
          "question": "How do I keep recorded OAuth fixtures from leaking a real user's health data?",
          "answer": "Scrub two classes of thing, not one. Credentials are the obvious class: client secret, access and refresh tokens, Authorization headers, and the authorization code if you recorded the initial exchange. The class teams miss is the response body, which for a fitness provider is somebody's resting heart rate, sleep stages, GPS track and stable provider identifier, now committed to a repository outside your deletion pipeline. Configure the filter before the first recording run, because adding it later does not clean the file already in git history, and post-process bodies to replace identifiers, shift timestamps to a fixed synthetic date, and overwrite values while keeping the field shape. The shape is the only part your parser exercises.",
          "url": "https://aifitnessapi.com/test/oauth-flows#faq-2"
        },
        {
          "question": "Why would two workers refreshing one user cost that person a full re-authorization?",
          "answer": "Because under rotation a refresh is destructive and non-idempotent. Both workers notice the same expired access token and both post the same refresh token; the second one arrives with a value the authorization server has already invalidated, and from the server's side a benign race inside your worker pool is indistinguishable from a stolen token being replayed. The documented response to that is to revoke the active refresh token, which means your concurrency bug ends as a real person being asked to reconnect their wearable through a browser. Test it with an actual concurrency primitive rather than two sequential awaits, and put a delay on the fake's token response — without the delay the first call finishes before the second starts and the test passes on a codebase with no lock in it at all. Then assert that exactly one token request reached the wire.",
          "url": "https://aifitnessapi.com/test/oauth-flows#faq-3"
        },
        {
          "question": "How do I test refresh token rotation when my fake always hands back the same token?",
          "answer": "Make the fake hostile. Script the token endpoint as an ordered sequence in which the first call returns a different refresh token and the second call rejects the original with 400 invalid_grant. A fake that accepts any refresh token forever cannot fail, so a client that reads the rotated value into memory and never commits it will pass. Then assert three things in order: the new value is in the store, the first outbound request carried the old value, and a second sync run sends the new value and does not trip the 400. It is that third assertion, which forces another round trip through persistence, that catches the real bug.",
          "url": "https://aifitnessapi.com/test/oauth-flows#faq-4"
        },
        {
          "question": "What should the nightly rollup write for a day when the provider grant was dead?",
          "answer": "A no-data state, never a zero, and this is the assertion most token-lifecycle suites never write. A dead grant in a checkout flow shows somebody an error; a dead grant in a health product produces a plausible chart, because a hole in a time series is indistinguishable from a fortnight of rest days. Script it against the clock you already injected: kill the grant, run the rollup for however many simulated days, and assert those days are marked unknown rather than zero, because zeros feed straight into averages, streaks and readiness scores with no error attached. Then assert the recovery leg: after re-authorization the incremental sync resumes from the watermark that predates the outage, any floor on how far back a fresh grant may read is applied, and the affected days are recomputed once real samples arrive. Skip that last one and the reconnect quietly ratifies the hole.",
          "url": "https://aifitnessapi.com/test/oauth-flows#faq-5"
        }
      ]
    },
    {
      "question": "fitbit api sandbox",
      "answer": "Write your assertions against a local fake you control, and keep exactly one real staging account per provider for a contract test a human runs on purpose. As of 2026-07-30 we could confirm a first-party test tool only for Android Health Connect, and the absence of a hosted sandbox only for Apple HealthKit. For the seven cloud providers we could not reach the documentation to check either way, so verify those against the provider's own current docs. Point continuous integration at the fake, never at a live provider, because a real account's data is a real person's body and it retro-edits itself underneath your assertions.",
      "title": "Provider Sandboxes: Build the Fake, Keep One Real Account",
      "url": "https://aifitnessapi.com/test/provider-sandboxes",
      "markdown": "https://aifitnessapi.com/test/provider-sandboxes.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Should I wait for a provider sandbox before writing integration tests?",
          "answer": "No, and the answer does not depend on whether one exists. Even a perfect hosted sandbox is the wrong target for continuous integration: its data is a living person's body and retro-edits itself under your assertions, its token state is shared so two parallel CI jobs look like a stolen-refresh-token attack, its quota is shared and the backfill test is the one that eats it, and its responses are real health data landing in your CI logs. Build the local fake now and keep one real account for a manual reality check. On Fitbit specifically: we could not confirm a sandbox either way on 2026-07-30, because every Fitbit developer host was refused by our outbound proxy, which is a fact about our network rather than about Fitbit. Check their current documentation and write the date beside whatever you find.",
          "url": "https://aifitnessapi.com/test/provider-sandboxes#faq-1"
        },
        {
          "question": "Why did a test that passed for three weeks against a real provider account suddenly go red?",
          "answer": "Almost certainly because the data moved, not because your code did. Wearable days get retro-edited when a device syncs late, sleep gets re-staged hours after the fact, and a second device joining the account starts contributing overlapping intervals. Any assertion on a live account's values has a shelf life of days. Assert on values only against fixtures you control, and use the real account only to check that the fixtures still resemble the provider.",
          "url": "https://aifitnessapi.com/test/provider-sandboxes#faq-2"
        },
        {
          "question": "How often should the contract test against the real provider run?",
          "answer": "On a named trigger rather than a cadence you will forget: before a release, and whenever the provider announces an API version change. Quarterly is a floor. Two rules make it survive: it must be allowed to fail without blocking a merge, because it is non-deterministic by construction, and the date of its last successful run must be committed to the repository. A fake's authority is exactly as old as its last contract check.",
          "url": "https://aifitnessapi.com/test/provider-sandboxes#faq-3"
        },
        {
          "question": "Can one real staging account replace the fake?",
          "answer": "No, and the ceiling is low. One account is one body, one timezone, one device mix and one history depth. It cannot give you a user whose local midnight differs from yours, two devices contributing overlapping samples, four years of history to exercise backfill pagination and quota, or a user who revokes consent mid-sync. That variation belongs in the fake. The staging account is a calibration instrument, not a test environment.",
          "url": "https://aifitnessapi.com/test/provider-sandboxes#faq-4"
        },
        {
          "question": "What should a fake return that a provider's own sandbox probably would not?",
          "answer": "Ugly days and rude faults. Two overlapping sleep segments from two devices, a day retro-edited between two reads, a night crossing a DST transition, a mid-day gap, a device clock two minutes off. On the fault side: a 429 with no Retry-After header at all, since RFC 6585 makes that header a MAY rather than a MUST, a Retry-After expressed as an HTTP-date rather than seconds, a truncated body, and an HTML error page from a CDN instead of JSON. A vendor sandbox is built to demonstrate the happy path; your fake exists to attack it.",
          "url": "https://aifitnessapi.com/test/provider-sandboxes#faq-5"
        }
      ]
    },
    {
      "question": "test strava webhook locally",
      "answer": "Write a test that POSTs the same signed delivery twice and asserts the user's day is unchanged and exactly one fetch job was enqueued. The constraint that shapes it is that most fitness webhooks are thin change pointers rather than data, so your handler's only real job is enqueueing work, and a duplicate processed twice silently doubles a step count instead of raising anything. Assert on the effect, not the status code: a correct handler returns 200 to a duplicate by design, so a test that checks for 200 twice cannot fail.",
      "title": "Testing Webhooks Locally: Replay Signed Payloads, Not Just the Handshake",
      "url": "https://aifitnessapi.com/test/webhooks-locally",
      "markdown": "https://aifitnessapi.com/test/webhooks-locally.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Do I need a tunnel like ngrok to test a webhook handler?",
          "answer": "Only for the subscription handshake and a first manual smoke test, because the provider has to reach a public HTTPS URL. Every test that matters afterwards runs faster and more deterministically without one, since you are POSTing fixture bytes straight at your own handler. A tunnel proves reachability, not correctness, and it should never be a CI dependency.",
          "url": "https://aifitnessapi.com/test/webhooks-locally#faq-1"
        },
        {
          "question": "How do I prove a replayed delivery did not double a user's step count?",
          "answer": "POST byte-identical bodies with the same delivery id twice, then assert two things that have nothing to do with the response: exactly one fetch job was enqueued, and the stored value for that civil day is unchanged. Asserting the endpoint returned 200 both times cannot fail, because a correct handler acknowledges duplicates so the provider stops retrying. The observable state is the only thing that distinguishes a no-op from doing the work twice.",
          "url": "https://aifitnessapi.com/test/webhooks-locally#faq-2"
        },
        {
          "question": "What should a webhook test assert on when the payload is only a change pointer?",
          "answer": "On the job that got enqueued. Most fitness notifications carry a subject, a metric and a window rather than values, so the handler resolves the subject and queues a fetch. Assert the job count, and assert the job key is the user, provider, metric and window, so that repeated notifications about the same day collapse into one API call. Asserting that a fake provider client was called only proves your fake is wired up.",
          "url": "https://aifitnessapi.com/test/webhooks-locally#faq-3"
        },
        {
          "question": "How do I test signing key rotation before the rotation happens?",
          "answer": "Standard Webhooks makes the signature header a space-delimited list of signatures precisely to allow zero-downtime secret rotation, so sign one body with the outgoing secret and one with the incoming secret, put both in a single header, and assert your verifier accepts it while both are configured. Then remove the old secret and assert the same request is rejected. A verifier written against one signature string passes for months and fails on the morning you rotate.",
          "url": "https://aifitnessapi.com/test/webhooks-locally#faq-4"
        },
        {
          "question": "Why does my signature check pass in tests but fail against the real provider?",
          "answer": "Almost always because the test signs the parsed object rather than the bytes. The Standard Webhooks spec calls this out as a very common failure mode: consumers parse the body as JSON and then serialize it again, and even a stray space breaks the signature. Sign a raw byte string held as a fixture and push those exact bytes through the real request path including body-parsing middleware, so the test is capable of catching it.",
          "url": "https://aifitnessapi.com/test/webhooks-locally#faq-5"
        }
      ]
    },
    {
      "question": "test api rate limit handling 429",
      "answer": "Point the fault injection at a historical backfill rather than at your retry helper, and assert observable outcomes: no date window silently skipped, a resumed job that re-requests zero completed windows, a bounded retry budget, and recovery traffic that is spread rather than synchronised. RFC 6585 section 4 defines 429 and makes Retry-After a MAY, so a named no-header case with your own backoff is mandatory, not a nice-to-have. Provider quotas are provider-specific and frequently unpublished, so design the job to degrade instead of tuning it to a figure. Test the slow response too, because it ties up workers silently while an outage at least fails loudly.",
      "title": "Testing 429 Rate-Limit and Outage Handling in a Health Backfill",
      "url": "https://aifitnessapi.com/test/rate-limits-and-outages",
      "markdown": "https://aifitnessapi.com/test/rate-limits-and-outages.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "How do I test 429 handling when the provider never sends a Retry-After header?",
          "answer": "RFC 6585 section 4 defines the 429 status code and says a response MAY include Retry-After, so a compliant provider is allowed to omit it. Add a named case where your fake returns 429 with no header at all and assert the client falls back to your own exponential backoff with jitter rather than busy-looping or raising on the missing key. Add a second case where Retry-After is an HTTP-date instead of an integer, which RFC 9110 also permits and which a parser that only calls int() will reject.",
          "url": "https://aifitnessapi.com/test/rate-limits-and-outages#faq-1"
        },
        {
          "question": "Should fault injection live in the retry helper's unit test or in the fake provider?",
          "answer": "In the fake. A unit test that hands a synthetic 429 to your backoff function asserts that your code slept the number your code computed, which is a test that cannot fail. Injecting the same fault at the HTTP boundary exercises the client, the response parser, the checkpoint writer and the worker pool together, and that combination is where the real defects are.",
          "url": "https://aifitnessapi.com/test/rate-limits-and-outages#faq-2"
        },
        {
          "question": "How do I prove a backfill resumes from its checkpoint instead of restarting?",
          "answer": "Have the fake log every request it serves, tagged with a run id. Run the job until the storm kills it, record which date windows committed, restart the worker against the same checkpoint store, and assert that the second run issued zero requests for windows the first run had already marked done. Then assert the final set of terminal windows covers the requested range exactly once.",
          "url": "https://aifitnessapi.com/test/rate-limits-and-outages#faq-3"
        },
        {
          "question": "Why is a slow provider response worse than an outage in a backfill test?",
          "answer": "An outage fails fast, so the window re-queues and the worker is free almost immediately. A response that arrives just inside your client timeout holds that worker for its whole duration, produces no errors to alert on, and cannot be compensated for by adding workers wherever the provider counts its quota per consented user rather than per app — which shape you are facing is usually undocumented, so assume the worse one. The only observable is that the job runs far past its budget, so assert a wall-clock bound on the entire job rather than on individual calls.",
          "url": "https://aifitnessapi.com/test/rate-limits-and-outages#faq-4"
        },
        {
          "question": "What should a test assert about recovery after a rate-limit storm?",
          "answer": "That the resumed traffic is spread out. Rate-limit every user in the fixture, restore success responses at a known instant, bucket the arrival times the fake recorded, and assert no bucket exceeds the share of quota you are willing to spend. Fixed backoff without jitter passes every single-user test and then synchronises every worker onto the same second the moment the provider recovers.",
          "url": "https://aifitnessapi.com/test/rate-limits-and-outages#faq-5"
        }
      ]
    },
    {
      "question": "test camera app ios simulator",
      "answer": "Write the assertion against a recorded video fixture rather than against a camera: push a known workout clip through the shipping pipeline and assert the rep count. Apple's AVCam documentation states that Simulator has no access to device cameras, and the Android emulator offers only a host webcam or an imported PNG or JPEG still, so a file is the only frame source both platforms can drive in CI. That forces one decision on day one, namely that every frame enters through an injectable frame source, because retrofitting the seam means re-deriving timestamps, orientation, backpressure and end-of-stream, which is a rewrite and not a refactor. On iOS, run Vision requests over the file with VNVideoProcessor instead of trying to give the Simulator a camera.",
      "title": "Testing Camera Features When You Have No Camera",
      "url": "https://aifitnessapi.com/test/camera-features-without-a-device",
      "markdown": "https://aifitnessapi.com/test/camera-features-without-a-device.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Why is adding a frame-source seam later a rewrite rather than a refactor?",
          "answer": "Because a capture session silently supplies five things besides pixels, and your analysis code will have come to depend on all of them. Timestamps: live code reads the wall clock, and a file replayed at decode speed makes that clock lie, so a tempo-sensitive rep counter rejects every rep in the fixture. Orientation: the capture connection knows the device orientation and the lens, and a file knows neither, so left-right joint mirroring becomes untestable. Pixel format: capture picks one, your decoder picks another. Backpressure: live pipelines drop late frames to stay real-time and a test must not, or the same fixture yields different counts on a loaded runner. End of stream: a live camera never ends and a file always does, so a pipeline with no flush path never completes the final rep and the test simply hangs. Inserting an interface is easy. Re-deriving those five contracts across a shipped pipeline is not.",
          "url": "https://aifitnessapi.com/test/camera-features-without-a-device#faq-1"
        },
        {
          "question": "Does VNVideoProcessor let me run body pose detection over a video file instead of a camera?",
          "answer": "Yes, and it is Apple's documented path for it. Apple describes VNVideoProcessor as an object that performs offline analysis of video content: you create it from a URL, attach requests with addRequest with processing options, and call analyze over a CMTimeRange. Two documented properties make it unusually good for tests. Apple documents analyze as synchronous, returning when the processor finishes the time range, so the results are complete on the next line and the test is deterministic. And sampling is configurable through RequestProcessingOptions cadence, with frame-rate and time-interval cadence types, so the fixture is analysed at a pinned rate rather than at whatever the hardware delivered. One qualification: Apple documents this as offline video analysis, not as a testing facility, so using it as a pose harness is our inference from documented behaviour. If your logic depends on temporal continuity, VNSequenceRequestHandler is the handler that takes frames one at a time.",
          "url": "https://aifitnessapi.com/test/camera-features-without-a-device#faq-2"
        },
        {
          "question": "Can the Android emulator play a recorded workout video into my camera pipeline?",
          "answer": "No. Google documents importing a still image in PNG or JPEG format into the virtual scene through the Extended controls window, the Camera tab, Virtual scene images, and Add image, and the emulator console exposes a virtualscene-image command taking wall or table plus an image path, which makes it scriptable from CI through the adb emu shortcut. But that is a still picture pasted onto a wall or a table inside a 3D scene, and Google's own stated use case is custom images such as QR codes. It is not a moving human, so it will not exercise a rep counter or anything that depends on motion between frames. The webcam back-end passes through your development machine's webcam, which is live and by construction not reproducible. Use the emulator to prove the capture plumbing, and use files for the analysis.",
          "url": "https://aifitnessapi.com/test/camera-features-without-a-device#faq-3"
        },
        {
          "question": "Are third-party tools that stream a Mac camera into the iOS Simulator worth depending on?",
          "answer": "They exist and they are all unofficial. As of 30 July 2026 we could read one of them directly: a macOS menu-bar app from Software Mansion that lets the Simulator use the Mac camera with images, videos or generated QR codes as sources, requiring no application code changes, shipping a command-line tool and carrying separate CI licensing. Two other commonly cited sources, a commercial simulator utility and a well-known Swift blog article, were unreachable from our research environment, so we describe no current behaviour for them. Our recommendation is to treat all of these as convenience for local development, not as CI infrastructure. Even the popular Designed for iPad on macOS trick, which is a developer suggestion on the Apple forums rather than Apple guidance, hands you a laptop webcam at laptop height with a laptop field of view, which is not the camera your users point at their squat.",
          "url": "https://aifitnessapi.com/test/camera-features-without-a-device#faq-4"
        },
        {
          "question": "What breaks on real hardware after a green video-fixture run?",
          "answer": "Five things, and they are the reason the fixture suite is a floor rather than a ceiling. Auto-exposure hunting in a dim room produces motion blur that wrecks wrist and ankle keypoints, and your fixture was filmed in whatever light you filmed it in. Sustained frame rate drops as a phone warms over a twenty-minute session, which a ninety-second clip on a cold runner never shows. Real permission dialogs, including the deny-then-open-settings path, only exist on a real OS. Front-camera mirroring as the hardware actually reports it is where left-right joint swaps live. And older accelerators may take a different delegate path with different numerics. Our recommendation is a fixed twenty-minute manual device script per release covering two lighting conditions and both cameras on your oldest supported device, plus production telemetry on dropped-frame rate, delivered FPS percentiles and the per-joint confidence distribution, which shifts before users complain and costs you no user video.",
          "url": "https://aifitnessapi.com/test/camera-features-without-a-device#faq-5"
        }
      ]
    },
    {
      "question": "how to test pose estimation accuracy",
      "answer": "Write a test that replays a fixed set of labelled clips through an explicitly pinned model revision and fails when any keypoint your product actually reads drifts outside a per-keypoint tolerance. The constraint is that no published benchmark figure tells you anything about your camera, your exercises or your users, so every threshold has to be derived from footage you labelled yourself and from the displacement at which your own rep verdict flips. Score per keypoint rather than as one aggregate, because a mean over nineteen joints hides the ankle regression that breaks your squat counter. And label occlusion as a state rather than scoring it as a miss, or the suite will punish the model for correctly admitting it cannot see a hidden joint.",
      "title": "Testing Pose Estimation Accuracy with a Regression Corpus",
      "url": "https://aifitnessapi.com/test/pose-detection-accuracy",
      "markdown": "https://aifitnessapi.com/test/pose-detection-accuracy.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Why would a mean keypoint error improve while the rep counter gets worse?",
          "answer": "Because the mean is averaging the joint you depend on against fifteen you never read. Your rep logic probably reads four joints. Apple's Vision body-pose observation exposes up to nineteen and other model families expose more, and most of the extra ones sit on the torso, which is the easiest region in the frame to predict. So a version that got better at shoulders and worse at ankles can move the aggregate in the flattering direction while your squat counter stops crossing its knee-angle threshold on the shallower reps. Score the per-keypoint residual instead. Rolled-up scores exist for ranking models against each other, and you are not ranking models — you are asking whether one specific joint got worse.",
          "url": "https://aifitnessapi.com/test/pose-detection-accuracy#faq-1"
        },
        {
          "question": "What pixel tolerance should I set for each keypoint?",
          "answer": "One you measured, in a scale-normalized unit, and nobody can give it to you. The tolerance is not a computer-vision constant, it is a property of your own downstream decision. Derive it by naming the scalar your feature thresholds, such as a knee angle, then taking a labelled decision frame and displacing that joint's ground truth by increasing amounts until the verdict flips. That displacement is your break-even, and the tolerance is a fraction of it, with the fraction being an explicit safety margin rather than a measurement. Express the result normalized by a body-derived length such as torso length or bounding-box height, not in raw pixels, so clips at different resolutions and standing distances are comparable. That is the same reasoning behind head-size normalization in PCKh. Re-derive whenever the rep logic changes.",
          "url": "https://aifitnessapi.com/test/pose-detection-accuracy#faq-2"
        },
        {
          "question": "How should the suite score a keypoint that was genuinely occluded?",
          "answer": "By scoring confidence rather than position, otherwise you will tune the suite until it prefers a model that guesses. Ground truth should carry a state per joint per frame with three values: visible, occluded, and out of frame. Visible joints get their position compared against the tolerance. Occluded joints get their position unscored and their confidence asserted to have dropped, because a hidden joint has no visual evidence and declining to report it is correct behaviour. Out-of-frame joints should be absent or at the confidence floor. Apple's documented rule for its body-pose points is to ignore recognized points with a confidence value of zero because they are invalid, which is the framework telling you absence is a legitimate answer. The asymmetry matters: a model that returns a confident plausible coordinate for a hidden joint is worse than one that returns low confidence, and a position-only metric scores them identically whenever the guess lands near the truth.",
          "url": "https://aifitnessapi.com/test/pose-detection-accuracy#faq-3"
        },
        {
          "question": "Should a pose accuracy regression fail the build, or just get reported?",
          "answer": "Both, split by clip category, and the split is a product decision rather than a technical one. The real question is whether it is acceptable for the counter to miss one rep in fifty for users filming from a three-quarter angle, and that is a call about a user-visible promise. Encode it once instead of relitigating it per pull request while a release is blocked. Two tiers work: a hard gate where any per-keypoint breach on a fair-condition clip fails the build with no averaging, and a tracked budget on clips that are deliberately outside the documented operating envelope, reported every run and reviewed when it moves. The gate is binary because averaging is exactly how a real regression gets absorbed. The budget exists because a suite that goes red for a condition you already documented as hard trains everyone to ignore it.",
          "url": "https://aifitnessapi.com/test/pose-detection-accuracy#faq-4"
        },
        {
          "question": "How do I make a pose SDK upgrade show up as a visible diff?",
          "answer": "Pin the model version in both production code and the test, then commit the numbers. On iOS the body-pose request carries an explicit revision, and Apple documents both the revision constant and a supported-revisions list, so you can assert that the set of revisions you expect is the set that exists. When an OS update adds one, that assertion fails and becomes the prompt for someone to look at the new revision against the corpus and move deliberately. If the model ships as a vendored asset file instead, hash it and assert the hash. Write a results file recording the revision or hash, the OS version, the runner identity and the per-keypoint residuals, and commit it, because the diff on that file is what a reviewer actually reads. One caution: output is not guaranteed bit-reproducible across hardware or OS, so a baseline is per-configuration and changing the runner is a knowing re-baseline, not a pass.",
          "url": "https://aifitnessapi.com/test/pose-detection-accuracy#faq-5"
        }
      ]
    },
    {
      "question": "test rep counting algorithm",
      "answer": "Score a rep counter against a labelled corpus as a classifier, but do not gate on aggregate precision and recall — gate on per-clip baseline movement, because two clips can break in opposite directions while the aggregate sits perfectly still. Comparing final counts per clip is weaker still: a miss and a double-count cancel and the suite passes on a counter that is wrong twice. Miscounts are uniquely damaging because the user was counting along in their own head and knows you are wrong.",
      "title": "How to Test a Rep Counting Algorithm",
      "url": "https://aifitnessapi.com/test/rep-counting",
      "markdown": "https://aifitnessapi.com/test/rep-counting.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Why is comparing the final rep count not enough?",
          "answer": "Because errors cancel. A clip where the counter misses one rep and double-counts another produces the correct total and a passing test, while the counter is wrong twice. You need per-rep alignment against labelled timestamps so a miss and a false positive both show up as what they are. The final count is a summary statistic, and summary statistics are exactly what hides compensating errors.",
          "url": "https://aifitnessapi.com/test/rep-counting#faq-1"
        },
        {
          "question": "How many clips does a rep-counting corpus need?",
          "answer": "We are deliberately not giving you a number, and you should distrust anyone who does without saying how they measured it. Coverage of failure modes is what matters, not volume: a corpus that deliberately contains partial reps, paused reps, off-frame limbs, tempo changes, a bad camera angle and a second person in frame will catch regressions that any quantity of clean sets filmed from one angle will not. Build it from the cases your own users generate, and grow it every time a real miscount is reported.",
          "url": "https://aifitnessapi.com/test/rep-counting#faq-2"
        },
        {
          "question": "Who should label the ground truth for a rep corpus?",
          "answer": "The person who performed the set should do the first pass, immediately, while they still remember it. Ground truth is what the human did, not what the camera could reasonably have seen — a rep performed with the wrists out of frame is still a rep — and intent is not recoverable from the video afterwards. Only the performer knows whether the movement at thirty-four seconds was a rep they abandoned or one they finished badly. Do not hand that first pass to general annotation labour that has not read your labelling policy: marking every frame where the bar touches the chest is outsourceable, but deciding whether something was a rep is a product judgement wearing the costume of a labelling task.",
          "url": "https://aifitnessapi.com/test/rep-counting#faq-3"
        },
        {
          "question": "Is over-counting or under-counting the worse rep-counting failure?",
          "answer": "They feel completely different to a user and you should refuse to collapse them into a single F-score, because that lets a gain in one silently pay for a regression in the other. Under-counting feels like theft: the user did the work, the app took it away, and they do an extra rep to get it back — so your bug just changed their training. Over-counting flatters in the moment and is usually not noticed until a personal record in their history turns out to be one they did not set. In our experience the right lean depends on the product: free-form tracking should bias toward recall, because the missed rep is the complaint that gets written down, while anything that auto-advances a set should lean the other way. Set two floors rather than one target.",
          "url": "https://aifitnessapi.com/test/rep-counting#faq-4"
        }
      ]
    },
    {
      "question": "ci for app that needs real device",
      "answer": "The assertion that justifies a device lab is a thermal soak: run one reference clip through the live capture pipeline eight times back to back on a physical phone. Fail the build if the count or the p95 frame latency drifted from pass one — no container can produce that number, and on iOS no simulator can produce a camera frame at all. Keep hosted CI for everything deterministic given bytes, and pick the device matrix by criteria rather than by model name — oldest supported chipset, weakest accelerator, one per camera-stack generation, one with a thermal ceiling. Run a small matrix on every build rather than a large one once a month.",
      "title": "CI for an App That Needs a Real Device",
      "url": "https://aifitnessapi.com/test/device-lab-and-ci",
      "markdown": "https://aifitnessapi.com/test/device-lab-and-ci.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I run my pose regression corpus on a hosted CI runner instead of a phone?",
          "answer": "Partly, and the split is worth making explicit. The logic that consumes keypoints — your rep state machine, your form thresholds, your smoothing — runs fine anywhere, so serialize keypoint sequences from a real device run of a clip you have already labelled, commit them as fixtures, and regression-test that layer on hosted CI for free. Those fixtures exercise the state machine only — they inherit whatever the pose model got wrong, so they never replace a video corpus. What cannot move is the inference itself: on a phone the model executes through an accelerator delegate, and an older or mid-tier one can fall back to CPU for a single unsupported op or take a different quantized path, producing keypoints that are subtly not the ones your container produced. And a hosted runner has no thermal behaviour at all, so latency assertions there are meaningless.",
          "url": "https://aifitnessapi.com/test/device-lab-and-ci#faq-1"
        },
        {
          "question": "Does Firebase Test Lab do camera image injection?",
          "answer": "We cannot tell you, and we would rather say so than guess. Our research environment could not reach firebase.google.com or cloud.google.com on 2026-07-30 — the proxy refused the connection — so nothing about Test Lab's fleet, API-level coverage or feature set was verifiable. What we did trace was camera image injection and microphone audio injection marketed by third-party device clouds, specifically LambdaTest and TestMu AI, in search results on that date, and we did not fetch their own documentation either. Check Google's docs directly before you design a camera test plan around Test Lab.",
          "url": "https://aifitnessapi.com/test/device-lab-and-ci#faq-2"
        },
        {
          "question": "How many devices belong in a fitness app's test matrix?",
          "answer": "Fewer than you want, chosen by criteria rather than by model name. The criteria we would use: the oldest chipset your app claims to support, so the claim gets falsified; one mid-tier Android where the accelerator is the bottleneck while the CPU spec still looks fine; one device per camera-stack generation you support; one thin, passively cooled device to own the thermal soak; one device that is genuinely common in your own analytics; and one iPhone, because iOS is device-only for anything camera-shaped. Take the smallest physical set that covers those and re-derive it quarterly from your install base.",
          "url": "https://aifitnessapi.com/test/device-lab-and-ci#faq-3"
        },
        {
          "question": "Why does my rep counter pass in CI and miss reps late in a long session on a mid-tier Android?",
          "answer": "Almost certainly thermal throttling changing your frame interval. A camera pose pipeline pins the camera, the ISP, the accelerator and the display simultaneously for twenty unbroken minutes, which is a sustained load almost nothing else on a phone produces, so your app finds a throttle curve other apps never touch. Nothing crashes; the SoC drops clocks, the inter-frame interval roughly doubles, and a rep sampled at 12 frames per second has a different shape than the same rep at 30, so temporal smoothing and velocity thresholds stop matching. Catch it by running the same clip repeatedly from a cold start and asserting that the count is identical across passes. That is a drift check — one clip against itself on one device — and not an accuracy test, because a total count can hide a miss cancelling a double-count.",
          "url": "https://aifitnessapi.com/test/device-lab-and-ci#faq-4"
        },
        {
          "question": "Which health sync tests actually need physical hardware?",
          "answer": "Far fewer than the camera tests. Token rotation races, webhook replays and duplicates, timezone day boundaries, deduplication and two-client offline conflicts are all bytes in and rows out, so they belong on hosted CI against recorded fixtures and injected faults. Android background behaviour mostly stays there too, because Doze can be forced with adb shell dumpsys deviceidle force-idle, which in our experience works against an emulator as well as a handset — Google's Doze documentation gives the commands but does not say either way. The one sync surface that genuinely requires a device is HealthKit background delivery: Apple states, on both the enableBackgroundDelivery documentation and the HKObserverQuery page, that background server queries are not supported on the Simulator and that you should test your background queries on a device.",
          "url": "https://aifitnessapi.com/test/device-lab-and-ci#faq-5"
        }
      ]
    },
    {
      "question": "test offline sync conflict mobile app",
      "answer": "Two sync engines in one test process, a fake server that holds no merge logic, an injected clock per client, and a seeded list of operations — that harness is the test. It is the only cheap way to reproduce what actually costs data: a watch and a phone both logging sets in a basement with no signal, flushing hours apart. Assert conservation on everything a person deliberately typed, and keep device-sourced samples in a separate suite, because there the assertion is the opposite one.",
      "title": "Testing Offline Sync and Conflict Resolution",
      "url": "https://aifitnessapi.com/test/offline-sync",
      "markdown": "https://aifitnessapi.com/test/offline-sync.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Why would adding content-hash deduplication to a workout log delete real sets?",
          "answer": "Because two identical sets are normal. Five reps at sixty kilos, logged twice ninety seconds apart, is a person doing their second set — not a duplicate delivery. Content hashing cannot tell those apart, so the moment someone adds it to close a duplicate-set report they start silently deleting genuine work. Write a guard test now, before anyone is tempted: one client, two identical sets ninety seconds apart, assert both survive.",
          "url": "https://aifitnessapi.com/test/offline-sync#faq-1"
        },
        {
          "question": "What should an offline workout sync test assert on?",
          "answer": "Three properties, all stated as things a user would see. Conservation: every set, weight correction and deletion the person performed is either in the folded session, superseded by a later event that names it, or in a tombstone with a cause. Convergence: the same events delivered in any order produce the same session and the same day rollup. Repeatability: the same seed produces the same result on every machine. Count conservation from the operation log outside the engine, never from a ledger the engine keeps.",
          "url": "https://aifitnessapi.com/test/offline-sync#faq-2"
        },
        {
          "question": "What breaks when someone is offline across an app update?",
          "answer": "The migration you did not notice was a migration. A shape change — bare kilograms becoming a value-and-unit pair — is caught by any decoder. A meaning change is not: a reps count that used to include warm-up sets and now does not will decode cleanly and quietly rewrite the person's personal-record history. Test it with frozen bytes captured from the shipped version and checked into the repo, and assert on the folded number rather than on whether parsing succeeded.",
          "url": "https://aifitnessapi.com/test/offline-sync#faq-3"
        },
        {
          "question": "Where does a set logged at 23:58 belong after it syncs at 00:40?",
          "answer": "On the previous civil day, and its rollup has to be recomputed to say so. The offline flush that crosses midnight is the common way this goes wrong in production, and the test that only checks the raw row landed will pass while the weekly volume chart stays wrong, because nothing recomputes a day nobody told it had changed. Re-run the same scenario with the watch clock a few minutes fast and it becomes 00:02, from a device that is barely wrong.",
          "url": "https://aifitnessapi.com/test/offline-sync#faq-4"
        },
        {
          "question": "Do device samples need the same conflict tests as user entries?",
          "answer": "No, and the practical rule is to never share an assertion helper between them. A no-duplicates helper written for a step stream will one day delete a real second set of five; a nothing-was-lost helper written for a set log will one day defend a doubled day as though it were data. Device samples belong in a deduplication suite whose assertion lands on the rollup. Do not run them through the conflict harness at all — nobody can arbitrate whether the watch or the phone counted a flight of stairs better.",
          "url": "https://aifitnessapi.com/test/offline-sync#faq-5"
        }
      ]
    },
    {
      "question": "how to verify user data deleted",
      "answer": "Write one assertion per store, with the store list enumerated from a registry checked into the repo, so the suite fails the day someone adds a table and forgets to purge it. The constraint that shapes every assertion here is RFC 7009: a token revocation endpoint returns HTTP 200 even for an invalid token, so a test that asserts revocation returned 200 cannot fail and proves nothing. Assert on the observable consequence instead — the next provider call fails, no new samples arrive after the tombstone, the connection row is gone. Never assert on the purge job's return value; assert on the stores it was supposed to empty.",
      "title": "Testing That a User's Health Data Is Actually Deleted",
      "url": "https://aifitnessapi.com/test/data-deletion",
      "markdown": "https://aifitnessapi.com/test/data-deletion.md",
      "cluster": "Testing",
      "cluster_url": "https://aifitnessapi.com/test",
      "last_reviewed": "2026-07-27",
      "first_party": false,
      "faqs": [
        {
          "question": "Why does asserting a 200 from a token revocation endpoint prove nothing?",
          "answer": "Because RFC 7009 requires it. The specification says the authorization server responds with HTTP status code 200 if the token has been revoked successfully or if the client submitted an invalid token, and explains that invalid tokens do not cause an error response since the client cannot handle such an error in a reasonable way. A conforming provider therefore returns 200 for a token you made up, a token that expired last year, and a token you never sent. An assertion on that status code is asserting that you sent a well-formed POST over HTTPS. It cannot fail on a system where revocation is completely broken, which makes it worse than having no assertion at all, because it reads as coverage in a test report.",
          "url": "https://aifitnessapi.com/test/data-deletion#faq-1"
        },
        {
          "question": "How do I make a deletion test fail when someone adds a new store and forgets to purge it?",
          "answer": "Do not hand-write the store list in the test. Keep a registry file in the repo with one entry per store, then write a test that discovers stores by introspection and fails on anything undeclared: every table carrying a user id or provider account id from the information schema, every queue topic, every search index, every object-storage prefix, every cache keyspace. The diff between discovered and declared is the assertion. Adding a table without a registry entry then breaks the build on the branch that added it, which is the only point at which the person who knows what the table holds is still looking at it. Give each registry entry a probe function that answers whether the store still holds a given user, and the same registry drives both the completeness check and the per-store sweep.",
          "url": "https://aifitnessapi.com/test/data-deletion#faq-2"
        },
        {
          "question": "What is the right assertion for a store whose delete is asynchronous, like a search index?",
          "answer": "Poll a read until a bounded timeout, and assert on the read result rather than on the delete call's status. Index deletions are frequently applied asynchronously, so a purge that returns success can still serve a hit for a while, and a test that checks only the return code will pass against an index that never applied the change. The same shape applies to any store with an acknowledged propagation window, including provider token revocation, where RFC 7009 explicitly acknowledges a delay in which some servers know about the invalidation while others do not. Bound the wait, fail on timeout, and record the observed convergence time so a regression that stretches it becomes visible instead of merely slow.",
          "url": "https://aifitnessapi.com/test/data-deletion#faq-3"
        },
        {
          "question": "What does a restore drill have to check before backup erasure is more than a claim?",
          "answer": "That a previously deleted user is still absent after the restore completes. Nobody surgically edits a snapshot, so the honest design is a documented retention window per backup class plus deletion-on-restore, and deletion-on-restore is the step that rots because restores are rare. The drill assertion is concrete: restore a snapshot into a scratch environment, run the tombstone replay as the first runbook step, then run the same per-store sweep the deletion suite uses against the restored copy and assert zero rows for every tombstone recorded since the snapshot was taken. A drill that only verifies the database came back up does not test the part of erasure that involves backups at all.",
          "url": "https://aifitnessapi.com/test/data-deletion#faq-4"
        },
        {
          "question": "What can only a real provider account prove about a revoked wearable grant?",
          "answer": "That the grant is genuinely dead upstream, which is the single thing a fake cannot tell you, because a fake returns whatever you programmed into it. Keep one real staging account per provider, run it on a slow cadence, and assert the consequence: after revocation an authenticated call to that provider fails, and nothing new arrives for that user inside a fixed observation window. Poll to a bounded timeout rather than asserting immediate failure, because RFC 7009 acknowledges that some of a provider's servers learn about an invalidation before others do. Everything else stays in CI against the local fake, where you can assert the part that actually breaks: that revocation is attempted before the first destructive purge task, and that a payload delivered after the tombstone creates no rows and no resurrected user. Do not point CI at a live provider, and do not let a fake be the only thing you ever revoke against.",
          "url": "https://aifitnessapi.com/test/data-deletion#faq-5"
        }
      ]
    },
    {
      "question": "oauth refresh token rotation code example",
      "answer": "Refresh-token rotation breaks integrations in four predictable ways: concurrent refreshes race each other into invalid_grant, the returned refresh token is not persisted, a 401 retry loop hammers the provider, and a dead grant gets retried forever. This recipe is a small JavaScript token client that closes all four — refresh is single-flight per user, both tokens are written in one atomic save that is awaited before the promise resolves, a 401 buys exactly one refresh and one retry, and invalid_grant marks the grant dead instead of retrying. The store, the clock and fetch are all injected, so it runs in tests without a network. Copy it, swap the store for your database, and keep the tests.",
      "title": "Recipe: Single-Flight Refresh-Token Rotation",
      "url": "https://aifitnessapi.com/cookbook/refresh-rotation",
      "markdown": "https://aifitnessapi.com/cookbook/refresh-rotation.md",
      "cluster": "Cookbook",
      "cluster_url": "https://aifitnessapi.com/cookbook",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Is this recipe safe to paste into a production backend?",
          "answer": "It is written to be, with one caveat about scale. The logic — per-user single flight, atomic persistence, bounded retry, dead-grant terminal state — is what a correct implementation needs, and the test file holds it to that contract on every CI run. The caveat is that the in-flight lock is a Map inside one process, so it serializes refreshes within a single worker only. If several processes or pods can refresh the same user at the same time, keep this shape but back the lock with something shared, such as a Postgres advisory lock or a Redis lock keyed by user id.",
          "url": "https://aifitnessapi.com/cookbook/refresh-rotation#faq-1"
        },
        {
          "question": "How would I plug my own database into the grant store?",
          "answer": "Implement two methods: load(userId), returning the stored record or null, and save(userId, record), writing the whole record in one statement. The single hard requirement is that save be atomic — one UPDATE setting the access token, the refresh token and the expiry together. A store that writes the access token in one statement and the refresh token in another recreates the exact bug this recipe exists to prevent, because a crash between the two leaves you holding a refresh token the provider has already invalidated.",
          "url": "https://aifitnessapi.com/cookbook/refresh-rotation#faq-2"
        },
        {
          "question": "What does the client do when the token endpoint returns 503 rather than invalid_grant?",
          "answer": "It raises a retryable error and leaves the stored grant completely untouched. That distinction is deliberate: invalid_grant means the credential is gone and no retry can help, so the grant is marked dead and the tokens are cleared. Anything else — a 5xx, a proxy hiccup, invalid_client — is transient from the grant's point of view. Clearing a good refresh token on an outage converts a bad afternoon into a re-authorization campaign across your whole user base.",
          "url": "https://aifitnessapi.com/cookbook/refresh-rotation#faq-3"
        },
        {
          "question": "Does the recipe still work with a provider that does not rotate refresh tokens?",
          "answer": "Yes, and that is the point of writing it this way. When the token response omits refresh_token, the client keeps the one it already had, so the same code path serves rotating and non-rotating providers. Treating every refresh token as single-use is the rule that is safe everywhere: it costs nothing against a provider that returns the same value, and it is the only correct behaviour against one that does not.",
          "url": "https://aifitnessapi.com/cookbook/refresh-rotation#faq-4"
        }
      ]
    },
    {
      "question": "idempotent webhook receiver code example",
      "answer": "A duplicated health webhook does not throw — it lands in an aggregate and quietly doubles somebody's day. This recipe is one ingest function that makes that impossible by construction: it verifies the HMAC over the raw request bytes before anything parses them, dedupes the delivery on its id, enqueues a thin pointer instead of trusting payload values, gates every effect on a monotonic version so an out-of-order delivery is a no-op, and routes a poisoned delivery to a dead-letter queue while still acknowledging. Every collaborator is injected, so the whole replay suite runs with no network and no tunnel. The behaviour is argued in full on the webhook ingestion page; this is the code.",
      "title": "Recipe: A Replay-Safe Health Webhook Receiver",
      "url": "https://aifitnessapi.com/cookbook/webhook-receiver",
      "markdown": "https://aifitnessapi.com/cookbook/webhook-receiver.md",
      "cluster": "Cookbook",
      "cluster_url": "https://aifitnessapi.com/cookbook",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Why acknowledge a delivery that blew up inside the handler?",
          "answer": "Because replaying the same bytes hits the same defect. The signature already proved who sent it, so answering with a 500 buys nothing except an escalating retry storm — and on platforms with an endpoint-disable policy, eventually an endpoint the provider stops talking to. The delivery goes to a dead-letter queue carrying the affected window, and recovery is a replay that re-pulls that window against a fixed adapter rather than re-applying a stored payload.",
          "url": "https://aifitnessapi.com/cookbook/webhook-receiver#faq-1"
        },
        {
          "question": "Why does the enqueued job carry a window instead of the numbers from the payload?",
          "answer": "Most fitness notifications are change pointers rather than data carriers, so the values in the body are either absent or untrustworthy. Keying the job on user, provider, metric and window makes the effect idempotent by construction: re-fetching a window and replacing what you hold is naturally repeatable, while parsing a delta out of a ping and applying it never will be. It also collapses eleven pings about the same Tuesday into one provider call.",
          "url": "https://aifitnessapi.com/cookbook/webhook-receiver#faq-2"
        },
        {
          "question": "Which parts of this file will I have to rewrite for my provider?",
          "answer": "Three, and they are isolated for exactly that reason. The hmac function, because signature schemes differ per vendor and some are not publicly documented. The header names, because the id, timestamp and signature headers are vendor-specific. And parsePointer, because only you know how your provider names its subject id, metric and window. Write the fixture from a real captured delivery rather than from a spec example, and the rest of the file stays as it is.",
          "url": "https://aifitnessapi.com/cookbook/webhook-receiver#faq-3"
        },
        {
          "question": "What stops a late delivery from resurrecting a user who asked to be erased?",
          "answer": "Subject resolution happens before any store is touched, and an unresolvable subject is acknowledged and dropped with no row written anywhere — not a delivery row, not a dead-letter row. The dead-letter queue is a store like any other and it is the one teams forget. The resolver must also be driven by a tombstone rather than by a missing user row, or an ingest path that reads absence as create-one will pass against an empty test database and resurrect a real erased person in production.",
          "url": "https://aifitnessapi.com/cookbook/webhook-receiver#faq-4"
        }
      ]
    },
    {
      "question": "retry after 429 exponential backoff fetch wrapper",
      "answer": "Fitness providers meter reads per consented user, so one runaway backfill starves that user and adding workers makes it worse. This recipe is a fetch wrapper that tracks a per-user budget, honours Retry-After in both the delay-seconds and HTTP-date forms, backs off 5xx with full jitter so a recovering provider does not get a synchronized stampede, opens a circuit that skips and records a gap rather than hammering a dead endpoint, and never replays a non-idempotent call it cannot prove failed. The clock, sleep, jitter source and fetch are injected, so the whole fault-injection suite runs against a fake clock in milliseconds. Nothing throws on an HTTP outcome: every call returns an envelope so the caller parks the window and moves on.",
      "title": "Recipe: A Rate-Limit-Aware Fetch Wrapper",
      "url": "https://aifitnessapi.com/cookbook/rate-limit-fetcher",
      "markdown": "https://aifitnessapi.com/cookbook/rate-limit-fetcher.md",
      "cluster": "Cookbook",
      "cluster_url": "https://aifitnessapi.com/cookbook",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Why does a 429 not count towards opening the circuit?",
          "answer": "A provider answering 429 is healthy and telling you the truth about your allowance. Tripping a breaker on it would degrade a service that is working correctly, and it would keep degrading for as long as you are over quota. In this wrapper only 5xx responses and transport errors increment the failure counter; a 429 consumes the retry budget instead, and once that budget is spent the call returns a rate-limited envelope with the time to retry so the caller can park the window.",
          "url": "https://aifitnessapi.com/cookbook/rate-limit-fetcher#faq-1"
        },
        {
          "question": "What makes full jitter better than a fixed backoff here?",
          "answer": "A fixed backoff passes every single-user test you will ever write and then synchronizes your whole fleet onto the same second the moment a provider recovers. Full jitter draws the delay uniformly from zero up to the exponential ceiling, which spreads recovery arrivals across the window instead of stacking them. That failure only shows up in a test with more than one user in the fixture, which is why the contract below asserts on the distribution rather than on a single sleep.",
          "url": "https://aifitnessapi.com/cookbook/rate-limit-fetcher#faq-2"
        },
        {
          "question": "Why does the wrapper return an envelope instead of throwing on failure?",
          "answer": "Because a backfill worker handling hundreds of windows should park the ones it could not read and carry on, not die on the first outage. Every call resolves with an outcome, the attempt count, how long it waited, and when it is worth trying again. Skipped and rate-limited outcomes also push an entry onto a gaps list, which is the input to the reconciliation sweep that eventually re-reads what you missed.",
          "url": "https://aifitnessapi.com/cookbook/rate-limit-fetcher#faq-3"
        },
        {
          "question": "How does the wrapper decide a call is too risky to replay?",
          "answer": "It looks at the method, and you can override it per call. GET, HEAD, OPTIONS, PUT and DELETE are treated as safe to repeat; POST and PATCH are not. When a call in the unsafe set dies in transit or comes back 5xx, the outcome is marked ambiguous and returned immediately with no retry, because the server may have applied the write before failing. A provider that documents a specific POST as idempotent can opt that one call back in.",
          "url": "https://aifitnessapi.com/cookbook/rate-limit-fetcher#faq-4"
        }
      ]
    },
    {
      "question": "group health samples by local day code example",
      "answer": "A copy-and-run implementation of the civil-date daily rollup: a writer that computes each sample's local date from its instant and its UTC offset at ingest, a rollup that groups strictly on that stored date and refuses to re-derive it at read time, and helpers that report how long a given civil day actually was. Plain modern JavaScript, no dependencies, Node 20 and above, with a node:test suite that injects the offset series and the sample store so nothing touches a clock or a network. The fixed-UTC-window version is exported alongside it, marked as the anti-pattern, so the tests can show exactly which samples it invents on a spring-forward day and which it loses in autumn. The pattern itself is argued on the timezones and day boundaries page; this is the code.",
      "title": "Day-Boundary Rollup: Grouping Samples by Civil Date",
      "url": "https://aifitnessapi.com/cookbook/day-boundary-rollup",
      "markdown": "https://aifitnessapi.com/cookbook/day-boundary-rollup.md",
      "cluster": "Cookbook",
      "cluster_url": "https://aifitnessapi.com/cookbook",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Where in a health pipeline should the local date get computed?",
          "answer": "At ingest, once, on the write path, and then stored as a real column. The writer in this recipe takes the instant and the UTC offset in effect at that instant and stamps the result onto the row before it reaches the store. Computing it later, in the query, means every daily read has to carry the user's full offset history in scope, gives up a plain index, and makes the answer to what were their steps on the 14th depend on where the user's phone happens to be when they ask. Denormalising one column buys a rollup that is indexable, transition-proof and travel-proof, and the cost is that you have to be willing to recompute the column when you learn an offset was wrong.",
          "url": "https://aifitnessapi.com/cookbook/day-boundary-rollup#faq-1"
        },
        {
          "question": "What should the writer do with a sample that arrives without an offset?",
          "answer": "Refuse it, loudly, rather than filling in a value. This implementation throws a TypeError instead of defaulting to UTC or to the device's current zone, because a filled-in offset is indistinguishable from an observed one a week later and it quietly rewrites every trip the user ever took. The practical handling is upstream of the writer: resolve the offset from the platform field, the device, or the recording zone at capture time, record which of those it was in the offsetSource column, and let anything you genuinely cannot resolve fail into a gap you can see. A recorded guess you can identify later is survivable; an invisible one is not.",
          "url": "https://aifitnessapi.com/cookbook/day-boundary-rollup#faq-2"
        },
        {
          "question": "How do I exercise a 23-hour day in tests without waiting for March?",
          "answer": "Inject the zone as a piecewise offset series rather than reading a real timezone database. The recipe's createOffsetSeries takes a list of segments, each a transition instant and the offset that takes effect there, and every helper resolves against that. So a spring-forward day is three lines of fixture, a traveller's 16-hour day is two segments built from that one user's own offset history, and the whole suite runs in milliseconds with no clock and no network. Keep the series out of production code, though: it is a stand-in built to reason about one transition, not a replacement for the real rules, which change when governments change them.",
          "url": "https://aifitnessapi.com/cookbook/day-boundary-rollup#faq-3"
        },
        {
          "question": "Can the rollup run against a real database rather than the in-memory store?",
          "answer": "Yes, and it is designed for that swap. The writer only ever calls put on whatever store you hand it, so a Postgres upsert keyed on the provider's own record identity drops straight in, and the rollup is a pure function over rows so it maps onto a group-by on the civil-date column. Two properties have to survive the swap. Writes stay idempotent on provider record identity, because a replayed window must be a no-op rather than a doubling. And the rollup write is an update rather than a do-nothing on conflict, or you pin a day to whichever partial value happened to arrive first that morning.",
          "url": "https://aifitnessapi.com/cookbook/day-boundary-rollup#faq-4"
        }
      ]
    },
    {
      "question": "rep counting state machine code example javascript",
      "answer": "A copy-and-run rep counter and the scoring harness that keeps it honest. The counter is a two-phase finite state machine over one smoothed joint angle, with an injectable EMA constant, separate up and down entry thresholds so jitter at one boundary cannot double-fire, a minimum phase duration that rejects a spike rather than delaying it, a confidence gate, and rep events emitted with timestamps. The scorer matches predicted rep timestamps one-to-one and greedily against labelled ground truth inside a tolerance window and reports precision and recall per clip, with no aggregate and no F-score anywhere, because both let a miss and a phantom cancel out. Plain modern JavaScript, no dependencies, Node 20 and above, with a node:test suite that runs on synthetic angle streams rather than a camera.",
      "title": "Rep Counter: A State Machine and the Scorer That Guards It",
      "url": "https://aifitnessapi.com/cookbook/rep-counter",
      "markdown": "https://aifitnessapi.com/cookbook/rep-counter.md",
      "cluster": "Cookbook",
      "cluster_url": "https://aifitnessapi.com/cookbook",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "What smoothing constant should the EMA use for a joint angle?",
          "answer": "There is no right value to copy, which is why it is a constructor argument here rather than a baked-in number. It is a straight trade: a heavier filter kills jitter and adds lag, and the lag is visible in this recipe's own end-to-end test as a systematic 52 millisecond delay on a two-second rep. Pick it against your frame rate and your movement tempo, then hold it still and let the corpus tell you when a change was worth it. Two practical notes. Setting it to 1 disables smoothing entirely, which is useful in tests where you want raw noise to reach the state machine. And if your signal is too noisy for an exponential average to handle, replace the filter behind the same seam rather than loosening the thresholds to compensate.",
          "url": "https://aifitnessapi.com/cookbook/rep-counter#faq-1"
        },
        {
          "question": "How do I choose the two hysteresis thresholds for a new exercise?",
          "answer": "Start from the joint whose angle swings most cleanly through the movement in the camera plane, then set the entry thresholds inside each extreme rather than at it, leaving a gap wide enough that ordinary keypoint noise cannot cross both. The gap is the hysteresis and it is the only thing preventing a double-count. This implementation throws at construction time if the two values are equal or inverted, so a mistake surfaces in your setup code rather than as a miscount in the field. Then calibrate: range of motion varies by body and mobility, so a pair that works for one person may never trigger for another, and the usual fix is a reference rep captured at the start of a set. Build the counter per set once you know the user's range.",
          "url": "https://aifitnessapi.com/cookbook/rep-counter#faq-2"
        },
        {
          "question": "Can I score the counter against keypoints my own pose model produced?",
          "answer": "Replaying recorded keypoint sequences captured from a real device run is exactly right, and this recipe is built for it: every frame carries its own timestamp, nothing reads a clock, so a whole corpus scores in milliseconds and the state machine regression-tests cheaply. What is circular is generating the clips themselves from the same pose model you are testing. That scores your state machine against your own model's opinion, and catching the cases where that opinion is wrong is the entire reason the corpus exists. The test is honest when the thing under test sits downstream of the recording, and dishonest when it is the recorder.",
          "url": "https://aifitnessapi.com/cookbook/rep-counter#faq-3"
        },
        {
          "question": "Why does the scorer return a null precision instead of a perfect score?",
          "answer": "Because a clip where nothing was predicted has no evidence about precision, and reporting 1.0 there would let a counter that fired zero times look flawless. The scorer returns null for a metric whose denominator is empty, and the same reasoning drives the rest of its output: no F-score, because collapsing the two lets a gain in one silently pay for a regression in the other, and no pooled figure across clips, because a pooled number is dominated by whichever exercise you filmed the most of. Under-counting and over-counting also do not feel remotely alike to a user, so they get two floors rather than one target. Gate the build on the per-clip diff instead, and let an improvement fail too, so accepting it means committing an updated baseline in the same change.",
          "url": "https://aifitnessapi.com/cookbook/rep-counter#faq-4"
        }
      ]
    },
    {
      "question": "resumable backfill checkpoint 429 retry code example",
      "answer": "A copy-and-run implementation of the resumable backfill job: newest-first civil-date windows that widen as they go back, a checkpoint written to an injectable store after each window commits rather than before, 429 and 5xx handled by retrying the same window with jittered exponential backoff and Retry-After as a floor, and an exhausted retry budget recorded as a gap carrying the window and the reason instead of silently advancing. A permission wall is a distinct terminal state that is never retried, and an unrecognised error crashes with the checkpoint intact rather than being laundered into a gap. Plain modern JavaScript, no dependencies, Node 20 and above, with a node:test suite that injects the fetcher, the sleeper, the clock and the store so the whole thing runs with no network and no waiting.",
      "title": "Backfill Checkpointer: A Resumable Window Walker",
      "url": "https://aifitnessapi.com/cookbook/backfill-checkpointer",
      "markdown": "https://aifitnessapi.com/cookbook/backfill-checkpointer.md",
      "cluster": "Cookbook",
      "cluster_url": "https://aifitnessapi.com/cookbook",
      "last_reviewed": "2026-08-12",
      "first_party": false,
      "faqs": [
        {
          "question": "Should the checkpoint be written before or after a window commits?",
          "answer": "After, always, and the ordering is the only reason this recipe offers any guarantee at all. Fetch, then commit, then checkpoint. Written in that order, a crash anywhere in the sequence leaves at most one window to redo, and the recipe's test suite proves it by failing the checkpoint write immediately after a window has committed and asserting the resumed run re-fetches exactly one window. Written the other way round, a crash between the checkpoint and the commit loses a window permanently and nothing downstream can tell. The price of the safe ordering is that the commit has to be idempotent on the provider's own record identity, because the redo is a re-commit.",
          "url": "https://aifitnessapi.com/cookbook/backfill-checkpointer#faq-1"
        },
        {
          "question": "What should a backfill worker do when its retry budget runs out on a window?",
          "answer": "Record the window and why it failed, then move on to the next one. Never mark it done and never let the walk stop. This implementation writes an entry carrying the window id, its civil-date bounds, a reason code, the attempt count and the last error, and it keeps that list in the checkpoint so it survives a restart. The reason the reason code matters is that each one implies a different next action: a retry-exhausted window is worth another pass later, while a window behind a permission wall is not, and collapsing them means either hammering the wall forever or abandoning recoverable history. What you must not do is advance quietly, because an advanced window is indistinguishable from a covered one afterwards.",
          "url": "https://aifitnessapi.com/cookbook/backfill-checkpointer#faq-2"
        },
        {
          "question": "How do I stop a recorded gap from being rendered as a zero-activity day?",
          "answer": "Keep the gap list as a first-class input to the display layer rather than as a log line. The walker returns the gaps and persists them, and the coverage report tells you how many days are covered against how many are gapped, which is the number a progress banner should use. Downstream, not imported yet, not permitted to read, and genuinely no activity have to render as three different empty states; a zero in place of the first two is a correctness bug rather than a display choice. Also suppress anything derived from a range that is still incomplete. A partial history produces a confident personal record the user knows they never set, and they remember the number long after the import finishes.",
          "url": "https://aifitnessapi.com/cookbook/backfill-checkpointer#faq-3"
        },
        {
          "question": "Is it safe to run two workers against one checkpoint store?",
          "answer": "Not as written, and that is deliberate. This walker owns its job and assumes one runner, because the guarantee it makes is about crash resumption rather than concurrency. To fan out, move claiming into the store: give each window a claimed-by and a claim expiry so a dead worker's window becomes reclaimable, and have workers claim the highest-priority unclaimed window rather than iterating a list. The other separation matters more in practice. Keep the backfill and the live incremental path in different queues with different cursors, and reserve a share of the per-user quota for the live path first, or a slow multi-year import makes today's data stale to complete a year nobody is looking at.",
          "url": "https://aifitnessapi.com/cookbook/backfill-checkpointer#faq-4"
        }
      ]
    },
    {
      "question": "connect a bluetooth heart rate monitor to an app",
      "answer": "A conforming Bluetooth heart rate monitor exposes the standardized Heart Rate service, so one integration works across straps and armbands from any vendor. The Bluetooth SIG's public assigned-numbers registry lists the Heart Rate service as 0x180D, Heart Rate Measurement as 0x2A37 and Body Sensor Location as 0x2A38. The flow is the same everywhere: scan filtered on the service UUID, connect, discover the service and its characteristics, enable notifications on the measurement characteristic, and read the body sensor location once for context. Parse the measurement value against the Heart Rate Service specification published by the Bluetooth SIG rather than against a copied snippet. Wrist and chest readings can differ because placement and sensor type differ, so record the source with every sample instead of assuming the two are interchangeable.",
      "title": "Connect a Bluetooth Heart Rate Monitor to Your App (2026)",
      "url": "https://aifitnessapi.com/devices/bluetooth-heart-rate-monitor",
      "markdown": "https://aifitnessapi.com/devices/bluetooth-heart-rate-monitor.md",
      "cluster": "Connected Devices",
      "cluster_url": "https://aifitnessapi.com/devices",
      "last_reviewed": "2026-08-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Which Bluetooth UUIDs does a heart rate strap use, and do I need one integration per brand?",
          "answer": "One integration covers conforming monitors. The Bluetooth SIG's assigned-numbers registry lists the Heart Rate service as 0x180D, the Heart Rate Measurement characteristic as 0x2A37 and Body Sensor Location as 0x2A38. Because those numbers are standardized, a chest strap and an optical armband from different vendors present the same interface: scan filtered on 0x180D, connect, discover by UUID rather than by handle, and enable notifications on 0x2A37. Vendor SDKs and cloud APIs are still useful for history, sleep and recovery data, but they are a separate integration answering a separate question.",
          "url": "https://aifitnessapi.com/devices/bluetooth-heart-rate-monitor#faq-1"
        },
        {
          "question": "What does the Body Sensor Location characteristic (0x2A38) actually tell my app?",
          "answer": "It reports where the monitor says it sits on the body. Treat it as provenance and as a UI label, not as anything you compute with. Read it once after connecting, store it alongside the samples so that later reconciliation has something to reason about, and degrade gracefully if the characteristic is not present on a given device. The one thing not to do is use it as a correction factor. Adjusting a reported heart rate because of a claimed sensor position invents precision your app does not have.",
          "url": "https://aifitnessapi.com/devices/bluetooth-heart-rate-monitor#faq-2"
        },
        {
          "question": "Why do a chest strap and a wrist watch report different heart rate for the same workout?",
          "answer": "Because they are different measurements, not the same measurement done well and badly. Wrist optical sensors and chest straps differ in both placement and sensor type, so their outputs can diverge without either being broken. We publish no accuracy figures, because that comparison depends on the activity, the fit and the population, and you should measure it for your own use case rather than taking a number from a blog post. The engineering consequence is concrete: record the source with every sample, never merge the two streams into one undifferentiated series, and let your deduplication layer decide which source wins for a given interval.",
          "url": "https://aifitnessapi.com/devices/bluetooth-heart-rate-monitor#faq-3"
        }
      ]
    },
    {
      "question": "read cycling power meter cadence sensor app",
      "answer": "Three standardized Bluetooth services cover the sensors most cycling and running apps need: Cycling Power 0x1818 with Cycling Power Measurement 0x2A63, Cycling Speed and Cadence 0x1816 with CSC Measurement 0x2A5B, and Running Speed and Cadence 0x1814 with RSC Measurement 0x2A53. The integration pattern is the same for all three: scan filtered on the service UUID, connect, discover by UUID, and enable notifications on the measurement characteristic. Wire formats are defined in the Bluetooth SIG's specifications for each service, so parse against those rather than a copied snippet. The trap is overlap: a smart trainer may expose the Cycling Power service and FTMS Indoor Bike Data at once, so pick one source of truth per metric or you will double-count.",
      "title": "Reading Cycling Power, Cadence, and Speed Sensors in an App",
      "url": "https://aifitnessapi.com/devices/cycling-sensors-power-cadence",
      "markdown": "https://aifitnessapi.com/devices/cycling-sensors-power-cadence.md",
      "cluster": "Connected Devices",
      "cluster_url": "https://aifitnessapi.com/devices",
      "last_reviewed": "2026-08-14",
      "first_party": false,
      "faqs": [
        {
          "question": "What are the BLE UUIDs for cycling power, cycling speed and cadence, and running speed and cadence?",
          "answer": "Per the Bluetooth SIG's assigned-numbers registry, Cycling Power is service 0x1818 with Cycling Power Measurement 0x2A63, Cycling Speed and Cadence is service 0x1816 with CSC Measurement 0x2A5B, and Running Speed and Cadence is service 0x1814 with RSC Measurement 0x2A53. All three follow the same integration pattern: scan filtered on the service UUID, connect, discover by UUID rather than caching handles, and enable notifications on the measurement characteristic. Write the transport once and parameterize it by service. Only parsing differs, and each service's specification from the Bluetooth SIG defines the layout of its measurement value.",
          "url": "https://aifitnessapi.com/devices/cycling-sensors-power-cadence#faq-1"
        },
        {
          "question": "My trainer reports power over both FTMS and the Cycling Power service — which one should I record?",
          "answer": "Pick one and record which one you picked. A smart trainer can expose the standalone Cycling Power service 0x1818 and Indoor Bike Data 0x2AD2 under the Fitness Machine Service 0x1826 at the same time, and a separate crank power meter adds a third claim about the same effort. Decide the source per metric at connection time from what is advertised, persist that decision on the session, and never switch mid-ride, because a switch produces a discontinuity that reads as a physiological event. Key the decision on the service rather than the peripheral, since one trainer making two claims defeats any per-device heuristic.",
          "url": "https://aifitnessapi.com/devices/cycling-sensors-power-cadence#faq-2"
        },
        {
          "question": "How should a cycling app remember multiple BLE sensors between rides?",
          "answer": "Store the pairing by role rather than as a flat device list. Riders think in terms of a power source, a cadence source and a heart rate source, so persist the platform's device identifier together with the role it fills and a user-editable label, and reconnect known sensors automatically at the start of a ride. Scope that mapping per bike, because a rider with two bikes has two sensor sets and expects the app to know which is which. When pairing, filter the scan by service UUID so the list only offers devices that can fill the role being paired, which matters in a garage or a bike shop where many sensors are in range.",
          "url": "https://aifitnessapi.com/devices/cycling-sensors-power-cadence#faq-3"
        }
      ]
    },
    {
      "question": "what is FTMS fitness machine service",
      "answer": "FTMS is the Bluetooth SIG's Fitness Machine Service, assigned number 0x1826, and it is the standard way a treadmill, rower, bike or climber streams its own data to an app. It defines a separate data characteristic per machine type: Treadmill Data 0x2ACD, Cross Trainer Data 0x2ACE, Step Climber Data 0x2ACF, Stair Climber Data 0x2AD0, Rower Data 0x2AD1 and Indoor Bike Data 0x2AD2. Capability discovery runs through Fitness Machine Feature 0x2ACC plus the Supported Range characteristics, and control runs through Fitness Machine Control Point 0x2AD9 with Fitness Machine Status 0x2ADA reporting back. Integrators commonly report that many machines broadcast FTMS data but ignore or restrict remote-control commands outside the brand's own app, so treat control as a per-model capability you must test.",
      "title": "What Is FTMS? The Bluetooth Fitness Machine Service (2026)",
      "url": "https://aifitnessapi.com/devices/ftms-fitness-machine-service",
      "markdown": "https://aifitnessapi.com/devices/ftms-fitness-machine-service.md",
      "cluster": "Connected Devices",
      "cluster_url": "https://aifitnessapi.com/devices",
      "last_reviewed": "2026-08-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Which Bluetooth service UUID is FTMS, and which characteristic carries each machine type's data?",
          "answer": "The Bluetooth SIG's assigned-numbers registry lists the Fitness Machine Service as 0x1826. It defines a distinct data characteristic per machine type: Treadmill Data 0x2ACD, Cross Trainer Data 0x2ACE, Step Climber Data 0x2ACF, Stair Climber Data 0x2AD0, Rower Data 0x2AD1 and Indoor Bike Data 0x2AD2, with Training Status at 0x2AD3. Because all six sit under the same service, your discovery, subscription, reconnection and session-assembly code is shared, and only parsing and the domain model change per machine. Wire formats are defined in the FTMS specification published by the Bluetooth SIG.",
          "url": "https://aifitnessapi.com/devices/ftms-fitness-machine-service#faq-1"
        },
        {
          "question": "Can my app actually control speed or resistance through the FTMS Control Point (0x2AD9)?",
          "answer": "The characteristic exists in the service, and Fitness Machine Status 0x2ADA is there for the machine to report state changes back. Whether a given machine honors a command is a different question. It is widely reported by integrators and reviewers that many machines broadcast FTMS data but ignore or restrict remote-control commands outside the brand's own app, and that control support varies by model and region. Treat control as a per-model capability you must test on real hardware, keep a capability flag in your own configuration, and design a path for machines that decline. Data is what FTMS reliably buys you.",
          "url": "https://aifitnessapi.com/devices/ftms-fitness-machine-service#faq-2"
        },
        {
          "question": "How do I discover what an FTMS machine supports before rendering controls for it?",
          "answer": "Use the discovery characteristics the service provides. Fitness Machine Feature 0x2ACC declares the machine's features, and the Supported Range characteristics give you bounds: Supported Speed Range 0x2AD4, Supported Inclination Range 0x2AD5, Supported Resistance Level Range 0x2AD6, Supported Heart Rate Range 0x2AD7 and Supported Power Range 0x2AD8. Our recommendation is to read these at connection time, cache them per device, and let them drive the interface, so you never render a metric tile or a control for something the connected machine has not confirmed. Confirmed capability also gives you the clamps for any value you send.",
          "url": "https://aifitnessapi.com/devices/ftms-fitness-machine-service#faq-3"
        }
      ]
    },
    {
      "question": "connect treadmill data to fitness app",
      "answer": "A treadmill that speaks the Bluetooth Fitness Machine Service exposes Treadmill Data on characteristic 0x2ACD under service 0x1826, and that is the one integration you need for the data side. Before rendering anything, read the capability characteristics: Supported Speed Range 0x2AD4 and Supported Inclination Range 0x2AD5 tell you the bounds this machine actually works within. Control is a separate matter: the Fitness Machine Control Point 0x2AD9 exists, but integrators commonly report that many machines broadcast data while ignoring or restricting remote-control commands outside the brand's own app, so treat it as a per-model capability you must test. If you do ship control, engineer it conservatively, because a human is standing on the belt.",
      "title": "Treadmill App Integration: Reading FTMS Treadmill Data",
      "url": "https://aifitnessapi.com/devices/treadmill-app-integration",
      "markdown": "https://aifitnessapi.com/devices/treadmill-app-integration.md",
      "cluster": "Connected Devices",
      "cluster_url": "https://aifitnessapi.com/devices",
      "last_reviewed": "2026-08-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Which BLE characteristic carries treadmill speed and incline data?",
          "answer": "Treadmill Data, characteristic 0x2ACD, under the Fitness Machine Service 0x1826, per the Bluetooth SIG's assigned-numbers registry. A conforming treadmill advertises the service and streams its metrics through that one characteristic, so you integrate against the profile rather than against a manufacturer. The exact contents and layout of the value are defined in the FTMS specification published by the Bluetooth SIG, and that document is the only thing worth parsing against. Pair it with Supported Speed Range 0x2AD4 and Supported Inclination Range 0x2AD5, read at connection time, so you know the bounds the machine reports within.",
          "url": "https://aifitnessapi.com/devices/treadmill-app-integration#faq-1"
        },
        {
          "question": "Can a third-party app change treadmill speed or incline over Bluetooth FTMS?",
          "answer": "Sometimes, and you have to test per model. The Fitness Machine Control Point 0x2AD9 is the characteristic for writing commands, with Fitness Machine Status 0x2ADA reporting state changes back. But it is widely reported by integrators and reviewers that many machines broadcast FTMS data while ignoring or restricting remote-control commands outside the brand's own app, with support varying by model and region. So the presence of the control point proves the characteristic exists, not that your write will move the belt. Keep a per-model capability flag in your own configuration and treat a machine that declines control as a supported configuration rather than an error.",
          "url": "https://aifitnessapi.com/devices/treadmill-app-integration#faq-2"
        },
        {
          "question": "How should a treadmill app use the Supported Inclination Range characteristic (0x2AD5)?",
          "answer": "Read it once at connection time, cache it per device, and let it drive the interface. Two things follow. First, presentation: do not render an incline slider or an incline-dependent workout preset on a machine that has not confirmed it can do incline, because a control that silently does nothing is worse than a control that is visibly absent. Second, safety: the discovered range is your clamp for any value you send, applied in the layer closest to the write rather than in the view. Pair it with Supported Speed Range 0x2AD4 and the Fitness Machine Feature characteristic 0x2ACC for the full capability picture.",
          "url": "https://aifitnessapi.com/devices/treadmill-app-integration#faq-3"
        }
      ]
    },
    {
      "question": "integrate smart bike trainer app",
      "answer": "A smart trainer usually presents two standardized interfaces at the same time: Indoor Bike Data, characteristic 0x2AD2, under the Fitness Machine Service 0x1826, and the standalone Cycling Power service 0x1818 with its Cycling Power Measurement characteristic 0x2A63. Both can describe the same pedaling, so pick one source of truth per metric per session and record which one you used. Discover capability before you render anything: Supported Resistance Level Range 0x2AD6 and Supported Power Range 0x2AD8 tell you the bounds a given trainer reports. The FTMS Control Point 0x2AD9 exists as a characteristic, but exact command support varies per trainer and integrators commonly report that machines restrict control outside the brand's own app, so verify against the hardware and the vendor's documentation.",
      "title": "Smart Bike Trainer Integration: FTMS and Cycling Power",
      "url": "https://aifitnessapi.com/devices/indoor-bike-trainer-integration",
      "markdown": "https://aifitnessapi.com/devices/indoor-bike-trainer-integration.md",
      "cluster": "Connected Devices",
      "cluster_url": "https://aifitnessapi.com/devices",
      "last_reviewed": "2026-08-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Should a smart trainer app read Indoor Bike Data (0x2AD2) or the Cycling Power service (0x1818)?",
          "answer": "Many trainers expose both, so the answer is to choose deliberately rather than subscribe to everything. Indoor Bike Data 0x2AD2 sits under the Fitness Machine Service 0x1826; Cycling Power Measurement 0x2A63 sits under the standalone Cycling Power service 0x1818. Both can describe the same pedaling, so decide a source per metric at connection time based on what the device advertises, persist that decision with the session, and do not switch mid-ride, because switching produces a discontinuity that looks like a physiological event. Key the decision on the service rather than the peripheral, since here both interfaces belong to one device.",
          "url": "https://aifitnessapi.com/devices/indoor-bike-trainer-integration#faq-1"
        },
        {
          "question": "Does every FTMS smart trainer accept resistance or target power commands from a third-party app?",
          "answer": "No, and you should assume nothing from the characteristic list. The Fitness Machine Control Point 0x2AD9 exists in the service, with Fitness Machine Status 0x2ADA for the machine to report changes back, but capability and exact command support vary per trainer. Integrators and reviewers widely report that many machines broadcast FTMS data while ignoring or restricting remote-control commands outside the brand's own app, varying by model and region. Verify against the actual hardware and the manufacturer's documentation, gate control features behind a per-model capability flag you set from testing, and make a report-only trainer a supported state rather than an error.",
          "url": "https://aifitnessapi.com/devices/indoor-bike-trainer-integration#faq-2"
        },
        {
          "question": "Which characteristics tell me a smart trainer's resistance and power limits?",
          "answer": "Supported Resistance Level Range 0x2AD6 and Supported Power Range 0x2AD8, both under the Fitness Machine Service 0x1826, alongside Fitness Machine Feature 0x2ACC for the machine's feature declaration. Supported Heart Rate Range 0x2AD7 also exists, though heart rate itself is served by its own service 0x180D. Read these once at connection time and cache them per device. They do two jobs: they tell you which controls are worth rendering at all, and they give you the bounds to clamp any value you send, applied close to the write rather than in the view layer.",
          "url": "https://aifitnessapi.com/devices/indoor-bike-trainer-integration#faq-3"
        }
      ]
    },
    {
      "question": "get rowing machine data into app",
      "answer": "The standard path for ergometer metrics is Rower Data, characteristic 0x2AD1, under the Bluetooth Fitness Machine Service 0x1826. A conforming rower advertises that service and streams its metrics through that characteristic, so one integration covers conforming machines from any vendor rather than one per brand. The exact contents and layout of the value are defined in the FTMS specification published by the Bluetooth SIG, which is the only thing worth parsing against. Some manufacturers also document their own proprietary interfaces alongside or instead of FTMS, and where that is the case the vendor's own documentation is the source of truth. Build the transport and session layers so a second data source can be added without rewriting them.",
      "title": "Getting Rowing Machine Data Into an App (2026)",
      "url": "https://aifitnessapi.com/devices/rowing-machine-data",
      "markdown": "https://aifitnessapi.com/devices/rowing-machine-data.md",
      "cluster": "Connected Devices",
      "cluster_url": "https://aifitnessapi.com/devices",
      "last_reviewed": "2026-08-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Which Bluetooth characteristic carries rowing machine data under FTMS?",
          "answer": "Rower Data, characteristic 0x2AD1, under the Fitness Machine Service 0x1826, per the Bluetooth SIG's assigned-numbers registry. A conforming ergometer advertises the service and streams its metrics through that characteristic, so the integration is against the profile rather than a manufacturer. The exact contents and layout of the value are defined in the FTMS specification published by the Bluetooth SIG, and that document is what your parser should be written against. Pair it with Fitness Machine Feature 0x2ACC and the Supported Range characteristics, read at connection time, so your interface only shows what this machine has confirmed.",
          "url": "https://aifitnessapi.com/devices/rowing-machine-data#faq-1"
        },
        {
          "question": "Why does my rowing machine expose a proprietary interface instead of FTMS Rower Data?",
          "answer": "Some manufacturers document their own interfaces alongside or instead of the standard service, and we make no claims about which ones, because that changes with firmware and we could not verify it for this page. The rule that holds is about authority: where a vendor documents its own interface, that documentation is the source of truth for it, not a forum thread or a reverse-engineering write-up. Note the date you read it and re-check when you next touch the integration. Design for it from the start by keeping your transport, domain model and session assembly independent of any one interface, so a second source is a new adapter rather than a rewrite.",
          "url": "https://aifitnessapi.com/devices/rowing-machine-data#faq-2"
        },
        {
          "question": "How should a rowing app record a session when the ergometer only streams live data?",
          "answer": "Build the session record yourself, because FTMS streams live and hands you no history. That means you own the timestamping, the pause semantics and the day-boundary decision about whose midnight ends the day. Model the session as a sequence of stroke-derived events from the data characteristic, and treat heart rate as an independent stream on service 0x180D that can drop without ending the session. When a secondary stream disappears, mark that range unknown rather than writing zeros, and if the user also wore a watch, pick one source of truth per metric and record which source the session used.",
          "url": "https://aifitnessapi.com/devices/rowing-machine-data#faq-3"
        }
      ]
    },
    {
      "question": "get live heart rate from apple watch in app",
      "answer": "HealthKit is a store, not a live stream, so polling it harder will not give you a number that updates while somebody is mid-interval. On Apple Watch the live path is a workout session: Apple documents that a session fine-tunes the watch's sensors for the activity you declare, and that all workout sessions generate high-frequency heart rate samples. HKWorkoutSession is available from watchOS 2.0, and Apple also lists iOS, iPadOS and Mac Catalyst 17.0 and visionOS 1.0. Apple Watch runs one session at a time, so a second workout started elsewhere ends yours, which makes session-ended a normal state your UI has to handle. If you need heart rate without requiring an Apple Watch at all, pair a Bluetooth strap directly and read the standard Heart Rate service instead.",
      "title": "Live Heart Rate From Apple Watch in Your App (2026)",
      "url": "https://aifitnessapi.com/devices/apple-watch-live-heart-rate",
      "markdown": "https://aifitnessapi.com/devices/apple-watch-live-heart-rate.md",
      "cluster": "Connected Devices",
      "cluster_url": "https://aifitnessapi.com/devices",
      "last_reviewed": "2026-08-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Does an HKWorkoutSession give higher-frequency heart rate than reading HealthKit samples on Apple Watch?",
          "answer": "Yes, and Apple states it directly: all workout sessions generate high-frequency heart rate samples. Apple also documents that the session fine-tunes Apple Watch's sensors for the activity type you declare, which is why the declared activity is a real input rather than a label. There is no equivalent query parameter on the store side. HealthKit is where samples are persisted and queried, so polling it more aggressively does not raise the rate at which the watch produces them. If your product needs a number that updates while somebody is mid-interval, the session is the mechanism, and the store is where the record lands afterward.",
          "url": "https://aifitnessapi.com/devices/apple-watch-live-heart-rate#faq-1"
        },
        {
          "question": "What happens to my watchOS workout session if the user starts a workout in Apple's Workout app?",
          "answer": "Yours ends. Apple documents that Apple Watch runs one workout session at a time, and that if a second workout starts while your workout is running, your session ends. Treat that as an ordinary state transition rather than an error. In practice it means your live screen must be able to say that data has stopped instead of leaving the last received value on screen to age silently, and any recording you were doing needs a defined close-out path. It also affects onboarding: if users are likely to run more than one fitness app during a gym session, you are competing for the single slot rather than sharing it.",
          "url": "https://aifitnessapi.com/devices/apple-watch-live-heart-rate#faq-2"
        },
        {
          "question": "Can an Apple Watch workout session keep running while the watch is locked and show data on iPhone?",
          "answer": "Both are documented capabilities of workout sessions. Apple lists background execution while the watch is locked, mirroring the workout to a companion iPhone, and starting, pausing, resuming or canceling the session with Siri. Background execution while locked is what makes a usable workout app possible, since a wrist that has gone to sleep is the normal case during exercise. Mirroring lets the phone act as the large display while the watch remains the sensor. Plan for Siri control specifically, because it means session state can change from outside your own interface, so your view has to follow session state rather than assume it drives it.",
          "url": "https://aifitnessapi.com/devices/apple-watch-live-heart-rate#faq-3"
        }
      ]
    },
    {
      "question": "wear os health services live workout data",
      "answer": "Health Services is the platform service on Wear OS 3 and later that sits between your app and the watch's sensors and algorithms, so you ask it for metrics rather than reading hardware yourself. Use ExerciseClient for an active workout: it manages the workout, sets exercise goals, reports exercise state updates, and delivers rapid data updates while exercise is in progress, across metrics Google lists as heart rate, distance, calories, elevation, floors, speed, pace and more. Use PassiveMonitoringClient for the long-lived, low-frequency case, which Google describes as suited to experiences where data updates are relatively infrequent. Google states that Health Services conserves battery using sensor configurations optimized for power efficiency, and verifies data consistency across all applications on the same device by using standardized platform computations. You would still pair a Bluetooth sensor directly when the signal has to come from hardware the watch does not contain, or when the same code has to run on phones and in a browser.",
      "title": "Wear OS Health Services for Live Workout Data (2026)",
      "url": "https://aifitnessapi.com/devices/wear-os-health-services",
      "markdown": "https://aifitnessapi.com/devices/wear-os-health-services.md",
      "cluster": "Connected Devices",
      "cluster_url": "https://aifitnessapi.com/devices",
      "last_reviewed": "2026-08-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Should a Wear OS app use ExerciseClient or PassiveMonitoringClient for heart rate?",
          "answer": "It depends on whether a workout is in progress. Google describes ExerciseClient as the API for managing workouts, setting exercise goals, listening for exercise state updates and receiving rapid data updates during active exercise, with metrics including heart rate, distance, calories, elevation, floors, speed and pace. PassiveMonitoringClient is for receiving updates about a data type or an event, and Google says it suits long-lived experiences where data updates are relatively infrequent. So an exercise the user explicitly started uses the exercise client, and an ambient all-day feature uses passive monitoring. Holding an exercise open to get frequent updates for a background feature is the classic battery mistake.",
          "url": "https://aifitnessapi.com/devices/wear-os-health-services#faq-1"
        },
        {
          "question": "What does Health Services on Wear OS do about battery and cross-app consistency?",
          "answer": "Google makes two specific claims. On power, Health Services conserves battery by using sensor configurations that are optimized for power efficiency, which is one of the main arguments for going through the platform service rather than approaching sensors yourself. On consistency, it verifies data consistency across all applications on the same device by using standardized platform computations. The practical effect is that two apps on the same watch report the same figure for the same activity, so a user does not see two contradictory calorie counts and assume one app is broken. The trade is that you are consuming the platform's computation rather than your own.",
          "url": "https://aifitnessapi.com/devices/wear-os-health-services#faq-2"
        },
        {
          "question": "Does Wear OS Health Services replace pairing a Bluetooth sensor to the watch?",
          "answer": "For anything the watch itself senses, it generally should be your default. It does not help for signals that come from hardware the watch does not contain, such as cycling power or cadence from bike-mounted sensors, or data from gym equipment reporting over the Fitness Machine Service. It also does not help when a user prefers a chest strap they already own, or when you need one implementation that also runs on iOS, on Android phones, or in a Chromium browser, since the standard Bluetooth GATT profiles are what port across those surfaces. Many products end up doing both: Health Services for wrist metrics, direct Bluetooth for external sensors.",
          "url": "https://aifitnessapi.com/devices/wear-os-health-services#faq-3"
        }
      ]
    },
    {
      "question": "ant+ vs bluetooth fitness sensors",
      "answer": "For a new fitness app in 2026, Bluetooth Low Energy is the default radio and ANT+ is a compatibility question about hardware your users already own. Widely quoted reporting from January 2025, citing thisisant.com, said the ANT+ membership and certification programs would be discontinued on June 30, 2025, with certification applications accepted only until March 31, 2025; the same coverage reported that device profiles and documentation remain available to developers and that existing ANT+ devices are unaffected. We could not reach the official page through our proxy, so treat those dates as reported rather than verified. BLE APIs are first-class on both iOS and Android, whereas receiving ANT+ on a phone has historically needed extra hardware or platform-specific plugins, which you should verify against current vendor documentation. The practical answer: build on BLE, and treat ANT+ as an ecosystem you interoperate with rather than a second radio you design around.",
      "title": "ANT+ vs Bluetooth for Fitness Sensors (2026)",
      "url": "https://aifitnessapi.com/devices/ant-plus-vs-bluetooth",
      "markdown": "https://aifitnessapi.com/devices/ant-plus-vs-bluetooth.md",
      "cluster": "Connected Devices",
      "cluster_url": "https://aifitnessapi.com/devices",
      "last_reviewed": "2026-08-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Is the ANT+ certification program really discontinued, and do existing ANT+ sensors stop working?",
          "answer": "Reported, not verified by us. Multiple consistent notices published in January 2025, including DC Rainmaker and the5krunner and community forum threads, all quoting thisisant.com, said the ANT+ membership and certification programs would be discontinued on June 30, 2025, with certification applications accepted only until March 31, 2025. The same coverage reported that device profiles and documentation remain available to developers and that existing ANT+ devices are not affected, and cited EU Radio Equipment Directive requirements as a driver. We could not reach the official page through our proxy. So nothing in that reporting says sensors in the field stop transmitting; what ended is the membership and certification apparatus.",
          "url": "https://aifitnessapi.com/devices/ant-plus-vs-bluetooth#faq-1"
        },
        {
          "question": "Can an iPhone or Android phone receive ANT+ sensor data without extra hardware?",
          "answer": "Historically this has needed more than the phone itself: additional hardware, platform-specific plugin software, or a handset whose manufacturer shipped support. We did not verify the current state for any specific device or vendor plugin this session, so check current vendor documentation before planning around it. What we can say plainly is that the comparison is lopsided. Bluetooth Low Energy reception is a documented, first-class platform capability on both iOS and Android, with Apple's Core Bluetooth and Android's equivalent stack, and needs no dongle or plugin. That asymmetry, rather than any claim about signal quality, is the practical reason new phone apps default to Bluetooth.",
          "url": "https://aifitnessapi.com/devices/ant-plus-vs-bluetooth#faq-2"
        },
        {
          "question": "Should a new fitness app in 2026 implement ANT+ support alongside Bluetooth Low Energy?",
          "answer": "Our judgement is no, not as a second radio integration. Build on Bluetooth Low Energy and the SIG-standard profiles, which are documented, cross-platform, and available through first-class APIs on both phone operating systems. Then treat ANT+ as a compatibility question about hardware your users already own. Many fitness sensors dual-broadcast, in which case your app connects over Bluetooth and the user's head unit keeps using ANT+ with no conflict. Where users are deep in an ecosystem whose sensors you cannot reach, the better answer is usually an account-level sync that imports the finished activity, rather than trying to receive the sensor stream yourself.",
          "url": "https://aifitnessapi.com/devices/ant-plus-vs-bluetooth#faq-3"
        }
      ]
    },
    {
      "question": "web bluetooth fitness app browser",
      "answer": "Web Bluetooth lets a web page talk to heart rate straps and gym machines over the same standard GATT profiles a native app uses, but the browser support is the whole story. Per the caniuse dataset, it is supported in Chrome 56 and later, Edge 79 and later, Opera 43 and later, and Samsung Internet 6.2 and later; it is not supported in Firefox at any version, and not in Safari on desktop or iOS, where a third-party app polyfill exists but is not WebKit. Support also varies by operating system, with Windows, macOS, Linux, Android from M, and ChromeOS listed. The product conclusion follows directly: a Chromium-only, kiosk-style or desktop experience is viable, and any product that must reach iPhone users in Safari cannot be built on it.",
      "title": "Web Bluetooth for Fitness Apps in the Browser (2026)",
      "url": "https://aifitnessapi.com/devices/web-bluetooth-fitness",
      "markdown": "https://aifitnessapi.com/devices/web-bluetooth-fitness.md",
      "cluster": "Connected Devices",
      "cluster_url": "https://aifitnessapi.com/devices",
      "last_reviewed": "2026-08-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Can a web page use Web Bluetooth to connect a heart rate strap in Safari on iPhone?",
          "answer": "No. Per the caniuse dataset, Safari does not support Web Bluetooth on desktop or on iOS. A third-party iOS app exists that polyfills the API, but it is not WebKit and it is not something you can assume your users have installed, so a page loaded in Safari on an iPhone has no path to a heart rate strap. Feature detection will correctly report the API as absent, and there is no flag or permission that changes that. If reaching iPhone users through a browser is a hard requirement for your product, Web Bluetooth is the wrong technology and you need either a native app or an account-level data sync.",
          "url": "https://aifitnessapi.com/devices/web-bluetooth-fitness#faq-1"
        },
        {
          "question": "Which browsers support Web Bluetooth for talking to fitness sensors and machines?",
          "answer": "Per the caniuse dataset, the supporting browsers are Chrome from version 56, Edge from 79, Opera from 43, and Samsung Internet from 6.2. Firefox does not support it in any version, and Safari does not support it on desktop or iOS. Support also varies by operating system, with Windows, macOS, Linux, Android from M, and ChromeOS listed as platforms. In practice that means Chromium is the target. Feature-detect and route unsupported browsers to a fallback rather than leaving a connect button that appears to do nothing, because a silent failure at the device chooser is indistinguishable from a broken page.",
          "url": "https://aifitnessapi.com/devices/web-bluetooth-fitness#faq-2"
        },
        {
          "question": "Does a Web Bluetooth fitness page read the same GATT services as a native app?",
          "answer": "Yes, and that is the main reason to consider it. A browser page connects to the same SIG-standard services a native application would: Heart Rate at 0x180D with the Heart Rate Measurement characteristic 0x2A37, the Fitness Machine Service at 0x1826 for gym equipment, Cycling Power at 0x1818, Cycling Speed and Cadence at 0x1816, and Running Speed and Cadence at 0x1814. The transport API differs between the browser and a native framework, but the profile, the characteristics and the domain model do not. Teams that write their device layer against the profile rather than the platform API can port between the two rather than reimplementing.",
          "url": "https://aifitnessapi.com/devices/web-bluetooth-fitness#faq-3"
        }
      ]
    },
    {
      "question": "ios core bluetooth fitness devices",
      "answer": "Core Bluetooth is the iOS framework for talking to heart rate straps, cycling sensors and gym machines, and Apple's abstract for it is to communicate with Bluetooth low energy and BR/EDR Classic devices. Your fitness app is almost always the central: CBCentralManager scans for, connects to and manages peripherals, while CBPeripheralManager is the other role, for advertising services from the device your code runs on. Since iOS 13 you must include NSBluetoothAlwaysUsageDescription in Info.plist, and Apple states that your app will crash if its Info.plist doesn't include usage description keys for the types of data it needs to access; iOS 12 and earlier used NSBluetoothPeripheralUsageDescription. Apple also says not to subclass any Core Bluetooth class, because overriding them isn't supported and results in undefined behavior. Keep the framework behind a narrow protocol so recorded device data can drive the rest of your pipeline without hardware.",
      "title": "Core Bluetooth for Fitness Devices on iOS (2026)",
      "url": "https://aifitnessapi.com/devices/ios-ble-fitness-devices",
      "markdown": "https://aifitnessapi.com/devices/ios-ble-fitness-devices.md",
      "cluster": "Connected Devices",
      "cluster_url": "https://aifitnessapi.com/devices",
      "last_reviewed": "2026-08-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Which Info.plist key does Core Bluetooth require on iOS 13 and later?",
          "answer": "NSBluetoothAlwaysUsageDescription. It is required to access Core Bluetooth APIs from iOS 13 onward; iOS 12 and earlier used NSBluetoothPeripheralUsageDescription. Apple's warning is unambiguous: your app will crash if its Info.plist doesn't include usage description keys for the types of data it needs to access. Because nothing in your Swift code looks wrong when the key is missing, this is worth enforcing mechanically rather than remembering. Add a test or a build-phase check that asserts the key exists and is non-empty, since plist merges, duplicated targets and new app extensions all drop it easily. Write the description for the user, naming the devices you connect to.",
          "url": "https://aifitnessapi.com/devices/ios-ble-fitness-devices#faq-1"
        },
        {
          "question": "Should an iOS fitness app use CBCentralManager or CBPeripheralManager for a heart rate strap?",
          "answer": "CBCentralManager. Apple describes the central role as scanning for, connecting to, and managing peripherals, which is exactly what an app reading a strap, a power meter or a treadmill does: the sensor is the peripheral and your app is the central. CBPeripheralManager is the opposite role, used to advertise local services from the device your code runs on, so it applies when the phone is the thing being read rather than the thing reading. That is occasionally useful in a test rig and rarely what a consumer fitness product needs. The two APIs are not interchangeable, so pick the role deliberately before writing the connection layer.",
          "url": "https://aifitnessapi.com/devices/ios-ble-fitness-devices#faq-2"
        },
        {
          "question": "Can I subclass CBCentralManager or CBPeripheral to make my BLE fitness layer testable?",
          "answer": "No, and Apple says so directly: don't subclass any of the classes of the Core Bluetooth framework, because overriding these classes isn't supported and results in undefined behavior. The instinct is understandable, since a fake central manager looks like the easy route to a testable device layer, but a subclass would still be a real manager attached to the real Bluetooth stack. The supported approach is to define your own narrow protocol expressing what your app asks of a device, put a Core Bluetooth adapter behind it as the only file importing the framework, and let everything downstream run against recorded data with no radio involved.",
          "url": "https://aifitnessapi.com/devices/ios-ble-fitness-devices#faq-3"
        }
      ]
    },
    {
      "question": "test bluetooth fitness device integration",
      "answer": "A physical device is the only reliable test target for live Bluetooth behavior, so the goal is not to fake the radio but to make sure almost nothing in your product depends on it. Put a narrow seam between the platform Bluetooth API and everything downstream, record real notification streams from real sensors and machines, and replay those recordings as fixtures in CI so parsing, aggregation and session assembly are covered without hardware. That leaves a small set of behaviors that only a device lab catches, in our judgement: first-time pairing, reconnection after a dropout, and interference in a room full of other sensors. Cover those with a short manual matrix per release rather than pretending a green CI run has tested them.",
      "title": "Testing Bluetooth Fitness Device Integrations (2026)",
      "url": "https://aifitnessapi.com/devices/testing-ble-fitness-devices",
      "markdown": "https://aifitnessapi.com/devices/testing-ble-fitness-devices.md",
      "cluster": "Connected Devices",
      "cluster_url": "https://aifitnessapi.com/devices",
      "last_reviewed": "2026-08-14",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I test a Bluetooth heart rate strap integration without physical hardware?",
          "answer": "Not the live radio behavior. A physical device is the only reliable test target for live BLE behavior, so the productive move is designing a seam that lets recorded data drive the pipeline in CI rather than hunting for a way to fake the radio. Record real characteristic notification streams with their arrival timestamps from real sensors, pin those recordings as fixtures, and replay them through everything below the seam. That covers parsing, unit handling, dropout and resume handling, session assembly and every rollup your users see. What remains hardware-only is a short list: first-time pairing, reconnection after going out of range, interference in a crowded room, and per-model machine control behavior.",
          "url": "https://aifitnessapi.com/devices/testing-ble-fitness-devices#faq-1"
        },
        {
          "question": "What should I record from a BLE fitness sensor or machine to replay as a test fixture?",
          "answer": "Two things are enough for deterministic replay: the device's advertised services and characteristics at connect time, and the stream of characteristic notifications with their arrival timestamps. Record from more than one device per profile, because a single strap or treadmill only teaches you one manufacturer's behavior and writing against a published profile is precisely a bet that you will meet others. Prioritize the ugly sessions over the clean ones: a dropout mid-session, a walk out of range and back, a machine that stops notifying and resumes, a device advertising a service it does not populate as expected. Pin the fixtures in source so the suite does not drift.",
          "url": "https://aifitnessapi.com/devices/testing-ble-fitness-devices#faq-2"
        },
        {
          "question": "Which Bluetooth fitness device failures only show up with real hardware in the room?",
          "answer": "In our judgement, four categories. First-time pairing, where permission prompts, bonding and manufacturer quirks all arrive at once for a specific handset, OS version and sensor combination, and which a recording made afterward cannot reproduce. Reconnection, covering whether your app recovers when a user walks away or the screen sleeps, and whether it creates a duplicate session on return. Interference and crowding, since a gym floor with a dozen active sensors behaves nothing like a desk with one strap. And per-model control behavior on gym equipment, since integrators commonly report that many machines broadcast data while ignoring or restricting remote-control commands outside the manufacturer's own app.",
          "url": "https://aifitnessapi.com/devices/testing-ble-fitness-devices#faq-3"
        }
      ]
    },
    {
      "question": "push notifications for fitness app",
      "answer": "A fitness app has to satisfy two different permission models. Google documents that Android 13 (API level 33) and higher requires the POST_NOTIFICATIONS runtime permission, that notifications are off by default for new installs on those devices, that the system pre-grants the permission to eligible apps when a user upgrades their device, and that a denial blocks all notification channels rather than only the one the user was thinking of. On iOS you request UNAuthorizationOptions, which Apple documents as including badge, sound, alert, carPlay, criticalAlert, providesAppNotificationSettings and provisional, the last of which posts noninterrupting notifications to Notification Center without an explicit prompt. The messages worth spending that permission on are the ones only your app knows about: a workout the user started and abandoned, a streak deadline that is about to pass, a result that just synced from a wearable. Generic re-engagement copy that could have been written before the user existed spends a permission you do not get back.",
      "title": "Push Notifications for a Fitness App: Permissions and Payload",
      "url": "https://aifitnessapi.com/engagement/push-notifications-fitness-app",
      "markdown": "https://aifitnessapi.com/engagement/push-notifications-fitness-app.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Does Android's POST_NOTIFICATIONS permission apply to users who upgraded their device rather than installing fresh?",
          "answer": "It applies, but they may never see a prompt. Google documents that the system automatically pre-grants the permission to all eligible apps when the user upgrades their device to Android 13 or higher, where eligible means the app must have an existing notification channel and must not have had its notifications explicitly disabled by the user on a device running 12L or lower. A fresh install on Android 13 or higher gets no such grace: notifications are off by default until the user grants the permission. That asymmetry means your reachable-user numbers mix two populations, so segment by whether a user was ever prompted.",
          "url": "https://aifitnessapi.com/engagement/push-notifications-fitness-app#faq-1"
        },
        {
          "question": "If a fitness app user taps don't allow on the Android notification prompt, do any of my notification channels still deliver?",
          "answer": "No, with narrow exceptions outside your control. Google's wording is that if the user selects the don't allow option, your app can't send notifications unless it qualifies for an exemption, and that all notification channels are blocked except for a few specific roles. So a denial does not mute the marketing channel and spare workout reminders; it removes the whole surface, including channels for features the user has not reached yet. Plan for the denied state as a supported configuration of your app rather than an error, and lean on surfaces that do not require the permission.",
          "url": "https://aifitnessapi.com/engagement/push-notifications-fitness-app#faq-2"
        },
        {
          "question": "What does iOS provisional authorization change about how a fitness app asks for notification permission?",
          "answer": "It changes the order of the conversation. Apple lists provisional among UNAuthorizationOptions and documents it as the ability to post noninterrupting notifications provisionally to the Notification Center. Because it does not require an explicit permission prompt, messages arrive quietly and the user can later promote them to full delivery or turn them off, which means your messages get to make the case before you ask for interruption rights. We are describing the mechanism only. What provisional does to opt-in outcomes depends on what you send, and no public figure covers your app.",
          "url": "https://aifitnessapi.com/engagement/push-notifications-fitness-app#faq-3"
        }
      ]
    },
    {
      "question": "live activity workout tracking ios",
      "answer": "A Live Activity is the iOS surface for a workout that is happening right now. Apple's ActivityKit documentation describes Live Activities as a way to share live updates from your app on iPhone, iPad, Apple Watch and the Mac, and lists the surfaces as the Lock Screen, Dynamic Island and Home Screen, the Apple Watch Smart Stack, the Mac menu bar and the CarPlay Home Screen; Apple also documents that visionOS does not support Live Activities and that start requests from a compatible iPad or iPhone app fail there. Apple documents two update paths, from your app with ActivityKit and from your server with ActivityKit push notifications, and states that a push notification can also start a Live Activity. Unlike widgets, Live Activities do not use the timeline mechanism, and buttons or toggles in the layout let people act without launching the app. The live data itself does not come from HealthKit, which is a store: on Apple platforms in-workout data comes from a workout session, and the Live Activity should be a projection of that session's state.",
      "title": "Live Activities for Workout Tracking on iOS",
      "url": "https://aifitnessapi.com/engagement/live-activities-workout-tracking",
      "markdown": "https://aifitnessapi.com/engagement/live-activities-workout-tracking.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Can my server start an iOS Live Activity for a workout, or does the app have to be running?",
          "answer": "Apple documents that you can start Live Activities with ActivityKit push notifications, in the same sentence that describes Live Activities receiving updated data from your app with ActivityKit and from your server with ActivityKit push notifications. So a server-initiated start is a documented capability, not a workaround, and it matters for fitness because the event that begins a session is often observed by your backend rather than by a foregrounded app: a coach starting a class, a partner beginning a shared session, or a device sync landing. Verify the current requirements against Apple's ActivityKit documentation before you design around it.",
          "url": "https://aifitnessapi.com/engagement/live-activities-workout-tracking#faq-1"
        },
        {
          "question": "Do Live Activities refresh through the same WidgetKit timeline model that Home Screen widgets use?",
          "answer": "No. Apple documents widgets and watch complications as updating through a timeline of data updates handed to WidgetKit, but Live Activities are explicitly not on that mechanism. They receive updated data from your app with ActivityKit and from your server with ActivityKit push notifications. The practical consequence is that the two need different mental models and usually different code: a widget is a description of what to show at a series of future moments, while a Live Activity is pushed as reality changes. Teams that reuse widget scheduling logic for a Live Activity end up fighting the framework.",
          "url": "https://aifitnessapi.com/engagement/live-activities-workout-tracking#faq-2"
        },
        {
          "question": "Where does the heart rate shown in a workout Live Activity come from if HealthKit is not a live stream?",
          "answer": "From a workout session, or from a sensor your app is connected to directly. HealthKit is a store: it is where a finished session lands, not a tap you can read continuously during exercise. On Apple platforms, live in-workout data comes from a workout session, and a directly paired Bluetooth heart rate monitor is the other live source. Structure it as three components: the session or sensor produces live state, your app projects that state into the Live Activity, and the store receives the completed workout afterward. Polling the store to feed a live surface is the common wrong turn.",
          "url": "https://aifitnessapi.com/engagement/live-activities-workout-tracking#faq-3"
        }
      ]
    },
    {
      "question": "fitness app widget complication",
      "answer": "Apple documents WidgetKit as the way to build widgets, watch complications, Live Activities and controls, with surfaces including the Today View, Home Screen and Lock Screen, the Mac desktop and Notification Center, the Apple Watch Smart Stack, Apple Vision Pro and CarPlay, plus complications on the watch face and up to three in the Smart Stack. Apple documents that widgets and watch complications update through a timeline of data updates you hand to WidgetKit, and that widgets can also be updated through APNs; Live Activities are the exception in that family and do not use timelines. On Android, Google describes Jetpack Glance as a framework built on the Jetpack Compose runtime for building app widgets with Kotlin APIs, and cautions that it is not directly interoperable with other existing Jetpack Compose UI elements, so budget for a separate widget UI. A useful fitness widget shows one thing: the last workout, the streak's deadline, or progress against a goal the user actually set. The hard part is staleness, because a widget showing yesterday's number looks identical to one showing today's.",
      "title": "Fitness App Widgets and Watch Complications",
      "url": "https://aifitnessapi.com/engagement/widgets-and-complications",
      "markdown": "https://aifitnessapi.com/engagement/widgets-and-complications.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I reuse my app's Jetpack Compose screens inside an Android app widget built with Glance?",
          "answer": "Not directly. Google documents Glance as a framework built on top of the Jetpack Compose runtime that lets you develop app widgets using Kotlin APIs, but it also warns that Glance requires Compose to be enabled, depends on the Runtime, Graphics and Unit UI Compose layers, and is not directly interoperable with other existing Jetpack Compose UI elements, advising you to avoid mixing the two. Plan the widget as a separate UI implementation that shares your data layer rather than your composables. Teams that assume code reuse discover the boundary late, usually after the widget design has already been signed off.",
          "url": "https://aifitnessapi.com/engagement/widgets-and-complications#faq-1"
        },
        {
          "question": "How many watch complications can a fitness app place in the Apple Watch Smart Stack?",
          "answer": "Apple documents up to three complications in the Smart Stack, alongside complications on the watch face itself. Both are built with WidgetKit, which Apple describes as covering widgets, watch complications, Live Activities and controls. For a fitness app the watch face is normally the highest-value surface available, because it is glanced at more often than any phone screen and sits on the device nearest the activity. Treat the Smart Stack slots as scarce: pick the single most decision-relevant piece of state per complication rather than trying to reproduce a dashboard in a space read in a second.",
          "url": "https://aifitnessapi.com/engagement/widgets-and-complications#faq-2"
        },
        {
          "question": "What should a fitness home screen widget display so it does not go stale between refreshes?",
          "answer": "Show state that ages gracefully and label when it is from. Last workout with its date, a streak expressed as today's deadline rather than a running count, and progress against a goal the user actually set all survive a delayed refresh, because the user can see what the value refers to. A bare number cannot: yesterday's steps and today's steps render identically. Build your timeline around known transitions such as midnight in the user's own time zone, push an update when a workout completes, and always test the no-data and broken-sync states.",
          "url": "https://aifitnessapi.com/engagement/widgets-and-complications#faq-3"
        }
      ]
    },
    {
      "question": "wear os ongoing activity workout",
      "answer": "Google documents that as of Wear OS 7 the way to represent a long-running activity is to pair an ongoing notification with an OngoingActivity, or to use a Live Update notification, which lets the device display information about the activity across the user interface and enables features like the tappable icon at the bottom of the watch face. Google also documents that an ongoing activity or Live Update keeps your app visible for longer, preventing the system from returning to the watch face after a period of inactivity, and that the activity appears in the Recents section of the global app launcher. Appropriate use of this is documented as a requirement under the Wear OS App Quality guidelines, which makes it table stakes for a workout tracker rather than a polish item. Because the carrier is an ongoing notification, Android's POST_NOTIFICATIONS rules apply and a denial can remove the surface entirely. Ongoing Activity handles presence and navigation only; the exercise data itself comes from Health Services.",
      "title": "Wear OS Ongoing Activity for Workout Tracking",
      "url": "https://aifitnessapi.com/engagement/wear-os-ongoing-activity",
      "markdown": "https://aifitnessapi.com/engagement/wear-os-ongoing-activity.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "How do I stop a Wear OS workout app from being replaced by the watch face mid-session?",
          "answer": "Use the documented mechanism rather than fighting the system. Google states that as of Wear OS 7 the solution is to pair an ongoing notification with an OngoingActivity, or to use a Live Update notification, and documents that this keeps your app visible for longer, preventing the system from returning to the watch face after a period of inactivity. The same pairing enables the tappable icon at the bottom of the watch face and puts the session in the Recents section of the global app launcher, so a user who does leave the app has two documented routes back into it.",
          "url": "https://aifitnessapi.com/engagement/wear-os-ongoing-activity#faq-1"
        },
        {
          "question": "Is a Wear OS Ongoing Activity the same thing as an iOS Live Activity, and can one implementation cover both?",
          "answer": "No, and no. On Wear OS the mechanism is an ongoing notification paired with an OngoingActivity, or a Live Update notification, and because the carrier is a notification it inherits Android's POST_NOTIFICATIONS rules, including that a denial blocks all channels. On iOS, ActivityKit is a dedicated framework with its own surfaces and its own update paths, including server-initiated starts. They solve a similar product problem with different primitives, so plan two implementations sharing a session model rather than one abstraction with two backends.",
          "url": "https://aifitnessapi.com/engagement/wear-os-ongoing-activity#faq-2"
        },
        {
          "question": "When should a workout app tear down its Wear OS ongoing activity?",
          "answer": "On every terminal path, including the ones that are not clean. Completed, cancelled, discarded and crashed are obvious; abandoned is the one that ships broken. Define abandonment before launch, and define it from the data rather than the clock: no sensor samples and no user interaction for a chosen window, so a long slow hike is not mistaken for a forgotten session. Tie the activity's lifetime to the session object rather than to a screen, since a session can start from a tile, a complication or the paired phone and can outlive an app process.",
          "url": "https://aifitnessapi.com/engagement/wear-os-ongoing-activity#faq-3"
        }
      ]
    },
    {
      "question": "best engagement sdk for fitness app",
      "answer": "No independent public dataset ranks fitness or engagement SDKs by their effect on retention, so any ordered list you find is repeating vendor case studies measured on other people's users. What you can compare is categories: platform-native surfaces, camera coaching SDKs, wearable and health-data sync, content libraries, gamification layers, and hosted messaging platforms. Our judgement is to exhaust the documented, free first-party surfaces from Apple and Google before paying for a platform, because those cannot churn out from under you. Ask any vendor what their control group was, over what window, and on whose users. The only number that describes your app is one you measure with a holdout in your app.",
      "title": "Engagement SDKs for Fitness Apps: The Categories, Honestly",
      "url": "https://aifitnessapi.com/engagement/engagement-sdks-compared",
      "markdown": "https://aifitnessapi.com/engagement/engagement-sdks-compared.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Which engagement SDK produces the biggest retention lift for a fitness app?",
          "answer": "Nobody can tell you from public data. There is no independent public dataset ranking fitness or engagement SDKs by retention impact, and the numbers vendors publish come from case studies run on other companies' apps, usually with no control group described and over a window the vendor chose. An effect measured on a running app with a large existing audience says very little about a rehab app used a few times a week. Treat category as the comparable unit, pick on what the category changes about your product, and get your own answer by shipping to a random fraction of users and comparing cohorts.",
          "url": "https://aifitnessapi.com/engagement/engagement-sdks-compared#faq-1"
        },
        {
          "question": "Should we add a hosted messaging platform before or after the platform's own notification surfaces?",
          "answer": "Our judgement is after. Apple's and Google's own surfaces are documented, cost nothing beyond engineering time, and are the delivery layer any external platform has to use anyway. Google documents that on Android 13 and higher an app's notifications are off by default until the user grants POST_NOTIFICATIONS, so permission strategy determines reach regardless of who composes the message. Build the surfaces, learn what your users tolerate, then decide whether you are buying scheduling, segmentation and orchestration you genuinely cannot maintain. We could not reach the documentation of the hosted platforms this session, so we make no claims about individual products.",
          "url": "https://aifitnessapi.com/engagement/engagement-sdks-compared#faq-2"
        },
        {
          "question": "What should I ask a vendor whose case study claims their product improved engagement?",
          "answer": "Four questions. What was the control group, and was there one? Over what window was the effect measured, and did it survive past four weeks, since novelty decays and a day-three reading mostly measures novelty? Whose users were these, and how does that app resemble mine? And what happened to the guardrail metrics — notification opt-out rate, uninstalls, session length — rather than only the metric being advertised? A vendor who answers all four is worth a pilot. A vendor whose whole answer is one percentage has told you the comparison was never run.",
          "url": "https://aifitnessapi.com/engagement/engagement-sdks-compared#faq-3"
        }
      ]
    },
    {
      "question": "how to build streaks in fitness app",
      "answer": "A streak has three parts: a rule for what makes a day qualify, a stored civil local date for each qualifying day, and a counter recomputed from those rows rather than incremented at write time. Store the date the user lived, along with the zone and the instant, because a streak computed in UTC breaks on daylight-saving days and for anyone who travels. Grace days and freezes are product decisions, not implementation details, so decide whether forgiveness is automatic, earned, or spent, and record a forgiven day as forgiven rather than as trained. The ethical edge is unavoidable: a streak is a commitment device the user consents to, and the same pressure that gets somebody moving can push an injured user to train. Design a deliberate pause, not just a way to fail.",
      "title": "Streaks and Habit Loops in a Fitness App",
      "url": "https://aifitnessapi.com/engagement/streaks-and-habit-loops",
      "markdown": "https://aifitnessapi.com/engagement/streaks-and-habit-loops.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Which date should a qualifying day be stored against so that travel and clock changes cannot corrupt a streak?",
          "answer": "Resolve the user's civil local date at the moment the qualifying event is recorded, store that as a date value, and keep the originating instant and time zone in the same row. Streak logic then compares dates and never re-derives boundaries, which is what makes recomputation deterministic. Deriving day boundaries in UTC at read time is the common failure: local days are not all the same length when clocks change, and a traveler's boundary moves with them, so the app deletes a day the user genuinely earned. Decide in advance how a mid-streak zone change is handled, and be generous in both directions.",
          "url": "https://aifitnessapi.com/engagement/streaks-and-habit-loops#faq-1"
        },
        {
          "question": "Should a streak freeze be automatic, earned through use, or purchasable?",
          "answer": "This is a product decision, and our judgement is that it depends on what you want the number to mean. Automatic forgiveness protects the user's relationship with the app but weakens the signal, since a streak nothing can break stops carrying information. Forgiveness the user spends deliberately keeps the meaning but makes a loss feel self-inflicted. Selling freezes turns a motivation feature into a loss-aversion payment, which we would avoid in a health product. Whichever you choose, show the rule in the interface before the day is lost, and record a forgiven day as forgiven so the workout log never claims a session that did not happen.",
          "url": "https://aifitnessapi.com/engagement/streaks-and-habit-loops#faq-2"
        },
        {
          "question": "How do I repair a streak when a workout syncs hours or days late?",
          "answer": "Treat the counter as a cache and recompute it from the stored qualifying-day rows whenever new evidence lands in the affected window. Watches upload after the fact, imports arrive in bulk, and users add sessions by hand, so any of those should be able to restore a broken streak. Make the recompute idempotent, and test it with a backfill: importing a year of history should yield exactly the streak that live arrival would have produced. If it does not, the qualifying rule still depends on arrival order and needs to be rewritten against the stored dates.",
          "url": "https://aifitnessapi.com/engagement/streaks-and-habit-loops#faq-3"
        }
      ]
    },
    {
      "question": "fitness app leaderboard implementation",
      "answer": "Both mobile platforms will host leaderboards for you. Google documents that Play Games Services automatically creates daily, weekly and all-time versions of every leaderboard, with daily boards resetting at UTC-7 and weekly boards resetting at midnight between Saturday and Sunday, a maximum of 70 leaderboards per game, optional score limits that discard clearly fraudulent submissions, and an ordering type that is fixed once the board is published. Apple's GameKit covers leaderboards and achievements but requires Game Center, returning a notAuthenticated error if the local player is not initialized, and its documentation is games-framed throughout, which a fitness app should confirm rather than assume fits. The two harder problems are contractual and adversarial: another provider's athlete data may carry display restrictions, and fitness scores can be faked in the physical world where your app cannot check them.",
      "title": "Leaderboards and Challenges in a Fitness App",
      "url": "https://aifitnessapi.com/engagement/leaderboards-and-challenges",
      "markdown": "https://aifitnessapi.com/engagement/leaderboards-and-challenges.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "When do Play Games Services leaderboards reset, and can the ordering be changed after publishing?",
          "answer": "Google's documentation states that the Play Games SDK automatically creates daily, weekly and all-time versions of every leaderboard you create, that daily leaderboards reset at UTC-7, and that weekly leaderboards reset at midnight between Saturday and Sunday. Those windows are the service's and will not match a local midnight for most users, so a competition you advertised as Monday-to-Sunday in local time has to be built yourself. Ordering type is fixed once a leaderboard is published, meaning a board created so that higher scores win cannot later be reinterpreted as fastest-time. Google also documents a maximum of 70 leaderboards per game.",
          "url": "https://aifitnessapi.com/engagement/leaderboards-and-challenges#faq-1"
        },
        {
          "question": "Does adding GameKit leaderboards mean my fitness app must enable Game Center?",
          "answer": "Yes. Apple documents that you use GameKit to implement Game Center social-gaming network features, and that before you can use GameKit classes you must enable Game Center in your project and initialize the local player, otherwise your app receives a notAuthenticated error. So Game Center authentication is a hard dependency, and a user who declines it sees no ranks. Worth noting separately: Apple's GameKit documentation is written for games throughout. We did not verify any review outcome for non-game use, so confirm the current guidelines before making a games framework the foundation of a fitness social layer.",
          "url": "https://aifitnessapi.com/engagement/leaderboards-and-challenges#faq-2"
        },
        {
          "question": "Can I rank users against each other using workouts imported from another provider's API?",
          "answer": "Check the provider agreement before designing the feature. Strava's developer rules reportedly include restrictions on how athlete data may be displayed and reportedly prohibit using its data to train AI or ML models, with standard access reportedly moving behind a paid subscription in 2026; we grade all of that reported, so verify the current wording at the source. The general principle holds regardless: data you obtained under one user's authorization is not automatically yours to render to a different user. Design a fallback that ranks only sessions your own app recorded, which also happens to be the version you can verify.",
          "url": "https://aifitnessapi.com/engagement/leaderboards-and-challenges#faq-3"
        }
      ]
    },
    {
      "question": "add social features to fitness app",
      "answer": "Friends, feeds, sharing and reactions are four separate features with different privacy and moderation consequences, and the decision that governs all of them is the default sharing scope. Because workout history can reveal injury, illness, pregnancy and location, our judgement is that anything derived from health data defaults to private, with scope stored per record and every widening made explicit and reversible. If activity came from another provider, showing it to a second user is a terms question first: Strava's developer rules reportedly restrict how athlete data may be displayed, so verify the current wording before designing the feed. Route data is the sharpest case, since a shared map usually starts at the user's home. Moderation is the recurring cost teams forget, so ship fixed-vocabulary reactions before free text if you cannot staff a review queue.",
      "title": "Adding Social Features to a Fitness App",
      "url": "https://aifitnessapi.com/engagement/social-features-fitness-app",
      "markdown": "https://aifitnessapi.com/engagement/social-features-fitness-app.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Should a workout feed default to visible to friends, or to nobody?",
          "answer": "Our judgement is nobody, with visibility stored per record rather than per account. Workout history can reveal injury, illness, pregnancy, weight change and where somebody was at a given time, which puts it in a different category from ordinary app content. Storing scope on the record lets a user post one session without exposing the rest, and showing the scope at the moment of posting beats hiding it in settings. A new social surface should never inherit a permission the user granted for storage or sync, and withdrawal has to propagate through any copies the feed fanned out, which is an architectural requirement rather than a support workflow.",
          "url": "https://aifitnessapi.com/engagement/social-features-fitness-app#faq-1"
        },
        {
          "question": "What is the safe way to show a running or cycling route to other users?",
          "answer": "Assume the route starts at the user's home, because it usually does. If you publish routes, treat user-defined privacy zones as a launch requirement rather than a later setting, and apply the trim on the server so untrimmed geometry never reaches another client. Strip precise coordinates from everything derived, including share images, previews and notifications. Remember that summaries leak too: a trimmed map published alongside a total distance can reconstruct what the trim removed. Keep route sharing off by default and describe the consequence of enabling it in plain language rather than linking to a policy.",
          "url": "https://aifitnessapi.com/engagement/social-features-fitness-app#faq-2"
        },
        {
          "question": "Who moderates comments and photos in a fitness community, and what does that cost?",
          "answer": "You do, from the first day text or images exist. Budget for reporting and blocking, a queue somebody actually reads, a display-name policy, fast removal of content and accounts, and obligations that grow with your user base and regions. Fitness communities carry a specific hazard beyond spam and abuse: content promoting disordered eating, extreme restriction or unsafe training, which is a health-safety problem rather than a taste one. Our judgement is that a team without review capacity should ship a fixed set of reactions instead of free text, since adding comments later is much easier than taking them away from an established community.",
          "url": "https://aifitnessapi.com/engagement/social-features-fitness-app#faq-3"
        }
      ]
    },
    {
      "question": "gamification in fitness apps",
      "answer": "Gamification in a fitness app differs from gamification in a game because the currency is effort produced by a body that tires and gets injured, not taps. Points, badges, levels, quests and daily goals each reward something different, and satisfiable goals like rings fit exercise best because the reward stops when the target is met. Any uncapped mechanic that rewards volume will be treated as a target by some users, which is why we cap daily contributions, reward consistency, technique and recovery rather than only totals, and never reward training through injury. Whether extrinsic rewards help or crowd out a user's own reasons is a design trade-off we treat as judgement, not as a research finding we can cite. Measure the whole thing with a holdout at four weeks and beyond, because novelty decays.",
      "title": "Gamification in Fitness Apps: Which Mechanics Fit Exercise",
      "url": "https://aifitnessapi.com/engagement/gamification-in-fitness-apps",
      "markdown": "https://aifitnessapi.com/engagement/gamification-in-fitness-apps.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Which game mechanics are unsafe to attach to exercise volume?",
          "answer": "Any mechanic without a ceiling. An uncapped points economy, a ranking on total minutes, or a reward for consecutive personal records all tell a motivated user that more is always better, and in a physical activity that can mean overtraining, training through pain, or an app-shaped justification for disordered behavior. This is incentive-design judgement rather than a cited finding. The countermeasures are concrete: cap what one day can contribute and show the cap, prefer satisfiable targets over maximizing ones, reward consistency, variety, technique and recovery alongside volume, make rest a rewardable state, and stop issuing rewards when a user has told you they are injured or ill.",
          "url": "https://aifitnessapi.com/engagement/gamification-in-fitness-apps#faq-1"
        },
        {
          "question": "Do points and badges crowd out a user's own reasons for exercising?",
          "answer": "We are not going to claim a research answer, because we verified no psychology literature for this page. As a design trade-off we treat it this way: extrinsic rewards are good at prompting a specific action now and are easy to render, but they are the app's story, while the reasons people train for years are usually their own. So we keep the game layer pointed at real progress the user already cares about, make it possible to ignore the mechanics entirely and still have a useful app, and treat the question as a bet testable in your own product with a holdout rather than one settled by citation.",
          "url": "https://aifitnessapi.com/engagement/gamification-in-fitness-apps#faq-2"
        },
        {
          "question": "Can I use platform achievement systems for fitness badges?",
          "answer": "Apple's GameKit documents achievements alongside leaderboards as a way to reward players, and Google Play Games Services hosts leaderboards with automatic daily, weekly and all-time versions. Two caveats. GameKit requires Game Center: Apple documents that you must enable it and initialize the local player or your app receives a notAuthenticated error. And Apple's documentation is written for games throughout, so a non-game fitness app should confirm the fit rather than assume it. For daily goals specifically, glanceable surfaces such as widgets, watch complications and Live Activities usually do more work than a scoring service does.",
          "url": "https://aifitnessapi.com/engagement/gamification-in-fitness-apps#faq-3"
        }
      ]
    },
    {
      "question": "does camera coaching improve retention",
      "answer": "Nobody can show you that camera-based coaching improves retention, because no public dataset measures it and every vendor case study you will find is marketing. The product argument is real and worth stating plainly: feedback delivered during a rep turns a workout from a video you follow into a session that responds to you. The costs are equally real, and they land before the first rep — a camera permission, a place to prop the phone, usable light, and a willingness to be watched, plus a workload that heats the device and drains the battery. Camera coaching also rules out contexts where plenty of workouts happen, like a crowded gym. Treat the retention question as an experiment you have to run yourself with a holdout, not a claim you can buy from a vendor.",
      "title": "Does Camera Coaching Improve Retention?",
      "url": "https://aifitnessapi.com/engagement/camera-coaching-engagement",
      "markdown": "https://aifitnessapi.com/engagement/camera-coaching-engagement.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": true,
      "faqs": [
        {
          "question": "Is there any published evidence that real-time form feedback keeps users coming back?",
          "answer": "Not that we can verify. No public dataset measures camera coaching against retention for fitness apps, and the material that circulates is vendor case-study marketing with unstated cohorts, unstated return events, and no comparison group. We will not cite it, and we publish no figures of our own. The mechanic may well work in your product, but the only credible way to know is a randomized holdout in your own app with the metric fixed in advance and the result read no earlier than four weeks in.",
          "url": "https://aifitnessapi.com/engagement/camera-coaching-engagement#faq-1"
        },
        {
          "question": "Should the camera be required to start a workout in our app?",
          "answer": "Our judgement: no. Requiring it puts a permission prompt, a phone-propping problem, and a lighting problem in front of the value, and it excludes the gym, the hotel gym, and anywhere the user does not want to be filmed. Treat camera coaching as an enhancement on a workout that can also run without it. That way a denied permission costs you a feature rather than a session, and the users who do opt in become a natural comparison group for whether the feature earns its place.",
          "url": "https://aifitnessapi.com/engagement/camera-coaching-engagement#faq-2"
        },
        {
          "question": "What does camera-based coaching cost in battery and heat during a session?",
          "answer": "We publish no numbers here because the answer is entirely device-dependent and we have not benchmarked it. What we can say as engineering judgement: continuous capture plus per-frame inference is among the heaviest sustained workloads a phone runs, and thermal throttling degrades exactly the feedback quality that justified turning the camera on. Measure it yourself on the oldest device tier you support, in a warm room, across your longest workout, and watch whether the user has enough battery left to train again that day.",
          "url": "https://aifitnessapi.com/engagement/camera-coaching-engagement#faq-3"
        }
      ]
    },
    {
      "question": "how to measure retention fitness app",
      "answer": "Retention is not one number, it is a cohort plus a return event plus a definition, and a fitness app gets a different answer for each choice. Group users by the week they first completed a workout rather than the day they installed, then decide explicitly whether returning means opening the app or finishing a session, because for a fitness product those are two different products' worth of truth. Pick one of the three standard definitions (classic, rolling, or range) and label every chart with which one you used. D1, D7, and D30 are reporting conventions borrowed from apps people use daily, and a fitness app that is meant to be used a few times a week is better described by weekly active days and weeks with at least one session. Watch seasonality, especially the January cohort, which behaves unlike any other intake you will ever measure.",
      "title": "How to Measure Retention in a Fitness App",
      "url": "https://aifitnessapi.com/engagement/measuring-retention-fitness-app",
      "markdown": "https://aifitnessapi.com/engagement/measuring-retention-fitness-app.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Should a fitness app cohort be grouped by install date or by first workout?",
          "answer": "First completed workout, in our judgement, and grouped by week rather than by day. Install-date cohorts blend real users with store-listing tourists and people who never finished onboarding, so the resulting curve mostly measures signup friction. Grouping on the first completed workout starts the clock at the behavior your product exists to cause, and weekly buckets absorb the weekday-versus-weekend rhythm that makes daily cohorts noisy. Whichever you choose, freeze the definition, because a retention comparison spanning a cohort-definition change is not a comparison at all.",
          "url": "https://aifitnessapi.com/engagement/measuring-retention-fitness-app#faq-1"
        },
        {
          "question": "Is classic, rolling, or range retention the right definition for a workout product?",
          "answer": "Range retention over week-long brackets usually describes a fitness product best, because the product is designed for a few sessions a week rather than daily use. Classic N-day retention asks whether the user returned on that exact day and will show a collapse that is really just your intended cadence. Rolling retention answers a different and narrower question: whether the user is gone permanently. None of the three is wrong, but the chart has to say which one it is, since a reader cannot infer the definition from the curve's shape.",
          "url": "https://aifitnessapi.com/engagement/measuring-retention-fitness-app#faq-2"
        },
        {
          "question": "Why does this site publish no benchmark retention curves for fitness apps?",
          "answer": "Because we could not find credible public ones for the category, and inventing a plausible-looking benchmark is the single most damaging thing a reference page can do. The figures that circulate come from vendor and agency material with undisclosed cohort definitions, undisclosed return events, and heavy survivorship bias toward products with good news to publish. A number of unknown provenance is worse than no number, because teams act on it. Use your own earlier cohorts, measured identically, as the only baseline you can actually defend.",
          "url": "https://aifitnessapi.com/engagement/measuring-retention-fitness-app#faq-3"
        }
      ]
    },
    {
      "question": "a/b test engagement feature app",
      "answer": "Randomize at the user, not the session or the device, and write down the metric, the duration, and the decision rule before the experiment starts. Keep a holdout that stays off the feature after launch, because that is the only group that can tell you a year from now whether the effect was real. Read the result at four weeks or later: engagement features flatter themselves in week one, when the novelty is doing the work. Track guardrail metrics such as notification opt-outs, uninstalls, and workout completion alongside the target, since an engagement win bought with an opt-out spike is a loss. The most common way teams convince themselves a feature worked is a staged rollout with no control group, where seasonality and the release itself are free to take the credit.",
      "title": "A/B Testing an Engagement Feature",
      "url": "https://aifitnessapi.com/engagement/ab-testing-engagement-features",
      "markdown": "https://aifitnessapi.com/engagement/ab-testing-engagement-features.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "How long should an engagement experiment run before we read the result?",
          "answer": "Four weeks at minimum, decided before the test starts. Fitness behavior runs on a weekly rhythm, so anything shorter cannot separate a durable habit change from novelty: new features get explored because they are new, and that burst inflates week one for a streak counter, a leaderboard, or a redesigned home screen alike. If the advantage has evaporated by week four, you learned something valuable about the mechanic. Fixing the duration up front also removes the temptation to stop the moment the chart looks favorable.",
          "url": "https://aifitnessapi.com/engagement/ab-testing-engagement-features#faq-1"
        },
        {
          "question": "Can we use a staged App Store or Play rollout as the control group?",
          "answer": "No. Staged rollout is a deployment safety valve, not randomization. The users who receive an early slice are self-selected toward fast updaters, who tend to be your most engaged users, and the comparison you end up making is this week against last week. That comparison is confounded with seasonality, marketing, store featuring, and everything else that happened in the calendar. If you read a staged rollout as an experiment, what you are actually measuring is your update-adoption curve.",
          "url": "https://aifitnessapi.com/engagement/ab-testing-engagement-features#faq-2"
        },
        {
          "question": "Which guardrail metrics should run alongside the target in an engagement test?",
          "answer": "At least four: notification opt-out rate, uninstalls, workout completion rate, and session length. Each catches a different way of winning the target metric while damaging the product — engagement bought by pushing notifications harder spends permission you cannot easily get back, uninstalls never show up in any in-app number, and sessions started only to protect a streak show up as completions falling while starts rise. Define the guardrail thresholds during pre-registration, while nobody is yet invested in the outcome.",
          "url": "https://aifitnessapi.com/engagement/ab-testing-engagement-features#faq-3"
        }
      ]
    },
    {
      "question": "fitness app engagement metrics",
      "answer": "A fitness product is described by six metrics: workout completion rate, active days per week, weeks with at least one session, streak survival, time to second workout, and reactivation after a lapse. Each one corresponds to a decision someone on the team can act on, which is the test a metric has to pass. Installs, cumulative sessions, and screen time fail that test, and screen time is arguably an anti-goal here, since a good workout is time spent away from the phone. The instrumentation detail that decides whether any of this works is the difference between a workout-started event and a workout-completed event; count completions and keep starts only as the denominator. Every one of these numbers depends on a day boundary, so define the civil date once and use the same rule in analytics and in product logic.",
      "title": "Fitness App Engagement Metrics That Matter",
      "url": "https://aifitnessapi.com/engagement/engagement-metrics-that-matter",
      "markdown": "https://aifitnessapi.com/engagement/engagement-metrics-that-matter.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Is time spent in the app a good engagement metric for a workout product?",
          "answer": "Our judgement is that it is close to an anti-goal. A fitness app succeeds when the person is training, which usually means the phone is propped against something or in a pocket rather than being interacted with. Long in-app time during a session more often indicates a confusing interface than an engaged user. Keep it as a diagnostic that gets read alongside workout completion rate, where a rise in one with a flat other points to friction, but keep it out of the goal column of any plan, because whatever sits there will get optimized.",
          "url": "https://aifitnessapi.com/engagement/engagement-metrics-that-matter#faq-1"
        },
        {
          "question": "Why track a workout-started event separately from a workout-completed event?",
          "answer": "Because the gap between them is where your product's real failure lives. If you only instrument one, it will be the start, since that is easier to detect, and every downstream number inflates while abandonment becomes invisible. Fire both with a shared session identifier, use completions as the metric and starts as the denominator, and define completion in product terms rather than as reaching a summary screen. Record partial sessions explicitly too: an abandoned workout is a signal about your content length or difficulty, not noise to be discarded.",
          "url": "https://aifitnessapi.com/engagement/engagement-metrics-that-matter#faq-2"
        },
        {
          "question": "What is the earliest metric that tells us whether onboarding is working?",
          "answer": "Time to second workout. The first completed workout is caused by whatever motivation brought the person to the app, so it mostly measures acquisition and the signup flow. The second one is caused by your product, which makes the gap between them the earliest honest read on whether onboarding produced a user or a trial. It also responds quickly to changes, unlike the multi-week measures, so it is the metric to instrument first if you are only going to build one well.",
          "url": "https://aifitnessapi.com/engagement/engagement-metrics-that-matter#faq-3"
        }
      ]
    },
    {
      "question": "notification opt out rate fitness app",
      "answer": "A notification permission is spent once. Google documents that if an Android user declines POST_NOTIFICATIONS then all notification channels are blocked except for a few specific roles, and there is no second system prompt, so an aggressive messaging experiment is a one-way door rather than a reversible test. Notification channels are both the user's volume control and your diagnostic: split them by message type so somebody can mute marketing and keep workout reminders instead of blocking the app outright. Apple's provisional authorization option, documented as the ability to post noninterrupting notifications provisionally to the Notification Center, does not require an explicit prompt, which lets your messages make the case before you ask for interruption rights. Track notification opt-out rate, uninstalls and session-length collapse as pre-registered guardrails beside whatever metric you are trying to move, and measure your own baseline rather than borrowing a figure from a vendor blog post.",
      "title": "Notification Fatigue and Opt-Out in Fitness Apps",
      "url": "https://aifitnessapi.com/engagement/notification-fatigue-and-optout",
      "markdown": "https://aifitnessapi.com/engagement/notification-fatigue-and-optout.md",
      "cluster": "Engagement & Retention",
      "cluster_url": "https://aifitnessapi.com/engagement",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "How should a fitness app split its Android notification channels so users mute a category instead of the whole app?",
          "answer": "Split by what the message is, not by which internal team requested it. Session events, plan and schedule reminders, results synced from a connected device, social activity, and marketing are five genuinely different appetites, and a user who mutes one while keeping the rest stays reachable. Shipping a single channel called Notifications forces an all-or-nothing decision and destroys your ability to learn which category caused the damage, which matters because Google documents that declining the permission outright blocks all channels. Settle the taxonomy before launch, since a channel's user-set importance is not yours to change later.",
          "url": "https://aifitnessapi.com/engagement/notification-fatigue-and-optout#faq-1"
        },
        {
          "question": "What is a normal notification opt-out rate for a fitness app, and what should I compare mine against?",
          "answer": "There is no verifiable public benchmark, and we will not invent one. Figures circulating in vendor marketing describe other apps, other categories and other message mixes, so they are not a baseline for yours. Measure your own opt-out rate per channel, track its direction over weeks rather than days, and evaluate any messaging change against a randomized holdout rather than against last month, which had a different app version and different people in it. Treat opt-out, uninstalls and session-length collapse as pre-registered guardrails next to the metric you are actually trying to move.",
          "url": "https://aifitnessapi.com/engagement/notification-fatigue-and-optout#faq-2"
        },
        {
          "question": "How should a fitness app send a streak-at-risk notification without burning its notification permission?",
          "answer": "Ration it and reframe it. Send at most one per at-risk day, and only to users who have already engaged with the streak, because pushing somebody into that mechanic by notification is a poor introduction. Write what counts rather than what will be lost: a short session that still qualifies today is a route back in, while a reminder of how many days are at stake reads as a debt collection letter. Then give the streak a way to survive without any message at all through a grace day, a repair or a rest day that counts. A mechanic that only works by interrupting people is the real problem.",
          "url": "https://aifitnessapi.com/engagement/notification-fatigue-and-optout#faq-3"
        }
      ]
    },
    {
      "question": "build apple watch workout app",
      "answer": "A watchOS workout app is two Apple objects plus a state machine you write yourself. HKWorkoutSession is the live half: Apple describes it as a session that tracks a person's workout, and documents that it fine-tunes Apple Watch's sensors for the activity you declare, with all workout sessions generating high-frequency heart rate samples. HKLiveWorkoutBuilder is the record-keeping half, described by Apple as a builder object that constructs a workout incrementally based on live data from an active workout session, and used to create the HKWorkout sample while the session is running. The work your app owns is the lifecycle around them: session state transitions, pause and resume, and the case where the session ends without you asking, because Apple documents that Apple Watch runs one workout session at a time and a second workout ending yours. Treat session state as the single source of truth and render every screen from it.",
      "title": "Anatomy of a watchOS Workout App",
      "url": "https://aifitnessapi.com/watch-apps/watchos-workout-app-anatomy",
      "markdown": "https://aifitnessapi.com/watch-apps/watchos-workout-app-anatomy.md",
      "cluster": "Watch Apps",
      "cluster_url": "https://aifitnessapi.com/watch-apps",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Which object owns what between HKWorkoutSession and HKLiveWorkoutBuilder?",
          "answer": "The session is the live half and the builder is the record. Apple describes HKWorkoutSession as a session that tracks a person's workout, and documents that it fine-tunes Apple Watch's sensors for the declared activity. Apple describes HKLiveWorkoutBuilder as a builder object that constructs a workout incrementally based on live data from an active workout session, and states you use it to create the HKWorkout sample during an active session. Practically: sensor behavior, lifecycle and exclusivity are session concerns, while accumulated samples, events and the saved result are builder concerns. A fault in one does not present like a fault in the other.",
          "url": "https://aifitnessapi.com/watch-apps/watchos-workout-app-anatomy#faq-1"
        },
        {
          "question": "Does elapsedTime on a live workout builder subtract the time a workout spent paused?",
          "answer": "No. Apple documents the property as the elapsed time for the workout based on the builder's current contents, including pauses. If your interface promises something like moving time or working time, that is a number you derive rather than one you read. Our advice, offered as judgement: define each clock your product shows in exactly one place in code, drive every screen and every saved summary from that definition, and never let a view compute its own version. Independently computed timers drift, and users notice a mismatch between the ring and the summary long before a test does.",
          "url": "https://aifitnessapi.com/watch-apps/watchos-workout-app-anatomy#faq-2"
        },
        {
          "question": "What does shouldCollectWorkoutEvents change about a saved watchOS workout?",
          "answer": "Apple documents it as a Boolean value that determines whether the workout builder automatically adds events generated by the workout session. Left on, session-generated events land in the accumulating sample without your involvement; turned off, they do not. Choose deliberately rather than by default, especially if your app also writes its own events for intervals, sets or laps. The failure mode is not a crash but a saved workout carrying two overlapping accounts of the same session, which is confusing in the Health app and worse in any analysis you run over your own history later.",
          "url": "https://aifitnessapi.com/watch-apps/watchos-workout-app-anatomy#faq-3"
        }
      ]
    },
    {
      "question": "healthkit on apple watch",
      "answer": "HealthKit on Apple Watch is the same framework as on iPhone doing a different job. On the phone it is mostly a store you query for history; on the watch it is the store where a workout lands, while the live numbers during that workout come from an active workout session instead. Apple documents HKLiveWorkoutBuilder as the object that creates the HKWorkout sample during an active HKWorkoutSession, so the write is the end of the session rather than a separate sync step. Authorization still behaves the way it does everywhere else on Apple platforms, including the part that catches everybody: the system does not tell you whether read access was granted, so an empty query result means no data or no permission and the two are indistinguishable by design. Design the watch app to read live from the session and treat the store as history, not as a stream.",
      "title": "HealthKit on Apple Watch: What Changes on the Wrist",
      "url": "https://aifitnessapi.com/watch-apps/healthkit-on-apple-watch",
      "markdown": "https://aifitnessapi.com/watch-apps/healthkit-on-apple-watch.md",
      "cluster": "Watch Apps",
      "cluster_url": "https://aifitnessapi.com/watch-apps",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Does a watchOS app learn whether the user allowed reading a health type, when an iPhone app cannot?",
          "answer": "No, and you should build for that. Across Apple platforms the system withholds read-permission status so that an app cannot infer whether somebody has health data at all. Write and share status is reported reliably; read status typically reads as not determined even after a grant. The documented pattern is to run the query and treat an empty result as either no data or no permission, since the two are indistinguishable by design. On a watch face-sized screen that means every stored-data view needs a real empty state, and no screen should be blocked behind a permission check that cannot return an answer.",
          "url": "https://aifitnessapi.com/watch-apps/healthkit-on-apple-watch#faq-1"
        },
        {
          "question": "During a workout, should a watch app query the HealthKit store for heart rate or take it from the session?",
          "answer": "Take it from the session. HealthKit is a store rather than a live feed, so querying it repeatedly during exercise spends power without improving how fresh the number is. Apple documents that a workout session fine-tunes Apple Watch's sensors for the specified activity and that all workout sessions generate high-frequency heart rate samples, which is the behavior a live screen depends on. Use the store for what happened before this session started — history, comparisons, streaks — and let the live view render from session data only. Mixing the two on one screen is how apps end up showing two different numbers for the same moment.",
          "url": "https://aifitnessapi.com/watch-apps/healthkit-on-apple-watch#faq-2"
        },
        {
          "question": "When does a watchOS workout actually get written into HealthKit?",
          "answer": "As it happens, then finalized at the end. Apple describes HKLiveWorkoutBuilder as a builder object that constructs a workout incrementally based on live data from an active workout session, and documents that you use it to create the HKWorkout sample during an active HKWorkoutSession. There is no separate upload step to schedule afterward. Two design notes follow: the ending sequence contains real work that can fail on a watch about to be dropped on a charger, and because Apple documents that a second workout starting will end yours, the ending is not always something your own UI initiated.",
          "url": "https://aifitnessapi.com/watch-apps/healthkit-on-apple-watch#faq-3"
        }
      ]
    },
    {
      "question": "apple watch background execution workout",
      "answer": "Apple Watch has two ways to keep your app running after somebody drops their wrist, and which one you get depends on what your app is. A training app uses an active HKWorkoutSession, which Apple documents as supporting background execution while the device is locked. Everything else uses WKExtendedRuntimeSession, described by Apple as a session that continues to run your app after the user has stopped interacting, with the app able to keep talking to Bluetooth devices, process data, or play sounds or haptics even after the screen turns off. Apple documents four extended runtime types — self care, mindfulness, physical therapy, and smart alarm — selected by enabling the matching Background Modes capability, and workout is deliberately not among them because workouts belong to HKWorkoutSession. That single fact is why a rehab or meditation app on watchOS takes a different architectural path than a training app.",
      "title": "Background Execution on Apple Watch: Two Mechanisms",
      "url": "https://aifitnessapi.com/watch-apps/apple-watch-background-execution",
      "markdown": "https://aifitnessapi.com/watch-apps/apple-watch-background-execution.md",
      "cluster": "Watch Apps",
      "cluster_url": "https://aifitnessapi.com/watch-apps",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Which extended runtime type should a training app enable in Background Modes on watchOS?",
          "answer": "None of them. Apple documents that each app supports a single type of extended runtime session — self care, mindfulness, physical therapy, or smart alarm — selected by enabling the matching Background Modes capability, and workout is not on that list. Workouts run under HKWorkoutSession instead, which Apple documents as supporting background execution while the device is locked. So a training app gets its runtime from running a workout session rather than from declaring a background mode. Looking for a workout entry in that capability list is a common early detour, and it does not exist.",
          "url": "https://aifitnessapi.com/watch-apps/apple-watch-background-execution#faq-1"
        },
        {
          "question": "Can one watchOS app declare both mindfulness and physical therapy extended runtime sessions?",
          "answer": "No. Apple's wording is that each app can support a single type of extended runtime session, chosen from self care, mindfulness, physical therapy, or smart alarm, and selected by enabling the appropriate Background Modes capability. That is a product-scoping constraint rather than a build setting to work around: a single app cannot cover a guided meditation experience and a rehab protocol under two different declared types. Decide which category the app genuinely is before you design the feature set, and if the roadmap really needs both, shipping two apps is the honest option to evaluate early.",
          "url": "https://aifitnessapi.com/watch-apps/apple-watch-background-execution#faq-2"
        },
        {
          "question": "What can a watchOS app keep doing after the screen turns off during an extended runtime session?",
          "answer": "Apple documents that with extended runtime sessions the app continues to run after the user stops interacting with it, and that it can continue to communicate with Bluetooth devices, process data, or play sounds or haptics even after the watch's screen turns off. That capability set is what makes an unattended guided experience possible: cues can fire, a paired sensor stays connected, and work continues with nobody looking. The session is finite, though — it carries an expirationDate, is started with start() or start(at:), and is ended with invalidate() — so design an explicit behavior for the case where the runtime ends before your protocol does.",
          "url": "https://aifitnessapi.com/watch-apps/apple-watch-background-execution#faq-3"
        }
      ]
    },
    {
      "question": "workoutkit scheduled workouts apple watch",
      "answer": "WorkoutKit is Apple's framework for creating, previewing, and syncing workout compositions to the Workout app. It gives you four composition types — CustomWorkout, SingleGoalWorkout, PacerWorkout and SwimBikeRunWorkout — wrapped in a WorkoutPlan that can be previewed or handed over with openInWorkoutApp(). With the user's permission, obtained through WorkoutScheduler.requestAuthorization() and applied with WorkoutScheduler.schedule(_:at:), scheduled compositions sync to Apple Watch and, as Apple documents, appear in a dedicated space in the Workout app carrying your app's icon and name. Apple lists WorkoutKit from iOS, iPadOS and Mac Catalyst 17.0 and watchOS 10.0. For a coaching product that changes the delivery question entirely: today's session can be waiting in Apple's own Workout app instead of requiring somebody to open yours.",
      "title": "WorkoutKit: Scheduling Workouts Into Apple's Workout App",
      "url": "https://aifitnessapi.com/watch-apps/workoutkit-scheduled-workouts",
      "markdown": "https://aifitnessapi.com/watch-apps/workoutkit-scheduled-workouts.md",
      "cluster": "Watch Apps",
      "cluster_url": "https://aifitnessapi.com/watch-apps",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Which composition types does WorkoutKit provide for describing a workout?",
          "answer": "Apple documents four. CustomWorkout is described as a structured interval workout with a series of steps containing custom goals and alerts. SingleGoalWorkout is a workout with a single goal, such as distance, energy, or time. PacerWorkout is a workout with distance and time goals. SwimBikeRunWorkout is described as a workout that allows triathletes to seamlessly transition between swim, bike, and run activities. Use the list as a compatibility check on your programming model: if what you prescribe cannot be described faithfully by one of the four, a composition is the wrong container for it and your own app should keep that programming.",
          "url": "https://aifitnessapi.com/watch-apps/workoutkit-scheduled-workouts#faq-1"
        },
        {
          "question": "Where does a scheduled WorkoutKit composition show up for the user?",
          "answer": "In Apple's Workout app. Apple documents that you can create and maintain a workout schedule and, with the user's permission, sync scheduled compositions to Apple Watch, and that these compositions appear in a dedicated space in the Workout app and include your app's icon and name. The scheduling flow is WorkoutScheduler.requestAuthorization() to obtain permission and WorkoutScheduler.schedule(_:at:) to place a composition at a time. For a coaching product this means today's session can be waiting on the watch, attributed to you, without the user opening your app at all.",
          "url": "https://aifitnessapi.com/watch-apps/workoutkit-scheduled-workouts#faq-2"
        },
        {
          "question": "What OS versions do I need before WorkoutKit is available?",
          "answer": "Apple lists WorkoutKit availability from iOS 17.0, iPadOS 17.0 and Mac Catalyst 17.0, together with watchOS 10.0. Anything below those floors has no access to the framework, so a deployment target that reaches further back needs a separate path for the same product need — in practice, your own watch app built on a workout session. Version floors are exactly the kind of claim worth rechecking against Apple's current documentation before you set a deployment target, since availability lines get extended to new platforms over time and this page states what was documented as of its review date.",
          "url": "https://aifitnessapi.com/watch-apps/workoutkit-scheduled-workouts#faq-3"
        }
      ]
    },
    {
      "question": "mirror apple watch workout to iphone",
      "answer": "Apple documents that a workout session supports mirroring the workout to a companion iPhone, along with Live Activities on the Lock Screen and Siri control for starting, pausing, resuming and canceling. That turns a watch app into a multidevice product, and the architectural decision it forces is which device owns session state. Our recommendation is that the session on the watch is the single source of truth and everything else — the phone screen, the Live Activity, a Siri command — is either a view of it or a command sent to it. Two devices each keeping their own idea of whether a workout is paused is the failure mode, and it produces bugs that only reproduce with two devices, one user and bad timing.",
      "title": "Mirroring an Apple Watch Workout to iPhone",
      "url": "https://aifitnessapi.com/watch-apps/mirroring-workouts-to-iphone",
      "markdown": "https://aifitnessapi.com/watch-apps/mirroring-workouts-to-iphone.md",
      "cluster": "Watch Apps",
      "cluster_url": "https://aifitnessapi.com/watch-apps",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "When a workout is mirrored, which device should hold the authoritative session state?",
          "answer": "The watch, in our judgement, because that is where the session and the sensors are and where Apple's one-session-at-a-time rule applies. Give the phone no independent notion of whether the workout is running: every phone interaction becomes a command sent to the watch, and every phone view renders from the state that came back. The distinction matters most for timers, where a phone counting seconds on its own will visibly diverge from the watch within a single session. Users read that divergence as the app being wrong about their workout rather than as a synchronization detail.",
          "url": "https://aifitnessapi.com/watch-apps/mirroring-workouts-to-iphone#faq-1"
        },
        {
          "question": "Can Siri pause or cancel a workout that my own app started on Apple Watch?",
          "answer": "Apple documents that workout sessions support Siri control for starting, pausing, resuming and canceling. The practical consequence is that state changes can originate outside any interface you wrote, which is the same lesson taught by the rule that a second workout starting will end your session. Build views as pure functions of session state and an externally initiated change stops being a special case: the state changed and the interface redrew. Hold state inside individual views instead and every external origin becomes a separate bug class, with combinations that multiply faster than you can test them.",
          "url": "https://aifitnessapi.com/watch-apps/mirroring-workouts-to-iphone#faq-2"
        },
        {
          "question": "What should the iPhone display if it loses contact with the watch mid-session?",
          "answer": "Something honest about what it does and does not know. The workout is running on the wrist, so it continues regardless of what the phone can see, and the phone's job is to stop presenting stale numbers as live ones. Define three behaviors up front: what the screen shows while a command is in flight, what it shows when no acknowledgement arrives, and what it shows when it reconnects to a session that ended without it. Anything the phone was solely responsible for during the session has to be either unnecessary or recoverable after a gap.",
          "url": "https://aifitnessapi.com/watch-apps/mirroring-workouts-to-iphone#faq-3"
        }
      ]
    },
    {
      "question": "wear os fitness app standalone",
      "answer": "A Wear OS app declares whether it is standalone with a com.google.android.wearable.standalone meta-data value in its manifest. Google defines a standalone app as one that does not require a phone app for core features, where \"Open on phone\" prompts are acceptable only if the app also provides an alternative means — such as a shortlink or QR code — to complete the function without a tethered phone; a non-standalone app depends on a phone app for a core feature such as authentication. The value is not just documentation: Google validates its accuracy during app serving, it affects visibility in the Play Store on untethered devices, and non-standalone apps as well as apps incorrectly designated standalone are not available to users on those devices. Even when the value is false, the watch app can be installed before the phone app, so the watch has to behave sensibly on its own regardless. For a fitness app the deciding feature is almost always authentication, because everything else — the exercise session, local history, network calls — already runs on the wrist.",
      "title": "Wear OS Fitness App Anatomy: Standalone or Not (2026)",
      "url": "https://aifitnessapi.com/watch-apps/wear-os-app-anatomy",
      "markdown": "https://aifitnessapi.com/watch-apps/wear-os-app-anatomy.md",
      "cluster": "Watch Apps",
      "cluster_url": "https://aifitnessapi.com/watch-apps",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Where does a Wear OS app declare that it is standalone, and what happens if the value is wrong?",
          "answer": "It is a meta-data entry named com.google.android.wearable.standalone in the watch app's manifest, set to true or false. Google's documentation states that it validates the accuracy of an app's standalone status during app serving, that the value affects visibility of apps within the Play Store on untethered devices, and that non-standalone apps — as well as apps developers incorrectly designate as standalone — are not available to users on those devices. Both kinds of error therefore cost you the same audience, so treat the value as a claim you can support rather than a switch you flip to widen distribution.",
          "url": "https://aifitnessapi.com/watch-apps/wear-os-app-anatomy#faq-1"
        },
        {
          "question": "Can a Wear OS watch app be installed before the phone app it depends on?",
          "answer": "Yes. Google documents that even if the value of com.google.android.wearable.standalone is false, the watch app can be installed before the phone app is installed. Declaring a dependency does not make the platform enforce an install order, so your first-run path has to assume the phone side may be missing. Practically that means the watch app needs a real state for it: explain what is not available yet and offer a route to fix it, rather than showing an empty screen or a spinner that never resolves because it is waiting for a device that was never there.",
          "url": "https://aifitnessapi.com/watch-apps/wear-os-app-anatomy#faq-2"
        },
        {
          "question": "How should a Wear OS fitness app handle sign-in when the paired phone is an iPhone?",
          "answer": "Assume you cannot detect the phone side at all. Google's documentation states that from Wear OS you cannot programmatically determine whether your phone app is installed on an iOS device, and recommends as a best practice that you provide a mechanism for the user to manually trigger opening the App Store. So do not branch the UI on a capability check that has no answer — show the manual affordance. Our judgement is to go further and make authentication independent of the phone entirely, using a QR code, shortlink or device-code flow, which is also what keeps the app standalone.",
          "url": "https://aifitnessapi.com/watch-apps/wear-os-app-anatomy#faq-3"
        }
      ]
    },
    {
      "question": "wear os health services exercise tracking",
      "answer": "On Wear OS 3 and later, Health Services is the platform service a watch app uses to track exercise, sitting between the app and the device's sensors and algorithms. Google documents ExerciseClient as the API for managing workouts, setting exercise goals, listening for exercise state updates and receiving rapid data updates during active exercise, across metrics it lists as heart rate, distance, calories, elevation, floors, speed, pace and more. PassiveMonitoringClient handles the other half: receiving updates about a data type or an event, which Google says suits long-lived experiences where data updates are relatively infrequent. Google also states that Health Services conserves battery using sensor configurations optimized for power efficiency and verifies data consistency across all applications on the same device by using standardized platform computations. Build the app's state around the exercise state updates it receives rather than around a flag your own UI sets, and pair a Bluetooth sensor directly only when the signal comes from hardware the watch does not have.",
      "title": "Wear OS Exercise Tracking with Health Services (2026)",
      "url": "https://aifitnessapi.com/watch-apps/wear-os-exercise-tracking",
      "markdown": "https://aifitnessapi.com/watch-apps/wear-os-exercise-tracking.md",
      "cluster": "Watch Apps",
      "cluster_url": "https://aifitnessapi.com/watch-apps",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Do Health Services exercise goals replace the target-checking logic in my own Wear OS code?",
          "answer": "For the cases the platform models, our judgement is yes, and you should delete the duplicate. Google documents ExerciseClient as able to set exercise goals alongside managing workouts and listening for exercise state updates, so a distance or duration target can be evaluated by the platform against the same numbers it is already reporting to your UI. Your own comparison only runs when your code runs, which is a weaker guarantee on a watch. Keep custom logic for what the platform does not model — interval structure, coaching cues, rep counting — and build it on top of the exercise rather than beside it.",
          "url": "https://aifitnessapi.com/watch-apps/wear-os-exercise-tracking#faq-1"
        },
        {
          "question": "Should the watch or the phone own a Wear OS workout session?",
          "answer": "The watch, because that is where Health Services and the sensors are. The exercise runs on the device, exercise state updates originate there, and the rapid data updates during active exercise are delivered there. Our judgement is to treat the watch as the recording device and the phone as one of several places the finished data eventually lands. Designing it the other way — the phone as session owner, the watch as a remote display — depends on a link that does not exist when the watch is paired to an iPhone, which is the constraint covered on our Wear OS phone sync page.",
          "url": "https://aifitnessapi.com/watch-apps/wear-os-exercise-tracking#faq-2"
        },
        {
          "question": "Which Wear OS versions can run a Health Services exercise app, and what about older watches?",
          "answer": "Google documents Health Services as a platform service on Wear OS 3 and later, and its ExerciseClient and PassiveMonitoringClient APIs come with it. We did not verify this session what a Wear OS 2 device offers instead, so check current documentation before promising support there rather than assuming a fallback exists. Our judgement is to fix the minimum supported version before you design the tracking layer: the exercise path is the app, and discovering late that a slice of your install base cannot run it is an architectural problem rather than a compatibility patch.",
          "url": "https://aifitnessapi.com/watch-apps/wear-os-exercise-tracking#faq-3"
        }
      ]
    },
    {
      "question": "wear os tile fitness app",
      "answer": "A Wear OS tile is a glanceable surface in a carousel that Google describes as revealed by a swipe on the watch face, with additional swipes switching between tiles. Google frames the purpose as showing a small amount of key information that users can read through after they glance at a tile for a few seconds. Tiles are built declaratively with Jetpack's protolayout and tiles libraries rather than with Compose or Views, and because they render in a separate, remote environment they need different approaches to load, display and update data. Two constraints drive the design: tiles themselves cannot be scrolled, and Google's guidance is not to fetch content frequently or start long-running asynchronous work in the tile service — schedule with WorkManager and cache locally instead. For a fitness app, our judgement is that a tile should start the workout the user actually does and show one figure for today's progress, with everything else a tap away.",
      "title": "Wear OS Tiles for a Fitness App (2026)",
      "url": "https://aifitnessapi.com/watch-apps/wear-os-tiles",
      "markdown": "https://aifitnessapi.com/watch-apps/wear-os-tiles.md",
      "cluster": "Watch Apps",
      "cluster_url": "https://aifitnessapi.com/watch-apps",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I build a Wear OS tile with Jetpack Compose, and can users scroll it?",
          "answer": "No to both. Google's documentation states that tiles are built declaratively using Jetpack's protolayout and tiles libraries rather than with Compose or Views, so your app's UI toolkit does not carry over to this surface. It also states plainly that tiles themselves cannot be scrolled. Together those two facts mean a tile is a fixed, self-contained layout that has to fit what it shows. Google's guidance for content that does not fit is to avoid overcrowding and instead let users tap on tiles to learn more and take action on another surface in your app.",
          "url": "https://aifitnessapi.com/watch-apps/wear-os-tiles#faq-1"
        },
        {
          "question": "Where should a Wear OS tile get its data, given that it renders in a separate process?",
          "answer": "From local storage that something else keeps up to date. Google's documentation states that tiles render in a separate, remote environment and therefore require different approaches to load, display and update data, and its guidance is not to fetch content frequently or start long-running asynchronous work in your tile service — use WorkManager and cache locally instead. Treat the tile service as a rendering function over state that already exists. If the cache is stale, our judgement is to render it as stale, with a timestamp, rather than blocking the render on a fetch the user will not wait for.",
          "url": "https://aifitnessapi.com/watch-apps/wear-os-tiles#faq-2"
        },
        {
          "question": "Should a fitness tile show a workout summary or a start button?",
          "answer": "Our judgement is a start button for the specific workout this person actually does, plus one figure for today. Google's framing is that a tile shows a small amount of key information a user reads after glancing for a few seconds, and that content should not be overcrowded because users can tap through to another surface. A menu of workout types spends that budget on navigation, and a multi-metric summary spends it on numbers nobody parses in two seconds. Put the picker and the detail inside the app, and let the tile be the fastest possible route into the session.",
          "url": "https://aifitnessapi.com/watch-apps/wear-os-tiles#faq-3"
        }
      ]
    },
    {
      "question": "wear os data layer sync phone",
      "answer": "The Wear OS Data Layer synchronizes data between a watch and a paired device: Google documents DataClient as the API for components to read or write a DataItem or an Asset, with assets automatically deduplicated so the same bytes are not transferred twice. Google is explicit that it is meant to synchronize data and not serve as a storage mechanism, and advises keeping your own copy — for example in a Room database. The constraint that should drive your architecture is that the Data Layer works only with phones running Android or with Wear OS watches: Google states that if a Wear OS device is paired with an iOS device the API will not work, and that for this reason you should not use it as the primary way to communicate with a network. The practical answer is to have the watch talk to your backend directly, with its own local queue and its own credentials, and to treat the phone link as an optimization that some users will never have.",
      "title": "Wear OS Phone Sync: The Data Layer and Its Limits (2026)",
      "url": "https://aifitnessapi.com/watch-apps/wear-os-phone-sync",
      "markdown": "https://aifitnessapi.com/watch-apps/wear-os-phone-sync.md",
      "cluster": "Watch Apps",
      "cluster_url": "https://aifitnessapi.com/watch-apps",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Does the Wear OS Data Layer work when the watch is paired to an iPhone?",
          "answer": "No. Google's documentation states that the Data Layer API can send messages and synchronize data only with phones that run Android or with Wear OS watches, that if a Wear OS device is paired with an iOS device the Data Layer API will not work, and that for this reason you should not use it as the primary way to communicate with a network. It is an absence rather than a degradation, and it will not appear during development on an Android phone, so a design that routes workout upload through the phone will silently fail for a slice of real users.",
          "url": "https://aifitnessapi.com/watch-apps/wear-os-phone-sync#faq-1"
        },
        {
          "question": "Can I use DataItem storage as my Wear OS app's local database?",
          "answer": "No, and Google says so directly: the class is meant to synchronize data and not serve as a storage mechanism, and its guidance is to create your own copy of the data that your app can access, such as in a Room database. Treat synchronized items as a transport for changes between two copies that each device owns independently. Anything you would be unhappy to lose — recorded workouts above all — belongs in your own persistence layer first, with synchronization as a downstream effect of writing it there rather than as the place it lives.",
          "url": "https://aifitnessapi.com/watch-apps/wear-os-phone-sync#faq-2"
        },
        {
          "question": "Should a Wear OS fitness app upload workouts from the watch or hand them to the phone?",
          "answer": "From the watch. Google's guidance is to make network calls from the watch as you would from a phone, precisely because the phone link is not always available. Our judgement is to put the durable outbound queue on the device that recorded the workout, drain it when connectivity allows, and give the watch credentials it can obtain and refresh on its own. Handing data to the phone can still be a worthwhile optimization when both devices are reachable, but only if the feature degrades to slower rather than broken when the transport is not there.",
          "url": "https://aifitnessapi.com/watch-apps/wear-os-phone-sync#faq-3"
        }
      ]
    },
    {
      "question": "watchos vs wear os development fitness",
      "answer": "On watchOS the workout owns the app: Apple documents HKWorkoutSession as a session that tracks a person's workout, and it drives both the exercise lifecycle and the background execution that comes with it, while HKLiveWorkoutBuilder turns the live session into a stored workout sample. On Wear OS 3 and later the equivalent authority is Health Services, whose ExerciseClient manages the workout, exercise goals, state updates and rapid data updates, with PassiveMonitoringClient for long-lived experiences whose updates are infrequent. The glanceable surfaces are not equivalent either: Apple's WidgetKit builds complications for the watch face and the Smart Stack, while Wear OS tiles are built declaratively on Jetpack's protolayout and tiles libraries and, in Google's words, cannot be scrolled. Pairing is the sharpest difference, because an Apple Watch pairs with an iPhone but a Wear OS watch may be paired with an iOS phone, where Google documents that the Data Layer API will not work at all. Distribution differs too: a Wear OS app declares a standalone flag that Google validates during app serving and that affects Play Store visibility on untethered devices.",
      "title": "watchOS vs Wear OS: Building the App That Runs on the Watch",
      "url": "https://aifitnessapi.com/watch-apps/watch-platform-differences",
      "markdown": "https://aifitnessapi.com/watch-apps/watch-platform-differences.md",
      "cluster": "Watch Apps",
      "cluster_url": "https://aifitnessapi.com/watch-apps",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "If we already ship an HKWorkoutSession app, what is the Wear OS equivalent we build against?",
          "answer": "Health Services, and specifically ExerciseClient. On Wear OS 3 and later, Health Services sits between apps and the sensors and algorithms beneath them, and Google documents ExerciseClient as the API that manages workouts, sets exercise goals, listens for exercise state updates and delivers rapid data updates during an active exercise, over metrics including heart rate, distance, calories, elevation, floors, speed and pace. The mapping is not one-to-one, though. On watchOS the workout session is also your background-execution grant, and it feeds HKLiveWorkoutBuilder, which Apple documents as building the workout sample from live session data. On Wear OS, collecting data, staying visible on screen and persisting the result are separate concerns with separate APIs.",
          "url": "https://aifitnessapi.com/watch-apps/watch-platform-differences#faq-1"
        },
        {
          "question": "Is a watchOS complication the same kind of surface as a Wear OS tile?",
          "answer": "They serve a similar purpose and are built nothing alike. Apple's complications come from WidgetKit, appear on the watch face and in the Smart Stack, and update from a timeline of data you hand to WidgetKit, with pushes available. Wear OS tiles live in a carousel that Google documents as revealed by a swipe on the watch face, and they are built declaratively with Jetpack's protolayout and tiles libraries rather than Compose or Views, rendering in a separate remote environment. The constraint that decides your layout is Google's own: tiles themselves cannot be scrolled. Design one glance and one tap target per surface instead of a shared component.",
          "url": "https://aifitnessapi.com/watch-apps/watch-platform-differences#faq-2"
        },
        {
          "question": "How much of a watchOS fitness app can we reuse when we add Wear OS?",
          "answer": "Labelled as judgement rather than documentation: reuse the domain model, the scoring and the sync protocol, and expect to write the watch app itself twice. The three contracts that make a watch app a watch app — the exercise lifecycle, the permission to keep running and the glanceable surface — are platform-specific and none maps one-to-one. Pairing breaks portability further, because a Wear OS watch may be paired with an iOS phone, and Google documents that the Data Layer API will not work in that case. Plan on a shared core with two thin native watch clients rather than one abstraction stretched over both platforms.",
          "url": "https://aifitnessapi.com/watch-apps/watch-platform-differences#faq-3"
        }
      ]
    },
    {
      "question": "watch app battery drain fitness",
      "answer": "Battery is the constraint that decides what a watch app can be, and the levers that matter are documented rather than guessed. On watchOS, the activity type you declare on the workout session configures hardware: Apple states that the session fine-tunes Apple Watch's sensors for the specified activity, and that an outdoor cycling activity generates accurate location data while an indoor cycling activity does not. On Wear OS, Google documents that Health Services conserves battery by using sensor configurations optimized for power efficiency, and that PassiveMonitoringClient suits long-lived experiences whose data updates are relatively infrequent, so you are not holding an active exercise open all day. Glanceable surfaces are a recurring workload rather than a free one, and Google's tile guidance says not to fetch content frequently or start long-running asynchronous work in the tile service, using WorkManager and a local cache instead. We publish no battery figures, because the profile depends on your sensors, your screen behavior and the user's hardware, and the only way to know it is to measure a repeatable session on a real device.",
      "title": "Watch App Battery: The Constraint That Decides Scope",
      "url": "https://aifitnessapi.com/watch-apps/watch-app-battery",
      "markdown": "https://aifitnessapi.com/watch-apps/watch-app-battery.md",
      "cluster": "Watch Apps",
      "cluster_url": "https://aifitnessapi.com/watch-apps",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Why does declaring the right workout activity type matter for power on Apple Watch?",
          "answer": "Because the declaration configures hardware. Apple documents that a workout session fine-tunes Apple Watch's sensors for the specified activity, and gives a concrete example: all workout sessions generate high-frequency heart rate samples, but an outdoor cycling activity generates accurate location data while an indoor cycling activity does not. Declaring accurately therefore stops you paying for signals your feature never reads. The failure mode is choosing a broad or aspirational activity type so that everything is available, since everything is then also what the watch keeps powered. Pick the type that describes what the user is actually doing, and change it when the activity changes.",
          "url": "https://aifitnessapi.com/watch-apps/watch-app-battery#faq-1"
        },
        {
          "question": "Is there a lower-power way to keep a long-lived Wear OS feature updating without an active exercise?",
          "answer": "Yes, and that is what PassiveMonitoringClient is for. Google describes it as receiving updates about a data type or an event, suited to long-lived experiences where data updates are relatively infrequent — a different shape from ExerciseClient's rapid updates during an active workout. A readiness score, a resting-heart-rate trend or an all-day nudge is not a workout, and running one as an exercise holds the expensive path open all day for data you read occasionally. Google's broader point about Health Services applies either way: its sensor configurations are documented as optimized for power efficiency, and its computations are standardized across apps on the same device.",
          "url": "https://aifitnessapi.com/watch-apps/watch-app-battery#faq-2"
        },
        {
          "question": "Why won't you publish a figure for how much battery a watch workout app uses?",
          "answer": "Because we have not measured your app, and neither has whoever published the number you found. Drain depends on which sensors your activity declaration turns on, whether you hold your own Bluetooth link, how long your screen stays lit, how often you recompute and sync, and the specific hardware and OS version on a user's wrist. A figure lifted from another app's profile is not evidence about yours, and repeating one would make this page worse, not more useful. The artifact worth having is a repeatable session re-run on the oldest hardware you support, recorded with device and OS version, and compared against your own previous baseline.",
          "url": "https://aifitnessapi.com/watch-apps/watch-app-battery#faq-3"
        }
      ]
    },
    {
      "question": "test watch app without device",
      "answer": "A simulator or emulator cannot give you real sensors, a real Bluetooth link, real pairing or a real battery profile, so treat a physical device as the reliable target for those four and verify separately what your current tooling does support, with the version written down. Everything else can run in CI, but only if the sample stream enters your pipeline through an interface you can swap — the same seam argument as testing camera features without a device. Behind that interface, a watchOS workout session, Wear OS Health Services and a recorded file all look alike: a source of timestamped samples that eventually ends. Automate session assembly, derived metrics, goal progression, day boundaries and reconciliation against recorded sessions and fixtures. Reserve a written device pass for pairing, reconnection, background and lifecycle transitions, permission flows, and thermal and battery behavior.",
      "title": "Testing Watch Apps Without a Watch on Every Desk",
      "url": "https://aifitnessapi.com/watch-apps/testing-watch-apps",
      "markdown": "https://aifitnessapi.com/watch-apps/testing-watch-apps.md",
      "cluster": "Watch Apps",
      "cluster_url": "https://aifitnessapi.com/watch-apps",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Can I test watch sensors on the watchOS simulator or the Wear OS emulator?",
          "answer": "Verify what your simulator or emulator supports today and write the answer down with the tool version beside it, because that surface changes between releases and forum posts age badly. What does not change is that real sensor output, a real Bluetooth link, a real pairing and a real battery profile are properties of hardware, so treat a physical device as the reliable target for those. The better move is to make the answer matter less: if recorded samples can drive your pipeline through a swappable source, your tooling's capabilities stop being on the critical path for everything downstream of the sensor.",
          "url": "https://aifitnessapi.com/watch-apps/testing-watch-apps#faq-1"
        },
        {
          "question": "Which watch behaviors still need a physical device pass before release?",
          "answer": "Pairing and installation across the combinations you support, including the phone-app-missing state. Reconnection: out of range and back, phone in a locker, radio off mid-session. Background and lifecycle transitions: wrist down, screen off, locked device, a call arriving, another app taking the watchOS workout slot. Permission flows on real OS versions, including deny and then change your mind. And thermal and battery behavior over a full-length session on the oldest hardware you support. Write it as a fixed script against a fixed device list so the pass is repeatable release to release, rather than as an intention to try a few things before shipping.",
          "url": "https://aifitnessapi.com/watch-apps/testing-watch-apps#faq-2"
        },
        {
          "question": "What should a recorded watch session contain to be useful as a test fixture?",
          "answer": "Timestamped samples in capture order, each carrying its own timestamp so nothing depends on the clock at replay time, plus a terminal signal so the pipeline can flush and the test can finish rather than hang. Include the ugly parts: a sensor going quiet, a gap where skin contact was lost, a pause and resume, a duplicated or out-of-order sample, and a session that ends unexpectedly. Record the device, OS version and declared activity type alongside the file so the fixture is still interpretable a year later, and keep each one small enough that a reviewer can read it in a pull request.",
          "url": "https://aifitnessapi.com/watch-apps/testing-watch-apps#faq-3"
        }
      ]
    },
    {
      "question": "voiceover live workout metrics",
      "answer": "A live workout number is not something you announce to VoiceOver; it is something you let VoiceOver read when it asks. Apple documents the updatesFrequently trait as one you use to characterize an accessibility element that updates its label or value too frequently to send update notifications, and says to include it when you want an assistive app to avoid handling continual notifications and, instead, poll for changes when it needs updated information. A timer, rep count, pace or live heart rate is exactly that element, so the work moves from how often you push the value to how the value reads when it is polled. Discrete events that genuinely interrupt, such as rest ending or a set finishing, belong instead to Apple's announcement notification, which Apple describes as a notification an app posts when it needs to convey an announcement to the assistive app. Anything that auto-dismisses needs isVoiceOverRunning, documented by Apple as a Boolean value indicating whether VoiceOver is in an enabled state, with the example that you might want UI elements that usually disappear quickly to persist onscreen for VoiceOver users.",
      "title": "VoiceOver and the numbers that change during a set",
      "url": "https://aifitnessapi.com/accessibility/voiceover-live-workout-metrics",
      "markdown": "https://aifitnessapi.com/accessibility/voiceover-live-workout-metrics.md",
      "cluster": "Accessibility",
      "cluster_url": "https://aifitnessapi.com/accessibility",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Should a rep counter announce every rep to a VoiceOver user?",
          "answer": "No. A rep count is the kind of element Apple's updatesFrequently documentation describes: one that updates its label or value too frequently to send update notifications. Apple says to include the trait when you want an assistive app to avoid handling continual notifications and, instead, poll for changes when it needs updated information. So the counter carries the trait and holds a current, self-contained value such as eight of ten reps. Reserve an interruption for the moment the set completes, which is an event rather than a moving number. That keeps the channel free for the thing the user actually has to act on.",
          "url": "https://aifitnessapi.com/accessibility/voiceover-live-workout-metrics#faq-1"
        },
        {
          "question": "What is the difference between the updatesFrequently trait and posting an announcement?",
          "answer": "They solve opposite problems. Apple documents updatesFrequently for an element that updates its label or value too frequently to send update notifications, and says to include it when you want an assistive app to poll for changes instead. Apple documents the announcement notification as one an app posts when it needs to convey an announcement to the assistive app, for events that do not update the app's UI, or that update it in a way the extraction we hold does not finish describing. A live pace readout is the first case. Rest being over is the second.",
          "url": "https://aifitnessapi.com/accessibility/voiceover-live-workout-metrics#faq-2"
        },
        {
          "question": "How do I stop a two-second rest toast from disappearing before a screen reader reaches it?",
          "answer": "Check whether the screen reader is on and change the lifetime. Apple documents isVoiceOverRunning as a Boolean value indicating whether VoiceOver is in an enabled state, and gives this exact example: you might want UI elements that usually disappear quickly to persist onscreen for VoiceOver users. Practically, keep the toast until it is dismissed, or give it an explicit dismissal control rather than a timer. Our judgement is to change the lifetime and nothing else. The flag is not a licence to branch into a separate, reduced version of the workout screen.",
          "url": "https://aifitnessapi.com/accessibility/voiceover-live-workout-metrics#faq-3"
        }
      ]
    },
    {
      "question": "talkback workout screen android",
      "answer": "A TalkBack user meets a workout screen as a sequence of stops, and the quality of that sequence is decided by the semantics you attach. Google's documentation states that semantic properties convey the meaning of the corresponding composable, describes contentDescription as conveying in text what the meaning of an icon is, and describes the state description as how the On state should be referenced, which can be made more specific based on the context. An exercise row should be one stop rather than four: Google documents that calling Modifier.semantics with mergeDescendants set to true indicates the semantics properties should be merged, and its principles page says consolidating related elements helps users of assistive technology discover the information on the screen more efficiently. For the alert-like moment when rest ends, Google documents the liveRegion semantics property, with LiveRegionMode.Polite in the documented example, allowing accessibility services to automatically notify the user of changes to that component or its children. This is what Google's documentation states rather than device behaviour we measured, and two things it does not cover are an Android equivalent of Reduce Motion and how Voice Access or Switch Access behave.",
      "title": "TalkBack and the Android workout screen",
      "url": "https://aifitnessapi.com/accessibility/talkback-workout-screens",
      "markdown": "https://aifitnessapi.com/accessibility/talkback-workout-screens.md",
      "cluster": "Accessibility",
      "cluster_url": "https://aifitnessapi.com/accessibility",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Should every cell of a set row be its own TalkBack stop?",
          "answer": "Usually not. Google documents that composables and modifiers can indicate they want to merge their descendants' semantics properties by calling Modifier.semantics (mergeDescendants = true) {}, and that setting it to true means the semantics properties should be merged. The principles page adds that consolidating related elements helps users of assistive technology discover the information on the screen more efficiently, and that merging groups inner elements so accessibility services can treat them as one unit. Our rule of thumb: merge whatever the user makes a single decision about. Keep separate controls, such as a weight stepper's increase and decrease, unmerged, because merging removes them as actions.",
          "url": "https://aifitnessapi.com/accessibility/talkback-workout-screens#faq-1"
        },
        {
          "question": "Which Compose semantics property should a rest-finished alert use?",
          "answer": "The live region property. Google documents that alert-like components can be marked with the liveRegion semantics property, which allows accessibility services to automatically notify the user of changes to this component or its children, and the documented example uses LiveRegionMode.Polite. Attach it to the component that appears or changes when rest ends, not to the ticking countdown itself. A live region on a value that changes every second is a decision to speak continuously. Our judgement is one live region per workout screen; a second competing alert-like component creates the same interruption problem in a form that is harder to debug.",
          "url": "https://aifitnessapi.com/accessibility/talkback-workout-screens#faq-2"
        },
        {
          "question": "Does Jetpack Compose label a workout screen's custom views for me?",
          "answer": "Only the standard parts. Google states that in most cases Compose APIs and Material have default accessibility support in place, and that if you need to manually specify a UI element's semantic properties you use the semantics modifier and the contentDescription property. A Material button with a text child is generally handled. The elements a fitness app invents are not: a plate diagram, a muscle heat map, a pose overlay, a chart drawn on a canvas. Those carry no default because the framework has no idea what they represent, and they are usually the parts carrying the product's real information.",
          "url": "https://aifitnessapi.com/accessibility/talkback-workout-screens#faq-3"
        }
      ]
    },
    {
      "question": "accessible labels for exercises and sets",
      "answer": "A screen reader reads the string you wrote, not the layout that gave it meaning, so 3x10 at 60kg arrives as characters rather than three sets of ten reps at sixty kilograms. Google's principles page states that users must be able to understand the content and purpose of each interactive and meaningful UI element within your app, and Apple describes VoiceOver as a screen reader that lets people experience your app's interface without needing to see the screen. Neither company writes your strings, so the work is editorial: expand the gym shorthand, name the unit once, put the exercise first, and read numbers as quantities rather than glyphs. Completion belongs in state rather than the name, and Google documents a state description as describing how the On state should be referenced, noting it can be made more specific based on the context. Group the row first, since Google documents merging descendants' semantics properties as the way to make related elements one unit, then write the sentence that one unit should say.",
      "title": "What to call an exercise, a set and a rep range",
      "url": "https://aifitnessapi.com/accessibility/labelling-exercises-and-sets",
      "markdown": "https://aifitnessapi.com/accessibility/labelling-exercises-and-sets.md",
      "cluster": "Accessibility",
      "cluster_url": "https://aifitnessapi.com/accessibility",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "How should a screen reader read a set row like 3x10 at 60kg?",
          "answer": "As a sentence, not as the characters. Our wording would be three sets of ten reps at sixty kilograms, generated from the same model that renders the row rather than typed as a literal. The reasoning comes from what both platforms ask for: Google states that users must be able to understand the content and purpose of each interactive and meaningful UI element within your app, and Apple describes VoiceOver as a screen reader that lets people experience an interface without needing to see the screen. A string that only makes sense in its column fails that test. The exact phrasing is editorial judgement, not a platform rule.",
          "url": "https://aifitnessapi.com/accessibility/labelling-exercises-and-sets#faq-1"
        },
        {
          "question": "Should the weight unit be spoken on every set or said once per exercise?",
          "answer": "Our judgement is once, on the value that carries it, and never as a suffix repeated across fragments of the same row. Hearing kilograms four times in one row costs the listener time and hides the number that changed. This is a wording decision rather than a platform behaviour: neither Apple's nor Google's documentation prescribes it. What does follow from the platforms is that the string must stand alone without the layout, so if a row can be reached in isolation it needs its unit somewhere. Generate the string from the model so a unit switch cannot leave it stale.",
          "url": "https://aifitnessapi.com/accessibility/labelling-exercises-and-sets#faq-2"
        },
        {
          "question": "Is a finished set's completion part of its label or its state?",
          "answer": "Its state. Renaming the row on completion moves the row's identity under the user, who then has to re-hear the whole thing to learn one bit of information. Google documents a state description as describing how the On state should be referenced, and notes it can be made more specific based on the context, giving Enabled as an example. In a training app your context supplies better words: completed, skipped, in progress, not started. Keep the row's name constant for its whole life and let the state carry the change.",
          "url": "https://aifitnessapi.com/accessibility/labelling-exercises-and-sets#faq-3"
        }
      ]
    },
    {
      "question": "accessible health charts",
      "answer": "A trend chart is usually the least accessible element in a health app, because the information lives in the shape of the line and nothing in the view says what that shape is. Apple documents one answer for its platforms: its audio graphs page says to define an accessible representation of your chart for VoiceOver to generate an audio graph, and that you use the audio graphs API to provide all the information VoiceOver needs to construct an audible representation of the data in your charts and graphs, making the data accessible to people who are blind or have low vision. We found no verified Android equivalent in this pass, which is a real gap in the guidance rather than a claim that none exists. The fallback that works on every platform and needs no API is a written summary of the series covering direction, range, latest value and any missing days, exposed as the chart's accessible description, plus a table view of the same numbers. Generate that summary from the data at render time so it cannot go stale, and expose the table to everybody rather than only to detected assistive technology.",
      "title": "Making a health chart readable without the chart",
      "url": "https://aifitnessapi.com/accessibility/accessible-health-charts",
      "markdown": "https://aifitnessapi.com/accessibility/accessible-health-charts.md",
      "cluster": "Accessibility",
      "cluster_url": "https://aifitnessapi.com/accessibility",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "What should the accessible description of an HRV trend chart say?",
          "answer": "Our format is four ingredients in a fixed order: direction over the window, the range with the dates of the low and the high, the latest value with its date, and how many days have no data. That is editorial judgement rather than a platform rule, but it answers the questions people actually bring to a trend. Generate the sentence from the same series the chart renders so it cannot go stale, keep the ordering identical across every chart in the app, and preserve the precision the visual chart uses rather than rounding the meaning away.",
          "url": "https://aifitnessapi.com/accessibility/accessible-health-charts#faq-1"
        },
        {
          "question": "Is there an Android equivalent of Apple's audio graphs?",
          "answer": "We could not verify one in this pass. We did not find and read a primary Google page describing an audio or sonified representation of chart data, so we will not describe a mechanism, name an API or claim that none exists. That gap has a practical consequence: a cross-platform product cannot rely on Apple's audio graphs as its chart accessibility strategy, because the Android build would ship a silent picture. Build the platform-independent layer first, which is a generated text summary of the series plus a table view of the same numbers, and treat platform APIs as an addition.",
          "url": "https://aifitnessapi.com/accessibility/accessible-health-charts#faq-2"
        },
        {
          "question": "Should a data-table view of a chart replace the chart or sit next to it?",
          "answer": "Sit next to it, and make it visible to everybody rather than revealing it only when an assistive technology is detected. A table of dates and values needs no platform API, serves keyboard and magnification users as well as screen reader users, and is frequently the quickest way for any user to answer a precise question about a specific day. Exposing it as an ordinary product feature also means it gets exercised in normal use, so it is far less likely to rot than an accessibility-only path that nobody on the team opens.",
          "url": "https://aifitnessapi.com/accessibility/accessible-health-charts#faq-3"
        }
      ]
    },
    {
      "question": "dynamic type workout screen",
      "answer": "Apple's Human Interface Guidelines say to ideally give people the option to enlarge text by at least 200 percent, or 140 percent in watchOS apps, and note that an interface can support enlargement either through custom UI or by adopting Dynamic Type. On a workout screen that is a layout problem rather than a typography one, because a timer, a rep count and a weight sharing one row have no spare width between them. Three changes carry most of the work: let rows grow instead of fixing their height, stack horizontal groups of numerics vertically above a size threshold, and never truncate the value itself, only its label. Thin weights fail first, and Apple's advice there is to increase the font size when using one, which costs you the space you were trying to save. On watchOS the ceiling is lower and the canvas is smaller, so plan for one primary value per screen.",
      "title": "Dynamic Type on a workout screen: what breaks at 200 percent",
      "url": "https://aifitnessapi.com/accessibility/dynamic-type-workout-screens",
      "markdown": "https://aifitnessapi.com/accessibility/dynamic-type-workout-screens.md",
      "cluster": "Accessibility",
      "cluster_url": "https://aifitnessapi.com/accessibility",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "At what enlarged text size should a workout row stop being horizontal and start stacking?",
          "answer": "There is no number to read off a spec, so find it empirically. Open the live screen at every text size the platform offers and note the first size at which two values in the same row touch or clip, then make the layout stack one step earlier than that. The reason to go early is that the last size before a collision already looks cramped at arm's length, which is the distance a phone on a bike mount or an armband is actually read from. Re-run the sweep whenever a metric is added to the row, because the threshold moves.",
          "url": "https://aifitnessapi.com/accessibility/dynamic-type-workout-screens#faq-1"
        },
        {
          "question": "Is it ever acceptable to truncate a rep count or a load when text is enlarged?",
          "answer": "No. A truncated label is untidy but a truncated value is wrong, and it is wrong invisibly, because a clipped number still reads as a number. Somebody glancing mid-set at 1,2 instead of 1,250 has no way to tell. Give the value the space unconditionally and let the label absorb the pressure: shorten it, move it above the value, or drop it where context already makes it obvious. If the value and its label still do not fit after the row has stacked, the row is carrying too many metrics and that is a design decision, not a text-layout fix.",
          "url": "https://aifitnessapi.com/accessibility/dynamic-type-workout-screens#faq-2"
        },
        {
          "question": "Does an ultralight numeral font need a larger size to stay legible on a timer?",
          "answer": "Apple's guidance points that way. The Human Interface Guidelines say thicker weights are easier to read at smaller font sizes and advise considering an increase in font size when using a thin weight. That trade matters on a workout screen because the reason teams pick an ultralight numeral is usually to fit three metrics into one row, and following the advice spends the space that choice was buying. A hairline stroke also has less area to carry contrast, so it degrades faster on a bright or sweaty screen. If the hero timer is ultralight, treat it as the first thing to test enlarged.",
          "url": "https://aifitnessapi.com/accessibility/dynamic-type-workout-screens#faq-3"
        }
      ]
    },
    {
      "question": "touch target size fitness app",
      "answer": "Apple's Human Interface Guidelines say to strive to meet the recommended minimum control size for each platform, and publish a default of 44x44 pt for iOS, iPadOS and watchOS with a 28x28 pt minimum. Google's Android guidance recommends a touch target of at least 48dpx48dp for touch interfaces and says larger is even better, noting that many built-in Material components in Jetpack Compose already enforce that minimum. Size alone is not enough: Apple asks you to consider spacing between controls as important as size, and to include enough padding to reduce the chance that someone taps the wrong control. During a workout that padding is the whole game, because the hand is wet, gloved or shaking and the phone is often on a mount at arm's length. Keep destructive controls such as end workout physically separated from pause, and keep control positions stable as the workout state changes.",
      "title": "Touch targets when the hand is shaking",
      "url": "https://aifitnessapi.com/accessibility/touch-targets-during-a-workout",
      "markdown": "https://aifitnessapi.com/accessibility/touch-targets-during-a-workout.md",
      "cluster": "Accessibility",
      "cluster_url": "https://aifitnessapi.com/accessibility",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "How much padding belongs between a pause button and an end workout button?",
          "answer": "Apple does not publish a spacing figure, only the instruction to consider spacing between controls as important as size and to include enough padding to reduce the chance that someone taps the wrong control. So this is judgement. Ours: on a screen operated during exertion, put the destructive control out of the thumb's natural arc entirely rather than trying to find a safe gap next to it. Where they must share a screen, prefer fewer controls at full size with generous separation over a dense row, and keep positions stable across start, paused and running states so muscle memory is not aiming at a moved target.",
          "url": "https://aifitnessapi.com/accessibility/touch-targets-during-a-workout#faq-1"
        },
        {
          "question": "Is Apple's 44 pt control size the same thing as Google's 48dp recommendation?",
          "answer": "Treat them as two separate figures for two separate platforms, and do not convert between them. Apple's Human Interface Guidelines publish a default control size of 44x44 pt for iOS, iPadOS and watchOS, with a minimum of 28x28 pt. Google's Android accessibility guidance recommends at least 48dpx48dp for touch interfaces and adds that larger is even better. We did not verify any equivalence between the units, so a cross-platform design system should carry both numbers and apply each on its own platform rather than picking one and rounding the other to it.",
          "url": "https://aifitnessapi.com/accessibility/touch-targets-during-a-workout#faq-2"
        },
        {
          "question": "Do Jetpack Compose Material components already meet the minimum touch target?",
          "answer": "Google states that in Jetpack Compose, many built-in Material components like Button, IconButton and ListItem already enforce this minimum size, in the same passage that recommends at least 48dpx48dp. That covers the standard controls. It does not cover the custom tappable surfaces a workout screen tends to accumulate: a bare box with a click modifier, a small glyph in a metrics header, a chip in a set row. Those are where the regression appears, so measure the focusable area rather than the drawn artwork, and extend the target beyond the visual rather than shrinking it inside it.",
          "url": "https://aifitnessapi.com/accessibility/touch-targets-during-a-workout#faq-3"
        }
      ]
    },
    {
      "question": "color contrast for outdoor fitness apps",
      "answer": "Apple's Human Interface Guidelines say to strive to meet color contrast minimum standards and to ensure there is enough contrast between foreground text and icons and background colors. Google's Android guidance is numeric: text smaller than 18sp, or bold text smaller than 14sp, should use colours giving a contrast ratio of at least 4.5:1, and all other text at least 3:1, checked with an online colour contrast checker or the Accessibility Scanner app. Apple also asks apps to provide a higher contrast colour scheme when the system Increase Contrast setting is on, and recommends preferring system-defined colours because they have accessible variants that adapt automatically. Outdoors the practical answer is to design above those thresholds rather than at them, since sunlight, sweat and reading distance all work against you. The most common failure in fitness apps is not a weak ratio at all: it is heart-rate zones and form feedback that carry their meaning through hue alone.",
      "title": "Colour contrast when the screen is in sunlight",
      "url": "https://aifitnessapi.com/accessibility/colour-contrast-outdoors",
      "markdown": "https://aifitnessapi.com/accessibility/colour-contrast-outdoors.md",
      "cluster": "Accessibility",
      "cluster_url": "https://aifitnessapi.com/accessibility",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "What contrast ratio does Google recommend for a 16sp secondary metric label?",
          "answer": "At least 4.5:1. Google's Android accessibility guidance says the exact threshold depends on font size and boldness: text smaller than 18sp, or bold text smaller than 14sp, should use foreground and background colours giving a ratio of at least 4.5:1, and all other text at least 3:1. A 16sp label falls under the 18sp line, so it takes the stricter number. On a workout screen most secondary text sits there — unit suffixes, set captions, pace lines — while only the hero value clears the threshold. Teams usually check the big number and ship the small ones untested.",
          "url": "https://aifitnessapi.com/accessibility/colour-contrast-outdoors#faq-1"
        },
        {
          "question": "How should heart-rate zones be shown without relying on hue alone?",
          "answer": "Give every zone a second channel besides colour. Put the zone number or name inside the band rather than only in a coloured legend, label the ring with text, and make chart bands distinguishable by fill, boundary or position as well as by colour. Apple's guidance is explicit about why: for someone with red-green colour blindness, indicators that differ only by colour might appear the same, and both visual indicators and colour help differentiate them. A useful test is to ask what a reader learns if two of your zone colours are indistinguishable to them. If the answer is nothing, that element is carrying no information.",
          "url": "https://aifitnessapi.com/accessibility/colour-contrast-outdoors#faq-2"
        },
        {
          "question": "Should brand accent colours be used for small text on a workout screen?",
          "answer": "Be careful with it. Brand accents are usually chosen large, saturated and isolated, and they end up on a workout screen as small text on a dark card, which is where the stricter of Google's two thresholds applies. Apple's own advice points the other way: prefer system-defined colours, because they have accessible variants that adapt automatically when someone enables Increase Contrast or switches between light and dark appearances. Our judgement is to let brand colour own large non-text surfaces and choose text colour for contrast, keeping the deliberate brand exceptions to a list short enough to check.",
          "url": "https://aifitnessapi.com/accessibility/colour-contrast-outdoors#faq-3"
        }
      ]
    },
    {
      "question": "reduce motion fitness app",
      "answer": "Apple's Human Interface Guidelines ask that when the Reduce Motion accessibility setting is active, an app responds by reducing automatic and repetitive animations, including zooming, scaling and peripheral motion, and warn that excessive fast-moving or blinking effects can be distracting, cause dizziness and in some cases result in epileptic episodes. Apple documents isReduceMotionEnabled as a Boolean value indicating whether the setting is in an enabled state, which is how an iOS app reads it. For a coaching product the useful split is decoration versus information: confetti, parallax, bounce and transition flourish are decoration and should be cut, while a countdown ring and a looping exercise demonstration carry facts the user needs. Replace the informational ones rather than deleting them, with a still frame, a user-driven scrubber, a play control instead of autoplay, and a written description of the movement. We could not verify an Android equivalent of the setting from Google's own documentation this session, so we do not describe one.",
      "title": "Reduce Motion in a coaching interface",
      "url": "https://aifitnessapi.com/accessibility/reduced-motion-coaching-ui",
      "markdown": "https://aifitnessapi.com/accessibility/reduced-motion-coaching-ui.md",
      "cluster": "Accessibility",
      "cluster_url": "https://aifitnessapi.com/accessibility",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Should a looping exercise demonstration be removed when Reduce Motion is turned on?",
          "answer": "No, replaced. The loop is not decoration: it is how somebody learns where their elbows go, so deleting it removes the instruction rather than the discomfort. Apple's guidance asks apps to reduce automatic and repetitive animations, and a loop is exactly that pair of words, which points at changing how the content plays rather than dropping it. Practical replacements, offered as judgement: a still frame at the position that carries the information, both extremes of the range shown side by side, a scrubber the user drives, a play control instead of autoplay, and a written description of the movement.",
          "url": "https://aifitnessapi.com/accessibility/reduced-motion-coaching-ui#faq-1"
        },
        {
          "question": "Does Android have a setting equivalent to Apple's Reduce Motion?",
          "answer": "We could not verify one. The Google documentation we fetched while researching this cluster contains no primary page describing an animation-scale or reduced-motion preference, so we will not name a setting, an API or a way to branch on it. That is a gap in our evidence rather than a statement that nothing exists. Check Google's current documentation before writing that branch. In the meantime there is a design answer that does not depend on it: expose the behaviour in your own settings on both platforms, so a user can stop demo loops autoplaying and turn celebration effects off without leaving your app.",
          "url": "https://aifitnessapi.com/accessibility/reduced-motion-coaching-ui#faq-2"
        },
        {
          "question": "Is a live pose overlay covered by Apple's guidance on reducing animation?",
          "answer": "Apple's paragraph addresses automatic and repetitive animations, including zooming, scaling and peripheral motion. A skeleton drawn over live camera frames is none of those in a straightforward way: it moves because the user moves, and its motion is the feedback. Whether it falls inside the guidance is a judgement rather than something the documentation we read answers. What we would do is keep the skeleton and cut the decoration layered on it — joint pulses, motion trails, easing, glow effects on a counted rep — and offer a plain mode independently of the system setting, since not everyone who wants less motion has enabled it.",
          "url": "https://aifitnessapi.com/accessibility/reduced-motion-coaching-ui#faq-3"
        }
      ]
    },
    {
      "question": "hands free controls fitness app",
      "answer": "Apple's Human Interface Guidelines say gestures can be less comfortable for people who have limited dexterity, so offer onscreen ways to achieve the same outcome, giving the example that if you use a swipe gesture to dismiss a view you should also make a button available so people can tap or use an assistive device. In a fitness app that rule covers more people than it first appears to, because hands-free is the normal operating condition: swipe to skip an exercise, long-press to end a set and pull-to-refresh mid-run all fail for somebody holding a barbell as surely as for somebody with a tremor. Apple also documents Voice Control, saying people can interact with their devices entirely by speaking commands, perform gestures, interact with screen elements and dictate text, which is another reason controls should be real named onscreen elements. Google's documentation notes that Android accessibility services include screen readers, Switch Access tools and voice control systems, and cautions that an accessibility service is a specialized tool, not a standard way to make your app accessible.",
      "title": "Gestures and hands-free control during a workout",
      "url": "https://aifitnessapi.com/accessibility/gestures-and-hands-free-control",
      "markdown": "https://aifitnessapi.com/accessibility/gestures-and-hands-free-control.md",
      "cluster": "Accessibility",
      "cluster_url": "https://aifitnessapi.com/accessibility",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Does every swipe gesture in a workout app need an onscreen button as well?",
          "answer": "Apple's guidance is to offer onscreen ways to achieve the same outcome, using the example of a swipe that dismisses a view also having a button so people can tap or use an assistive device. Note the wording: the same outcome, onscreen, not a reduced path in a settings screen. In practice that means the skip, the end-set action and the sheet dismissal all need visible controls in the view where the gesture lives. The gesture can stay. It just stops being the only way through the flow.",
          "url": "https://aifitnessapi.com/accessibility/gestures-and-hands-free-control#faq-1"
        },
        {
          "question": "Should I build an Android accessibility service to add a hands-free mode?",
          "answer": "Google's own documentation pushes back on that. It describes accessibility services as running in the background to inspect screen content and interact with apps on the user's behalf, giving screen readers like TalkBack, Switch Access tools and voice control systems as examples, and then cautions that an accessibility service is a specialized tool, not a standard way to make your app accessible. If the goal is a workout flow usable without precise touch, the standard route is cheaper and more durable: labelled controls, real onscreen elements and accessibility actions.",
          "url": "https://aifitnessapi.com/accessibility/gestures-and-hands-free-control#faq-2"
        },
        {
          "question": "How does Voice Control change what I need to do to a workout screen?",
          "answer": "Less than teams expect, and it is work you should be doing anyway. Apple describes Voice Control as letting people interact with their devices entirely by speaking commands, performing gestures, interacting with screen elements and dictating text. You do not build a speech pipeline for that. Our judgement, which Apple's sentence does not state, is that unlabelled elements are the hardest to address by name, so the practical task is making the controls that matter during a session exist as real, named onscreen elements rather than gestures over a canvas.",
          "url": "https://aifitnessapi.com/accessibility/gestures-and-hands-free-control#faq-3"
        }
      ]
    },
    {
      "question": "haptic feedback fitness app",
      "answer": "In a fitness app the audio channel is usually already occupied by the user's own music, a podcast or a coach voiceover, so a chime is an unreliable way to signal that a set is over. Apple's Human Interface Guidelines say to use haptics in addition to audio cues, and to consider pairing a sound such as a success chime or error sound with matching haptics for people who cannot perceive the audio or have their audio turned off. Haptics carry binary, expected events well: set complete, rest over, work interval starting, and a form warning treated as an alert to look at the screen rather than as a diagnosis. They cannot carry anything with more than a few distinguishable states, and a person wearing gloves, with reduced sensation, or with the phone in an armband may feel nothing at all. Treat a haptic as a second channel alongside sound and a persistent visual state, never as the only one.",
      "title": "Haptics when the audio channel is already busy",
      "url": "https://aifitnessapi.com/accessibility/haptics-when-audio-is-busy",
      "markdown": "https://aifitnessapi.com/accessibility/haptics-when-audio-is-busy.md",
      "cluster": "Accessibility",
      "cluster_url": "https://aifitnessapi.com/accessibility",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Should a rest-timer haptic replace the chime or play alongside it?",
          "answer": "Alongside. Apple's guidance is to use haptics in addition to audio cues, and to consider pairing a sound with matching haptics for people who cannot perceive the audio or have it turned off. The word is addition, not instead. Replacing the chime moves the problem rather than solving it, because a haptic reaches nobody whose phone is in an armband, a jersey pocket or a bike mount. Keep the sound, add the tap, and make sure the screen still shows a persistent state that survives both being missed.",
          "url": "https://aifitnessapi.com/accessibility/haptics-when-audio-is-busy#faq-1"
        },
        {
          "question": "How many distinct haptic patterns can somebody tell apart during a set?",
          "answer": "Fewer than you want. We have measured nothing here, so treat this as design judgement rather than a platform fact: assume two or three patterns per app, and only for events the user is already expecting. Set complete and rest over work because they are binary and anticipated. Encoding which of eight exercises is next, or which of five heart-rate zones the user is in, does not, because the person feeling it is under load and cannot check their answer without looking at the screen anyway. If a cue needs more states than that, the haptic means look at the screen.",
          "url": "https://aifitnessapi.com/accessibility/haptics-when-audio-is-busy#faq-2"
        },
        {
          "question": "What happens to haptic cues when the user is wearing gloves or the phone is in an armband?",
          "answer": "They may not arrive at all, and your app will never know. Gloves, lifting straps, cold hands and reduced sensation all cut the channel at the skin; an armband, a jersey pocket or a bike mount cuts it before that, because a device nobody is touching cannot tap anybody. This is the reason a haptic is a second channel rather than a replacement. Give every event that matters an audible cue, a visible state that persists after the moment has passed, and a haptic, then confirm the app is still usable when any one of the three is missed.",
          "url": "https://aifitnessapi.com/accessibility/haptics-when-audio-is-busy#faq-3"
        }
      ]
    },
    {
      "question": "captions for workout videos",
      "answer": "Apple's Human Interface Guidelines define four distinct alternatives and a fitness library usually needs more than one: captions give the textual equivalent of audible information, subtitles let people read live onscreen dialogue in their preferred language, audio descriptions are interspersed between natural pauses in the main audio and supply spoken narration of important information presented only visually, and transcripts give a complete textual description covering both audible and visual information. Captions fix a coach's voiceover, but an exercise demo carries its information in the picture, so a blind user gets almost nothing from a soundtrack of breathing and music. That makes audio description the alternative this category cannot skip, and the script is usually close to what a good coach already says while demonstrating. This page is written from Apple's guidance only: we could not verify Android's captions API surface in this pass and describe none of it.",
      "title": "Captions, subtitles and audio descriptions for workout video",
      "url": "https://aifitnessapi.com/accessibility/captions-for-workout-video",
      "markdown": "https://aifitnessapi.com/accessibility/captions-for-workout-video.md",
      "cluster": "Accessibility",
      "cluster_url": "https://aifitnessapi.com/accessibility",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "What is the difference between captions and audio descriptions for an exercise demo video?",
          "answer": "They move information in opposite directions. Apple defines captions as the textual equivalent of audible information in video or audio-only content, and audio descriptions as narration interspersed between natural pauses in the main audio that supplies important information presented only visually. A demo loop is mostly visual information, so captions have almost nothing to carry while an audio description has to carry the whole movement: start position, what moves, tempo, and where the rep ends. Captioning a silent demo and calling the video accessible is the common mistake in fitness libraries.",
          "url": "https://aifitnessapi.com/accessibility/captions-for-workout-video#faq-1"
        },
        {
          "question": "Does a silent exercise demo loop need anything if there is no dialogue to caption?",
          "answer": "Yes, and it needs the most work of anything in your library. With no dialogue there is nothing for captions to do, but the whole instruction is in the picture, which is exactly the case Apple's audio description definition covers: spoken narration of important information presented only visually. A transcript, which Apple defines as a complete textual description covering both audible and visual information, is the cheaper companion artefact and is usually reusable elsewhere in the product. Start from what your coach says on camera and fill the gaps the camera was carrying.",
          "url": "https://aifitnessapi.com/accessibility/captions-for-workout-video#faq-2"
        },
        {
          "question": "Do you have verified guidance for captioning video in an Android fitness app?",
          "answer": "No, and we will not improvise it. When we compiled the evidence for this cluster the Android captions reference loaded but produced no sentence we were prepared to quote, so we describe no class names, no defaults, and nothing about how a system captioning preference is expected to reach a player. What transfers from Apple's guidance is the conceptual model: four separate jobs rather than one, with audio description as the one fitness content usually lacks. Verify the Android API surface against Google's current documentation before you build against anything.",
          "url": "https://aifitnessapi.com/accessibility/captions-for-workout-video#faq-3"
        }
      ]
    },
    {
      "question": "test accessibility fitness app",
      "answer": "Tooling is the starting point, not the test. Google's documentation recommends using all four approaches together: manual testing with Android accessibility services, testing using analysis tools, automated testing with Compose testing APIs, and user testing with people who interact with your app. Google describes Accessibility Scanner as scanning your screen and suggesting improvements after looking at content labels, clickable items, contrast and more, and Apple describes Accessibility Inspector as a way to display, query and test accessibility information in your view hierarchy and to audit for issues such as clipped text and unlabeled elements. Neither can see the two failures that matter most in a fitness app: a screen reader that will not stop talking while a rep counter updates, and a flow that is impossible to complete while somebody is actually moving. Find those by starting a workout with the screen reader on and the display off, completing one set and ending the workout, then repeating the same task with people who use assistive technology every day.",
      "title": "Testing accessibility in a fitness app",
      "url": "https://aifitnessapi.com/accessibility/testing-accessibility-fitness-app",
      "markdown": "https://aifitnessapi.com/accessibility/testing-accessibility-fitness-app.md",
      "cluster": "Accessibility",
      "cluster_url": "https://aifitnessapi.com/accessibility",
      "last_reviewed": "2026-08-22",
      "first_party": false,
      "faqs": [
        {
          "question": "Can Accessibility Scanner or Accessibility Inspector find the accessibility bugs specific to a live workout screen?",
          "answer": "Only some of them. Google describes Accessibility Scanner as looking at content labels, clickable items, contrast and more, and Apple describes Accessibility Inspector as auditing for issues such as clipped text and unlabeled elements plus text size and contrast. Those are properties of a screen at one instant. A rep counter that makes a screen reader speak continuously, and a control that is unreachable while somebody is under a loaded bar, are properties of a screen changing over time and of the user's physical situation. Apple's own wording is that the inspector supplements testing.",
          "url": "https://aifitnessapi.com/accessibility/testing-accessibility-fitness-app#faq-1"
        },
        {
          "question": "Which accessibility failures in a fitness app only show up while somebody is moving?",
          "answer": "The ones that define the category. A live metric that updates several times a second can turn a screen reader into continuous speech, so the announcement that mattered is buried, and nothing about that is visible in a static check. Controls that are correctly sized and labelled can still be unreachable during a plank, a ride or a heavy set. Audio cues that are clear in a quiet office are inaudible over the user's own music. All three are invisible from a desk chair and obvious within two minutes of doing the workout for real.",
          "url": "https://aifitnessapi.com/accessibility/testing-accessibility-fitness-app#faq-2"
        },
        {
          "question": "How do I run an accessibility pass on a workout flow with the screen reader on and the display off?",
          "answer": "Turn the screen reader on and leave it on. Start a workout from your app's home screen without looking, then turn the display off or put the phone face down. Complete one set: identify the exercise, start it, know when it ended, know the rest length and know when rest is over. Log the result, end the workout, and confirm what the app told you against what was saved. Record every time you had to look, every overlapping announcement, and every control you could not find. Then repeat it while genuinely moving.",
          "url": "https://aifitnessapi.com/accessibility/testing-accessibility-fitness-app#faq-3"
        }
      ]
    }
  ],
  "posts": [
    {
      "title": "The Fitness API Cost Your Users Pay",
      "description": "5 of 24 products bill your end user, not you. All five are direct wearable integrations, and the hardware requirement, not your budget, sets your reach.",
      "url": "https://aifitnessapi.com/blog/wearable-api-user-side-cost",
      "markdown": "https://aifitnessapi.com/blog/wearable-api-user-side-cost.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "wearables",
        "cost",
        "api"
      ],
      "faqs": [
        {
          "question": "Do users need to own a device to connect a wearable API?",
          "answer": "For the direct wearable integrations in our API directory, yes. Five products state a user-side cost, and each one requires the person to own that brand of hardware or hold an account with it. Two go further and require an active paid membership for data to flow. Every other product in the directory states no user-side cost at all."
        },
        {
          "question": "Does the WHOOP API require the end user to have a membership?",
          "answer": "Yes. Our directory records that every end user needs an active WHOOP membership for their data to flow, and that the developer must hold a membership too. WHOOP has restructured its membership recently, which is reported rather than confirmed by us, so verify the current terms directly with the vendor before you build a feature that depends on them."
        },
        {
          "question": "How do I estimate how many users can connect a wearable?",
          "answer": "Measure it rather than guessing. Ask during onboarding which devices people own, log every connect attempt by provider including the ones that fail, and check how many accounts already have data in the platform health store. Run that for a few weeks before you commit engineering time. The answer is usually smaller than the product plan assumed."
        }
      ]
    },
    {
      "title": "Ten Health Metrics, Two Platforms",
      "description": "We checked 10 metrics against Apple's and Google's own docs. Every one exists on both. The shapes don't match, and that is the part that costs you.",
      "url": "https://aifitnessapi.com/blog/ten-metrics-two-platforms",
      "markdown": "https://aifitnessapi.com/blog/ten-metrics-two-platforms.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "healthkit",
        "health-connect",
        "data",
        "api"
      ],
      "faqs": [
        {
          "question": "Does Health Connect have an equivalent for every HealthKit metric?",
          "answer": "For the metrics this site has verified, yes. All 10 in our cross-platform matrix exist on both platforms, checked against Apple's and Google's own documentation. What differs is shape: how many records a concept is split across, whether it is stored as a sample or a session, and which permission gates it. Existence is not equivalence."
        },
        {
          "question": "How do Apple and Android differ on calories burned?",
          "answer": "Apple splits the day into active energy burned and basal energy burned. Health Connect offers an active calories record and a total calories record. Those are different partitions of the same day, so a single field named calories burned in your schema means different things depending on which platform wrote it. Never add an active figure to a total figure."
        },
        {
          "question": "What is the hardest metric to normalise across HealthKit and Health Connect?",
          "answer": "Heart rate variability. Apple stores it as SDNN and Health Connect stores it as RMSSD, which are different computations and are not interconvertible. Every other metric in the matrix can be reconciled with mapping, de-duplication or an explicit definition. That one cannot, so it needs separate storage and separate baselines per platform."
        }
      ]
    },
    {
      "title": "Your HealthKit Bridge Last Shipped in 2024",
      "description": "The main React Native HealthKit bridge last released in October 2024. Its Android counterpart cut five versions in one week this August.",
      "url": "https://aifitnessapi.com/blog/react-native-health-stale",
      "markdown": "https://aifitnessapi.com/blog/react-native-health-stale.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "healthkit",
        "health-connect",
        "ecosystem",
        "architecture"
      ],
      "faqs": [
        {
          "question": "Is react-native-health abandoned?",
          "answer": "Nothing in the release data says abandoned. Our tracker shows no published release since October 2024, but the default branch was pushed in April 2026 and the repository is not archived. Those are different signals. Treat a long release gap as a prompt to test the bridge against your own toolchain, not as proof that the project is dead."
        },
        {
          "question": "Why does the Android Health Connect bridge release so much more often?",
          "answer": "Health Connect is a younger and faster-moving store than HealthKit, and its wrapper has to track both React Native architectures. A bridge over a slower-changing API can legitimately go quiet. Release frequency measures how much the underlying platform is churning at least as much as it measures maintainer effort."
        },
        {
          "question": "How do I check whether a health bridge still supports the types I need?",
          "answer": "List the identifiers your product actually reads, then grep the bridge for each one rather than trusting the README. Apple has added identifiers since the bridge's last release, including hypertensionEvent at iOS 26.2 and two more at iOS 27.0. If a type you need is missing, you are writing native code regardless."
        }
      ]
    },
    {
      "title": "'No Data' Means Four Different Things",
      "description": "An empty health read has several causes and only one is 'connect your device'. Here is the order to rule them out before you write that empty state.",
      "url": "https://aifitnessapi.com/blog/no-data-means-four-things",
      "markdown": "https://aifitnessapi.com/blog/no-data-means-four-things.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "healthkit",
        "health-connect",
        "architecture",
        "data"
      ],
      "faqs": [
        {
          "question": "Why is HealthKit returning no data even though the user granted permission?",
          "answer": "The most common causes are a query window that does not overlap the samples, a day boundary computed in the wrong timezone, or a store that genuinely holds nothing because no device has written that type. Rule those out in order before concluding anything about permissions, because permission problems and genuine absence look identical from inside a query."
        },
        {
          "question": "How can I detect that a user denied HealthKit read access?",
          "answer": "You cannot detect it from the read itself. Apple documents the authorization-denied error for saving data, so a refused read returns no error and an empty result, indistinguishable from a store with nothing in it. Build one empty state that is honest under both readings rather than guessing which one applies."
        },
        {
          "question": "What should my empty state say when a health query returns nothing?",
          "answer": "Say what you looked for and over what period, then offer both branches without asserting either: a way to widen the range, and a way to check sharing settings. Do not tell the user to connect a device you have no evidence is disconnected. Every unnecessary instruction sends someone to fix something that is not broken."
        }
      ]
    },
    {
      "title": "HRV Is SDNN on iOS and RMSSD on Android",
      "description": "Apple stores heart rate variability as SDNN. Health Connect stores RMSSD. Different statistics, no conversion factor, and one chart that quietly misleads.",
      "url": "https://aifitnessapi.com/blog/hrv-sdnn-vs-rmssd",
      "markdown": "https://aifitnessapi.com/blog/hrv-sdnn-vs-rmssd.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "healthkit",
        "health-connect",
        "data",
        "architecture"
      ],
      "faqs": [
        {
          "question": "Can you convert SDNN to RMSSD?",
          "answer": "Not for the purposes of a product. Apple exposes heart rate variability as SDNN and Health Connect exposes it as RMSSD, and this site's cross-platform matrix records them as different measures that are not interconvertible. Treat them as two separate fields with two separate baselines rather than looking for a factor to multiply by."
        },
        {
          "question": "What does Health Connect store for heart rate variability?",
          "answer": "Health Connect exposes HeartRateVariabilityRmssdRecord. Apple's equivalent is the quantity type identifier heartRateVariabilitySDNN. Both are summary statistics derived from the intervals between heartbeats, but they are different summaries, so a field called simply hrv in your schema means something different depending on which platform the sample came from."
        },
        {
          "question": "Why did a user's HRV change when they switched from iPhone to Android?",
          "answer": "Most likely because the stored statistic changed, not because anything about the user did. Your app started reading a different computation under the same field name. If your product shows a baseline, a trend line, or a recovery score built on heart rate variability, a platform switch will move it for reasons that have nothing to do with the person."
        }
      ]
    },
    {
      "title": "How We Verify, and What a Stamp Can't Say",
      "description": "341 pages, 1188 FAQ entries, 283 resolving citations, median stamp age 36 days. What those numbers prove, and the larger thing they do not.",
      "url": "https://aifitnessapi.com/blog/how-we-verify",
      "markdown": "https://aifitnessapi.com/blog/how-we-verify.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "methodology",
        "data",
        "ecosystem"
      ],
      "faqs": [
        {
          "question": "What does a verification date on a reference page actually mean?",
          "answer": "It means a person opened the primary source on that date and confirmed the page still matched it. It does not mean the fact is true today. Between the stamp and your reading, a vendor can change anything without telling anyone. Read the stamp as the age of the last check, not as a guarantee of current accuracy."
        },
        {
          "question": "How often should technical reference content be re-verified?",
          "answer": "Frequently enough that the oldest entry is younger than the rate at which your subject changes. We rank entries by stamp age and re-check the oldest first, and pages flag themselves once a stamp passes ninety days. Picking what to re-check by memory instead of by age reliably leaves the quietest and stalest entries untouched."
        },
        {
          "question": "Why does a broken build matter for content accuracy?",
          "answer": "Because it removes the option to publish something wrong quietly. Our build asserts that every published citation anchor resolves and that generated datasets parsed the number of rows they expected. A truncated dataset or a dead citation fails the build rather than shipping. Automation cannot check whether a fact is true, but it can refuse to ship an obviously broken one."
        }
      ]
    },
    {
      "title": "64 Cumulative, 53 Discrete: Sum or Average",
      "description": "64 HealthKit quantity types state cumulative aggregation, 53 state discrete. Choose wrong and nothing errors, no test fails, and the chart still renders.",
      "url": "https://aifitnessapi.com/blog/healthkit-sum-or-average",
      "markdown": "https://aifitnessapi.com/blog/healthkit-sum-or-average.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "healthkit",
        "data",
        "architecture",
        "api"
      ],
      "faqs": [
        {
          "question": "Should I sum or average HealthKit samples?",
          "answer": "It depends on the type's aggregation style. In the documentation we parsed, 64 quantity types state cumulative aggregation and 53 state discrete. Cumulative values add up over a window, so summing is correct and averaging is meaningless. Discrete values are readings at a point in time, so averaging or taking a minimum and maximum is correct and summing is nonsense."
        },
        {
          "question": "Which HealthKit types are cumulative?",
          "answer": "Only quantity types carry an aggregation style at all, and 64 of them state cumulative. The test that works without looking anything up is whether doubling the time window should roughly double the number. Distance and energy behave that way. A heart rate or a body weight does not, because those are readings rather than totals."
        },
        {
          "question": "Why are my HealthKit step totals higher than the Health app shows?",
          "answer": "Usually because you summed duplicates. A phone and a watch can both write steps for the same walk, and Apple's Health app resolves that overlap before it displays a total. If you export samples into your own database and add them up, nothing performs that resolution for you, so you get the same steps counted more than once."
        }
      ]
    },
    {
      "title": "Nutrition: HealthKit's Biggest Group at 39",
      "description": "Nutrition is HealthKit's largest group with 39 identifiers, ahead of Activity at 37. It is also the group almost nobody fills. Your food database is why.",
      "url": "https://aifitnessapi.com/blog/healthkit-nutrition-is-biggest",
      "markdown": "https://aifitnessapi.com/blog/healthkit-nutrition-is-biggest.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "healthkit",
        "nutrition",
        "data",
        "api"
      ],
      "faqs": [
        {
          "question": "How many nutrition types does HealthKit have?",
          "answer": "Nutrition is the largest group in Apple's own grouping of the identifiers, with 39 of them. Activity is next with 37, then Exercise and fitness with 21. That makes nutrition the single biggest area of the API by count, which surprises people who assume HealthKit is mostly about movement and heart rate."
        },
        {
          "question": "Do I have to write every HealthKit nutrition field?",
          "answer": "No, and most apps write only a few. The cost of writing a subset is that a blank field is indistinguishable from a real zero for anything reading your samples later, including Apple's own Health app and any other app the user has connected. Decide which fields you can source reliably, then write those consistently."
        },
        {
          "question": "Which food database should I use for a HealthKit nutrition app?",
          "answer": "Pick the one whose per-item coverage matches the fields you intend to write, not the one with the largest item count. Our directory lists nutrition sources with their developer cost and engineering effort. Test coverage yourself on a sample of real foods your users eat, because headline item counts say nothing about how many nutrient fields each item carries."
        }
      ]
    },
    {
      "title": "Apple's Newest HealthKit Types Are a Roadmap",
      "description": "Apple ships the data type years before most apps ship the feature. The additions since iOS 16 are a public preview of what the platform expects to matter.",
      "url": "https://aifitnessapi.com/blog/healthkit-newest-types-roadmap",
      "markdown": "https://aifitnessapi.com/blog/healthkit-newest-types-roadmap.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "healthkit",
        "ios",
        "ecosystem",
        "data"
      ],
      "faqs": [
        {
          "question": "Which HealthKit data types did iOS 18 add?",
          "answer": "Ten identifiers arrived in iOS 18.0: sleeping breathing disturbances, cross-country skiing speed and distance, paddle sports distance and speed, rowing distance and speed, skating sports distance, workout effort score, and estimated workout effort score. Apple's documentation, read for this site's dataset on 2026-08-28, records the introducing version for every identifier, which is how that grouping was counted."
        },
        {
          "question": "Are any HealthKit identifiers still in beta?",
          "answer": "Two are: bleedingAfterMenopause and menopausalState, both introduced in iOS 27.0. They are the only identifiers in the whole set marked as beta on any platform. At the same time none of the 240 identifiers is marked deprecated, so Apple's type catalogue only grows. Do not ship production features against the beta pair."
        },
        {
          "question": "Why do the newest HealthKit types have so little documentation?",
          "answer": "Apple lists four identifiers with no abstract at all, and every one of them arrived in iOS 18.0 or later. Three quantity types state no aggregation style, and they are the same recent additions. Median discussion length across the catalogue is fifteen words, so thin prose is normal, but the newest types are the thinnest. Test on device."
        }
      ]
    },
    {
      "title": "HealthKit's 9 Mobility Types, Barely Used",
      "description": "HealthKit's Mobility group is 9 identifiers the system derives from ordinary walking. No workout to start, no extra hardware, and almost nobody reads them.",
      "url": "https://aifitnessapi.com/blog/healthkit-mobility-types-unused",
      "markdown": "https://aifitnessapi.com/blog/healthkit-mobility-types-unused.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "healthkit",
        "mobility",
        "ios",
        "data"
      ],
      "faqs": [
        {
          "question": "What is in HealthKit's Mobility group?",
          "answer": "Apple's Mobility group holds 9 identifiers. They cover walking speed, step length, double support percentage, walking asymmetry percentage, stair ascent and descent speed, walking steadiness and a matching steadiness event, plus the six-minute walk test distance. All of them describe how someone walks rather than how far or how often."
        },
        {
          "question": "Do HealthKit mobility metrics require an Apple Watch?",
          "answer": "Not at the API level. Every identifier in the dataset is listed as available on all six platforms Apple names, so nothing in this group is watch-only. Whether values actually exist for a given user is a separate question that depends on their device and settings, and your code has to treat an empty read as a normal outcome."
        },
        {
          "question": "Can a fitness app tell a user their fall risk from HealthKit data?",
          "answer": "Showing a measurement and issuing an assessment are different things, and the second one changes what your product is. Presenting gait values as a clinical judgement moves you toward regulated territory. Read our page on fitness app regulation and take your own legal advice before you ship anything phrased as a risk or a diagnosis."
        }
      ]
    },
    {
      "title": "The HealthKit Error That Never Fires",
      "description": "HealthKit defines 17 error cases. The authorization-denied one is documented for saving, not reading — which is why an empty read is so hard to debug.",
      "url": "https://aifitnessapi.com/blog/healthkit-error-that-never-fires",
      "markdown": "https://aifitnessapi.com/blog/healthkit-error-that-never-fires.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "healthkit",
        "ios",
        "api"
      ],
      "faqs": [
        {
          "question": "Does HealthKit return an error when the user denies read access?",
          "answer": "No. Apple documents the authorization-denied error as the case where the user has not given the app permission to save data. A read the user refused completes normally and hands you an empty result, with no error to inspect. Your query code cannot distinguish a refusal from a store that genuinely holds nothing for that type."
        },
        {
          "question": "How many error cases does HKError define?",
          "answer": "Apple's documentation, read for this site's dataset on 2026-08-28, lists 17 cases. They cover device and environment problems, programming mistakes, authorization state, workout session lifecycle, user cancellation, and an unknown catch-all. Several carry no description text in Apple's own documentation, so their meaning has to be established by testing rather than by reading."
        },
        {
          "question": "How do I tell whether a HealthKit read was denied or the data is simply missing?",
          "answer": "From the query alone, you cannot. Establish everything you can rule out first: confirm the store is available on the device, confirm you actually requested authorization, then widen the time range and check the day boundary you are using. Whatever remains after that is a refusal or genuine absence, and you must design a single empty state that is true for both."
        }
      ]
    },
    {
      "title": "58 HealthKit Types Apple Never Explains",
      "description": "58 of HealthKit's 240 identifiers carry zero words of discussion prose, and the median across all 240 is 15 words. What to do when the docs say nothing.",
      "url": "https://aifitnessapi.com/blog/healthkit-58-silent-types",
      "markdown": "https://aifitnessapi.com/blog/healthkit-58-silent-types.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "healthkit",
        "data",
        "methodology",
        "ios"
      ],
      "faqs": [
        {
          "question": "Does Apple document every HealthKit type identifier?",
          "answer": "Not in any useful sense. Of the 240 identifiers we parsed from Apple's developer documentation, 58 have no discussion prose at all, and the median discussion across the whole set is 15 words. A handful get real treatment, with vo2Max at 323 words. For most identifiers the name and a one-line abstract are all you get."
        },
        {
          "question": "How do I find out what unit a HealthKit type expects?",
          "answer": "For most quantity types the documentation resolves a unit family, though for four of them it does not. When it does not, the reliable method is a probe: write a sample with an explicit unit, read it back, and see which unit round-trips without an argument error. Then check what the Health app displays for the same sample."
        },
        {
          "question": "What does it mean when a HealthKit identifier has no abstract?",
          "answer": "It means Apple listed the symbol without a summary line. Four identifiers in the set are in that state. You get a name and nothing else, so the value's meaning, its sign convention and how often the system writes it are all unknown until you record a sample yourself and inspect what the store actually holds."
        }
      ]
    },
    {
      "title": "HealthKit: 127 of 240 Types Are iOS 8.0",
      "description": "HealthKit has 240 type identifiers and 127 of them shipped in iOS 8.0. None is marked deprecated. The full version histogram, and what it costs you.",
      "url": "https://aifitnessapi.com/blog/healthkit-240-types-ios-8",
      "markdown": "https://aifitnessapi.com/blog/healthkit-240-types-ios-8.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "healthkit",
        "ios",
        "deprecation",
        "ecosystem"
      ],
      "faqs": [
        {
          "question": "How many HealthKit type identifiers are there?",
          "answer": "There are 240 type identifiers in the dataset we parsed from Apple's developer documentation. They break down into 120 quantity types, 84 workout activity types, 30 category types and 6 characteristic types. That total moves upward with each iOS release, so treat any figure you see quoted as a reading taken on a particular date rather than a constant."
        },
        {
          "question": "Has Apple ever deprecated a HealthKit type identifier?",
          "answer": "None of the 240 identifiers carries a deprecation marker in the documentation we read. Apple's own grouping does contain a bucket labelled Deprecated activity types holding 3 workout activity types, so the concept exists in the docs. A single snapshot cannot prove nothing was ever withdrawn, but the list we can see is entirely additions."
        },
        {
          "question": "Are some HealthKit types available only on Apple Watch?",
          "answer": "No. Every identifier in the dataset is listed as available on all six platforms Apple names, which are iOS, iPadOS, Mac Catalyst, macOS, visionOS and watchOS. Nothing is watchOS-only or iOS-only. The branch your code needs is an OS version check, not a platform check, because availability varies by release rather than by device."
        }
      ]
    },
    {
      "title": "Google Fit: The Signal Came in 2024",
      "description": "Google closed Fit API sign-ups on 2024-05-01 and documented support ends in 2026-12. Both confirmed. The first date was the one that mattered.",
      "url": "https://aifitnessapi.com/blog/google-fit-timeline",
      "markdown": "https://aifitnessapi.com/blog/google-fit-timeline.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "deprecation",
        "ecosystem",
        "android",
        "api"
      ],
      "faqs": [
        {
          "question": "When do the Google Fit APIs stop working?",
          "answer": "Google's own documentation states the Fit APIs will be supported until the end of 2026, which we verified against developer.android.com on July 31, 2026. That is an end of documented support, not a published shutdown hour. Treat it as the outer bound of your migration window rather than a date on which everything is guaranteed to still work."
        },
        {
          "question": "Why did Google close Google Fit sign-ups before shutting the API down?",
          "answer": "Closing new developer registration stops the installed base from growing while existing integrations keep running. It is the cheapest possible first step in a wind-down and it costs the vendor nothing in support obligations. That is exactly why it is the most reliable early signal that a platform is being retired."
        },
        {
          "question": "What should a Google Fit integration migrate to?",
          "answer": "It depends on the shape of the integration, not on preference. On-device Android reads move to Health Connect, Wear OS workout sessions move to Health Services, and server-side reads move to the Google Health API. Those are three different pieces of work, so audit which of them your app actually does before you scope anything."
        }
      ]
    },
    {
      "title": "Four Fitness APIs Are Free and Expensive",
      "description": "12 of 24 products cost the developer nothing, and four of those are rated high engineering effort. The API price is the smallest term in the integration.",
      "url": "https://aifitnessapi.com/blog/free-fitness-apis-are-expensive",
      "markdown": "https://aifitnessapi.com/blog/free-fitness-apis-are-expensive.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "cost",
        "api",
        "ecosystem"
      ],
      "faqs": [
        {
          "question": "Why is a free fitness API still expensive to ship?",
          "answer": "Because the licence is the smallest term in the total. Twelve of the 24 products in our API directory carry a developer cost of free, but that label covers two different things. Some are hosted services or platform SDKs you simply call. Others are open models or self-hosted projects where the running, tuning and maintenance are yours, and that is where budgets go wrong."
        },
        {
          "question": "Which free fitness APIs take the most engineering work?",
          "answer": "Four products in our directory are both free to the developer and rated high engineering effort: the wger exercise project, MediaPipe, MoveNet, and Apple Vision body pose. Three of those four are pose models, which is the pattern. Nothing about them is expensive to license, and all of them make you own the accuracy, the device testing and the runtime."
        },
        {
          "question": "Is a free pose estimation model cheaper than a paid motion SDK?",
          "answer": "Only if you count licence cost alone. A free model shifts the work to you: camera pipeline, accuracy evaluation on real devices, thermal and battery behaviour, and version pinning when the weights stop being updated. A paid SDK moves some of that to a vendor. Which is cheaper depends on how much of that work your team was going to do anyway."
        }
      ]
    },
    {
      "title": "Four Ways an API Says Contact Sales",
      "description": "4 of 24 products list contact-sales, and their gate text describes four different waits. What to ask for, and what to have ready before the call.",
      "url": "https://aifitnessapi.com/blog/fitness-api-talk-to-sales",
      "markdown": "https://aifitnessapi.com/blog/fitness-api-talk-to-sales.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "cost",
        "api",
        "ecosystem"
      ],
      "faqs": [
        {
          "question": "What does contact sales mean for a fitness API?",
          "answer": "It means the vendor sets terms per customer, and it tells you a lead time rather than a figure. In our API directory four of the 24 products list contact-sales as the developer cost, and the gate text differs for each. One requires partner approval first, one offers a trial before the conversation, one runs onboarding through sales with an implementation engineer attached."
        },
        {
          "question": "Can you evaluate a motion SDK before talking to sales?",
          "answer": "Sometimes. Sency's gate records a free trial first, with no credit card according to the vendor's site at our last check, and the sales conversation after it. Spike starts you in a sandbox with a dedicated implementation engineer. Verify both directly, because trial terms change more often than documentation does, and a stale trial page is not a commitment."
        },
        {
          "question": "What should you ask a health data API vendor before signing?",
          "answer": "Ask what the unit of metering is, what remains gated after signature, which underlying providers still need your own credentials, whether sandbox access comes before the contract, how implementation support is bounded, and what happens to your users' connections if you leave. Get the answers in writing. Anything a salesperson will not write down is not a term."
        }
      ]
    },
    {
      "title": "Integrate Fitness APIs in Risk Order",
      "description": "Three directory columns decide your build order: approval gate, engineering effort, user-side cost. Start the clocks you cannot compress on day one.",
      "url": "https://aifitnessapi.com/blog/fitness-api-integration-order",
      "markdown": "https://aifitnessapi.com/blog/fitness-api-integration-order.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "architecture",
        "api",
        "cost"
      ],
      "faqs": [
        {
          "question": "What order should you integrate fitness APIs in?",
          "answer": "File every approval application first, because that wait is wall-clock time you cannot shorten by working harder. Build the platform health stores next, since they carry no user-side cost and cover the metrics most products need. Add an aggregator when breadth matters more than depth. Leave the direct wearable integrations until you know how many of your users own the hardware."
        },
        {
          "question": "Should you integrate HealthKit or a wearable API first?",
          "answer": "The platform store first, in almost every case. HealthKit and Health Connect state no user-side cost, so every user with a supported phone is reachable, and our cross-platform matrix documents 10 metrics verified on both platforms. A direct wearable integration reaches only the people who own that brand, which is a smaller and less predictable group."
        },
        {
          "question": "Is an aggregator faster than direct wearable integrations?",
          "answer": "Usually, in engineering time. All four aggregators in our directory are rated low engineering effort, against medium or high for the direct wearable products. What an aggregator does not remove is the hardware requirement on your users, and one of them notes that some underlying providers still need your own developer credentials."
        }
      ]
    },
    {
      "title": "12 of 24 Fitness APIs Have an Approval Gate",
      "description": "Half the directory makes you get approved before production, and the gates are six different obstacles. Which ones start clocks you cannot compress.",
      "url": "https://aifitnessapi.com/blog/fitness-api-approval-gates",
      "markdown": "https://aifitnessapi.com/blog/fitness-api-approval-gates.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "api",
        "ecosystem",
        "compliance"
      ],
      "faqs": [
        {
          "question": "Which fitness APIs require approval before you can go live?",
          "answer": "In this site's API directory, 12 of the 24 products state an approval gate and 12 state none. The gated ones include two wearable platforms that cap your user count until review, a vendor whose partner program you apply to, a platform with display and branding rules, both mobile app stores, an aggregator needing your own credentials, and four products reached through sales."
        },
        {
          "question": "How long does Garmin API approval take?",
          "answer": "We have no verified timeline, and neither does anyone quoting one at you. What our directory records is the gate itself: partner approval through the Garmin Connect Developer Program, with third parties reporting that sign-ups have been paused at times. That report is unconfirmed. Treat the wait as unbounded, apply on day one, and design a first release that ships without it."
        },
        {
          "question": "Does the WHOOP API limit how many users you can connect?",
          "answer": "Yes. Our directory records a hard ten-member cap until your app receives production approval, and WHOOP also requires the developer to hold a membership. That cap covers everyone, so your engineers, your internal testers, and your pilot customer all draw from the same seats. Plan who gets a seat before you start, because the number does not stretch during review."
        }
      ]
    },
    {
      "title": "6 Confirmed, 7 Reported: Grade Your Dates",
      "description": "We track 13 dated ecosystem changes. Only 6 come from a primary source. A confirmed date is a plan; a reported one is a rumour with a number on it.",
      "url": "https://aifitnessapi.com/blog/confirmed-vs-reported",
      "markdown": "https://aifitnessapi.com/blog/confirmed-vs-reported.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "ecosystem",
        "deprecation",
        "methodology",
        "api"
      ],
      "faqs": [
        {
          "question": "What is the difference between a confirmed and a reported API deadline?",
          "answer": "Confirmed means the vendor's own documentation or announcement states it and we read that page. Reported means credible third parties say it and the vendor has not published anything we could verify. A confirmed date can carry a migration plan. A reported one should carry a plan plus a contingency for the date being wrong."
        },
        {
          "question": "Should I ignore reported deadlines until they are confirmed?",
          "answer": "No. Reported items are usually right about direction and unreliable about timing, and waiting for confirmation means starting the work with the least time left. Act on the direction, verify the date yourself before anything depends on it, and never let a reported date be the only thing standing between you and a broken integration."
        },
        {
          "question": "Why is a precise reported date weaker evidence than a vague one?",
          "answer": "Precision reads as authority. A guide naming a specific day looks better sourced than a vendor's vague month, but the guide's certainty comes from its own editorial choice, not from new information. When you cannot trace a specific date back to the vendor, the specificity is presentation rather than evidence."
        }
      ]
    },
    {
      "title": "One Field, Three Tries, Two Honest Nulls",
      "description": "Resolving which value enum decodes a HealthKit category type took three attempts. The first resolved 29 of 30 and was wrong in the worst way.",
      "url": "https://aifitnessapi.com/blog/building-the-healthkit-dataset",
      "markdown": "https://aifitnessapi.com/blog/building-the-healthkit-dataset.md",
      "published": "2026-09-01",
      "last_reviewed": "2026-09-01",
      "tags": [
        "healthkit",
        "data",
        "methodology"
      ],
      "faqs": [
        {
          "question": "Why do some HealthKit category types have no value enum listed?",
          "answer": "Because Apple's documentation for those types does not reference one in a form we could resolve without guessing, and a guess in this field ships a wrong decoding rule to whoever trusts it. Two category types in our dataset carry null for that reason. Null means we could not source it, not that no enum exists."
        },
        {
          "question": "What is a HealthKit category value enum and why does it matter?",
          "answer": "A category sample stores an integer, and the integer is meaningless on its own. The value enum is the type that decodes it into something like a sleep stage or a flow level. Read a category sample without knowing which enum applies and you get a number you can store, chart and completely misinterpret."
        },
        {
          "question": "How should a generated dataset handle facts it cannot extract?",
          "answer": "Write null and keep the evidence for everything it did extract. The alternative, filling gaps with plausible defaults, produces a file that looks complete and cannot be audited. A null is a visible hole that someone can go and fill. A guess is an invisible error that survives every review because nothing about it looks wrong."
        }
      ]
    },
    {
      "title": "The Health App That Never Touches HealthKit",
      "description": "Most health apps read data before they do anything. A whole category skips it — no OAuth, no entitlement, no PHI. Here's when that's the right call.",
      "url": "https://aifitnessapi.com/blog/health-app-without-health-data",
      "markdown": "https://aifitnessapi.com/blog/health-app-without-health-data.md",
      "published": "2026-08-31",
      "last_reviewed": "2026-08-31",
      "tags": [
        "architecture",
        "compliance",
        "consumer health",
        "product"
      ],
      "faqs": [
        {
          "question": "Does a health app have to read health data?",
          "answer": "No. A large category of consumer health product delivers its intervention without reading anything from a sensor. The test is whether reading the data changes what your app does: if the content, the timing and the intervention are identical either way, sensing is decoration and you are taking on the hardest parts of health engineering in exchange for a chart."
        },
        {
          "question": "What do you avoid by not reading health data?",
          "answer": "The whole permissions and integration stack. No HealthKit or Health Connect read permission, so no entitlement and no App Review justification for it. No per-vendor wearable OAuth, developer program or refresh-token rotation. And no ambiguity between an empty result and a refused read, which is one of the harder states to diagnose in health engineering."
        },
        {
          "question": "What do you give up by not reading health data?",
          "answer": "Real things, and you should count them. No personalization from the user's own history, no retention loop built on their trend, no efficacy story grounded in measured change, and no presence in the platform health app where people go looking. Skipping the data is a legitimate architecture, not a free one."
        }
      ]
    },
    {
      "title": "Welcome to AIFitnessAPI",
      "description": "Why we're building a hub for the people shipping the next generation of health, wellness, and fitness products — and what you can expect to find here.",
      "url": "https://aifitnessapi.com/blog/welcome-to-aifitnessapi",
      "markdown": "https://aifitnessapi.com/blog/welcome-to-aifitnessapi.md",
      "published": "2026-07-08",
      "last_reviewed": "2026-07-08",
      "tags": [
        "announcements",
        "health tech",
        "community"
      ],
      "faqs": []
    },
    {
      "title": "How to Choose a Fitness API in 2026",
      "description": "A practical framework for evaluating fitness and workout APIs: exercise data, motion tracking, AI coaching, pricing, and the questions that matter.",
      "url": "https://aifitnessapi.com/blog/how-to-choose-a-fitness-api",
      "markdown": "https://aifitnessapi.com/blog/how-to-choose-a-fitness-api.md",
      "published": "2026-07-08",
      "last_reviewed": "2026-07-08",
      "tags": [
        "fitness API",
        "guides",
        "product",
        "integration"
      ],
      "faqs": [
        {
          "question": "How do you evaluate a fitness API before integrating it?",
          "answer": "Start with the data model rather than the demo. Check exercise coverage against your actual niche, how deep the metadata goes on muscle groups, equipment and difficulty, and whether you can add your own movements or are locked to the vendor catalog. Every demo looks good; if the underlying model is wrong for your product, nothing else about the integration rescues it."
        },
        {
          "question": "How much intelligence should a fitness API provide?",
          "answer": "Fitness APIs run from a plain exercise database up to a full coaching layer. Content gives you exercises, routines and media. Tracking adds reps, sets and motion analysis. Coaching adds real-time feedback and personalization. Buy more than you need and you pay in cost and latency; buy less and you rebuild the difference yourself later."
        },
        {
          "question": "What should you check first, the pricing or the data?",
          "answer": "The data. Pricing is easy to compare and easy to renegotiate, while a data model that does not carry the movements or metadata your product depends on is a rewrite. Confirm coverage and extensibility for your specific niche before you compare tiers, and before you write any integration code."
        }
      ]
    }
  ],
  "changes": [
    {
      "date": "2026-12",
      "title": "Google Fit APIs: end of documented support",
      "summary": "Google's own documentation states Fit APIs \"will be supported until the end of 2026\" (verified against developer.android.com on July 31, 2026). Migration targets differ by integration shape: Health Connect on-device, Health Services on Wear OS, or the Google Health API for server-side reads.",
      "status": "confirmed",
      "url": "https://aifitnessapi.com/google-fit-shutdown",
      "verified_on": "2026-07-31"
    },
    {
      "date": "2026-09",
      "title": "Fitbit → Google Health side-by-side window reported to close",
      "summary": "A window in which the legacy Fitbit Web API and the Google Health API run side by side is reported to extend into late September 2026 — the practical dual-read period for migrating integrations.",
      "status": "reported",
      "url": "https://aifitnessapi.com/migrate/fitbit-web-api-to-google-health",
      "verified_on": "2026-08-11"
    },
    {
      "date": "2026-09",
      "title": "Fitbit Web API turndown (reported window)",
      "summary": "The legacy Fitbit Web API's retirement in favour of the cloud Google Health API is reported to land around September 2026. No official day is confirmed on a page we could verify; some third-party guides name September 30, which is weaker evidence, not stronger. Tokens are reported not to transfer — every user re-consents via Google OAuth.",
      "status": "reported",
      "url": "https://aifitnessapi.com/fitbit-api-shutdown",
      "verified_on": "2026-08-11"
    },
    {
      "date": "2026",
      "title": "Strava developer terms: Standard-tier subscription (reported)",
      "summary": "Strava's developer access terms reportedly changed during 2026, with Standard-tier developers said to need a paid Strava subscription. The architectural constraints matter more than the fee: athlete data may generally only be displayed back to that athlete, and using it to train AI/ML models is prohibited.",
      "status": "reported",
      "url": "https://aifitnessapi.com/migrate/adapt-to-strava-api-changes",
      "verified_on": "2026-08-12"
    },
    {
      "date": "2026-05",
      "title": "Fitbit accounts: Google Account consolidation gate (reported)",
      "summary": "Users on legacy Fitbit-only logins are reported to need consolidation into a Google Account by roughly mid-May 2026, and reportedly cannot use the successor API until they do — a gate on your migration, not a detail inside it.",
      "status": "reported",
      "url": "https://aifitnessapi.com/fitbit-api-shutdown",
      "verified_on": "2026-08-11"
    },
    {
      "date": "2026",
      "title": "WHOOP membership restructuring",
      "summary": "WHOOP has restructured its membership recently. Because WHOOP requires both a developer membership and an active end-user membership for data to flow, a restructuring moves two columns of the cost model at once — verify current terms before budgeting.",
      "status": "reported",
      "url": "https://aifitnessapi.com/pricing/whoop-api-pricing",
      "verified_on": "2026-08-12"
    },
    {
      "date": "2026",
      "title": "Nutritionix open free tier reportedly curtailed",
      "summary": "Reports conflict on whether Nutritionix's open free tier still exists; higher tiers route through a Syndigo sales contact. If the free tier is gone, the freemium classification shifts toward sales-gated.",
      "status": "reported",
      "url": "https://aifitnessapi.com/pricing/nutrition-api-pricing",
      "verified_on": "2026-08-12"
    },
    {
      "date": "2025-12",
      "title": "Oura personal access tokens deprecated",
      "summary": "Oura deprecated personal access tokens in December 2025 — scripts and internal tools built on PATs need the OAuth flow instead. This page's phrasing has been quoted back to us in search queries, a sign assistants cite it.",
      "status": "confirmed",
      "url": "https://aifitnessapi.com/fix/oura-personal-access-token-deprecated",
      "verified_on": "2026-08-02"
    },
    {
      "date": "2025-06-30",
      "title": "ANT+ membership and certification programs discontinued (reported)",
      "summary": "Per widely-quoted announcements from the ANT+ organization — the official page was unreachable in our research pass, so this stays reported — the ANT+ membership and certification programs were discontinued on June 30, 2025, with certification applications accepted only until March 31, 2025. Device profiles and documentation reportedly remain available and existing devices are unaffected; coverage cites the EU Radio Equipment Directive as a driver. For new fitness apps, BLE is the practical default radio.",
      "status": "reported",
      "url": "https://aifitnessapi.com/devices/ant-plus-vs-bluetooth",
      "verified_on": "2026-08-14"
    },
    {
      "date": "2024",
      "title": "Strava tightened its developer program",
      "summary": "Strava tightened developer-program rules in 2024 — the start of the stricter display, branding, and access regime its API operates under today.",
      "status": "confirmed",
      "url": "https://aifitnessapi.com/migrate/adapt-to-strava-api-changes",
      "verified_on": "2026-08-12"
    },
    {
      "date": "2024",
      "title": "MoveNet: no model updates observed since 2024",
      "summary": "No updates to the MoveNet pose models have been observed since 2024. The single-person models remain Apache-2.0; treat the weights as stable rather than evolving.",
      "status": "confirmed",
      "url": "https://aifitnessapi.com/motion/mediapipe-vs-movenet",
      "verified_on": "2026-08-02"
    },
    {
      "date": "2024-05-01",
      "title": "Google Fit: new developer sign-ups closed",
      "summary": "Google closed Google Fit API sign-ups for new developers on May 1, 2024 — the first hard milestone of the Fit sunset. Existing integrations continued to work.",
      "status": "confirmed",
      "url": "https://aifitnessapi.com/google-fit-shutdown",
      "verified_on": "2026-07-31"
    },
    {
      "date": "2023-04",
      "title": "MediaPipe Pose Landmarker weights: last modification",
      "summary": "The served MediaPipe Pose Landmarker .task model files were last modified in April 2023. The framework evolves; the pose weights have not — pin versions and treat model updates as an event, not a stream.",
      "status": "confirmed",
      "url": "https://aifitnessapi.com/motion/mediapipe-pose-landmarker-models",
      "verified_on": "2026-08-02"
    }
  ],
  "watching": [
    {
      "title": "Google Health API pricing and quota model",
      "summary": "The Fitbit successor's pricing model is not clearly public. Until it is, the free-to-call classification of the Fitbit ecosystem is the least stable cell in our dataset.",
      "url": "https://aifitnessapi.com/pricing/fitbit-api-pricing"
    },
    {
      "title": "MoveNet MultiPose licence gap",
      "summary": "The MultiPose model card we read carried no licence line, while the single-person models are Apache-2.0. Confirm independently before shipping multi-person tracking commercially.",
      "url": "https://aifitnessapi.com/motion/multi-person-pose-tracking"
    },
    {
      "title": "Garmin developer program sign-ups",
      "summary": "Third parties report new partner sign-ups paused at times, with no reopening ETA. Existing partners are unaffected. Verify current status before planning a Garmin integration.",
      "url": "https://aifitnessapi.com/fix/garmin-api-approval"
    }
  ],
  "facts": {
    "description": "Individually citable reference facts. Each `id` is a resolvable URL with a fragment addressing the exact row. Cite the id, not the page.",
    "healthkit_type_identifiers": {
      "count": 240,
      "families": [
        {
          "key": "quantity",
          "label": "HKQuantityTypeIdentifier",
          "count": 120
        },
        {
          "key": "category",
          "label": "HKCategoryTypeIdentifier",
          "count": 30
        },
        {
          "key": "characteristic",
          "label": "HKCharacteristicTypeIdentifier",
          "count": 6
        },
        {
          "key": "workoutActivity",
          "label": "HKWorkoutActivityType",
          "count": 84
        }
      ],
      "source_read_on": "2026-08-28",
      "source": "https://developer.apple.com/documentation/healthkit",
      "derivation_note": "aggregation and unit_family are derived from Apple's prose, which states them in sentences rather than as properties. Both apply only to quantity types: elsewhere null means the concept does not apply, not that Apple was silent — read them together with `family`. Everything else is copied from Apple's payload.",
      "items": [
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-activeenergyburned",
          "identifier": "activeEnergyBurned",
          "objc_constant": "HKQuantityTypeIdentifierActiveEnergyBurned",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of active energy the user has burned.",
          "aggregation": "cumulative",
          "aggregation_evidence": "Active energy samples use energy units (described in ) and measure cumulative values (described in ).",
          "unit_family": "energy",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/activeenergyburned"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-appleexercisetime",
          "identifier": "appleExerciseTime",
          "objc_constant": "HKQuantityTypeIdentifierAppleExerciseTime",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of time the user spent exercising.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use time units (described in ) and measure cumulative values (described in ).",
          "unit_family": "time",
          "value_enum": null,
          "ios_introduced": "9.3",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/appleexercisetime"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-applemovetime",
          "identifier": "appleMoveTime",
          "objc_constant": "HKQuantityTypeIdentifierAppleMoveTime",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of time the user has spent performing activities that involve full-body movements during the specified day.",
          "aggregation": "cumulative",
          "aggregation_evidence": "For younger users, HealthKit’s activity summary can track move time instead of active energy burned: These samples use time units (described in ) and measure cumulative values (described in ).",
          "unit_family": "time",
          "value_enum": null,
          "ios_introduced": "14.5",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/applemovetime"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-applesleepingbreathingdisturbances",
          "identifier": "appleSleepingBreathingDisturbances",
          "objc_constant": "HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances",
          "family": "HKQuantityTypeIdentifier",
          "abstract": null,
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "18.0",
          "apple_documents_it": false,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/applesleepingbreathingdisturbances"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-applesleepingwristtemperature",
          "identifier": "appleSleepingWristTemperature",
          "objc_constant": "HKQuantityTypeIdentifierAppleSleepingWristTemperature",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that records the wrist temperature during sleep.",
          "aggregation": "discrete",
          "aggregation_evidence": "Sleeping wrist temperature samples use temperature units (described in ) and measure discrete values (described in ).",
          "unit_family": "temperature",
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/applesleepingwristtemperature"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-applestandtime",
          "identifier": "appleStandTime",
          "objc_constant": "HKQuantityTypeIdentifierAppleStandTime",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of time the user has spent standing.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use time units (described in ) and measure cumulative values (described in ).",
          "unit_family": "time",
          "value_enum": null,
          "ios_introduced": "13.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/applestandtime"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-applewalkingsteadiness",
          "identifier": "appleWalkingSteadiness",
          "objc_constant": "HKQuantityTypeIdentifierAppleWalkingSteadiness",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the steadiness of the user’s gait.",
          "aggregation": "discrete",
          "aggregation_evidence": "Samples that match the Walking Steadiness identifier use percentage units (described in ) and measure discrete values (described in ).",
          "unit_family": "percentage",
          "value_enum": null,
          "ios_introduced": "15.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/applewalkingsteadiness"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-atrialfibrillationburden",
          "identifier": "atrialFibrillationBurden",
          "objc_constant": "HKQuantityTypeIdentifierAtrialFibrillationBurden",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity type that measures an estimate of the percentage of time a person’s heart shows signs of atrial fibrillation (AFib) while wearing Apple Watch.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use percentage units (described in ) and measure discrete values (described in ).",
          "unit_family": "percentage",
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/atrialfibrillationburden"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-basalbodytemperature",
          "identifier": "basalBodyTemperature",
          "objc_constant": "HKQuantityTypeIdentifierBasalBodyTemperature",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that records the user’s basal body temperature.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use temperature units (described in ) and measure discrete values (described in ).",
          "unit_family": "temperature",
          "value_enum": null,
          "ios_introduced": "9.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/basalbodytemperature"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-basalenergyburned",
          "identifier": "basalEnergyBurned",
          "objc_constant": "HKQuantityTypeIdentifierBasalEnergyBurned",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the resting energy burned by the user.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use energy units (described in ) and measure cumulative values (described in ).",
          "unit_family": "energy",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/basalenergyburned"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-bloodalcoholcontent",
          "identifier": "bloodAlcoholContent",
          "objc_constant": "HKQuantityTypeIdentifierBloodAlcoholContent",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s blood alcohol content.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use percent units (described in ) and measure discrete values (described in ).",
          "unit_family": "percent",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/bloodalcoholcontent"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-bloodglucose",
          "identifier": "bloodGlucose",
          "objc_constant": "HKQuantityTypeIdentifierBloodGlucose",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s blood glucose level.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use mass/volume units (described in ) and measure discrete values (described in ).",
          "unit_family": "mass/volume",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/bloodglucose"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-bloodpressurediastolic",
          "identifier": "bloodPressureDiastolic",
          "objc_constant": "HKQuantityTypeIdentifierBloodPressureDiastolic",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s diastolic blood pressure.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use pressure units (described in ) and measure discrete values (described in ).",
          "unit_family": "pressure",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/bloodpressurediastolic"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-bloodpressuresystolic",
          "identifier": "bloodPressureSystolic",
          "objc_constant": "HKQuantityTypeIdentifierBloodPressureSystolic",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s systolic blood pressure.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use pressure units (described in ) and measure discrete values (described in ).",
          "unit_family": "pressure",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/bloodpressuresystolic"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-bodyfatpercentage",
          "identifier": "bodyFatPercentage",
          "objc_constant": "HKQuantityTypeIdentifierBodyFatPercentage",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s body fat percentage.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use percent units (described in ) and measure discrete values (described in ).",
          "unit_family": "percent",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/bodyfatpercentage"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-bodymass",
          "identifier": "bodyMass",
          "objc_constant": "HKQuantityTypeIdentifierBodyMass",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s weight.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use mass units (described in ) and measure discrete values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/bodymass"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-bodymassindex",
          "identifier": "bodyMassIndex",
          "objc_constant": "HKQuantityTypeIdentifierBodyMassIndex",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s body mass index.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use count units (described in ) and measure discrete values (described in ).",
          "unit_family": "count",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/bodymassindex"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-bodytemperature",
          "identifier": "bodyTemperature",
          "objc_constant": "HKQuantityTypeIdentifierBodyTemperature",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s body temperature.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use temperature units (described in ) and measure discrete values (described in ).",
          "unit_family": "temperature",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/bodytemperature"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-crosscountryskiingspeed",
          "identifier": "crossCountrySkiingSpeed",
          "objc_constant": "HKQuantityTypeIdentifierCrossCountrySkiingSpeed",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures how fast you are traveling while cross country skiing.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use distance per time units (described in ) and measure discrete values (described in ).",
          "unit_family": "distance per time",
          "value_enum": null,
          "ios_introduced": "18.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/crosscountryskiingspeed"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-cyclingcadence",
          "identifier": "cyclingCadence",
          "objc_constant": "HKQuantityTypeIdentifierCyclingCadence",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that represents the rate at which the user is pedaling.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use counts per minute units (described in ) and measure discrete values (described in ).",
          "unit_family": "counts per minute",
          "value_enum": null,
          "ios_introduced": "17.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/cyclingcadence"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-cyclingfunctionalthresholdpower",
          "identifier": "cyclingFunctionalThresholdPower",
          "objc_constant": "HKQuantityTypeIdentifierCyclingFunctionalThresholdPower",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the estimated maximum average power sustained while riding a bike for 60 minutes.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use power units (described in ) and measure discrete values (described in ).",
          "unit_family": "power",
          "value_enum": null,
          "ios_introduced": "17.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/cyclingfunctionalthresholdpower"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-cyclingpower",
          "identifier": "cyclingPower",
          "objc_constant": "HKQuantityTypeIdentifierCyclingPower",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the estimated power being used while riding a bike.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use power units (described in ) and measure discrete values (described in ).",
          "unit_family": "power",
          "value_enum": null,
          "ios_introduced": "17.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/cyclingpower"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-cyclingspeed",
          "identifier": "cyclingSpeed",
          "objc_constant": "HKQuantityTypeIdentifierCyclingSpeed",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures how fast you are traveling while riding a bike.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use distance per time units (described in ) and measure discrete values (described in ).",
          "unit_family": "distance per time",
          "value_enum": null,
          "ios_introduced": "17.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/cyclingspeed"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarybiotin",
          "identifier": "dietaryBiotin",
          "objc_constant": "HKQuantityTypeIdentifierDietaryBiotin",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of biotin (vitamin B7) consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarybiotin"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarycaffeine",
          "identifier": "dietaryCaffeine",
          "objc_constant": "HKQuantityTypeIdentifierDietaryCaffeine",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of caffeine consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarycaffeine"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarycalcium",
          "identifier": "dietaryCalcium",
          "objc_constant": "HKQuantityTypeIdentifierDietaryCalcium",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of calcium consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarycalcium"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarycarbohydrates",
          "identifier": "dietaryCarbohydrates",
          "objc_constant": "HKQuantityTypeIdentifierDietaryCarbohydrates",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of carbohydrates consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarycarbohydrates"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarychloride",
          "identifier": "dietaryChloride",
          "objc_constant": "HKQuantityTypeIdentifierDietaryChloride",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of chloride consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarychloride"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarycholesterol",
          "identifier": "dietaryCholesterol",
          "objc_constant": "HKQuantityTypeIdentifierDietaryCholesterol",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of cholesterol consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarycholesterol"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarychromium",
          "identifier": "dietaryChromium",
          "objc_constant": "HKQuantityTypeIdentifierDietaryChromium",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of chromium consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarychromium"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarycopper",
          "identifier": "dietaryCopper",
          "objc_constant": "HKQuantityTypeIdentifierDietaryCopper",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of copper consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarycopper"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryenergyconsumed",
          "identifier": "dietaryEnergyConsumed",
          "objc_constant": "HKQuantityTypeIdentifierDietaryEnergyConsumed",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of energy consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use energy units (described in ) and measure cumulative values (described in ).",
          "unit_family": "energy",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryenergyconsumed"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryfatmonounsaturated",
          "identifier": "dietaryFatMonounsaturated",
          "objc_constant": "HKQuantityTypeIdentifierDietaryFatMonounsaturated",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of monounsaturated fat consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryfatmonounsaturated"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryfatpolyunsaturated",
          "identifier": "dietaryFatPolyunsaturated",
          "objc_constant": "HKQuantityTypeIdentifierDietaryFatPolyunsaturated",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of polyunsaturated fat consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryfatpolyunsaturated"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryfatsaturated",
          "identifier": "dietaryFatSaturated",
          "objc_constant": "HKQuantityTypeIdentifierDietaryFatSaturated",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of saturated fat consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryfatsaturated"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryfattotal",
          "identifier": "dietaryFatTotal",
          "objc_constant": "HKQuantityTypeIdentifierDietaryFatTotal",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the total amount of fat consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryfattotal"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryfiber",
          "identifier": "dietaryFiber",
          "objc_constant": "HKQuantityTypeIdentifierDietaryFiber",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of fiber consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryfiber"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryfolate",
          "identifier": "dietaryFolate",
          "objc_constant": "HKQuantityTypeIdentifierDietaryFolate",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of folate (folic acid) consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryfolate"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryiodine",
          "identifier": "dietaryIodine",
          "objc_constant": "HKQuantityTypeIdentifierDietaryIodine",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of iodine consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryiodine"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryiron",
          "identifier": "dietaryIron",
          "objc_constant": "HKQuantityTypeIdentifierDietaryIron",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of iron consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryiron"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarymagnesium",
          "identifier": "dietaryMagnesium",
          "objc_constant": "HKQuantityTypeIdentifierDietaryMagnesium",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of magnesium consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarymagnesium"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarymanganese",
          "identifier": "dietaryManganese",
          "objc_constant": "HKQuantityTypeIdentifierDietaryManganese",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of manganese consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarymanganese"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarymolybdenum",
          "identifier": "dietaryMolybdenum",
          "objc_constant": "HKQuantityTypeIdentifierDietaryMolybdenum",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of molybdenum consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarymolybdenum"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryniacin",
          "identifier": "dietaryNiacin",
          "objc_constant": "HKQuantityTypeIdentifierDietaryNiacin",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of niacin (vitamin B3) consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryniacin"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarypantothenicacid",
          "identifier": "dietaryPantothenicAcid",
          "objc_constant": "HKQuantityTypeIdentifierDietaryPantothenicAcid",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of pantothenic acid (vitamin B5) consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarypantothenicacid"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryphosphorus",
          "identifier": "dietaryPhosphorus",
          "objc_constant": "HKQuantityTypeIdentifierDietaryPhosphorus",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of phosphorus consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryphosphorus"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarypotassium",
          "identifier": "dietaryPotassium",
          "objc_constant": "HKQuantityTypeIdentifierDietaryPotassium",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of potassium consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarypotassium"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryprotein",
          "identifier": "dietaryProtein",
          "objc_constant": "HKQuantityTypeIdentifierDietaryProtein",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of protein consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryprotein"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryriboflavin",
          "identifier": "dietaryRiboflavin",
          "objc_constant": "HKQuantityTypeIdentifierDietaryRiboflavin",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of riboflavin (vitamin B2) consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryriboflavin"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryselenium",
          "identifier": "dietarySelenium",
          "objc_constant": "HKQuantityTypeIdentifierDietarySelenium",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of selenium consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryselenium"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarysodium",
          "identifier": "dietarySodium",
          "objc_constant": "HKQuantityTypeIdentifierDietarySodium",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of sodium consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarysodium"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarysugar",
          "identifier": "dietarySugar",
          "objc_constant": "HKQuantityTypeIdentifierDietarySugar",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of sugar consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarysugar"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarythiamin",
          "identifier": "dietaryThiamin",
          "objc_constant": "HKQuantityTypeIdentifierDietaryThiamin",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of thiamin (vitamin B1) consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarythiamin"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryvitamina",
          "identifier": "dietaryVitaminA",
          "objc_constant": "HKQuantityTypeIdentifierDietaryVitaminA",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of vitamin A consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryvitamina"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryvitaminb12",
          "identifier": "dietaryVitaminB12",
          "objc_constant": "HKQuantityTypeIdentifierDietaryVitaminB12",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of cyanocobalamin (vitamin B12) consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryvitaminb12"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryvitaminb6",
          "identifier": "dietaryVitaminB6",
          "objc_constant": "HKQuantityTypeIdentifierDietaryVitaminB6",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of pyridoxine (vitamin B6) consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryvitaminb6"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryvitaminc",
          "identifier": "dietaryVitaminC",
          "objc_constant": "HKQuantityTypeIdentifierDietaryVitaminC",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of vitamin C consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryvitaminc"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryvitamind",
          "identifier": "dietaryVitaminD",
          "objc_constant": "HKQuantityTypeIdentifierDietaryVitaminD",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of vitamin D consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryvitamind"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryvitamine",
          "identifier": "dietaryVitaminE",
          "objc_constant": "HKQuantityTypeIdentifierDietaryVitaminE",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of vitamin E consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryvitamine"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryvitamink",
          "identifier": "dietaryVitaminK",
          "objc_constant": "HKQuantityTypeIdentifierDietaryVitaminK",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of vitamin K consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryvitamink"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietarywater",
          "identifier": "dietaryWater",
          "objc_constant": "HKQuantityTypeIdentifierDietaryWater",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of water consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use volume units (described in ) and measure cumulative values (described in ).",
          "unit_family": "volume",
          "value_enum": null,
          "ios_introduced": "9.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietarywater"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dietaryzinc",
          "identifier": "dietaryZinc",
          "objc_constant": "HKQuantityTypeIdentifierDietaryZinc",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of zinc consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use mass units (described in ) and measure cumulative values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/dietaryzinc"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-distancecrosscountryskiing",
          "identifier": "distanceCrossCountrySkiing",
          "objc_constant": "HKQuantityTypeIdentifierDistanceCrossCountrySkiing",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the distance the user has moved by cross country skiing.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use length units (described in ) and measure cumulative values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "18.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/distancecrosscountryskiing"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-distancecycling",
          "identifier": "distanceCycling",
          "objc_constant": "HKQuantityTypeIdentifierDistanceCycling",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the distance the user has moved by cycling.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use length units (described in ) and measure cumulative values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/distancecycling"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-distancedownhillsnowsports",
          "identifier": "distanceDownhillSnowSports",
          "objc_constant": "HKQuantityTypeIdentifierDistanceDownhillSnowSports",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the distance the user has traveled while skiing or snowboarding.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use length units (described in ) and measure cumulative values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "11.2",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/distancedownhillsnowsports"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-distancepaddlesports",
          "identifier": "distancePaddleSports",
          "objc_constant": "HKQuantityTypeIdentifierDistancePaddleSports",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the distance the user has moved by paddling sports.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use length units (described in ) and measure cumulative values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "18.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/distancepaddlesports"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-distancerowing",
          "identifier": "distanceRowing",
          "objc_constant": "HKQuantityTypeIdentifierDistanceRowing",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the distance the user has moved by rowing.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use length units (described in ) and measure cumulative values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "18.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/distancerowing"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-distanceskatingsports",
          "identifier": "distanceSkatingSports",
          "objc_constant": "HKQuantityTypeIdentifierDistanceSkatingSports",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the distance the user has moved by skating.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use length units (described in ) and measure cumulative values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "18.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/distanceskatingsports"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-distanceswimming",
          "identifier": "distanceSwimming",
          "objc_constant": "HKQuantityTypeIdentifierDistanceSwimming",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the distance the user has moved while swimming.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use length units (described in ) and measure cumulative values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/distanceswimming"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-distancewalkingrunning",
          "identifier": "distanceWalkingRunning",
          "objc_constant": "HKQuantityTypeIdentifierDistanceWalkingRunning",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the distance the user has moved by walking or running.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use length units (described in ) and measure cumulative values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/distancewalkingrunning"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-distancewheelchair",
          "identifier": "distanceWheelchair",
          "objc_constant": "HKQuantityTypeIdentifierDistanceWheelchair",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the distance the user has moved using a wheelchair.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use length units (described in ) and measure cumulative values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/distancewheelchair"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-electrodermalactivity",
          "identifier": "electrodermalActivity",
          "objc_constant": "HKQuantityTypeIdentifierElectrodermalActivity",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures electrodermal activity.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use conductance units (described in ) and measure discrete values (described in ).",
          "unit_family": "conductance",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/electrodermalactivity"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-environmentalaudioexposure",
          "identifier": "environmentalAudioExposure",
          "objc_constant": "HKQuantityTypeIdentifierEnvironmentalAudioExposure",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures audio exposure to sounds in the environment.",
          "aggregation": "discrete",
          "aggregation_evidence": "They measure discrete values of the equivalent continuous sound pressure level, described in .",
          "unit_family": "sound pressure",
          "value_enum": null,
          "ios_introduced": "13.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/environmentalaudioexposure"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-environmentalsoundreduction",
          "identifier": "environmentalSoundReduction",
          "objc_constant": "HKQuantityTypeIdentifierEnvironmentalSoundReduction",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the difference in sound intensity when wearing headphones that lower environmental sound levels.",
          "aggregation": "discrete",
          "aggregation_evidence": "They measure discrete values of the equivalent continuous sound pressure level, described in .",
          "unit_family": "sound pressure",
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/environmentalsoundreduction"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-estimatedworkouteffortscore",
          "identifier": "estimatedWorkoutEffortScore",
          "objc_constant": "HKQuantityTypeIdentifierEstimatedWorkoutEffortScore",
          "family": "HKQuantityTypeIdentifier",
          "abstract": null,
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "18.0",
          "apple_documents_it": false,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/estimatedworkouteffortscore"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-flightsclimbed",
          "identifier": "flightsClimbed",
          "objc_constant": "HKQuantityTypeIdentifierFlightsClimbed",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the number flights of stairs that the user has climbed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use count units (described in ) and measure cumulative values (described in ).",
          "unit_family": "count",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/flightsclimbed"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-forcedexpiratoryvolume1",
          "identifier": "forcedExpiratoryVolume1",
          "objc_constant": "HKQuantityTypeIdentifierForcedExpiratoryVolume1",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of air that can be forcibly exhaled from the lungs during the first second of a forced exhalation.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use volume units (described in ) and measure discrete values (described in ).",
          "unit_family": "volume",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/forcedexpiratoryvolume1"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-forcedvitalcapacity",
          "identifier": "forcedVitalCapacity",
          "objc_constant": "HKQuantityTypeIdentifierForcedVitalCapacity",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of air that can be forcibly exhaled from the lungs after taking the deepest breath possible.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use volume units (described in ) and measure discrete values (described in ).",
          "unit_family": "volume",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/forcedvitalcapacity"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-headphoneaudioexposure",
          "identifier": "headphoneAudioExposure",
          "objc_constant": "HKQuantityTypeIdentifierHeadphoneAudioExposure",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures audio exposure from headphones.",
          "aggregation": "discrete",
          "aggregation_evidence": "They measure discrete values of the equivalent continuous sound pressure level, described in .",
          "unit_family": "sound pressure",
          "value_enum": null,
          "ios_introduced": "13.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/headphoneaudioexposure"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-heartrate",
          "identifier": "heartRate",
          "objc_constant": "HKQuantityTypeIdentifierHeartRate",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s heart rate.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use count/time units (described in ) and measure discrete values (described in ).",
          "unit_family": "count/time",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/heartrate"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-heartraterecoveryoneminute",
          "identifier": "heartRateRecoveryOneMinute",
          "objc_constant": "HKQuantityTypeIdentifierHeartRateRecoveryOneMinute",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample that records the reduction in heart rate from the peak exercise rate to the rate one minute after exercising ended.",
          "aggregation": "discrete",
          "aggregation_evidence": "Heart rate recovery samples use count units (described in ) and measure discrete values (described in ).",
          "unit_family": "count",
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/heartraterecoveryoneminute"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-heartratevariabilitysdnn",
          "identifier": "heartRateVariabilitySDNN",
          "objc_constant": "HKQuantityTypeIdentifierHeartRateVariabilitySDNN",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the standard deviation of heartbeat intervals.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use time units (described in ) and measure discrete values (described in ).",
          "unit_family": "time",
          "value_enum": null,
          "ios_introduced": "11.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/heartratevariabilitysdnn"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-height",
          "identifier": "height",
          "objc_constant": "HKQuantityTypeIdentifierHeight",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s height.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use length units (described in ) and measure discrete values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/height"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-inhalerusage",
          "identifier": "inhalerUsage",
          "objc_constant": "HKQuantityTypeIdentifierInhalerUsage",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the number of puffs the user takes from their inhaler.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use count units (described in ) and measure cumulative values (described in ).",
          "unit_family": "count",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/inhalerusage"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-insulindelivery",
          "identifier": "insulinDelivery",
          "objc_constant": "HKQuantityTypeIdentifierInsulinDelivery",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample that measures the amount of insulin delivered.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use international units (IU) (described in ) and measure cumulative values (described in ).",
          "unit_family": "international",
          "value_enum": null,
          "ios_introduced": "11.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/insulindelivery"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-leanbodymass",
          "identifier": "leanBodyMass",
          "objc_constant": "HKQuantityTypeIdentifierLeanBodyMass",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s lean body mass.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use mass units (described in ) and measure discrete values (described in ).",
          "unit_family": "mass",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/leanbodymass"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-nikefuel",
          "identifier": "nikeFuel",
          "objc_constant": "HKQuantityTypeIdentifierNikeFuel",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the number of NikeFuel points the user has earned.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use count units (described in ) and measure cumulative values (described in ).",
          "unit_family": "count",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/nikefuel"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-numberofalcoholicbeverages",
          "identifier": "numberOfAlcoholicBeverages",
          "objc_constant": "HKQuantityTypeIdentifierNumberOfAlcoholicBeverages",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the number of standard alcoholic drinks that the user has consumed.",
          "aggregation": "cumulative",
          "aggregation_evidence": "The samples use count units (described in ) to measure cumulative values (described in ).",
          "unit_family": "count",
          "value_enum": null,
          "ios_introduced": "15.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/numberofalcoholicbeverages"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-numberoftimesfallen",
          "identifier": "numberOfTimesFallen",
          "objc_constant": "HKQuantityTypeIdentifierNumberOfTimesFallen",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the number of times the user fell.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use count units (described in ) and measure cumulative values (described in ).",
          "unit_family": "count",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/numberoftimesfallen"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-oxygensaturation",
          "identifier": "oxygenSaturation",
          "objc_constant": "HKQuantityTypeIdentifierOxygenSaturation",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s oxygen saturation.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use percent units (described in ) and measure discrete values (described in ).",
          "unit_family": "percent",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/oxygensaturation"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-paddlesportsspeed",
          "identifier": "paddleSportsSpeed",
          "objc_constant": "HKQuantityTypeIdentifierPaddleSportsSpeed",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the distance the user has moved by paddling sports.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use distance per time units (described in ) and measure cumulative values (described in ).",
          "unit_family": "distance per time",
          "value_enum": null,
          "ios_introduced": "18.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/paddlesportsspeed"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-peakexpiratoryflowrate",
          "identifier": "peakExpiratoryFlowRate",
          "objc_constant": "HKQuantityTypeIdentifierPeakExpiratoryFlowRate",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s maximum flow rate generated during a forceful exhalation.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use volume/time units (described in ) and measure discrete values (described in ).",
          "unit_family": "volume/time",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/peakexpiratoryflowrate"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-peripheralperfusionindex",
          "identifier": "peripheralPerfusionIndex",
          "objc_constant": "HKQuantityTypeIdentifierPeripheralPerfusionIndex",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s peripheral perfusion index.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use percent units (described in ) and measure discrete values (described in ).",
          "unit_family": "percent",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/peripheralperfusionindex"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-physicaleffort",
          "identifier": "physicalEffort",
          "objc_constant": "HKQuantityTypeIdentifierPhysicalEffort",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the estimated amount of energy being used to perform a task excluding other factors such as temperature, altitude, or heart rate.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use power in Metabolic Equivalent of Task (METs) units (described in ) and measure discrete values (described in ).",
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "17.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/physicaleffort"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-pushcount",
          "identifier": "pushCount",
          "objc_constant": "HKQuantityTypeIdentifierPushCount",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the number of pushes that the user has performed while using a wheelchair.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use count units (described in ) and measure cumulative values (described in ).",
          "unit_family": "count",
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/pushcount"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-respiratoryrate",
          "identifier": "respiratoryRate",
          "objc_constant": "HKQuantityTypeIdentifierRespiratoryRate",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s respiratory rate.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use count/time units (described in ) and measure discrete values (described in ).",
          "unit_family": "count/time",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/respiratoryrate"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-restingheartrate",
          "identifier": "restingHeartRate",
          "objc_constant": "HKQuantityTypeIdentifierRestingHeartRate",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s resting heart rate.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use count/time units (described in ) and measure discrete values (described in ).",
          "unit_family": "count/time",
          "value_enum": null,
          "ios_introduced": "11.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/restingheartrate"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-rowingspeed",
          "identifier": "rowingSpeed",
          "objc_constant": "HKQuantityTypeIdentifierRowingSpeed",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures how fast the rower is moving.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use distance per time units (described in ) and measure discrete values (described in ).",
          "unit_family": "distance per time",
          "value_enum": null,
          "ios_introduced": "18.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/rowingspeed"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-runninggroundcontacttime",
          "identifier": "runningGroundContactTime",
          "objc_constant": "HKQuantityTypeIdentifierRunningGroundContactTime",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the amount of time the runner’s foot is in contact with the ground while running.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use time units (described in ) and measure discrete values (described in ).",
          "unit_family": "time",
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/runninggroundcontacttime"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-runningpower",
          "identifier": "runningPower",
          "objc_constant": "HKQuantityTypeIdentifierRunningPower",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the rate of work required for the runner to maintain their speed.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use power units (described in ) and measure discrete values (described in ).",
          "unit_family": "power",
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/runningpower"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-runningspeed",
          "identifier": "runningSpeed",
          "objc_constant": "HKQuantityTypeIdentifierRunningSpeed",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the runner’s speed.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use distance per time units (described in ) and measure discrete values (described in ).",
          "unit_family": "distance per time",
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/runningspeed"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-runningstridelength",
          "identifier": "runningStrideLength",
          "objc_constant": "HKQuantityTypeIdentifierRunningStrideLength",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the distance covered by a single step while running.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use length units (described in ) and measure discrete values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/runningstridelength"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-runningverticaloscillation",
          "identifier": "runningVerticalOscillation",
          "objc_constant": "HKQuantityTypeIdentifierRunningVerticalOscillation",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type measuring pelvis vertical range of motion during a single running stride.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use length units (described in ) and measure discrete values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/runningverticaloscillation"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-sixminutewalktestdistance",
          "identifier": "sixMinuteWalkTestDistance",
          "objc_constant": "HKQuantityTypeIdentifierSixMinuteWalkTestDistance",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that stores the distance a user can walk during a six-minute walk test.",
          "aggregation": "discrete",
          "aggregation_evidence": "samples use length units (described in ) and measure discrete values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/sixminutewalktestdistance"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-stairascentspeed",
          "identifier": "stairAscentSpeed",
          "objc_constant": "HKQuantityTypeIdentifierStairAscentSpeed",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type measuring the user’s speed while climbing a flight of stairs.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use distance/time units (described in ) and measure discrete values (described in ).",
          "unit_family": "distance/time",
          "value_enum": null,
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/stairascentspeed"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-stairdescentspeed",
          "identifier": "stairDescentSpeed",
          "objc_constant": "HKQuantityTypeIdentifierStairDescentSpeed",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type measuring the user’s speed while descending a flight of stairs.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use distance/time units (described in ) and measure discrete values (described in ).",
          "unit_family": "distance/time",
          "value_enum": null,
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/stairdescentspeed"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-stepcount",
          "identifier": "stepCount",
          "objc_constant": "HKQuantityTypeIdentifierStepCount",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the number of steps the user has taken.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use count units (described in ) and measure cumulative values (described in ).",
          "unit_family": "count",
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/stepcount"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-swimmingstrokecount",
          "identifier": "swimmingStrokeCount",
          "objc_constant": "HKQuantityTypeIdentifierSwimmingStrokeCount",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the number of strokes performed while swimming.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use count units (described in ) and measure cumulative values (described in ).",
          "unit_family": "count",
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/swimmingstrokecount"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-timeindaylight",
          "identifier": "timeInDaylight",
          "objc_constant": "HKQuantityTypeIdentifierTimeInDaylight",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures amount of time the user spent in daylight.",
          "aggregation": "cumulative",
          "aggregation_evidence": "These samples use time units (described in ) and measure cumulative values (described in ).",
          "unit_family": "time",
          "value_enum": null,
          "ios_introduced": "17.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/timeindaylight"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-underwaterdepth",
          "identifier": "underwaterDepth",
          "objc_constant": "HKQuantityTypeIdentifierUnderwaterDepth",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample that records a person’s depth underwater.",
          "aggregation": "discrete",
          "aggregation_evidence": "Underwater depth samples use length units (described in ) and measure discrete values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/underwaterdepth"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-uvexposure",
          "identifier": "uvExposure",
          "objc_constant": "HKQuantityTypeIdentifierUVExposure",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s exposure to UV radiation.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use count units (described in ) and measure discrete values (described in ).",
          "unit_family": "count",
          "value_enum": null,
          "ios_introduced": "9.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/uvexposure"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-vo2max",
          "identifier": "vo2Max",
          "objc_constant": "HKQuantityTypeIdentifierVO2Max",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample that measures the maximal oxygen consumption during exercise.",
          "aggregation": "discrete",
          "aggregation_evidence": "They measure discrete values (described in ).",
          "unit_family": "volume/mass/time",
          "value_enum": null,
          "ios_introduced": "11.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/vo2max"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-waistcircumference",
          "identifier": "waistCircumference",
          "objc_constant": "HKQuantityTypeIdentifierWaistCircumference",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s waist circumference.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use length units (described in ) and measure discrete values (described in ).",
          "unit_family": "length",
          "value_enum": null,
          "ios_introduced": "11.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/waistcircumference"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-walkingasymmetrypercentage",
          "identifier": "walkingAsymmetryPercentage",
          "objc_constant": "HKQuantityTypeIdentifierWalkingAsymmetryPercentage",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the percentage of steps in which one foot moves at a different speed than the other when walking on flat ground.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use percentage units (described in ) and measure discrete values (described in ).",
          "unit_family": "percentage",
          "value_enum": null,
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/walkingasymmetrypercentage"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-walkingdoublesupportpercentage",
          "identifier": "walkingDoubleSupportPercentage",
          "objc_constant": "HKQuantityTypeIdentifierWalkingDoubleSupportPercentage",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the percentage of time when both of the user’s feet touch the ground while walking steadily over flat ground.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use percentage units (described in ) and measure discrete values (described in ).",
          "unit_family": "percentage",
          "value_enum": null,
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/walkingdoublesupportpercentage"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-walkingheartrateaverage",
          "identifier": "walkingHeartRateAverage",
          "objc_constant": "HKQuantityTypeIdentifierWalkingHeartRateAverage",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s heart rate while walking.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use count/time units (described in ) and measure discrete values (described in ).",
          "unit_family": "count/time",
          "value_enum": null,
          "ios_introduced": "11.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/walkingheartrateaverage"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-walkingspeed",
          "identifier": "walkingSpeed",
          "objc_constant": "HKQuantityTypeIdentifierWalkingSpeed",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the user’s average speed when walking steadily over flat ground.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use distance per time units (described in ) and measure discrete values (described in ).",
          "unit_family": "distance per time",
          "value_enum": null,
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/walkingspeed"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-walkingsteplength",
          "identifier": "walkingStepLength",
          "objc_constant": "HKQuantityTypeIdentifierWalkingStepLength",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample type that measures the average length of the user’s step when walking steadily over flat ground.",
          "aggregation": "discrete",
          "aggregation_evidence": "These samples use distance units (described in ) and measure discrete values (described in ).",
          "unit_family": "distance",
          "value_enum": null,
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/walkingsteplength"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-watertemperature",
          "identifier": "waterTemperature",
          "objc_constant": "HKQuantityTypeIdentifierWaterTemperature",
          "family": "HKQuantityTypeIdentifier",
          "abstract": "A quantity sample that records the water temperature.",
          "aggregation": "discrete",
          "aggregation_evidence": "Water temperature samples use temperature units (see ) and measure discrete values (see ).",
          "unit_family": "temperature",
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/watertemperature"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-workouteffortscore",
          "identifier": "workoutEffortScore",
          "objc_constant": "HKQuantityTypeIdentifierWorkoutEffortScore",
          "family": "HKQuantityTypeIdentifier",
          "abstract": null,
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "18.0",
          "apple_documents_it": false,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifier/workouteffortscore"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-applestandhour",
          "identifier": "appleStandHour",
          "objc_constant": "HKCategoryTypeIdentifierAppleStandHour",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type that counts the number of hours in the day during which the user has stood and moved for at least one minute per hour.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueAppleStandHour",
          "ios_introduced": "9.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/applestandhour"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-applewalkingsteadinessevent",
          "identifier": "appleWalkingSteadinessEvent",
          "objc_constant": "HKCategoryTypeIdentifierAppleWalkingSteadinessEvent",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type that records an incident where the user showed a reduced score for their gait’s steadiness.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueAppleWalkingSteadinessEvent",
          "ios_introduced": "15.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/applewalkingsteadinessevent"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-audioexposureevent",
          "identifier": "audioExposureEvent",
          "objc_constant": "HKCategoryTypeIdentifierAudioExposureEvent",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type for audio exposure events.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueAudioExposureEvent",
          "ios_introduced": "13.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/audioexposureevent"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-bleedingaftermenopause",
          "identifier": "bleedingAfterMenopause",
          "objc_constant": "HKCategoryTypeIdentifierBleedingAfterMenopause",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "An identifier for samples that record bleeding after menopause.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "27.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/bleedingaftermenopause"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-cervicalmucusquality",
          "identifier": "cervicalMucusQuality",
          "objc_constant": "HKCategoryTypeIdentifierCervicalMucusQuality",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type that records the quality of the user’s cervical mucus.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueCervicalMucusQuality",
          "ios_introduced": "9.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/cervicalmucusquality"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-contraceptive",
          "identifier": "contraceptive",
          "objc_constant": "HKCategoryTypeIdentifierContraceptive",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type that records the use of contraceptives.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueContraceptive",
          "ios_introduced": "14.3",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/contraceptive"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-environmentalaudioexposureevent",
          "identifier": "environmentalAudioExposureEvent",
          "objc_constant": "HKCategoryTypeIdentifierEnvironmentalAudioExposureEvent",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type that records exposure to potentially damaging sounds from the environment.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueEnvironmentalAudioExposureEvent",
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/environmentalaudioexposureevent"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-handwashingevent",
          "identifier": "handwashingEvent",
          "objc_constant": "HKCategoryTypeIdentifierHandwashingEvent",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type for handwashing events.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/handwashingevent"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-headphoneaudioexposureevent",
          "identifier": "headphoneAudioExposureEvent",
          "objc_constant": "HKCategoryTypeIdentifierHeadphoneAudioExposureEvent",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type that records exposure to potentially damaging sounds from headphones.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueHeadphoneAudioExposureEvent",
          "ios_introduced": "14.2",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/headphoneaudioexposureevent"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-highheartrateevent",
          "identifier": "highHeartRateEvent",
          "objc_constant": "HKCategoryTypeIdentifierHighHeartRateEvent",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type for high heart rate events.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "12.2",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/highheartrateevent"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-hypertensionevent",
          "identifier": "hypertensionEvent",
          "objc_constant": "HKCategoryTypeIdentifierHypertensionEvent",
          "family": "HKCategoryTypeIdentifier",
          "abstract": null,
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "26.2",
          "apple_documents_it": false,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/hypertensionevent"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-infrequentmenstrualcycles",
          "identifier": "infrequentMenstrualCycles",
          "objc_constant": "HKCategoryTypeIdentifierInfrequentMenstrualCycles",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample that indicates an infrequent menstrual cycle.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/infrequentmenstrualcycles"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-intermenstrualbleeding",
          "identifier": "intermenstrualBleeding",
          "objc_constant": "HKCategoryTypeIdentifierIntermenstrualBleeding",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type that records spotting outside the normal menstruation period.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "9.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/intermenstrualbleeding"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-irregularheartrhythmevent",
          "identifier": "irregularHeartRhythmEvent",
          "objc_constant": "HKCategoryTypeIdentifierIrregularHeartRhythmEvent",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type for irregular heart rhythm events.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "12.2",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/irregularheartrhythmevent"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-irregularmenstrualcycles",
          "identifier": "irregularMenstrualCycles",
          "objc_constant": "HKCategoryTypeIdentifierIrregularMenstrualCycles",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample that indicates an irregular menstrual cycle.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/irregularmenstrualcycles"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-lactation",
          "identifier": "lactation",
          "objc_constant": "HKCategoryTypeIdentifierLactation",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category type that records lactation.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "14.3",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/lactation"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-lowcardiofitnessevent",
          "identifier": "lowCardioFitnessEvent",
          "objc_constant": "HKCategoryTypeIdentifierLowCardioFitnessEvent",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "An event that indicates the user’s VO2 max values consistently fall below a particular aerobic fitness threshold.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueLowCardioFitnessEvent",
          "ios_introduced": "14.3",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/lowcardiofitnessevent"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-lowheartrateevent",
          "identifier": "lowHeartRateEvent",
          "objc_constant": "HKCategoryTypeIdentifierLowHeartRateEvent",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type for low heart rate events.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "12.2",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/lowheartrateevent"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-menopausalstate",
          "identifier": "menopausalState",
          "objc_constant": "HKCategoryTypeIdentifierMenopausalState",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "An identifier for samples that record a person’s menopausal state.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueMenopausalState",
          "ios_introduced": "27.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/menopausalstate"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-menstrualflow",
          "identifier": "menstrualFlow",
          "objc_constant": "HKCategoryTypeIdentifierMenstrualFlow",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type that records menstrual cycles.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueMenstrualFlow",
          "ios_introduced": "9.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/menstrualflow"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-mindfulsession",
          "identifier": "mindfulSession",
          "objc_constant": "HKCategoryTypeIdentifierMindfulSession",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type for recording a mindful session.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/mindfulsession"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-ovulationtestresult",
          "identifier": "ovulationTestResult",
          "objc_constant": "HKCategoryTypeIdentifierOvulationTestResult",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type that records the result of an ovulation home test.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueOvulationTestResult",
          "ios_introduced": "9.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/ovulationtestresult"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-persistentintermenstrualbleeding",
          "identifier": "persistentIntermenstrualBleeding",
          "objc_constant": "HKCategoryTypeIdentifierPersistentIntermenstrualBleeding",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample that indicates persistent intermenstrual bleeding.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/persistentintermenstrualbleeding"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-pregnancy",
          "identifier": "pregnancy",
          "objc_constant": "HKCategoryTypeIdentifierPregnancy",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category type that records pregnancy.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "14.3",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/pregnancy"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-pregnancytestresult",
          "identifier": "pregnancyTestResult",
          "objc_constant": "HKCategoryTypeIdentifierPregnancyTestResult",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category type that represents the results from a home pregnancy test.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValuePregnancyTestResult",
          "ios_introduced": "15.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/pregnancytestresult"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-progesteronetestresult",
          "identifier": "progesteroneTestResult",
          "objc_constant": "HKCategoryTypeIdentifierProgesteroneTestResult",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category type that represents the results from a home progesterone test.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueProgesteroneTestResult",
          "ios_introduced": "15.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/progesteronetestresult"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-prolongedmenstrualperiods",
          "identifier": "prolongedMenstrualPeriods",
          "objc_constant": "HKCategoryTypeIdentifierProlongedMenstrualPeriods",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample that indicates a prolonged menstrual cycle.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/prolongedmenstrualperiods"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-sexualactivity",
          "identifier": "sexualActivity",
          "objc_constant": "HKCategoryTypeIdentifierSexualActivity",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type that records sexual activity.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "9.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/sexualactivity"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-sleepanalysis",
          "identifier": "sleepAnalysis",
          "objc_constant": "HKCategoryTypeIdentifierSleepAnalysis",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type for sleep analysis information.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValueSleepAnalysis",
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/sleepanalysis"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-toothbrushingevent",
          "identifier": "toothbrushingEvent",
          "objc_constant": "HKCategoryTypeIdentifierToothbrushingEvent",
          "family": "HKCategoryTypeIdentifier",
          "abstract": "A category sample type for toothbrushing events.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": "HKCategoryValue",
          "ios_introduced": "13.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/toothbrushingevent"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-activitymovemode",
          "identifier": "activityMoveMode",
          "objc_constant": "HKCharacteristicTypeIdentifierActivityMoveMode",
          "family": "HKCharacteristicTypeIdentifier",
          "abstract": "A characteristic identifier for the user’s activity mode.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcharacteristictypeidentifier/activitymovemode"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-biologicalsex",
          "identifier": "biologicalSex",
          "objc_constant": "HKCharacteristicTypeIdentifierBiologicalSex",
          "family": "HKCharacteristicTypeIdentifier",
          "abstract": "A characteristic type identifier for the user’s sex.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcharacteristictypeidentifier/biologicalsex"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-bloodtype",
          "identifier": "bloodType",
          "objc_constant": "HKCharacteristicTypeIdentifierBloodType",
          "family": "HKCharacteristicTypeIdentifier",
          "abstract": "A characteristic type identifier for the user’s blood type.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcharacteristictypeidentifier/bloodtype"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dateofbirth",
          "identifier": "dateOfBirth",
          "objc_constant": "HKCharacteristicTypeIdentifierDateOfBirth",
          "family": "HKCharacteristicTypeIdentifier",
          "abstract": "A characteristic type identifier for the user’s date of birth.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcharacteristictypeidentifier/dateofbirth"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-fitzpatrickskintype",
          "identifier": "fitzpatrickSkinType",
          "objc_constant": "HKCharacteristicTypeIdentifierFitzpatrickSkinType",
          "family": "HKCharacteristicTypeIdentifier",
          "abstract": "A characteristic type identifier for the user’s skin type.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "9.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcharacteristictypeidentifier/fitzpatrickskintype"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-wheelchairuse",
          "identifier": "wheelchairUse",
          "objc_constant": "HKCharacteristicTypeIdentifierWheelchairUse",
          "family": "HKCharacteristicTypeIdentifier",
          "abstract": "A characteristic identifier for the user’s use of a wheelchair.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkcharacteristictypeidentifier/wheelchairuse"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-americanfootball",
          "identifier": "americanFootball",
          "objc_constant": "HKWorkoutActivityTypeAmericanFootball",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing American football.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/americanfootball"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-archery",
          "identifier": "archery",
          "objc_constant": "HKWorkoutActivityTypeArchery",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for shooting archery.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/archery"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-australianfootball",
          "identifier": "australianFootball",
          "objc_constant": "HKWorkoutActivityTypeAustralianFootball",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing Australian football.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/australianfootball"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-badminton",
          "identifier": "badminton",
          "objc_constant": "HKWorkoutActivityTypeBadminton",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing badminton.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/badminton"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-barre",
          "identifier": "barre",
          "objc_constant": "HKWorkoutActivityTypeBarre",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for barre workout.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/barre"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-baseball",
          "identifier": "baseball",
          "objc_constant": "HKWorkoutActivityTypeBaseball",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing baseball.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/baseball"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-basketball",
          "identifier": "basketball",
          "objc_constant": "HKWorkoutActivityTypeBasketball",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing basketball.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/basketball"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-bowling",
          "identifier": "bowling",
          "objc_constant": "HKWorkoutActivityTypeBowling",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for bowling.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/bowling"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-boxing",
          "identifier": "boxing",
          "objc_constant": "HKWorkoutActivityTypeBoxing",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for boxing.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/boxing"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-cardiodance",
          "identifier": "cardioDance",
          "objc_constant": "HKWorkoutActivityTypeCardioDance",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for cardiovascular dance workouts.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/cardiodance"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-climbing",
          "identifier": "climbing",
          "objc_constant": "HKWorkoutActivityTypeClimbing",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for climbing.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/climbing"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-cooldown",
          "identifier": "cooldown",
          "objc_constant": "HKWorkoutActivityTypeCooldown",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for low intensity stretching and mobility exercises following a more vigorous workout.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/cooldown"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-coretraining",
          "identifier": "coreTraining",
          "objc_constant": "HKWorkoutActivityTypeCoreTraining",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for core training.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/coretraining"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-cricket",
          "identifier": "cricket",
          "objc_constant": "HKWorkoutActivityTypeCricket",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing cricket.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/cricket"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-crosscountryskiing",
          "identifier": "crossCountrySkiing",
          "objc_constant": "HKWorkoutActivityTypeCrossCountrySkiing",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for cross country skiing.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/crosscountryskiing"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-crosstraining",
          "identifier": "crossTraining",
          "objc_constant": "HKWorkoutActivityTypeCrossTraining",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for exercise that includes any mixture of cardio, strength, and/or flexibility training.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/crosstraining"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-curling",
          "identifier": "curling",
          "objc_constant": "HKWorkoutActivityTypeCurling",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for curling.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/curling"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-cycling",
          "identifier": "cycling",
          "objc_constant": "HKWorkoutActivityTypeCycling",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for cycling.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/cycling"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-dance",
          "identifier": "dance",
          "objc_constant": "HKWorkoutActivityTypeDance",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for dancing.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/dance"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-danceinspiredtraining",
          "identifier": "danceInspiredTraining",
          "objc_constant": "HKWorkoutActivityTypeDanceInspiredTraining",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for workouts inspired by dance, including Pilates, Barre, and Feldenkrais.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/danceinspiredtraining"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-discsports",
          "identifier": "discSports",
          "objc_constant": "HKWorkoutActivityTypeDiscSports",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing disc sports such as Ultimate and Disc Golf.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "13.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/discsports"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-downhillskiing",
          "identifier": "downhillSkiing",
          "objc_constant": "HKWorkoutActivityTypeDownhillSkiing",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for downhill skiing.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/downhillskiing"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-elliptical",
          "identifier": "elliptical",
          "objc_constant": "HKWorkoutActivityTypeElliptical",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for workouts on an elliptical machine.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/elliptical"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-equestriansports",
          "identifier": "equestrianSports",
          "objc_constant": "HKWorkoutActivityTypeEquestrianSports",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for activities that involve riding a horse, including polo, horse racing, and horse riding.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/equestriansports"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-fencing",
          "identifier": "fencing",
          "objc_constant": "HKWorkoutActivityTypeFencing",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for fencing.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/fencing"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-fishing",
          "identifier": "fishing",
          "objc_constant": "HKWorkoutActivityTypeFishing",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for fishing.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/fishing"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-fitnessgaming",
          "identifier": "fitnessGaming",
          "objc_constant": "HKWorkoutActivityTypeFitnessGaming",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing fitness-based video games.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "13.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/fitnessgaming"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-flexibility",
          "identifier": "flexibility",
          "objc_constant": "HKWorkoutActivityTypeFlexibility",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for a flexibility workout.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/flexibility"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-functionalstrengthtraining",
          "identifier": "functionalStrengthTraining",
          "objc_constant": "HKWorkoutActivityTypeFunctionalStrengthTraining",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for strength training, primarily with free weights and body weight.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/functionalstrengthtraining"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-golf",
          "identifier": "golf",
          "objc_constant": "HKWorkoutActivityTypeGolf",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing golf.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/golf"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-gymnastics",
          "identifier": "gymnastics",
          "objc_constant": "HKWorkoutActivityTypeGymnastics",
          "family": "HKWorkoutActivityType",
          "abstract": "Performing gymnastics.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/gymnastics"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-handball",
          "identifier": "handball",
          "objc_constant": "HKWorkoutActivityTypeHandball",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing handball.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/handball"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-handcycling",
          "identifier": "handCycling",
          "objc_constant": "HKWorkoutActivityTypeHandCycling",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for hand cycling.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "11.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/handcycling"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-highintensityintervaltraining",
          "identifier": "highIntensityIntervalTraining",
          "objc_constant": "HKWorkoutActivityTypeHighIntensityIntervalTraining",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for high intensity interval training.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/highintensityintervaltraining"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-hiking",
          "identifier": "hiking",
          "objc_constant": "HKWorkoutActivityTypeHiking",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for hiking.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/hiking"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-hockey",
          "identifier": "hockey",
          "objc_constant": "HKWorkoutActivityTypeHockey",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing hockey, including ice hockey, field hockey, and related sports.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/hockey"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-hunting",
          "identifier": "hunting",
          "objc_constant": "HKWorkoutActivityTypeHunting",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for hunting.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/hunting"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-jumprope",
          "identifier": "jumpRope",
          "objc_constant": "HKWorkoutActivityTypeJumpRope",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for jumping rope.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/jumprope"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-kickboxing",
          "identifier": "kickboxing",
          "objc_constant": "HKWorkoutActivityTypeKickboxing",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for kickboxing.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/kickboxing"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-lacrosse",
          "identifier": "lacrosse",
          "objc_constant": "HKWorkoutActivityTypeLacrosse",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing lacrosse.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/lacrosse"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-martialarts",
          "identifier": "martialArts",
          "objc_constant": "HKWorkoutActivityTypeMartialArts",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for practicing martial arts.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/martialarts"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-mindandbody",
          "identifier": "mindAndBody",
          "objc_constant": "HKWorkoutActivityTypeMindAndBody",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for performing activities like walking meditation, Gyrotonic exercise, and Qigong.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/mindandbody"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-mixedcardio",
          "identifier": "mixedCardio",
          "objc_constant": "HKWorkoutActivityTypeMixedCardio",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for workouts that mix a variety of cardio exercise machines or modalities.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "11.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/mixedcardio"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-mixedmetaboliccardiotraining",
          "identifier": "mixedMetabolicCardioTraining",
          "objc_constant": "HKWorkoutActivityTypeMixedMetabolicCardioTraining",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for performing any mix of cardio-focused exercises.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/mixedmetaboliccardiotraining"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-other",
          "identifier": "other",
          "objc_constant": "HKWorkoutActivityTypeOther",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for a workout that does not match any of the other workout activity types.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/other"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-paddlesports",
          "identifier": "paddleSports",
          "objc_constant": "HKWorkoutActivityTypePaddleSports",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for canoeing, kayaking, paddling an outrigger, paddling a stand-up paddle board, and related sports.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/paddlesports"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-pickleball",
          "identifier": "pickleball",
          "objc_constant": "HKWorkoutActivityTypePickleball",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing pickleball.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/pickleball"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-pilates",
          "identifier": "pilates",
          "objc_constant": "HKWorkoutActivityTypePilates",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for a pilates workout.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/pilates"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-play",
          "identifier": "play",
          "objc_constant": "HKWorkoutActivityTypePlay",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for play-based activities like tag, dodgeball, hopscotch, tetherball, and playing on a jungle gym.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/play"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-preparationandrecovery",
          "identifier": "preparationAndRecovery",
          "objc_constant": "HKWorkoutActivityTypePreparationAndRecovery",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for warm-up and therapeutic activities like foam rolling and stretching.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/preparationandrecovery"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-racquetball",
          "identifier": "racquetball",
          "objc_constant": "HKWorkoutActivityTypeRacquetball",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing racquetball.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/racquetball"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-rowing",
          "identifier": "rowing",
          "objc_constant": "HKWorkoutActivityTypeRowing",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for rowing.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/rowing"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-rugby",
          "identifier": "rugby",
          "objc_constant": "HKWorkoutActivityTypeRugby",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing rugby.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/rugby"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-running",
          "identifier": "running",
          "objc_constant": "HKWorkoutActivityTypeRunning",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for running and jogging.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/running"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-sailing",
          "identifier": "sailing",
          "objc_constant": "HKWorkoutActivityTypeSailing",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for sailing.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/sailing"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-skatingsports",
          "identifier": "skatingSports",
          "objc_constant": "HKWorkoutActivityTypeSkatingSports",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for skating activities, including ice skating, speed skating, inline skating, and skateboarding.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/skatingsports"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-snowboarding",
          "identifier": "snowboarding",
          "objc_constant": "HKWorkoutActivityTypeSnowboarding",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for snowboarding.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/snowboarding"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-snowsports",
          "identifier": "snowSports",
          "objc_constant": "HKWorkoutActivityTypeSnowSports",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for a variety of snow sports, including sledding, snowmobiling, or building a snowman.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/snowsports"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-soccer",
          "identifier": "soccer",
          "objc_constant": "HKWorkoutActivityTypeSoccer",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing soccer.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/soccer"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-socialdance",
          "identifier": "socialDance",
          "objc_constant": "HKWorkoutActivityTypeSocialDance",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for dancing with a partner or partners, such as swing, salsa, or folk dances.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "14.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/socialdance"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-softball",
          "identifier": "softball",
          "objc_constant": "HKWorkoutActivityTypeSoftball",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing softball.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/softball"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-squash",
          "identifier": "squash",
          "objc_constant": "HKWorkoutActivityTypeSquash",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing squash.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/squash"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-stairclimbing",
          "identifier": "stairClimbing",
          "objc_constant": "HKWorkoutActivityTypeStairClimbing",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for workouts using a stair climbing machine.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/stairclimbing"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-stairs",
          "identifier": "stairs",
          "objc_constant": "HKWorkoutActivityTypeStairs",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for running, walking, or other drills using stairs (for example, in a stadium or inside a multilevel building).",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/stairs"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-steptraining",
          "identifier": "stepTraining",
          "objc_constant": "HKWorkoutActivityTypeStepTraining",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for training using a step bench.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/steptraining"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-surfingsports",
          "identifier": "surfingSports",
          "objc_constant": "HKWorkoutActivityTypeSurfingSports",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for a variety of surf sports, including surfing, kite surfing, and wind surfing.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/surfingsports"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-swimbikerun",
          "identifier": "swimBikeRun",
          "objc_constant": "HKWorkoutActivityTypeSwimBikeRun",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for multisport activities like triathlons.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/swimbikerun"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-swimming",
          "identifier": "swimming",
          "objc_constant": "HKWorkoutActivityTypeSwimming",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for swimming.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/swimming"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-tabletennis",
          "identifier": "tableTennis",
          "objc_constant": "HKWorkoutActivityTypeTableTennis",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing table tennis.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/tabletennis"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-taichi",
          "identifier": "taiChi",
          "objc_constant": "HKWorkoutActivityTypeTaiChi",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for tai chi.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "11.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/taichi"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-tennis",
          "identifier": "tennis",
          "objc_constant": "HKWorkoutActivityTypeTennis",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing tennis.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/tennis"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-trackandfield",
          "identifier": "trackAndField",
          "objc_constant": "HKWorkoutActivityTypeTrackAndField",
          "family": "HKWorkoutActivityType",
          "abstract": "Participating in track and field events, including shot put, javelin, pole vaulting, and related sports.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/trackandfield"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-traditionalstrengthtraining",
          "identifier": "traditionalStrengthTraining",
          "objc_constant": "HKWorkoutActivityTypeTraditionalStrengthTraining",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for strength training exercises primarily using machines or free weights.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/traditionalstrengthtraining"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-transition",
          "identifier": "transition",
          "objc_constant": "HKWorkoutActivityTypeTransition",
          "family": "HKWorkoutActivityType",
          "abstract": "A constant for the transition time between activities in a multisport workout.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "16.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/transition"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-underwaterdiving",
          "identifier": "underwaterDiving",
          "objc_constant": "HKWorkoutActivityTypeUnderwaterDiving",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for underwater diving.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "17.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/underwaterdiving"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-volleyball",
          "identifier": "volleyball",
          "objc_constant": "HKWorkoutActivityTypeVolleyball",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing volleyball.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/volleyball"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-walking",
          "identifier": "walking",
          "objc_constant": "HKWorkoutActivityTypeWalking",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for walking.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/walking"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-waterfitness",
          "identifier": "waterFitness",
          "objc_constant": "HKWorkoutActivityTypeWaterFitness",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for aerobic exercise performed in shallow water.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/waterfitness"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-waterpolo",
          "identifier": "waterPolo",
          "objc_constant": "HKWorkoutActivityTypeWaterPolo",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for playing water polo.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/waterpolo"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-watersports",
          "identifier": "waterSports",
          "objc_constant": "HKWorkoutActivityTypeWaterSports",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for a variety of water sports, including water skiing, wake boarding, and related activities.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/watersports"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-wheelchairrunpace",
          "identifier": "wheelchairRunPace",
          "objc_constant": "HKWorkoutActivityTypeWheelchairRunPace",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for wheelchair workout at running pace.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/wheelchairrunpace"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-wheelchairwalkpace",
          "identifier": "wheelchairWalkPace",
          "objc_constant": "HKWorkoutActivityTypeWheelchairWalkPace",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for a wheelchair workout at walking pace.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "10.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/wheelchairwalkpace"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-wrestling",
          "identifier": "wrestling",
          "objc_constant": "HKWorkoutActivityTypeWrestling",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for wrestling.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/wrestling"
        },
        {
          "id": "https://aifitnessapi.com/healthkit-identifiers#id-yoga",
          "identifier": "yoga",
          "objc_constant": "HKWorkoutActivityTypeYoga",
          "family": "HKWorkoutActivityType",
          "abstract": "The constant for practicing yoga.",
          "aggregation": null,
          "aggregation_evidence": null,
          "unit_family": null,
          "value_enum": null,
          "ios_introduced": "8.0",
          "apple_documents_it": true,
          "apple_docs": "https://developer.apple.com/documentation/healthkit/hkworkoutactivitytype/yoga"
        }
      ]
    },
    "cross_platform_types": {
      "count": 10,
      "note": "Scoped deliberately to the two on-device stores. A metric's absence means we could not verify it on both platforms, not that it does not exist.",
      "items": [
        {
          "id": "https://aifitnessapi.com/matrix#heart-rate",
          "metric": "Heart rate",
          "apple_healthkit": "HKQuantityTypeIdentifier.heartRate, .restingHeartRate",
          "android_health_connect": "HeartRateRecord, RestingHeartRateRecord",
          "caveat": "Both expose samples plus a separate resting value — don't derive resting yourself.",
          "guide": "https://aifitnessapi.com/data/heart-rate-api"
        },
        {
          "id": "https://aifitnessapi.com/matrix#hrv",
          "metric": "HRV",
          "apple_healthkit": "HKQuantityTypeIdentifier.heartRateVariabilitySDNN",
          "android_health_connect": "HeartRateVariabilityRmssdRecord",
          "caveat": "The big one: Apple stores SDNN, Health Connect stores RMSSD. They are different measures and are not interconvertible — do not normalize one into the other.",
          "guide": "https://aifitnessapi.com/data/hrv-api"
        },
        {
          "id": "https://aifitnessapi.com/matrix#vo2-max",
          "metric": "VO2 max",
          "apple_healthkit": "HKQuantityTypeIdentifier.vo2Max",
          "android_health_connect": "Vo2MaxRecord",
          "caveat": "An estimate on both platforms, not a lab measurement. Health Connect tags a measurement method.",
          "guide": "https://aifitnessapi.com/data/vo2-max-api"
        },
        {
          "id": "https://aifitnessapi.com/matrix#blood-oxygen",
          "metric": "Blood oxygen",
          "apple_healthkit": "HKQuantityTypeIdentifier.oxygenSaturation",
          "android_health_connect": "OxygenSaturationRecord",
          "caveat": "The type existing doesn't mean data exists — SpO2 is device-gated, and Apple Watch availability in the US has been subject to litigation. Verify current status.",
          "guide": "https://aifitnessapi.com/data/blood-oxygen-api"
        },
        {
          "id": "https://aifitnessapi.com/matrix#sleep",
          "metric": "Sleep",
          "apple_healthkit": "HKCategoryTypeIdentifier.sleepAnalysis (values: inBed, awake, asleepCore, asleepDeep, asleepREM, asleepUnspecified)",
          "android_health_connect": "SleepSessionRecord (carries stages)",
          "caveat": "Stage vocabularies differ and stages are estimated, not measured. Apple's .asleep is deprecated in favour of the specific stages.",
          "guide": "https://aifitnessapi.com/data/sleep-tracking-api"
        },
        {
          "id": "https://aifitnessapi.com/matrix#steps",
          "metric": "Steps",
          "apple_healthkit": "HKQuantityTypeIdentifier.stepCount (CMPedometer for live counts)",
          "android_health_connect": "StepsRecord, StepsCadenceRecord",
          "caveat": "De-duplicate: phone and watch both write steps. On Android, from the June 2026 update on-device steps are attributed to a per-device Synthetic Package Name — read it via getCurrentDeviceDataSource(), never hardcode it.",
          "guide": "https://aifitnessapi.com/data/step-counting-api"
        },
        {
          "id": "https://aifitnessapi.com/matrix#workouts",
          "metric": "Workouts",
          "apple_healthkit": "HKWorkout (HKWorkoutBuilder)",
          "android_health_connect": "ExerciseSessionRecord, PlannedExerciseSessionRecord",
          "caveat": "Activity-type taxonomies differ between platforms — map them explicitly rather than by name.",
          "guide": "https://aifitnessapi.com/data/workout-detection-api"
        },
        {
          "id": "https://aifitnessapi.com/matrix#gps-route",
          "metric": "GPS route",
          "apple_healthkit": "HKWorkoutRoute (array of CLLocation), HKWorkoutRouteQuery",
          "android_health_connect": "ExerciseRoute with ExerciseRoute.Location",
          "caveat": "Health Connect gates routes behind their own permission (READ_EXERCISE_ROUTES) and restricts background reads of other apps' routes.",
          "guide": "https://aifitnessapi.com/data/gps-activity-api"
        },
        {
          "id": "https://aifitnessapi.com/matrix#calories",
          "metric": "Calories",
          "apple_healthkit": "HKQuantityTypeIdentifier.activeEnergyBurned, .basalEnergyBurned",
          "android_health_connect": "ActiveCaloriesBurnedRecord, TotalCaloriesBurnedRecord",
          "caveat": "Modelled estimates, not measurements. Note the asymmetry: Apple splits active/basal, Android offers active and total — don't add active to total.",
          "guide": "https://aifitnessapi.com/data/calorie-tracking-api"
        },
        {
          "id": "https://aifitnessapi.com/matrix#body-composition",
          "metric": "Body composition",
          "apple_healthkit": "HKQuantityTypeIdentifier.bodyMass, .bodyFatPercentage, .leanBodyMass, .bodyMassIndex",
          "android_health_connect": "WeightRecord, BodyFatRecord, LeanBodyMassRecord, BoneMassRecord, BodyWaterMassRecord, BasalMetabolicRateRecord",
          "caveat": "The store holds it, but something has to write it — usually a smart scale or manual entry. Body fat is a bioimpedance estimate.",
          "guide": "https://aifitnessapi.com/data/body-composition-api"
        }
      ]
    },
    "glossary": {
      "count": 33,
      "items": [
        {
          "id": "https://aifitnessapi.com/glossary#term-hrv",
          "term": "HRV (heart rate variability)",
          "definition": "Beat-to-beat variation in heart rhythm, used as a recovery signal — but not one number: Apple stores SDNN while Health Connect stores RMSSD, and the two are not interconvertible.",
          "group": "Health data & metrics",
          "explained_at": "https://aifitnessapi.com/learn/what-is-hrv"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-sdnn",
          "term": "SDNN",
          "definition": "The HRV statistic Apple HealthKit stores — the standard deviation of intervals between normal heartbeats. Do not mix it with RMSSD in one column.",
          "group": "Health data & metrics",
          "explained_at": "https://aifitnessapi.com/matrix"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-rmssd",
          "term": "RMSSD",
          "definition": "The HRV statistic Health Connect stores — the root mean square of successive interval differences. A different measure from SDNN, not a unit conversion away.",
          "group": "Health data & metrics",
          "explained_at": "https://aifitnessapi.com/data/hrv-api"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-vo2-max",
          "term": "VO2 max",
          "definition": "An estimate of aerobic capacity. On consumer devices it is modeled from heart rate and pace, not measured — treat it as a trend, not a lab value.",
          "group": "Health data & metrics",
          "explained_at": "https://aifitnessapi.com/learn/what-is-vo2-max"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-spo2",
          "term": "SpO2 (blood oxygen)",
          "definition": "Peripheral oxygen saturation from an optical sensor. A data type existing does not mean data will be there — it needs a device that measures it.",
          "group": "Health data & metrics",
          "explained_at": "https://aifitnessapi.com/data/blood-oxygen-api"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-sleep-stages",
          "term": "Sleep stages",
          "definition": "Light, deep, REM and awake segments a device infers from movement and heart rate. Definitions and boundaries differ by vendor, so they do not compare one-to-one.",
          "group": "Health data & metrics",
          "explained_at": "https://aifitnessapi.com/learn/what-are-sleep-stages"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-active-vs-total-calories",
          "term": "Active vs total calories",
          "definition": "Active calories are the burn above rest; total adds basal metabolic rate. Providers disagree on which they report, which is a normalization trap.",
          "group": "Health data & metrics",
          "explained_at": "https://aifitnessapi.com/learn/how-fitness-apps-estimate-calories"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-measured-vs-estimated",
          "term": "Measured vs estimated",
          "definition": "Some metrics are sensed (steps, heart rate); others are modeled (VO2 max, calories, some sleep). Storing the distinction keeps you from presenting a guess as a reading.",
          "group": "Health data & metrics",
          "explained_at": "https://aifitnessapi.com/data"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-healthkit",
          "term": "HealthKit",
          "definition": "Apple's on-device health store. Not a cloud API — there is no server endpoint; your app reads it locally with permission and syncs itself.",
          "group": "Platforms & providers",
          "explained_at": "https://aifitnessapi.com/integrate/healthkit"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-health-connect",
          "term": "Health Connect",
          "definition": "Android's on-device health store — Google's counterpart to HealthKit. Also local-only, and it deduplicates only Activity and Sleep, via its aggregate API.",
          "group": "Platforms & providers",
          "explained_at": "https://aifitnessapi.com/integrate/google-health-connect"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-health-data-aggregator",
          "term": "Health-data aggregator",
          "definition": "A third party (Terra, Rook, and others) that normalizes many wearable and health sources behind one API — often the right buy instead of building integrations yourself.",
          "group": "Platforms & providers",
          "explained_at": "https://aifitnessapi.com/learn/what-is-a-health-data-aggregator"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-exercise-database-api",
          "term": "Exercise database API",
          "definition": "A catalogue of exercises with metadata and media. Watch the licensing — some open options are AGPL copyleft, which matters for closed-source apps.",
          "group": "Platforms & providers",
          "explained_at": "https://aifitnessapi.com/fitness-apis/exercise-database-apis"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-fitness-api",
          "term": "Fitness API",
          "definition": "Any API a developer uses to get fitness or health data or content — wearables, aggregators, exercise or nutrition catalogues, or AI motion tracking. Choose by job.",
          "group": "Platforms & providers",
          "explained_at": "https://aifitnessapi.com/learn/what-is-a-fitness-api"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-oauth",
          "term": "OAuth (for health data)",
          "definition": "The delegated-access handshake that lets a user grant your app read access to their provider account without sharing a password. The token lifecycle is where it breaks in production.",
          "group": "Integration & auth",
          "explained_at": "https://aifitnessapi.com/learn/what-is-oauth-for-health-data"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-webhook",
          "term": "Webhook",
          "definition": "A provider-initiated callback telling you something changed. Most fitness webhooks are thin change-pointers, so the handler's job is usually to enqueue a fetch, not to trust the payload.",
          "group": "Integration & auth",
          "explained_at": "https://aifitnessapi.com/learn/what-are-webhooks"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-401-vs-403",
          "term": "401 vs 403",
          "definition": "A 401 means your token is bad, missing, expired or revoked; a 403 means the token is valid but lacks the scope. They point at different fixes.",
          "group": "Integration & auth",
          "explained_at": "https://aifitnessapi.com/fix/fitness-api-401-unauthorized"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-rate-limit-429",
          "term": "Rate limit / 429",
          "definition": "A provider capping your request volume. 429 is defined in RFC 6585, where the Retry-After header is optional — so design to back off even when it is absent.",
          "group": "Integration & auth",
          "explained_at": "https://aifitnessapi.com/fix/fitbit-api-429-rate-limit"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-refresh-token-rotation",
          "term": "Refresh token rotation",
          "definition": "When a provider issues a new refresh token on every refresh. Lose the new one and the user is disconnected permanently — a case worth testing explicitly.",
          "group": "Integration & auth",
          "explained_at": "https://aifitnessapi.com/fix/refresh-token-not-working"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-pose-estimation",
          "term": "Pose estimation",
          "definition": "Finding body keypoints in each camera frame. A normal RGB phone camera is enough for 2D and even monocular 3D — no depth sensor required.",
          "group": "AI motion & camera",
          "explained_at": "https://aifitnessapi.com/learn/what-is-pose-estimation"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-2d-vs-3d-pose",
          "term": "2D vs 3D pose",
          "definition": "2D gives pixel coordinates; monocular 3D adds an estimated depth that is less reliable for occluded and out-of-plane joints. Say which you need.",
          "group": "AI motion & camera",
          "explained_at": "https://aifitnessapi.com/motion/2d-vs-3d-pose-estimation"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-rep-counting",
          "term": "Rep counting",
          "definition": "Turning a keypoint stream into a count — a classification problem, tested with precision and recall against a labelled corpus, not a demo of ten push-ups.",
          "group": "AI motion & camera",
          "explained_at": "https://aifitnessapi.com/motion/how-rep-counting-works"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-form-feedback",
          "term": "Form feedback",
          "definition": "Comparing joint angles and range of motion to a target. A coaching aid, not medical or physical-therapy advice — a distinction worth stating in the product.",
          "group": "AI motion & camera",
          "explained_at": "https://aifitnessapi.com/motion/how-form-feedback-works"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-on-device-vs-cloud-inference",
          "term": "On-device vs cloud inference",
          "definition": "Running the model on the phone (low latency, private, no per-frame cost) versus in the cloud (heavier models, consistent, but latency and streaming-video privacy weight).",
          "group": "AI motion & camera",
          "explained_at": "https://aifitnessapi.com/motion/on-device-vs-cloud-pose-estimation"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-deduplication",
          "term": "Deduplication",
          "definition": "Resolving the same activity written by several apps or devices. Neither platform does it for raw reads the way people assume — it is a resolution layer you design.",
          "group": "Architecture & data quality",
          "explained_at": "https://aifitnessapi.com/architecture/deduplicate-health-data"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-day-boundary-problem",
          "term": "Day boundary problem",
          "definition": "“Today's steps” is a civil-date question, not a UTC range. DST days aren't 24 hours, so a fixed window silently drops or double-counts an hour twice a year.",
          "group": "Architecture & data quality",
          "explained_at": "https://aifitnessapi.com/day-boundaries"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-late-arriving-data",
          "term": "Late-arriving data",
          "definition": "Health samples are not append-only — a watch syncs hours late, a user edits yesterday, a provider revises last night's sleep. Any total computed once and considered final will be wrong.",
          "group": "Architecture & data quality",
          "explained_at": "https://aifitnessapi.com/architecture/incremental-sync"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-idempotent-ingestion",
          "term": "Idempotent ingestion",
          "definition": "Making a duplicated event a no-op. In health data a doubly-processed event silently doubles a user's calories rather than throwing, so the dedupe key is load-bearing.",
          "group": "Architecture & data quality",
          "explained_at": "https://aifitnessapi.com/architecture/webhook-ingestion"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-backfill",
          "term": "Backfill",
          "definition": "Importing a user's history as a budgeted, resumable job — recent-first so the app is useful immediately, and chunked so a crash resumes rather than restarts.",
          "group": "Architecture & data quality",
          "explained_at": "https://aifitnessapi.com/architecture/historical-backfill"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-metric-versioning",
          "term": "Metric versioning",
          "definition": "Recording which formula produced a derived value, so improving a calorie or readiness formula doesn't silently rewrite a user's history.",
          "group": "Architecture & data quality",
          "explained_at": "https://aifitnessapi.com/architecture/metric-versioning-and-recompute"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-phi",
          "term": "PHI (protected health information)",
          "definition": "The HIPAA category. Whether your fitness data is PHI depends on who you are and who you share it with — a consumer app is often outside HIPAA entirely, but not always.",
          "group": "Compliance & AI",
          "explained_at": "https://aifitnessapi.com/compliance/is-fitness-data-phi"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-general-wellness-policy",
          "term": "General wellness policy",
          "definition": "The FDA position that it does not intend to examine low-risk wellness products. There is no approval to claim — and diagnosis or treatment claims can push you out of it.",
          "group": "Compliance & AI",
          "explained_at": "https://aifitnessapi.com/compliance/fda-fitness-app-regulation"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-rag-grounding",
          "term": "RAG / grounding",
          "definition": "Constraining an LLM to a vetted catalogue instead of free-generating. For a few-thousand-row exercise table, plain retrieval usually beats vector search.",
          "group": "Compliance & AI",
          "explained_at": "https://aifitnessapi.com/ai/ground-llm-in-exercise-database"
        },
        {
          "id": "https://aifitnessapi.com/glossary#term-guardrails",
          "term": "Guardrails (health advice)",
          "definition": "The deterministic gate in front of an LLM giving exercise or nutrition guidance. A model asked to police itself in the same call gets talked out of it.",
          "group": "Compliance & AI",
          "explained_at": "https://aifitnessapi.com/ai/llm-safety-fitness-advice"
        }
      ]
    }
  }
}