GitHub announced that the GitHub CLI collects pseudoanonymous telemetry, and the HackerNews thread lit up with the usual mix of “this is fine” pragmatists and people who feel genuinely deceived. The reaction is predictable, but the underlying technical question is worth taking seriously: what does “pseudoanonymous” actually mean, and why does that word choice matter?
Anonymous Is Not Pseudoanonymous
These two words are not interchangeable, and the distinction is not pedantic.
Anonymous telemetry means the data is collected without any persistent identifier. Each event is independent. You can count how many people ran gh pr create today, but you cannot tell whether it was the same person who ran it yesterday. The data has no memory.
Pseudoanonymous telemetry means the data is collected with a stable but non-identifying token, typically a randomly generated UUID stored on disk the first time the tool runs. You still cannot tie it back to a name or email address, but you can now track behavioral patterns over time for the same installation. GitHub can see that a specific (anonymous) user went from running gh issue list to gh pr create to gh pr merge across a week of sessions. That is a fundamentally different kind of data.
The GitHub CLI stores this identifier at ~/.config/gh/telemetry or similar, and it persists across updates. The practical implication is that usage cohorts become traceable. Churn analysis becomes possible. Feature adoption curves can be drawn per-user rather than just per-event. This is standard product analytics tooling, and it is genuinely useful for making decisions, but it is not anonymous in any meaningful sense of that word.
What Gets Collected
According to the official telemetry page, GitHub CLI collects command names, flags used, exit codes, error messages, platform and shell information, and the version of the CLI. It does not collect argument values, so gh repo clone your-private-repo does not send the repo name. That is a reasonable boundary.
The platform and shell data alone is surprisingly rich. Combined with a persistent identifier, GitHub can model things like: “users who switched from bash to zsh on macOS are more likely to adopt the new interactive prompts.” Again, not evil, but not nothing either.
Errors are particularly interesting to collect because they reveal where the tool breaks for real users in ways that internal testing never surfaces. Knowing that a certain error code spikes after a particular release is actionable signal. This is the part of telemetry that is hardest to argue against, and it is also the part that makes opt-out telemetry defensible in principle.
The Opt-Out Mechanism
You can disable telemetry by setting the environment variable GH_NO_TELEMETRY=1, or through gh config set telemetry disabled. For CI environments, the environment variable approach is more reliable because it does not depend on the config file being present or correctly scoped.
This is the standard pattern across the ecosystem. Next.js has NEXT_TELEMETRY_DISABLED=1. The .NET CLI has DOTNET_CLI_TELEMETRY_OPTOUT=1. VS Code has a settings toggle. Homebrew had a long debate about this before adding HOMEBREW_NO_ANALYTICS. The convention is well-established enough that most CI providers set these variables by default in their base images now, which is a quiet acknowledgment that opt-out telemetry in automated pipelines was always going to be a problem.
For local development, the friction of opting out is real. Most developers do not read changelog entries carefully enough to notice a new telemetry section, and they will not visit cli.github.com/telemetry unless something prompts them to. The only prompt is usually a HackerNews post.
Why Opt-Out Is a Bet, Not an Oversight
Every developer tool team that ships opt-out telemetry knows exactly what they are doing. If the goal were purely data quality, opt-in would be sufficient. A self-selected group of engaged users who actively enable telemetry still produces useful signal about error rates and feature adoption. The reason teams choose opt-out is that participation rates for opt-in telemetry hover around 10-20%, while opt-out rates hover around 5-15%. The difference in sample size is significant enough to affect statistical confidence on smaller features.
That is a legitimate engineering argument. It is also an argument that explicitly trades user trust for data volume, and that trade-off deserves to be named plainly rather than buried in a telemetry documentation page that nobody reads until it hits the front page of HackerNews.
The .NET team was notably transparent about this when they launched .NET Core telemetry in 2017. They published the exact collection schema upfront, explained the opt-out mechanism in the CLI’s first-run output, and documented their reasoning for the data points they chose. That transparency did not prevent criticism, but it made the criticism more productive. GitHub’s approach with the CLI is less communicative. The telemetry page exists, but it was not surfaced prominently when the feature shipped.
Enterprise and Shared Environments
The pseudonymous identifier creates a specific problem in enterprise environments that pure anonymous telemetry does not. In a shared CI/CD environment where multiple engineers’ workflows are executed by the same runner, the persistent identifier conflates multiple users into a single behavioral profile. The data becomes misleading to GitHub and potentially leaks workflow shape information (what sequences of gh commands your pipelines run) in ways that engineers at that organization did not consent to.
Most enterprise GitHub customers operate under agreements that restrict data flows to GitHub’s servers beyond authentication tokens and API calls. Whether telemetry data falls under those agreements is a question that legal teams at larger organizations are presumably looking at right now.
The standard mitigation is to set GH_NO_TELEMETRY=1 at the environment level for all CI systems, which is straightforward to do in most CI platforms. GitHub Actions, for instance, lets you define environment variables in organization-level settings that propagate to all workflows. This is worth doing regardless of how you feel about the telemetry itself, because CI environments are not consenting users.
The Broader Pattern
This is not a GitHub-specific story. The pattern runs through most developer tooling maintained by companies rather than volunteers: npm, cargo via Rust’s survey tooling, Go’s build telemetry proposal from 2023, Homebrew’s analytics, the VS Code telemetry debate. Each one follows roughly the same arc: opt-out ships quietly, someone notices, HackerNews post, documentation gets updated, the ecosystem moves on.
The Go team’s proposal for build telemetry is worth reading as a counter-example of how to do this carefully. They published the exact schema before shipping, gave the community a long comment period, and ultimately shipped with a very conservative set of metrics. The process was slow, but it produced something that most Go users accepted without strong objection.
GitHub’s position is structurally different because the CLI is a distribution channel for GitHub’s own products, not a community-maintained tool. The incentive to understand user behavior is higher, and the accountability structure is different. That does not make opt-out wrong, but it does make the choice more visible when it surfaces.
What to Actually Do
If you manage infrastructure where gh runs in automation, add GH_NO_TELEMETRY=1 to your environment configuration. This is not paranoia; it is good hygiene for any tool that phones home by default in automated pipelines.
For local development, the choice is genuinely low-stakes. GitHub already knows a great deal about how you use their platform through API calls, authentication events, and web sessions. The CLI telemetry adds behavioral data about command-line workflows specifically, which they do not otherwise have visibility into. Whether that feels acceptable is a values question, not a technical one.
The thing worth pushing back on is the framing, not necessarily the practice. “Pseudoanonymous” sounds reassuring but means something precise and materially different from anonymous. Documentation that uses the term without explaining it is not being forthcoming, and developer tools companies are capable of doing better. The Go team proved that. Homebrew proved it eventually. GitHub can too.