Why
We can answer "how many people signed up to download?" (the D1 subscribers table behind the download gate) but not "how many kept using it?" — and several counters we do have are leaky or ephemeral. Current state, verified 2026-07-18:
- Download gate works: every pullread.com download click records email + platform in D1 (
source = 'download').
- Update check-ins are the only usage signal:
latest.json download counts per tagged release ≈ installs checking daily (v0.4.10: 19 over ~4 days ≈ 4–5 daily actives).
- Blind spots: direct GitHub downloads (README, releases page) bypass the gate; the rolling
latest DMG counter resets on every push to main; GitHub traffic stats only cover a rolling 14 days; nothing correlates signups to retained installs.
Plan
Phase 1 — capture what already exists (no app changes)
Phase 2 — active-install signal (ships with a client release, e.g. 0.5.1)
Phase 3 — decide on opt-in telemetry (separate decision, not started by default)
Non-goals
- No third-party analytics SDKs in the app.
- No tracking pixels in the Rundown email (it goes through the user's own SMTP; their reading habits are their business).
Success criteria
A monthly glance at one CSV (or /api/stats) answers: downloads this month, split by platform; active installs checking for updates; rough retention of gated signups.
Filed by Claude Code on behalf of @shellen; context in the 0.5.0 release session.
Why
We can answer "how many people signed up to download?" (the D1
subscriberstable behind the download gate) but not "how many kept using it?" — and several counters we do have are leaky or ephemeral. Current state, verified 2026-07-18:source = 'download').latest.jsondownload counts per tagged release ≈ installs checking daily (v0.4.10: 19 over ~4 days ≈ 4–5 daily actives).latestDMG counter resets on every push to main; GitHub traffic stats only cover a rolling 14 days; nothing correlates signups to retained installs.Plan
Phase 1 — capture what already exists (no app changes)
check-models.yml) that appends todata/metrics.csv: per-release asset download counts (latest.json, DMGs,.app.tar.gz), rollinglatestcounts (rescued before the next reset), repo traffic views/clones, and D1 subscriber counts by source/platform (via a small authenticated worker endpoint, see below)./api/statsendpoint:ADMIN_KEY-protected JSON counts (total/active subscribers, by source, by platform, by week) so the snapshot workflow and a curious human can pull numbers without exporting the full CSV of emails.Phase 2 — active-install signal (ships with a client release, e.g. 0.5.1)
latest.jsonfrom pullread.com via the worker (302 or proxy to the GitHub asset), counting one row per check-in day with a salted IP hash for uniques — no PII beyond what a web server sees. Add it as the FIRST entry intauri.conf.jsonupdaterendpoints, keeping the GitHub URL second as fallback so a worker outage never blocks updates./api/statswith check-in counts so retention ≈ check-ins vs. gate signups is one query.Phase 3 — decide on opt-in telemetry (separate decision, not started by default)
Non-goals
Success criteria
A monthly glance at one CSV (or
/api/stats) answers: downloads this month, split by platform; active installs checking for updates; rough retention of gated signups.Filed by Claude Code on behalf of @shellen; context in the 0.5.0 release session.