An unofficial status page for Garmin Connect, with 180 days of uptime history.
A small daemon (deployed in Kubernetes) polls Garmin's public status page every few minutes and publishes the result to GitHub over an SSH deploy key, using three branches:
master— code + static site source only (branch-protected, CI required).data— the append-only "database" (data/snapshots.jsonl, a change-log).gh-pages— the rendered site (served by GitHub Pages).
Live page: https://tamcore.github.io/garminstatus/
Not affiliated with Garmin. Status is scraped from Garmin's public status page.
flowchart LR
G["Garmin status page<br/>(public)"]
VM[("VictoriaMetrics")]
subgraph daemon["k8s daemon · every 5 min"]
direction TB
F["fetch status"] --> B["rollup.Build"]
end
D[["data branch<br/>snapshots.jsonl"]]
P[["gh-pages branch<br/>site + status.json"]]
Pages["GitHub Pages"]
U(["visitors"])
G -->|scrape| F
B -->|"append (on change / 3h heartbeat)"| D
B -->|"fast-forward commit (on change / heartbeat)"| P
P --> Pages --> U
F -.->|"/metrics /live /ready"| VM
- The
databranch grows only when a service's status changes (plus a periodic heartbeat), so its history stays meaningful and small. - The
gh-pagesbranch gets a normal fast-forward commit whenever the change-log advances, withstatus.json.generatedstamped at publish time. GitHub Pages serves the branch directly and each build completes — a force-pushed rolling commit would be orphaned mid-build and never publish. - Uptime is reconstructed by time-weighted integration between recorded transitions.
go run . status # fetch current status, print JSON (default)
go run . snapshot # append a change-log record if status changed (local file)
go run . build # render site/data/status.json from a local change-log
go run . daemon --repo git@github.com:tamcore/garminstatus.git --key /keys/id_ed25519
# the k8s collect+publish loopdaemon flags: --interval (default 5m), --heartbeat (default 3h), --repo
(SSH remote), --key (deploy-key path), --work (clone dir, default /work), --http
(metrics/health addr, default :8080).
Exposed on /metrics:
garmin_platform_status{service}/garmin_feature_status{service}— 1 up / 0 down.garminstatus_fetch_success— last Garmin fetch (1/0).garminstatus_sync_success{branch,op}/garminstatus_sync_timestamp_seconds{branch,op}/garminstatus_sync_errors_total{branch,op}— git pull/push health per branch.garminstatus_cycle_timestamp_seconds— last completed loop.
data/snapshots.jsonl (data branch) — append-only change-log, one JSON object per line:
{"ts":"2026-07-08T12:00:00Z","kind":"change","platforms":{"Garmin Connect":{"status":"up"}},"features":{}}data/status.json (gh-pages branch) — pre-aggregated artifact the page reads:
{
"generated": "2026-07-08T12:05:00Z",
"dataThrough": "2026-07-08T12:00:00Z",
"services": {
"platforms": [{"name":"Garmin Connect","current":"up","days":[{"date":"2026-04-01","upFrac":0.993,"worst":"down"}]}],
"features": []
},
"incidents": [{"service":"Garmin Connect","start":"...","end":"...","reasons":[]}]
}go test ./...
go run . snapshot && go run . build # writes ./data + ./site/data locally
cd site && python3 -m http.server # open http://localhost:8000See repository metadata.