You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Browse filesBrowse the repository at this point in the historyBrowse files
Agent
committed
feat(cli): report anonymous install telemetry
After a successful pgflow install, send one strict allowlisted contribution with the fixed package version, fresh/update/no-op result, and bucketed copied-migration count. CI, tests, DO_NOT_TRACK, and PGFLOW_TELEMETRY_DISABLED suppress the event; request failures never affect installation.
Reuse the existing telemetry worker and retention policy, extend its allowlist and tests, and expand the single telemetry reference page with an upfront no-identifiers guarantee, exact CLI payload, and both CLI and database opt-out controls. Raw migration timestamps, filenames, paths, errors, and project values never leave the machine.
Report anonymous fresh, update, or no-op install completion telemetry with the pgflow version and a bucketed migration count. CI, tests, `DO_NOT_TRACK`, and `PGFLOW_TELEMETRY_DISABLED` disable the event.
Copy file name to clipboardExpand all lines: pkgs/website/src/content/docs/reference/telemetry.mdx
+56-13Lines changed: 56 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,17 +3,48 @@ title: Telemetry
3
3
description: What anonymous usage data pgflow collects, how to inspect it, and how to disable it
4
4
---
5
5
6
-
pgflow includes anonymous, opt-out telemetry. It answers one question for the maintainers: **is pgflow actually used, and which features matter?** Your data stays yours — nothing below can identify you, your project, or your users.
6
+
pgflow includes anonymous, opt-out telemetry. It answers one question for the maintainers: **is pgflow actually used, and which features matter?**
7
+
8
+
**pgflow never sends or stores information that can identify you, your project, or your users.** The only variable exact value from your installation that is stored as telemetry is a pgflow semantic version such as `0.18.0`. Everything else is a fixed label defined in the source code or a coarse bucket. No exact usage count, duration, source timestamp, migration filename, or other exact project value leaves your machine or database.
9
+
10
+
Two narrowly scoped signals are sent:
11
+
12
+
- After `pgflow install` completes successfully outside CI and tests, the CLI sends one installation-result event.
13
+
- Once per active day, a non-local database sends one aggregate usage report. Nothing is sent per run, step, or task, so telemetry never touches the execution path.
7
14
8
15
## What is collected
9
16
10
-
Once per day, your database aggregates yesterday's activity into coarse buckets and sends one small JSON document. Nothing is sent per run, per step, or per task — telemetry never touches the execution path.
17
+
### Installation command
11
18
12
-
The payload contains only:
19
+
A successful `pgflow install` sends only:
20
+
21
+
- The exact pgflow CLI version
22
+
- A fixed result label: `fresh`, `update`, or `noop`
23
+
- The number of copied pgflow migrations as a coarse bucket (`0`, `1`, `2-3`, `4-7`, and so on)
24
+
25
+
`fresh` means that no recognized pgflow migration existed, `update` means that older pgflow migrations existed and new ones were copied, and `noop` means that all bundled pgflow migrations were already present. Raw migration timestamps, filenames, project migration counts, paths, and installation errors are never sent. The event looks like this:
26
+
27
+
```json
28
+
{
29
+
"schema": 1,
30
+
"contributions": [
31
+
{
32
+
"metric": "cli_install_update",
33
+
"bucket": "0.18.0",
34
+
"count": "4-7"
35
+
}
36
+
]
37
+
}
38
+
```
39
+
40
+
### Daily database report
41
+
42
+
Once per day, your database aggregates yesterday's activity into coarse buckets and sends one small JSON document. The payload contains only:
13
43
14
44
- Whether any runs happened that day
15
45
- Which pgflow versions started workers, and whether a version changed
- Registered worker start modes (`http` or `process`)
17
48
- Flow shape in buckets: steps per flow, which features appear (map steps, conditions, retries, delays, graceful failure, step queues)
18
49
- Coarse durations and task counts in fixed ranges
19
50
@@ -39,11 +70,13 @@ A payload never exceeds 64 contributions or 2 KB. On an unusually varied day the
39
70
40
71
## What is never collected
41
72
42
-
No slugs, flow or step names, queue names, function names, run or task IDs, inputs, outputs, error messages, URLs, hostnames, environment names, IP addresses, or any free text. No cookies. No account. Nothing that could identify you, your project, or your users.
73
+
pgflow collects no slugs, flow or step names, queue names, function names, migration names or timestamps, run or task IDs, inputs, outputs, error messages, URLs, file paths, hostnames, environment names, operating-system details, IP addresses, or free text. It creates no account, persistent installation ID, machine ID, project ID, or cookie.
74
+
75
+
The telemetry application cannot connect two reports to the same installation. It cannot count unique users or reconstruct one project's history.
43
76
44
77
## Inspect exactly what is sent
45
78
46
-
Every payload is stored before it leaves, so you can audit the real bytes:
79
+
The installation event shape is shown above and is fixed in the open-source CLI. Every daily database payload is stored before it leaves, so you can audit its exact bytes:
47
80
48
81
```sql
49
82
select jsonb_pretty(payload)
@@ -61,11 +94,21 @@ select pgflow_telemetry.preview('2026-09-10'); -- any past day
61
94
62
95
## Disable or re-enable
63
96
64
-
Telemetry is opt-out and runs as a daily `pg_cron` job. The job's presence is the switch:
97
+
Telemetry is opt-out. The CLI shows a disclosure before installation and does not ask for permission.
The CLI also honors the conventional `DO_NOT_TRACK=1` environment variable. It never sends installation telemetry in CI or tests. Set either variable in your shell profile to disable CLI telemetry permanently on that machine.
106
+
107
+
Daily database telemetry uses a `pg_cron` job. The job's presence is the switch:
`disable()` errors instead of reporting success when it cannot prove the job absent — for example when the job was scheduled by a different database role and `cron.job` row security hides it from yours. In that case run `disable()` as the role that installed pgflow (the migration or `enable()` caller). On a vanilla PostgreSQL install where pgflow's migration owner is neither superuser, `BYPASSRLS`, nor a role that inherits the privileges of the `cron.job` owner, the same row security also hides the job from the privileged check itself; the error then names the one-line fix, reassigning `pgflow_telemetry.job_is_scheduled()` to a capable owner (on Supabase the migration owner `postgres` already qualifies, so this never applies there). Calling `disable()` when no job exists is a safe no-op.
@@ -74,9 +117,9 @@ Local development databases (`supabase start`) never send telemetry, and days wi
74
117
75
118
## Privacy
76
119
77
-
-Data goes to `https://pgflow-telemetry.workers.dev`, a [Cloudflare Worker](https://workers.cloudflare.com/) backed by [Workers Analytics Engine](https://developers.cloudflare.com/analytics/analytics-engine/).
78
-
-On the ingest side, stored data is retained for three months, then expires automatically.
120
+
-Both signals go to `https://pgflow-telemetry.workers.dev`, a [Cloudflare Worker](https://workers.cloudflare.com/) backed by [Workers Analytics Engine](https://developers.cloudflare.com/analytics/analytics-engine/).
121
+
-Stored data expires automatically after three months.
79
122
- The `sent_reports` audit table in your database is separate: its 90-day prune runs only as part of a successful daily report. Disabled databases and databases with inactive days keep their audit rows until you delete them yourself.
80
-
- pgflow sends no identifiers and the ingest application stores no transport metadata (no IPs, no user agents). Cloudflare necessarily processes source IPs as network transport.
81
-
- Counts are undercounts in practice: opt-outs, blocked egress, and failed sends are invisible. The maintainers treat every number as a lower bound and as directional product evidence only.
82
-
-The sender is the open-source SQL in this repository; the receiver is the open-source Worker in `apps/telemetry-worker/`.
123
+
- pgflow sends no identifiers and the telemetry application stores no transport metadata, including IP addresses or user agents. Cloudflare necessarily processes source IPs to carry the network request.
124
+
- Counts are undercounts in practice: opt-outs, CI exclusion, blocked egress, and failed sends are invisible. The maintainers treat every number as a lower bound and as directional product evidence only.
125
+
-Both senders and the receiver are opensource: the CLI is in `pkgs/cli/`, the daily database sender is in `pkgs/core/schemas/`, and the receiver is in `apps/telemetry-worker/`.
0 commit comments