A private, self-hosted Google Apps Script connector that lets your TRMNL screen show your daily Google Fit metrics.
It displays:
- Steps
- Heart Points
- Move Minutes
- Calories
- Daily goals
- Progress percentages
- Step pace tracking, for example: "by 9 AM target 1,000 steps, by 10 AM target 2,000 steps, by 7 PM target 10,000 steps"
This project is designed for private personal use. Each user deploys their own Google Apps Script so their data stays under their own Google account.
The Apps Script Web App must be reachable by TRMNL, so the deployment is set to:
- Execute as:
Me - Who has access:
Anyone
To prevent random access, the script requires a private token query parameter.
Without the correct token, the endpoint returns:
{"error":"Unauthorized"}Treat the token like a password. Do not publish screenshots or logs containing your full TRMNL polling URL.
Google Fit REST APIs are deprecated and may not be available for every Google account or project. This project is a personal/private workaround and is not recommended as the foundation for a public marketplace product.
trmnl-google-fit-connector/
├── README.md
├── LICENSE
├── .gitignore
├── src/
│ ├── Code.gs
│ ├── appsscript.json
│ └── trmnl-markup.liquid
- A Google account that has Google Fit data
- Google Apps Script access
- Google Cloud Console access
- A TRMNL account/device
- 10–20 minutes
Go to:
https://script.new
This creates a new Google Apps Script project.
Rename it something like:
TRMNL Google Fit Connector
Open src/Code.gs from this repository.
Copy the entire file.
Paste it into your Apps Script Code.gs, replacing anything already there.
Save.
In Apps Script:
- Click the gear icon on the left: Project Settings
- Turn on: Show "appsscript.json" manifest file in editor
- Go back to the code editor
- Click
appsscript.json
Open src/appsscript.json from this repository.
Copy the whole file.
Paste it into your Apps Script appsscript.json.
Save.
The manifest should include:
{
"timeZone": "America/New_York",
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": [
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/script.storage",
"https://www.googleapis.com/auth/fitness.activity.read",
"https://www.googleapis.com/auth/fitness.body.read"
],
"webapp": {
"executeAs": "USER_DEPLOYING",
"access": "ANYONE_ANONYMOUS"
}
}Change timeZone if needed.
Examples:
America/New_York
America/Chicago
America/Denver
America/Los_Angeles
Europe/London
Asia/Kolkata
The Google Fit API usually will not work from the default Apps Script project. Use a standard Google Cloud project.
Open:
https://console.cloud.google.com/
Then:
- Click the project dropdown near the top
- Click New Project
- Name it:
TRMNL Google Fit Connector
- Click Create
In Google Cloud Console:
- Open the project dropdown
- Select your new project
- Go to IAM & Admin → Settings
- Copy the Project number
It will look like a long number.
Back in Apps Script:
- Click Project Settings
- Find Google Cloud Platform (GCP) Project
- Click Change project
- Paste the Cloud Project number
- Click Set project
In Google Cloud Console, with your project selected:
- Go to APIs & Services → OAuth consent screen
- Choose External for a personal Gmail account
- Fill:
- App name:
TRMNL Google Fit Connector - User support email: your email
- Developer contact email: your email
- App name:
- Continue through the wizard
- Add yourself as a Test user
- Save
If you use a Workspace account, your admin may control these settings.
In Google Cloud Console:
- Go to APIs & Services → Library
- Search for:
Fitness API
- Click Google Fitness API
- Click Enable
Wait 1–3 minutes.
Back in Apps Script:
- Click the function dropdown near the top
- Select:
setupToken
- Click Run
- Approve permissions
- Open the Execution log
- Copy the value after:
TRMNL_TOKEN=
It will look like a long random string.
Save this token somewhere safe.
If the token ever leaks, run resetToken and update your TRMNL polling URL.
In Apps Script:
- Select function:
testFetch
- Click Run
- Check the execution log
You should see something like:
{steps=2500, heartPoints=0, moveMinutes=34, calories=900}
If you get a Fitness API 403 error, the Fitness API is not enabled on the linked Cloud project.
If you get a permission error for UrlFetchApp.fetch, confirm script.external_request is in appsscript.json, save, run testFetch again, and approve permissions.
In Apps Script:
- Click Deploy
- Click New deployment
- Select type: Web app
- Set:
- Description:
Initial deployment - Execute as:
Me - Who has access:
Anyone
- Description:
- Click Deploy
- Copy the Web App URL
It should look like:
https://script.google.com/macros/s/AKfycb.../exec
Open your browser and test without a token:
https://script.google.com/macros/s/YOUR_SCRIPT_ID/exec
Expected result:
{"error":"Unauthorized"}Now test with your token:
https://script.google.com/macros/s/YOUR_SCRIPT_ID/exec?token=YOUR_SECRET_TOKEN&steps_goal=6500&heart_goal=20&move_goal=60&cal_goal=2200
Expected result:
{
"dateISO": "2026-01-01",
"nowHour": 15,
"totals": {
"steps": 2500,
"heartPoints": 0,
"moveMinutes": 34,
"calories": 900
},
"goals": {
"steps": 6500,
"heartPoints": 20,
"moveMinutes": 60,
"calories": 2200
},
"progress": {
"steps_pct": 0.3846153846,
"heart_pct": 0,
"move_pct": 0.5666666667,
"cal_pct": 0.4090909091
}
}In TRMNL:
- Go to Plugins
- Create a Private Plugin
- Choose Polling
- Set:
Polling Verb: GET
- Polling URL must be one line:
https://script.google.com/macros/s/YOUR_SCRIPT_ID/exec?token=YOUR_SECRET_TOKEN&steps_goal=6500&heart_goal=20&move_goal=60&cal_goal=2200
-
Leave these empty:
- Polling Headers
- Polling Body
-
Click Parse
You should see variables like:
dateISO
nowHour
totals
goals
progress
Open src/trmnl-markup.liquid.
Copy the full markup into TRMNL's Markup editor.
Save the plugin.
Add it to your playlist.
| Parameter | Description | Default |
|---|---|---|
token |
Required private token | none |
steps_goal |
Daily step goal | 6500 |
heart_goal |
Daily heart points goal | 20 |
move_goal |
Daily move minutes goal | 60 |
cal_goal |
Daily calorie goal | 2200 |
window |
Optional rolling window: 24h, 48h, 72h |
today midnight -> now |
debug |
Optional debug mode: 1 |
off |
Example debug URL:
https://script.google.com/macros/s/YOUR_SCRIPT_ID/exec?token=YOUR_SECRET_TOKEN&debug=1
You forgot the token or pasted the wrong token.
Fix:
- Run
setupToken - Copy the token from the execution log
- Add it to the URL as:
?token=YOUR_SECRET_TOKEN
If your URL already has ?, use &token=....
Confirm appsscript.json includes:
https://www.googleapis.com/auth/script.external_request
Then run testFetch from Apps Script and approve permissions.
Redeploy a new Web App version.
Make sure your manifest does not include:
https://www.googleapis.com/auth/script.properties
Use this instead:
https://www.googleapis.com/auth/script.storage
Enable the Google Fitness API in the linked Google Cloud project.
Use debug mode:
/exec?token=YOUR_SECRET_TOKEN&debug=1
This script includes fallbacks for Samsung and other device-specific top_level streams.
If the Google Fit app itself shows 0, the API will also show 0.
Check:
- Google Fit activity detection is on
- Health Connect permissions allow Google Fit to read/write activity data
- Your wearable or phone is syncing data to Fit
- Your height/weight/profile are set for calorie estimates
In TRMNL:
- Make sure the Polling URL is one line
- Headers are empty
- Body is empty
- Click Parse
- Confirm variables appear
MIT is included by default. Change it if you prefer another license.