Telemetry
What the zitadel CLI reports about how it is used, and how to turn that off.
The zitadel CLI sends anonymous usage analytics: which commands run, how they end, and on what kind of setup. They show us where the CLI lets people down. Telemetry is on by default, and one setting turns it off.
What it sends
Every command sends two events to Vercel Web Analytics on the Zitadel cloud (preview.zitadel.com):
cli_command_started, once the command has read its flags.cli_command_completedwhen it finishes, orcli_command_failedwhen it fails.
Each event keeps at most eight properties:
| Property | What it holds |
|---|---|
surface | The Zitadel component that sent it: always cli. |
cli_version | The version of the CLI. |
server_kind | The kind of server it talked to: cloud, local, self_hosted or unknown, never its URL. |
command | The command, such as variables:set. |
status | How the command ended: ok, skipped or error. |
reason | A failed command's error code, such as E_NETWORK. |
host_agent | What ran it: claude_code, cursor, vscode or unknown. |
non_interactive | Whether it ran without prompts. |
A few commands add one property of their own. When a failed command's event already holds eight, it takes the place of non_interactive.
| Command | Property | What it holds |
|---|---|---|
setup | framework | The framework it set up. |
claim | claim_outcome | How the claim ended, such as completed, link_issued or expired. |
doctor | failed_checks | The names of the checks that failed, never their messages. |
api | operation | The operation it called, such as listReleases, never a path, an id or a field. |
start | runtime | The runtime: binary or docker. |
Vercel records a location (country, region and city) worked out from the IP address an event comes from. Runs in CI send nothing.
Run a command with --debug to see each event on stderr before it is sent.
What Mixpanel would get
The CLI can also send its events to Mixpanel, in its EU region, through the Zitadel cloud (preview.zitadel.com/telemetry/mixpanel passes them on to api-eu.mixpanel.com). That is paused: the CLI sends Mixpanel nothing. When it sends again, cli_command_completed also carries duration_ms, cli_command_failed carries exit_code and duration_ms, and each event carries:
| Property | What it holds |
|---|---|
surface | The Zitadel component that sent it: always cli. |
command | The command, such as variables:set. |
cli_version, node_version | The versions of the CLI and of Node.js. |
os, $os, arch | The platform, such as darwin, Mac OS X and arm64. |
mp_country_code | The country of your timezone, for the timezones the CLI knows; none for others. |
is_tty, non_interactive, dry_run, force | Whether it ran in a terminal, without prompts, as a dry run, and with --force. |
is_ci, ci_provider | Whether it ran in CI, and which: github_actions, gitlab_ci, circleci, buildkite, jenkins or unknown. |
host_agent | What ran it: claude_code, cursor, vscode or unknown. |
invocation_channel | The package manager that started it: npm, pnpm, yarn, bun or unknown. |
server_kind | The kind of server it talked to: cloud, local, self_hosted or unknown, never its URL. |
invocation_id | A random id that ties one run's events together. |
distinct_id | The install id. |
Some commands add what they did, as counts and fixed values:
| Command | Adds |
|---|---|
setup | The framework, renderer, package manager, preset and use case, the sign-in provider (its slug, custom, none or multiple), whether a minimum password length was set (never the value), whether it created the app, skipped the install or was given a port, how many files it wrote, and the last step it reached. |
deploy | How many resources the release pinned, and how many origins it went live on. |
doctor | How many checks ran, failed and warned, and the names of the checks that failed. |
policies test | Whether it tested the policy files or a release, and how many cases ran and failed, never a case, an input or a config. |
start | The runtime: binary or docker. |
claim | How the claim ended, how often it polled, and whether it opened a browser. |
variables | Whether a variable is secret, and how many list found, never a name or a value. |
branding eject | The design it ejected. |
api | The operation it called, and whether it followed pagination. |
Mixpanel is told not to locate you by your IP address (ip: 0); the country comes from your timezone instead.
What it never sends
Nothing that identifies you, your machine or your project: no name, email address, server URL, project or resource id, file path, secret, variable, or error message. Every value is a fixed name, a boolean, a count or a version. Vercel locates an event by the IP address it comes from.
The install id
The first time it sends anything, the CLI creates a random id for the install and keeps it in ~/.config/zitadel/cli/telemetry.json: under $XDG_CONFIG_HOME when that is set, and under %APPDATA% on Windows. The id ties the runs of one install together in Mixpanel, and holds nothing about you or the machine. The events for Vercel leave it out, so while Mixpanel is paused it stays on your machine. Delete the file to start over with a new one. Where the file cannot be written, every run takes a new id.
On that first run, in an interactive terminal, the CLI says on stderr that it collects analytics, and how to opt out. With Mixpanel, it also records the install itself, with the platform, versions, country and host_agent its events carry.
When it sends
Events go out while the command runs. At exit the CLI waits about a second for them at most, so a slow or blocked network does not hold it up. Sending never fails a command and never writes to stdout, so the --json output stays one envelope.
Turn it off
Any of these turns telemetry off:
| Setting | What it turns off |
|---|---|
--no-telemetry | Telemetry for that one command. |
DO_NOT_TRACK=1 | Telemetry for every tool that follows Console Do Not Track; any value but 0 counts. |
ZITADEL_TELEMETRY=0 | Telemetry for the Zitadel CLI; false, off and no work too. |
Set the variable in your shell's profile, or in your CI's environment, to keep it off for good. The CLI also sends nothing under a test runner: with VITEST set, or NODE_ENV=test. Turned off, it builds no event and writes no install id.
To see what it decided, run a command with --debug: it prints [telemetry] consent: and the reason to stderr, such as do-not-track or enabled.
The User-Agent
Every HTTP request the CLI makes, to the Zitadel API among others, names the CLI and its platform in its User-Agent, such as zitadel-cli/0.1.0 node/v24.12.0 darwin/24.6.0 arch/arm64. It also names the CI provider (ci/github_actions) and what ran the CLI (host/claude_code) when it detects them, unless you turned telemetry off with one of the settings above.
Was this helpful?