Docs

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_completed when it finishes, or cli_command_failed when it fails.

Each event keeps at most eight properties:

PropertyWhat it holds
surfaceThe Zitadel component that sent it: always cli.
cli_versionThe version of the CLI.
server_kindThe kind of server it talked to: cloud, local, self_hosted or unknown, never its URL.
commandThe command, such as variables:set.
statusHow the command ended: ok, skipped or error.
reasonA failed command's error code, such as E_NETWORK.
host_agentWhat ran it: claude_code, cursor, vscode or unknown.
non_interactiveWhether 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.

CommandPropertyWhat it holds
setupframeworkThe framework it set up.
claimclaim_outcomeHow the claim ended, such as completed, link_issued or expired.
doctorfailed_checksThe names of the checks that failed, never their messages.
apioperationThe operation it called, such as listReleases, never a path, an id or a field.
startruntimeThe 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:

PropertyWhat it holds
surfaceThe Zitadel component that sent it: always cli.
commandThe command, such as variables:set.
cli_version, node_versionThe versions of the CLI and of Node.js.
os, $os, archThe platform, such as darwin, Mac OS X and arm64.
mp_country_codeThe country of your timezone, for the timezones the CLI knows; none for others.
is_tty, non_interactive, dry_run, forceWhether it ran in a terminal, without prompts, as a dry run, and with --force.
is_ci, ci_providerWhether it ran in CI, and which: github_actions, gitlab_ci, circleci, buildkite, jenkins or unknown.
host_agentWhat ran it: claude_code, cursor, vscode or unknown.
invocation_channelThe package manager that started it: npm, pnpm, yarn, bun or unknown.
server_kindThe kind of server it talked to: cloud, local, self_hosted or unknown, never its URL.
invocation_idA random id that ties one run's events together.
distinct_idThe install id.

Some commands add what they did, as counts and fixed values:

CommandAdds
setupThe 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.
deployHow many resources the release pinned, and how many origins it went live on.
doctorHow many checks ran, failed and warned, and the names of the checks that failed.
policies testWhether it tested the policy files or a release, and how many cases ran and failed, never a case, an input or a config.
startThe runtime: binary or docker.
claimHow the claim ended, how often it polled, and whether it opened a browser.
variablesWhether a variable is secret, and how many list found, never a name or a value.
branding ejectThe design it ejected.
apiThe 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:

SettingWhat it turns off
--no-telemetryTelemetry for that one command.
DO_NOT_TRACK=1Telemetry for every tool that follows Console Do Not Track; any value but 0 counts.
ZITADEL_TELEMETRY=0Telemetry 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?