Thanks to visit codestin.com
Credit goes to github.com

Skip to content

coaxk/subarr-telemetry

Repository files navigation

subarr-telemetry

Cloudflare Worker that receives anonymous install-heartbeat pings from self-hosted subarr instances and serves aggregated stats.

Backs telemetry.subarr.com (the receiver) and subarr.com/stats (the public dashboard).

What gets sent, what gets stored

The privacy posture is enforced at the schema level. The worker has a hard allow-list of columns; anything else in the payload is silently dropped, and a payload containing forbidden fields (paths, titles, IPs, hostnames, API keys, tokens, languages, usernames, emails) is rejected entirely with HTTP 400.

Mirrors the regression test in subarr/tests/test_telemetry.py::test_payload_never_includes_forbidden_fields exactly. If you add a new payload field on the subarr side, add it here too in ALLOWED_FIELDS and the test will catch any drift.

What's stored per ping

Column Example What for
install_id fd19004ba4e14885910c09d06ff8cc71 Random UUID generated by subarr on first run. NOT a user identity.
subarr_version 1.0.0 Adoption + upgrade pace
python_version 3.12.13 Compat matrix
os_arch Linux/x86_64 Build target priority
docker_tier tier3 Which discovery mode users actually pick
subgen_kind subarr-subgen / vanilla / unreachable Compat-mode adoption split
subgen_version 2026.05.3 Patch-rev adoption
integrations_json {"bazarr":true,"sonarr":true,"tautulli":false,...} Per-integration usage %
library_bucket 1k_10k Distribution of library size
scheduler_mode manual_confirm / auto_queue / disabled Workflow split
walks_per_day 4.2 Cadence distribution
error_counts_json {"SubgenUnavailable":3,"BazarrTimeout":1} Top exception classes globally

What's not stored, ever

File paths, episode/movie titles, IPs, hostnames, API keys, OAuth tokens, language identifiers, usernames, email addresses, anything user-fingerprintable. The forbidden-pattern check in validatePayload() rejects 400 if any of these fields appear in the inbound JSON.

Rate limit + flood detection

Per install_id:

  • MIN_INTERVAL_S (default 3600s): pings closer than this are 429'd with {ok:false, reason:"rate_limited"}. Normal daily-cadence client never hits this.
  • FLOOD_THRESHOLD_S (default 60s): pings closer than this are 429'd with {ok:false, flood_detected:true, user_message:"..."}. Subarr's Settings panel surfaces user_message verbatim so the user sees "Your install is pinging too often, this is likely a bug, please file an issue."
  • After 3 consecutive floods, the install_id is flagged=1 in install_state for permanent attention.

This is the in-product alert path you wanted — no Discord/email webhook, just a structured response field the subarr UI knows how to render.

Endpoints

Method + path What it does
POST /v1/ping Receive a heartbeat. Returns {ok:true} or rate-limit / validation error
GET /v1/health Liveness check (no DB read)
GET /v1/stats/installs Active installs in last 7d / 30d + total
GET /v1/stats/subgen-mix % running subarr-subgen vs vanilla vs unreachable (last 30d, latest per install)
GET /v1/stats/integrations Per-integration usage % (last 30d, latest per install)
GET /v1/stats/library-size Distribution across library buckets
GET /v1/stats/walks-per-day Distribution across cadence buckets
GET /v1/stats/scheduler-modes manual_confirm vs auto_queue vs disabled distribution

The stats endpoints are public read-only, CORS-allowed for subarr.com and www.subarr.com. They power the planned subarr.com/stats dashboard.

Local development

npm install
npm run db:init:local      # create local D1 with the baseline schema
npm run dev                # wrangler dev — http://localhost:8787
npm test                   # unit tests

First-time deploy

# One time setup
wrangler login
wrangler d1 create subarr-telemetry
# Copy the returned UUID into wrangler.toml's database_id field
npm run db:init            # apply schema/001_baseline.sql to remote D1
wrangler deploy

# Then in the Cloudflare dashboard:
# Workers & Pages -> subarr-telemetry -> Settings -> Triggers -> Custom Domains
# add telemetry.subarr.com

CI

GitHub Actions runs vitest on every PR. On push to main, it auto-deploys via wrangler deploy. Requires two repo secrets:

  • CLOUDFLARE_API_TOKEN — scoped to Workers + D1 for this account
  • CLOUDFLARE_ACCOUNT_ID — visible in the Cloudflare dashboard URL

License

MIT.

About

Cloudflare Worker receiving anonymous install heartbeats from self-hosted subarr instances. Backs telemetry.subarr.com + subarr.com/stats.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors