Skip to content

Add Google Health Plugin#96

Open
Daniel-Hodgson-SquaredUp wants to merge 6 commits into
mainfrom
add-googlehealth-plugin
Open

Add Google Health Plugin#96
Daniel-Hodgson-SquaredUp wants to merge 6 commits into
mainfrom
add-googlehealth-plugin

Conversation

@Daniel-Hodgson-SquaredUp

@Daniel-Hodgson-SquaredUp Daniel-Hodgson-SquaredUp commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

🔌 Plugin overview

  • Plugin name: Google Health
  • Purpose / problem solved: Recently, Fitbit retired its standalone ecosystem and brought health and fitness data under Google Health. At the same time, Google retired the official Fitbit web dashboard, leaving many users without a comprehensive desktop view of their data.
    There has been consistent demand from the community for a modern replacement. This plugin brings personal health and fitness data from Google Health (Fitbit / Pixel devices) into SquaredUp, providing dashboards for the complete suite of activity, health and sleep metrics.
  • Primary audience: Individuals monitoring their own health and fitness
    data. Anyone using a Fitbit / Pixel device who wants a good quality dashboard.
  • Authentication method(s): OAuth 2.0 (authorization code) against a
    user-supplied Google Cloud project with the Google Health API enabled
    (client ID + client secret, then interactive Google sign-in).

🖼️ Plugin screenshots

Plugin configuration

image

Default dashboards

Today

image

Activity

image

Diet & Nutrition

image

Trends over time

image

Sleep

image

User

image

Device

image

⚙️ Configuration

Setup needs a Google Cloud project with the Google Health API enabled and an
OAuth client (client ID + secret), then an interactive Google sign-in — the
docs README walks through this step by step, matching the format of the other
Google plugins.

The config also has a Daily goals section (steps, distance, active
calories, zone minutes, sleep, water, calorie/protein/carb/fat budgets). The
Google Health API does not expose the goals set in the Fitbit app, so they
can't be imported. However, users can enter them manually (as they do in the Google Health app), with sensible defaults
pre-filled.

The default dashboard gauges fill towards these targets, and the goal-based colouring
(green/amber/red) across the dashboards is measured against them (without needing monitoring enabled!).


🧪 Testing

  • Every data stream tested against a live, authenticated datasource with the
    squaredup CLI (squaredup test) across multiple timeframes, verifying
    shaped rows, computed columns (goal %, status, goal bands) and formatting.
  • All seven default dashboards (Today, Activity, Diet & Nutrition, Sleep,
    Trends Over Time, User and Device perspectives) verified in-product against
    real Fitbit data, including drilldown tables and goal-based bar colouring.
  • Custom timeframes (e.g. "Yesterday") verified on the daily streams: any
    timeframe ≤ 25 hours resolves to the calendar day it ends in.
  • squaredup validate passes.

⚠️ Known limitations

  • Daily goals need manual entry — the Google Health API doesn't expose
    goals set in the Fitbit app, so they're configured in the data source
    rather than imported.
  • One account per configuration — the API is strictly single-user
    (users/me), so this is a personal dashboard rather than a fleet view.
  • Day boundaries and chart hour labels use UTC (consistent with how the
    API's civil timestamps are handled); for users far from UTC the "day"
    window is offset from local midnight.
  • No "today" timeframe enum exists in the platform, so the intraday
    streams treat any timeframe ≤ 25 hours as the calendar day it ends in
    (midnight-to-midnight) — this is what powers the Today dashboard.
  • API range caps — daily roll-ups max out at 90 days (14 for
    heart-rate–derived metrics); longer trends are viewed month by month.

📚 Checklist

  • Plugin, datastream and UI naming follow SquaredUp guidelines
  • Logo added
  • One or more dashboards added
  • README added including configuration guidance
  • No secrets or credentials included
  • I agree to the Code of Conduct

Summary by CodeRabbit

  • New Features
    • Added a Google Health integration with OAuth sign-in, connection validation, and onboarding.
    • Introduced user/profile and paired-device support, plus new health data streams for steps, distance, calories, heart rate (intraday and zones), body measurements, nutrition (including macro breakdown), sleep sessions, and workouts.
    • Added default dashboards for Today, Activity, Diet & Nutrition, Sleep, Trends, User, and Device, with gauges/charts/tables and goal tracking.
    • Added configurable daily goal settings.
  • Documentation
    • Added a full Google Health API setup and troubleshooting guide, including credential setup and common issue resolution.

Dan H and others added 5 commits July 17, 2026 15:42
Integrates the Google Health API (v4, successor to the Fitbit Web API)
with Google OAuth 2.0 auth-code flow and automatic token refresh.

- Imports the authenticated user and paired devices as objects
- 13 data streams: daily/intraday activity metrics, nutrition and
  per-item food log, macro breakdown, sleep sessions, workouts,
  heart rate (intraday + daily zones), body measurements, profile
  and devices
- Personal goals (steps, calories, macros, sleep, water) set at
  config level; gauges, monitors, status columns and chart colours
  all derive from them
- 7 single-pane dashboards: Today, Activity, Diet & Nutrition,
  Trends Over Time, Sleep, plus User and Device perspectives
- Sub-24h timeframes snap to the current civil day so "24 hours"
  means today, matching the app's daily view

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Allow all timeframes (including custom day ranges like Yesterday) on
  every range-driven data stream; day-length timeframes resolve to the
  calendar day they end in, handling exclusive-midnight ends correctly
- Clamp intraday streams to midnight-to-midnight of the target day so
  the Today dashboard covers the calendar day, with hour-aligned windows
- Plot actual values instead of % of goal on the Sleep Duration, Daily
  Steps and Active Zone Minutes bar charts, keeping goal-completion
  colours via hidden computed goal-band columns, with bar labels off
- Move the Sleep Stages Breakdown legend to the right
- Show time-only x-axis labels on the by-hour Today tiles via a computed
  HH:mm label column (charts ignore date column formats)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…owns

- Order Calories by Meal top-to-bottom as Anytime, Breakfast, Lunch,
  Dinner by re-ranking the foodLog mealOrder column and sorting the
  tile by it
- Keep Activity tiles tied to the dashboard timeframe (defaulting to
  last7days) rather than pinning per tile
- Unhide Goal, % of Goal and Goal Status columns in dailyMetric and
  sleepSessions so tile drilldowns show goal context, and drop the
  stale formatExpressions that rendered the % columns as raw values

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follows the Before you start / OAuth credentials / Configuring the
plugin / Troubleshooting structure used by the Google Search Console
and Google Sheets plugins, and documents that daily goals cannot be
imported from the API and must be entered manually in the config.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Daniel-Hodgson-SquaredUp
Daniel-Hodgson-SquaredUp requested a review from a team July 18, 2026 13:17
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: bb7784bd-778f-4938-a0b0-7fa5e52baad6

📥 Commits

Reviewing files that changed from the base of the PR and between 71cff6a and 32e7664.

📒 Files selected for processing (10)
  • plugins/GoogleHealth/v1/dataStreams/dailyMetric.json
  • plugins/GoogleHealth/v1/dataStreams/nutritionDaily.json
  • plugins/GoogleHealth/v1/dataStreams/scripts/dailyMetric.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/foodLog.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/heartRateZonesDaily.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/sleepSessions.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/userProfile.js
  • plugins/GoogleHealth/v1/dataStreams/sleepSessions.json
  • plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json
  • plugins/GoogleHealth/v1/defaultContent/trends.dash.json

📝 Walkthrough

Walkthrough

Adds a complete Google Health v1 plugin with OAuth configuration, health and nutrition data streams, response transformations, indexed user/device objects, default dashboards, and setup documentation.

Changes

Google Health plugin

Layer / File(s) Summary
Plugin foundation and authentication
plugins/GoogleHealth/v1/metadata.json, ui.json, configValidation.json, custom_types.json, defaultContent/scopes.json, defaultContent/manifest.json, indexDefinitions/default.json, docs/README.md
Defines OAuth2 configuration, onboarding fields, validation, custom user/device types, dashboard registration, object indexing, scopes, and setup guidance.
Data stream requests and schemas
plugins/GoogleHealth/v1/dataStreams/*.json
Adds Google Health request definitions, paging and timeframe behavior, metric selectors, normalized output schemas, computed goal/status fields, and result sorting.
Health data transformations
plugins/GoogleHealth/v1/dataStreams/scripts/*.js
Converts Google Health responses into normalized profile, activity, nutrition, heart-rate, sleep, workout, body-metric, and paired-device records.
Default dashboard views
plugins/GoogleHealth/v1/defaultContent/*.dash.json
Adds Today, Activity, Diet & Nutrition, Sleep, Trends, User, and Device dashboards using gauges, charts, tables, variables, and data-stream bindings.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant GoogleHealthOAuth
  participant GoogleHealthAPI
  participant DataStreamScripts
  participant Dashboards
  User->>GoogleHealthOAuth: provide client credentials
  GoogleHealthOAuth->>GoogleHealthAPI: authorize API access
  GoogleHealthAPI->>DataStreamScripts: return health datapoints
  DataStreamScripts->>Dashboards: provide normalized metrics
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: adding a Google Health plugin.
Description check ✅ Passed The description is complete and covers overview, screenshots, configuration, testing, limitations, and checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/GoogleHealth/v1/dataStreams/dailyMetric.json`:
- Line 4: Update the description field in the dailyMetric stream to mention only
the supported metrics: steps, distance, floors, active zone minutes, active
calories, and hydration. Keep it concise, neutral, and as a single sentence
without a final full stop.

In `@plugins/GoogleHealth/v1/dataStreams/scripts/dailyMetric.js`:
- Around line 106-124: Update the empty snapshot record construction in the
daily metric flow to use the snapped day containing timeframe.end minus 1
millisecond, rather than timeframe.end itself. Preserve the existing zero value,
goal, percentage, unit, and metric fields while correcting the date used in the
generated record.

In `@plugins/GoogleHealth/v1/dataStreams/scripts/foodLog.js`:
- Line 30: Update the calories mapping in the food-log transformation so
Math.round is only applied when energy.kcal is present and valid; otherwise emit
undefined instead of NaN. Preserve the existing rounding behavior for valid kcal
values and use the existing N conversion.

In `@plugins/GoogleHealth/v1/dataStreams/scripts/heartRateZonesDaily.js`:
- Around line 5-8: Update durMin to return the finite duration value divided by
60 without rounding, preserving fractional minutes for zone and total
calculations; leave invalid or non-string input handling unchanged and defer
formatting to the later presentation logic.

In `@plugins/GoogleHealth/v1/dataStreams/scripts/sleepSessions.js`:
- Around line 49-52: Update the stage duration mappings in the sleep session
transformation so valid zero-minute values for DEEP, REM, LIGHT, and AWAKE are
preserved rather than converted to undefined. Replace truthiness-based fallbacks
in the affected expressions with nullish handling, while retaining undefined for
genuinely absent stage values and preserving the existing awake fallback
behavior.

In `@plugins/GoogleHealth/v1/dataStreams/scripts/userProfile.js`:
- Around line 29-39: Update the userProfile stream configuration to declare its
single-record output by using httpRequestScopedSingle or setting objectLimit to
1. Keep the transformation in the userProfile script unchanged.
- Line 36: Update the walkingStrideCm assignment to use
autoWalkingStrideLengthMm when userConfiguredWalkingStrideLengthMm is missing,
matching the existing fallback behavior used for the running stride while
preserving manual values when present.

In `@plugins/GoogleHealth/v1/dataStreams/sleepSessions.json`:
- Around line 167-171: Update the sleepStatus metadata in the sleep session data
stream so its displayName capitalization matches the surrounding metadata naming
convention, changing “sleep Status” to the correctly capitalized status label
while leaving the computed expression and shape unchanged.

In `@plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json`:
- Line 443: Normalize the affected dashboard tile titles to title case: update
plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json lines 443-443 to
“Macro Split (Calories)” and 485-485 to “Macros (Grams)”; update
plugins/GoogleHealth/v1/defaultContent/trends.dash.json lines 190-190 to
“Calories Consumed (30 Days)” and 231-231 to “Active Calories Burned (30 Days)”.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: fbf4a34a-cd2c-4717-b113-3e856d87819e

📥 Commits

Reviewing files that changed from the base of the PR and between 9dafcf7 and 71cff6a.

⛔ Files ignored due to path filters (1)
  • plugins/GoogleHealth/v1/icon.svg is excluded by !**/*.svg
📒 Files selected for processing (41)
  • plugins/GoogleHealth/v1/configValidation.json
  • plugins/GoogleHealth/v1/custom_types.json
  • plugins/GoogleHealth/v1/dataStreams/bodyMetric.json
  • plugins/GoogleHealth/v1/dataStreams/dailyHealthMetric.json
  • plugins/GoogleHealth/v1/dataStreams/dailyMetric.json
  • plugins/GoogleHealth/v1/dataStreams/foodLog.json
  • plugins/GoogleHealth/v1/dataStreams/heartRateIntraday.json
  • plugins/GoogleHealth/v1/dataStreams/heartRateZonesDaily.json
  • plugins/GoogleHealth/v1/dataStreams/intradayMetric.json
  • plugins/GoogleHealth/v1/dataStreams/macroBreakdown.json
  • plugins/GoogleHealth/v1/dataStreams/nutritionDaily.json
  • plugins/GoogleHealth/v1/dataStreams/pairedDevices.json
  • plugins/GoogleHealth/v1/dataStreams/scripts/bodyMetric.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/dailyHealthMetric.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/dailyMetric.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/foodLog.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/heartRateIntraday.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/heartRateZonesDaily.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/intradayMetric.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/macroBreakdown.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/nutritionDaily.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/pairedDevices.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/sleepSessions.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/userProfile.js
  • plugins/GoogleHealth/v1/dataStreams/scripts/workouts.js
  • plugins/GoogleHealth/v1/dataStreams/sleepSessions.json
  • plugins/GoogleHealth/v1/dataStreams/userProfile.json
  • plugins/GoogleHealth/v1/dataStreams/workouts.json
  • plugins/GoogleHealth/v1/defaultContent/activity.dash.json
  • plugins/GoogleHealth/v1/defaultContent/devicePerspective.dash.json
  • plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json
  • plugins/GoogleHealth/v1/defaultContent/manifest.json
  • plugins/GoogleHealth/v1/defaultContent/scopes.json
  • plugins/GoogleHealth/v1/defaultContent/sleep.dash.json
  • plugins/GoogleHealth/v1/defaultContent/today.dash.json
  • plugins/GoogleHealth/v1/defaultContent/trends.dash.json
  • plugins/GoogleHealth/v1/defaultContent/userPerspective.dash.json
  • plugins/GoogleHealth/v1/docs/README.md
  • plugins/GoogleHealth/v1/indexDefinitions/default.json
  • plugins/GoogleHealth/v1/metadata.json
  • plugins/GoogleHealth/v1/ui.json

Comment thread plugins/GoogleHealth/v1/dataStreams/dailyMetric.json Outdated
Comment thread plugins/GoogleHealth/v1/dataStreams/scripts/dailyMetric.js
Comment thread plugins/GoogleHealth/v1/dataStreams/scripts/foodLog.js Outdated
Comment thread plugins/GoogleHealth/v1/dataStreams/scripts/heartRateZonesDaily.js Outdated
Comment thread plugins/GoogleHealth/v1/dataStreams/scripts/sleepSessions.js Outdated
Comment thread plugins/GoogleHealth/v1/dataStreams/scripts/userProfile.js
Comment thread plugins/GoogleHealth/v1/dataStreams/scripts/userProfile.js Outdated
Comment thread plugins/GoogleHealth/v1/dataStreams/sleepSessions.json
"z": 0,
"config": {
"_type": "tile/data-stream",
"title": "Macro Split (calories)",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Normalize title case across the affected dashboard tiles.

  • plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json#L443-L443: rename to Macro Split (Calories).
  • plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json#L485-L485: rename to Macros (Grams).
  • plugins/GoogleHealth/v1/defaultContent/trends.dash.json#L190-L190: rename to Calories Consumed (30 Days).
  • plugins/GoogleHealth/v1/defaultContent/trends.dash.json#L231-L231: rename to Active Calories Burned (30 Days).

As per coding guidelines, “Out-of-the-box dashboard and tile names must use title case.”

📍 Affects 2 files
  • plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json#L443-L443 (this comment)
  • plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json#L485-L485
  • plugins/GoogleHealth/v1/defaultContent/trends.dash.json#L190-L190
  • plugins/GoogleHealth/v1/defaultContent/trends.dash.json#L231-L231
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json` at line 443,
Normalize the affected dashboard tile titles to title case: update
plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json lines 443-443 to
“Macro Split (Calories)” and 485-485 to “Macros (Grams)”; update
plugins/GoogleHealth/v1/defaultContent/trends.dash.json lines 190-190 to
“Calories Consumed (30 Days)” and 231-231 to “Active Calories Burned (30 Days)”.

Source: Coding guidelines

- Limit the dailyMetric description to the metrics its selector offers
- Attribute the empty single-day snapshot to the snapped day
  (timeframe.end - 1ms) rather than the day containing the raw end
- Guard foodLog calories against NaN when energy.kcal is absent
- Preserve fractional minutes in heart-rate zone durations so per-zone
  and total minutes sum accurately (display still rounds)
- Keep legitimate zero-minute sleep stages while leaving stages blank
  for sessions with no stage data at all
- Fall back to the auto-calculated walking stride when no manual value
  is configured, matching the running stride
- Capitalize status column display names and tile title case

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🧩 Plugin PR Summary

📦 Modified Plugins

  • plugins/GoogleHealth/v1

📋 Results

Step Status
Validation ✅ Passed
Deployment 🚀 Deployed

🔍 Validation Details

google-health
{
  "valid": true,
  "pluginName": "google-health",
  "pluginType": "cloud",
  "summary": {
    "Data Streams": 13,
    "Import Definitions": 1,
    "UI Configuration": true,
    "Has Icon": true,
    "Has Default Content": true,
    "Config Validation": true,
    "Custom Types": true
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants