Google's Fitness REST API (deprecated 2024 but still accessible) uses standard OAuth 2.0 — Bubble calls it server-side via the API Connector with a Private Bearer token. This guide covers creating a Google Cloud project, handling OAuth token exchange in a Bubble Backend Workflow (paid plan required), configuring the non-obvious POST /dataset:aggregate call, and being transparent that Fitbit or Garmin are safer long-term choices for new health app builds.
| Fact | Value |
|---|---|
| Tool | Google Fit |
| Category | Health & Fitness |
| Method | Bubble API Connector |
| Difficulty | Intermediate |
| Time required | 3–5 hours |
| Last updated | July 2026 |
How to Connect Bubble to the Google Fitness REST API (With Honest Deprecation Context)
The Google Fitness REST API is one of the most searched health integrations for Bubble — and one of the most misunderstood. Let's clarify the landscape before you write a single workflow.
Google Fit exists as two separate things. The Android Health Connect framework is on-device, Android-only, and has no REST API. Bubble cannot access it because Bubble is a web application. The Google Fitness REST API is cloud-based, accessible via HTTPS, and uses standard OAuth 2.0. Bubble can access this. The confusion arises because Google announced Health Connect as the replacement for the REST API, and in 2024 formally deprecated the REST API — but it still functions for existing integrations and continues to be accessible during the deprecation period.
For Bubble specifically: if your users have fitness data in Google Fit and you need to access it today, the REST API is your only viable path. This guide shows you exactly how to set it up. If you are starting a new health app from scratch with no existing user base on Google Fit, Fitbit or Garmin (which have stable, long-term-supported APIs) are more sustainable choices.
The OAuth 2.0 setup in Bubble mirrors the Fitbit integration closely — a Backend Workflow receives the authorization code, exchanges it server-side (keeping client_secret Private), stores tokens on the User record, and schedules a refresh before the 1-hour access token expiry. The main technical wrinkle unique to Google Fit is the aggregation endpoint: fetching step counts or heart rate requires a POST request with a JSON body specifying data types, time buckets, and date ranges — not a GET with query parameters. Many developers configure a GET call, receive a 404 or 405 error, and abandon the integration. This guide walks through the correct POST configuration.
Backend Workflows are required for OAuth token exchange and are available only on paid Bubble plans (Starter at $32/month or higher). Flag this as prerequisite #1 before any other setup step.
Integration method
Bubble calls the Google Fitness REST API (https://www.googleapis.com/fitness/v1/users/me) with an OAuth 2.0 Bearer token stored in a Private Authorization header. Token exchange and refresh run in Backend Workflows (paid Bubble plan required).
Prerequisites
- A paid Bubble plan (Starter at $32/month or higher) — Backend Workflows for OAuth token exchange are not available on the free plan
- A Google account with access to Google Cloud Console (console.cloud.google.com)
- A Google Cloud project with the Fitness API enabled (APIs & Services → Library → search Fitness API → Enable)
- OAuth 2.0 credentials created in Google Cloud Console (APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID → Web application)
- The Bubble API Connector plugin installed in your app (Plugins tab → Add plugins → API Connector by Bubble)
- At least one Google account with Google Fit data (steps recorded from an Android device or the Fit app) for testing API responses
Step-by-step guide
Step 1: Create a Google Cloud Project and Enable the Fitness API
All Google API access begins in the Google Cloud Console. Follow these steps carefully — skipping any one of them is the most common cause of failed OAuth setups. Create or select a Google Cloud project Go to console.cloud.google.com. Click the project selector at the top of the page and click New Project. Give it a name related to your Bubble app (e.g., my-bubble-health-app) and click Create. Wait for the project to be created and confirm it is selected as the active project. Enable the Fitness API In the left sidebar, go to APIs & Services → Library. Search for Fitness API. Click on it and click Enable. This is the API that gives your Google Cloud project permission to access users' Google Fit data. Do not skip this step — calls to the Fitness REST API will return 403 errors if the API is not enabled on the project. Configure the OAuth consent screen Go to APIs & Services → OAuth consent screen. Select External (for apps serving any Google user) and click Create. Fill in: - App name: the name of your Bubble app - User support email: your email address - Developer contact information: your email address Click Save and Continue. On the Scopes page, click Add or Remove Scopes and add: - https://www.googleapis.com/auth/fitness.activity.read - https://www.googleapis.com/auth/fitness.heart_rate.read (if you need heart rate) - https://www.googleapis.com/auth/fitness.sleep.read (if you need sleep data) Verify the exact scope names at developers.google.com/fit/datatypes — Google has updated scope naming over time. Click Save and Continue. Create OAuth 2.0 credentials Go to APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID. Select Web application as the application type. Under Authorized redirect URIs, add your Bubble app's OAuth callback URL. This URL follows the pattern: https://your-app-name.bubbleapps.io/api/1.1/wf/google_oauth_callback (you will create this Backend Workflow in Step 2). If your app uses a custom domain, use that domain instead. Click Create. Note the Client ID and Client Secret — you will need both in the next steps.
1{2 "Fitness API scopes": [3 "https://www.googleapis.com/auth/fitness.activity.read",4 "https://www.googleapis.com/auth/fitness.heart_rate.read",5 "https://www.googleapis.com/auth/fitness.sleep.read"6 ],7 "OAuth redirect URI pattern": "https://<your-app>.bubbleapps.io/api/1.1/wf/google_oauth_callback"8}Pro tip: Under the OAuth consent screen, your app will initially be in Testing mode, which limits access to 100 test users. Add your Google account as a test user under APIs & Services → OAuth consent screen → Test users before testing the OAuth flow. You must publish the app to production before real users can authorize it.
Expected result: Your Google Cloud project has the Fitness API enabled, an OAuth consent screen configured with the correct fitness scopes, and a Web Application OAuth 2.0 client ID with your Bubble app's callback URL added as an authorized redirect URI.
Step 2: Build the OAuth Token Exchange Backend Workflow
The OAuth 2.0 authorization code flow requires a server-side step: when Google redirects the user back to your app with an authorization code, you must exchange that code for access and refresh tokens server-side using your client_secret. In Bubble, this server-side step runs in a Backend Workflow. Enable the Workflow API In Bubble's editor, go to Settings → API. Check the box labeled This app exposes a Workflow API. This enables Backend Workflows and makes your app's Backend Workflow URLs publicly accessible. This feature requires a paid Bubble plan (Starter $32/month or higher). Create the OAuth callback Backend Workflow Click on the Backend Workflows section in the left panel. Click New API Workflow. Name it google_oauth_callback. Add one URL parameter: code (type Text). This is the authorization code Google sends back after the user approves access. Inside the workflow, add these steps: Step 1 — Exchange the authorization code: add a Plugins → API Connector action. Call the token exchange endpoint (you will add this call to the API Connector in the next step). Pass code = code (URL parameter). Step 2 — Store the tokens on the User: add a Make changes to a thing action. Thing to change: Do a search for Users where (condition to identify the correct user — see tip below). Set two fields: - google_access_token (Text) = result of Step 1's access_token field - google_refresh_token (Text) = result of Step 1's refresh_token field - google_token_issued_at (Date) = Current date/time Add token fields to the User Data Type Go to Data → User → click Edit fields. Add: - google_access_token (Text) - google_refresh_token (Text) - google_token_issued_at (Date) Add a Privacy rule to the User Data Type: ensure google_access_token and google_refresh_token are only visible to Current User = This User. Token data must never be readable by other users. Configure the token exchange API call In the API Connector, under the Google Fit group (created in Step 3), add a call named Exchange Token: - Method: POST - URL: https://oauth2.googleapis.com/token - Body type: Form data (application/x-www-form-urlencoded) - Body fields: - code: (dynamic — the code from the URL parameter) - client_id: your Google Cloud Client ID (can be Public) - client_secret: your Google Cloud Client Secret — mark Private - redirect_uri: your callback URL - grant_type: authorization_code (static) Initialize this call with a test auth code. The initialization will fail because codes expire quickly — that is acceptable. Bubble only needs to detect the response shape (access_token, refresh_token, expires_in). Use a dummy response from the Google token endpoint documentation to manually type the field structure if needed.
1{2 "Token exchange POST": {3 "url": "https://oauth2.googleapis.com/token",4 "method": "POST",5 "content_type": "application/x-www-form-urlencoded",6 "body": {7 "code": "<authorization_code>",8 "client_id": "<your_client_id>",9 "client_secret": "<your_client_secret_PRIVATE>",10 "redirect_uri": "https://<your-app>.bubbleapps.io/api/1.1/wf/google_oauth_callback",11 "grant_type": "authorization_code"12 }13 }14}Pro tip: To identify the correct user in the token storage step, you need to pass the Bubble user's unique ID through the OAuth flow. Add a state parameter to the authorization URL in Step 3 containing the Bubble user's unique ID, then read it back in the callback workflow to match the token to the right user.
Expected result: The Backend Workflow google_oauth_callback is created and configured to receive an authorization code, exchange it for tokens via the Google token endpoint, and store the tokens on the corresponding User record.
Step 3: Configure the Bubble API Connector for Google Fit
With the token exchange workflow in place, configure the API Connector to make the actual Google Fit data calls. Create the Google Fit API group In the Plugins tab, click API Connector → Add another API. Set: - API Name: Google Fit - Authentication: None or self-handled - Shared headers: - Authorization: Bearer <access_token> — check the Private checkbox The access_token value in the shared header will be dynamically replaced when you make calls in workflows — you will pass Current User's google_access_token as the Bearer value. The Private checkbox ensures this token value is never exposed in client-side JS, even though it varies per user. Add the Initialize data sources call Click Add another call. Configure: - Call name: Get Data Sources - Method: GET - URL: https://www.googleapis.com/fitness/v1/users/me/dataSources - Use as: Data Click Initialize call with a real Google access token for a test user who has Google Fit data. Bubble will detect the response structure (a dataSources array). This is your initialization call — use it every time you need to verify credentials are working. Add the Connect Google Fit button on your app's settings page Create a button element labeled Connect Google Fit. In its workflow, add a Navigate to an external website action with this URL: https://accounts.google.com/o/oauth2/v2/auth?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_CALLBACK_URL&response_type=code&scope=https://www.googleapis.com/auth/fitness.activity.read&access_type=offline&prompt=consent Replace YOUR_CLIENT_ID and YOUR_CALLBACK_URL with your actual values. The access_type=offline parameter is critical — it tells Google to issue a refresh token so the user does not need to re-authorize every hour. The prompt=consent forces Google to always show the consent screen (necessary to receive a new refresh token on subsequent authorizations).
1{2 "Google Fit API group": {3 "API Name": "Google Fit",4 "Shared headers": [5 {6 "key": "Authorization",7 "value": "Bearer <access_token>",8 "private": true9 }10 ]11 },12 "Authorization URL": "https://accounts.google.com/o/oauth2/v2/auth?client_id=<CLIENT_ID>&redirect_uri=<CALLBACK_URL>&response_type=code&scope=https://www.googleapis.com/auth/fitness.activity.read&access_type=offline&prompt=consent"13}Pro tip: If you add the google_token_issued_at field to the User record (as set up in Step 2), you can show a Connected since date on the settings page and check whether the token is likely expired (issued more than 55 minutes ago) before making API calls.
Expected result: The Google Fit API group is created in the API Connector with a Private Authorization header. The Get Data Sources call is initialized. Clicking Connect Google Fit on the settings page redirects the user to Google's consent screen.
Step 4: Configure the Aggregation Call (POST, Not GET)
This step is the most technically distinctive part of the Google Fit integration. Unlike most REST APIs, Google Fit uses a POST request to fetch aggregated fitness data — not a GET. Developers who try to use GET receive 404 or 405 errors and assume the API is broken. It is not; the endpoint simply uses POST with a JSON body. Understand the aggregation endpoint The endpoint is: POST https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate The request body specifies: - aggregateBy: the data type(s) to fetch (e.g., com.google.step_count.delta for steps) - bucketByTime: how to group results (e.g., 86400000 milliseconds = 1 day) - startTimeMillis: start of the date range (Unix milliseconds) - endTimeMillis: end of the date range (Unix milliseconds) Add the aggregation call to the API Connector In the Google Fit API group, click Add another call. Configure: - Call name: Aggregate Steps - Method: POST - URL: https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate - Body type: JSON - Use as: Data Set the body to: { "aggregateBy": [{"dataTypeName": "com.google.step_count.delta"}], "bucketByTime": {"durationMillis": 86400000}, "startTimeMillis": <start_ms>, "endTimeMillis": <end_ms> } For the Initialize call, calculate a real Unix millisecond timestamp for today minus 7 days. For example, a startTimeMillis of 7 days ago and endTimeMillis of now (both as numbers without quotes). The Initialize call must succeed with a real response for Bubble to detect the nested response structure. Understand the response structure The aggregate response is nested: { "bucket": [ { "startTimeMillis": "...", "endTimeMillis": "...", "dataset": [ { "point": [ { "value": [{"intVal": 8432}] } ] } ] } ] } The actual step count is at bucket → dataset → point → value → intVal — four levels deep. Bubble can detect this nested path after initialization, but you may need to use a JavaScript transformer (via the Toolbox plugin → Run JavaScript action) to extract the value cleanly for display in page elements. Note on the deprecation context: the Google Fitness REST API was deprecated in 2024. The exact shutdown date has not been confirmed by Google. Build monitoring into your app: if the API starts returning 410 Gone or similar error codes, surface a clear message to your users and pause further calls. For new apps without an existing Google Fit user base, Fitbit is a more stable long-term choice.
1{2 "Aggregate Steps call": {3 "method": "POST",4 "url": "https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate",5 "headers": {6 "Authorization": "Bearer <access_token_PRIVATE>",7 "Content-Type": "application/json"8 },9 "body": {10 "aggregateBy": [{"dataTypeName": "com.google.step_count.delta"}],11 "bucketByTime": {"durationMillis": 86400000},12 "startTimeMillis": "<start_ms>",13 "endTimeMillis": "<end_ms>"14 }15 }16}Pro tip: To calculate Unix milliseconds in Bubble's dynamic expressions: use Current date/time :formatted as Unix timestamp and multiply by 1000. For 7 days ago: Current date/time :minus 7 days :formatted as Unix timestamp × 1000. Bubble's expression editor supports arithmetic on date values.
Expected result: The Aggregate Steps call is initialized in the API Connector. Bubble has detected the nested response structure. You can now bind this call to page elements in a Repeating Group, passing real start and end timestamps from date picker inputs.
Step 5: Build the Activity Dashboard and Handle Token Refresh
Build the Bubble pages that display Google Fit data and implement the token refresh mechanism to keep the integration running beyond the 1-hour access token expiry. Build the dashboard page Create a page called fitness-dashboard. Add: - A date range picker (two Date Inputs: start date and end date) - A Repeating Group with data source: Get data from an external API → Google Fit — Aggregate Steps. Pass the date range inputs as startTimeMillis and endTimeMillis (converted to Unix milliseconds) - Inside the Repeating Group: text elements showing the date and step count extracted from the nested response - A summary section above the Repeating Group showing total steps (sum all bucket values) and average daily steps For charts, install a chart plugin (e.g., ApexCharts by Zeroqode) and bind the step data to a bar chart element. Add the token refresh Backend Workflow Create a second Backend Workflow called refresh_google_token. Inside it: - Add an API Connector action calling a new Refresh Token call (POST https://oauth2.googleapis.com/token with grant_type=refresh_token, client_id, client_secret (Private), and refresh_token from the User record) - Update the User's google_access_token field with the new access_token from the response - Update the google_token_issued_at field to Current date/time Schedule the refresh On the fitness-dashboard page's page load workflow, add a conditional step: If Current User's google_token_issued_at is less than 55 minutes ago — do nothing. Otherwise — Schedule API Workflow: refresh_google_token for Current User. This ensures tokens are refreshed before they expire, not after a failed API call. RapidDev's team has configured OAuth 2.0 flows and token refresh systems in dozens of Bubble apps with third-party APIs. If you need help setting up the complete token lifecycle for Google Fit or other OAuth providers, book a free scoping call at rapidevelopers.com/contact.
1{2 "Refresh Token call": {3 "method": "POST",4 "url": "https://oauth2.googleapis.com/token",5 "content_type": "application/x-www-form-urlencoded",6 "body": {7 "client_id": "<your_client_id>",8 "client_secret": "<your_client_secret_PRIVATE>",9 "refresh_token": "<user_refresh_token>",10 "grant_type": "refresh_token"11 }12 }13}Pro tip: Google access tokens expire in 1 hour — shorter than Fitbit's 8-hour expiry. Trigger the refresh proactively (55 minutes after token issue) rather than reactively (after a 401 error). Reactive refresh creates a bad user experience: the dashboard shows an error, then auto-refreshes, then re-loads data — three confusing state changes for the user.
Expected result: The fitness dashboard displays Google Fit step data for the selected date range in a Repeating Group and chart. The token refresh Backend Workflow runs automatically before the access token expires, keeping the dashboard continuously populated without requiring the user to re-authorize.
Step 6: Add Privacy Rules and Test the Full OAuth Flow
Before testing with real users, lock down data access and verify the complete authorization and data flow end to end. Verify Privacy rules Go to Data → Privacy → User. Confirm that the google_access_token, google_refresh_token, and google_token_issued_at fields are only visible when Current User is This User. These fields contain sensitive credentials and must not be readable by other users through Bubble's data API. Test the full flow In Bubble's editor, click Preview to open the preview mode. Navigate to your settings page and click Connect Google Fit. Verify: 1. The browser redirects to Google's OAuth consent screen 2. After approving access, Google redirects back to your Bubble app's callback URL 3. The Backend Workflow fires, exchanges the code for tokens (check Logs tab → Workflow logs) 4. The User record now has google_access_token and google_refresh_token populated (check Data tab → User) 5. Navigate to the fitness-dashboard page — the Repeating Group populates with step data for the past 7 days 6. Check the Logs tab to verify no 401 or 403 errors, and review WU consumption per API call Test token refresh Change the google_token_issued_at field on the test User to a time 56 minutes in the past (manually in the Data tab). Reload the dashboard page and verify the refresh_google_token Backend Workflow fires and the token is updated in the User record. Test error handling Set the User's google_access_token to an invalid value and reload the dashboard. Verify that your app displays a clear error message rather than a blank Repeating Group. Add a conditional in the page's workflow: if the API call returns an error, navigate to the settings page with a message: Your Google Fit connection has expired — click Reconnect to restore access.
Pro tip: The Google OAuth consent screen will show your app as Unverified during testing. This is expected for apps in Testing mode. Users who are not added as test users in the Google Cloud Console will see a warning and cannot proceed. Add your test accounts to the Test users list under APIs & Services → OAuth consent screen.
Expected result: The complete Google Fit OAuth flow works end to end: user clicks Connect, authorizes via Google, tokens are stored, fitness data appears on the dashboard. Token refresh works proactively. Privacy rules prevent cross-user data access. Error states are handled gracefully.
Common use cases
Daily Activity Dashboard for Wellness Apps
Pull the current user's step count, active minutes, and calories burned from Google Fit and display them on a Bubble dashboard page. Query the aggregation endpoint with daily buckets for the past 7 days and display trend lines using a chart plugin. Suitable for corporate wellness platforms where employees already use Android devices with Google Fit enabled.
Build a Bubble dashboard page that shows the current user's Google Fit data for the past 7 days: daily step count, active minutes, and calories burned. Use the Google Fit POST /dataset:aggregate endpoint, display results in a Repeating Group with one row per day, and add a bar chart using a charting plugin.
Copy this prompt to try it in Bubble
Heart Rate Monitoring Integration
Fetch heart rate data from Google Fit for users who wear Android-compatible heart rate monitors or smartwatches. Use the aggregation endpoint with heart rate data type and daily or hourly buckets. Display average resting heart rate alongside activity data for a biometric health overview.
Add a heart rate section to the Bubble health dashboard. Call POST /dataset:aggregate with dataTypeName com.google.heart_rate.bpm, bucket by day, for the past 30 days. Display average BPM per day in a Repeating Group, with a color indicator (green below 80, yellow 80-100, red above 100).
Copy this prompt to try it in Bubble
Fitness Goal Tracking with Weekly Reports
Compare a user's Google Fit step data against a personal daily step goal stored in the Bubble User record. Calculate whether the goal was met each day and display a weekly streak. Generate a weekly summary (steps walked, goal hit or missed, active vs. sedentary days) that can be emailed via an email service integration.
Build a Bubble weekly fitness report: query the current user's Google Fit steps for the past 7 days, compare each day against their goal (stored in User's daily_step_goal field), mark each day as Goal Met or Missed in a Repeating Group, and display a weekly success rate percentage.
Copy this prompt to try it in Bubble
Troubleshooting
POST /dataset:aggregate returns 404 or 405 Method Not Allowed
Cause: The API Connector call is configured as GET instead of POST. The Google Fitness aggregation endpoint requires a POST with a JSON body — it does not accept GET with query parameters.
Solution: Open the Aggregate Steps call in the API Connector and confirm the Method is set to POST. Add the JSON body with aggregateBy, bucketByTime, startTimeMillis, and endTimeMillis fields. Re-initialize the call after switching the method.
The Google Fitness REST API returns 403 Forbidden for all calls
Cause: The Fitness API is not enabled on the Google Cloud project, or the OAuth scopes used in the authorization URL do not match the data type being requested.
Solution: In Google Cloud Console, go to APIs & Services → Library → search Fitness API and verify it shows Enabled. Also verify that the authorization URL includes the specific fitness scopes required (e.g., fitness.activity.read for steps). If scopes are missing, the user's access token will not have permission to read that data type.
The Bubble API Connector Initialize call fails with 'There was an issue setting up your call'
Cause: The Initialize call requires a real successful API response with the expected JSON structure. For the aggregation endpoint, this means sending a valid startTimeMillis and endTimeMillis with an authorized access token for a user who has actual Google Fit data.
Solution: Use a real access token from a Google account that has Google Fit step data recorded. Calculate startTimeMillis as 7 days ago in Unix milliseconds. Ensure endTimeMillis is the current time in Unix milliseconds. If the test user has no step data, the response body will contain empty buckets and Bubble may not detect the nested field structure — use a test account with real step data.
Users see a blank dashboard or empty Repeating Group after authorizing
Cause: The access token is not being passed correctly in the Authorization header, or the token expired (Google tokens expire in 1 hour) before the dashboard was loaded.
Solution: Check the Logs tab → Workflow logs to see the exact API call that was made and its response. A 401 response means the token is invalid or expired. Verify that the Repeating Group's data source is passing Current User's google_access_token as the Bearer value in the shared header. If the token was issued more than an hour ago, the refresh workflow should have fired — verify it is configured correctly.
The Google OAuth consent screen shows 'This app isn't verified' and users cannot proceed
Cause: Your app is in Testing mode in the Google Cloud Console and the user is not in the test users list.
Solution: For testing: go to APIs & Services → OAuth consent screen → Test users → Add users, and add the email address of the Google account you are testing with. For production: submit your app for Google's OAuth verification process, which requires providing app justification and may take several days to weeks.
Best practices
- Be transparent with your users about the Google Fitness REST API deprecation. If your app relies on this API, include a note in your user documentation and plan a migration path to Fitbit or another stable API for the long term.
- Always use POST for the /dataset:aggregate endpoint, never GET. Document this in your team's notes — it is the single most common configuration mistake and the first thing to check when debugging data retrieval issues.
- Store OAuth tokens (google_access_token, google_refresh_token) with Bubble Privacy rules that restrict visibility to the authenticated user only. Token exposure would allow an attacker to read another user's fitness data.
- Refresh access tokens proactively (55 minutes after issue) rather than reactively (after a 401 error). Reactive refresh creates a degraded user experience with visible loading errors before data reappears.
- Use the access_type=offline and prompt=consent parameters in your authorization URL to ensure a refresh token is always issued. Without a refresh token, users must re-authorize every hour.
- Add the Fitness API enablement step to your onboarding checklist. It is easy to forget to enable the API in Google Cloud Console, and the resulting 403 error looks identical to a permissions error, creating confusion.
- Monitor WU consumption per Google Fit API call in the Bubble Logs tab during beta testing. Aggregation calls for date ranges longer than 30 days return larger payloads and consume more WU per call.
- Design for the deprecated API's eventual sunset. Add a health check endpoint in your app that tests the Google Fit connection weekly and surfaces an alert if the API stops responding with 200 status codes.
Alternatives
Fitbit is the recommended alternative for new Bubble health apps. It uses the same OAuth 2.0 flow as Google Fit, is self-serve (no partner approval), and is actively maintained with no deprecation announcement. Fitbit's API uses standard GET endpoints for data retrieval (unlike Google Fit's non-intuitive POST aggregate endpoint), making it easier to configure in the API Connector. Access tokens expire in 8 hours rather than 1 hour, reducing refresh frequency.
Garmin Connect targets serious athletes and fitness professionals using Garmin wearables. The Garmin Health API is stable and actively maintained, but requires partner program approval (not self-serve) and uses OAuth 1.0a HMAC-SHA1 signing that cannot be done natively in Bubble's API Connector — a signing proxy (e.g., Cloudflare Worker) is required. Significantly more complex than both Google Fit and Fitbit. Choose Garmin only if your users specifically have Garmin devices.
Withings is a biometrics-focused platform (smart scales, blood pressure, SpO2) rather than activity tracking. It uses OAuth 2.0 (same Backend Workflow pattern as Google Fit) but with an unusual API design where all requests use POST method regardless of whether they retrieve or mutate data. Choose Withings if your users have Withings hardware and you need weight, blood pressure, or sleep biometric data rather than step counts.
Frequently asked questions
Is the Google Fitness REST API going to shut down?
The Google Fitness REST API was formally deprecated in 2024. Google has announced it will eventually be shut down but has not confirmed a specific sunset date as of this writing. The API continues to function for existing integrations during the deprecation period. Monitor the Google Fit developer blog and the API status in your Google Cloud Console for shutdown announcements. For new apps, consider Fitbit or Garmin as more stable long-term alternatives.
Do I need a paid Bubble plan to connect Google Fit?
Yes. The OAuth 2.0 authorization code exchange must happen server-side to keep your client_secret secure. In Bubble, server-side operations that receive incoming HTTP requests (like an OAuth callback) require Backend Workflows, which are only available on paid plans (Starter at $32/month or higher). The free Bubble plan cannot complete the token exchange step, blocking the entire integration.
Why does the aggregation endpoint require POST instead of GET?
Google designed the Fitness REST API's aggregation endpoint to accept complex query parameters (data types, bucket sizes, date ranges) that are too long and structured for URL query parameters. Using a JSON body in a POST request is more flexible for nested structures like the aggregateBy array. This is a deliberate design choice specific to Google Fit — most other fitness APIs use GET with query parameters. Always use POST with the correct JSON body structure; GET calls to this endpoint will return 404 or 405 errors.
How often do Google Fit access tokens expire?
Google OAuth 2.0 access tokens expire after 1 hour (3600 seconds). This is shorter than Fitbit's 8-hour expiry. Implement proactive token refresh in a scheduled Bubble workflow triggered approximately 55 minutes after token issue. Your refresh token is long-lived and used to obtain new access tokens without requiring the user to re-authorize.
Can Bubble access Android Health Connect (the replacement for Google Fit)?
No. Android Health Connect is an on-device framework that runs only on Android devices through native Android apps. It has no REST API accessible from a web application. Bubble is a web platform and cannot call on-device Android frameworks. If you need to access Health Connect data in a Bubble app, you would need a companion native Android app that reads Health Connect data and forwards it to a Bubble Backend Workflow endpoint — a significant additional development effort.
What fitness data types can I access through the Google Fitness REST API?
The Google Fitness REST API supports steps (com.google.step_count.delta), calories (com.google.calories.expended), active minutes (com.google.active_minutes), heart rate (com.google.heart_rate.bpm), sleep stages (com.google.sleep.segment), weight (com.google.weight), and others. Each data type requires the corresponding OAuth scope to be requested during authorization. Verify the current list of supported data type names at developers.google.com/fit/datatypes — some names have changed across API versions.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation