How RTK Anonymous Telemetry Works and Ensures GDPR Compliance

RTK implements a privacy-first, opt-in telemetry system that sends a single daily ping containing only aggregate, non-identifiable metrics, with explicit consent management and automated data erasure mechanisms built directly into the Rust source code.

The rtk-ai/rtk CLI tool collects usage insights through a privacy-by-design telemetry architecture that strictly adheres to RTK anonymous telemetry GDPR compliance standards. Unlike conventional analytics, this system operates on an explicit opt-in basis, transmitting a minimal payload—hashed device identifiers, version strings, and aggregate counts—no more than once every 23 hours. Understanding how this balances data utility with legal requirements requires examining the specific Rust implementations in src/core/telemetry.rs and the user-facing controls in src/core/telemetry_cmd.rs.

Telemetry Initialization and Rate Limiting

The telemetry lifecycle begins with the maybe_ping() function in [src/core/telemetry.rs](https://github.com/rtk-ai/rtk/blob/master/src/core/telemetry.rs#L18-L66), which executes at the start of every CLI invocation. This function implements a cascade of early-exit guards to ensure zero network activity unless all strict conditions are met.

Compile-Time and Environment Controls

RTK provides two layers of hard disabling that prevent telemetry compilation or execution:

  • Compile-time URL check: The code checks if TELEMETRY_URL.is_none() { return; } using option_env!. If the RTK_TELEMETRY_URL environment variable is not present during build, the telemetry module returns immediately, guaranteeing zero network activity in the resulting binary.
  • Runtime environment override: Users can block telemetry without modifying configuration files by setting RTK_TELEMETRY_DISABLED=1. The function checks std::env::var("RTK_TELEMETRY_DISABLED") and returns early if set.

Before any network request, the system verifies user intent through the configuration struct loaded from config.toml:

  1. Consent flag: cfg.telemetry.consent_given must be Some(true). If None (never asked) or Some(false), the function returns immediately.
  2. Enable flag: Even after consent, cfg.telemetry.enabled must be true, allowing users to disable collection without revoking consent formally.

The 23-Hour Rate Limiter

To minimize data volume (GDPR Article 5 data minimisation), RTK limits pings to one per day using a marker file stored at ~/.local/share/rtk/.telemetry_marker. The code compares the file’s modification time against the constant PING_INTERVAL_SECS = 23 * 60 * 60 (23 hours), ensuring at most one ping per daily cycle.

Device Anonymization and Payload Structure

RTK ensures device-level anonymity by cryptographically hashing identifiers before transmission, making re-identification computationally infeasible.

Per-Device Salt Generation

Upon first telemetry-enabled run, RTK generates a 64-character hexadecimal random salt stored at ~/.local/share/rtk/.device_salt (path determined by salt_file_path() in src/core/telemetry.rs). This salt persists for the device’s lifetime but is never transmitted.

The telemetry payload uses SHA-256(salt) as the device_hash. Because the salt is random and never leaves the local machine, the hash cannot be reverse-engineered to identify the user or hardware.

Aggregate-Only Data Collection

The send_ping() function constructs a JSON payload containing strictly non-personal fields. As documented in [docs/TELEMETRY.md](https://github.com/rtk-ai/rtk/blob/master/docs/TELEMETRY.md#what-is-not-collected), the following data is never collected: command arguments, file paths, repository URLs, environment variables, or hostnames.

The payload includes only aggregate metrics:

{
  "device_hash": "a3f8c9…",
  "version": "0.34.1",
  "os": "macos",
  "arch": "aarch64",
  "install_method": "homebrew",
  "commands_24h": 142,
  "top_commands": ["git","cargo","ls"],
  "tokens_saved_24h": 450000,
  "hook_type": "claude",
  "custom_toml_filters": 3
}

Usage statistics (e.g., commands_24h) are aggregated locally in a SQLite database (tracking.db) by src/core/tracking.rs before being included in the telemetry payload.

Non-Blocking Delivery and Security

To ensure CLI responsiveness, the ping dispatch occurs in a background thread spawned via std::thread::spawn. The HTTP request uses a 2-second timeout (req.timeout(Duration::from_secs(2))) to prevent hanging if the telemetry server is unreachable. All network traffic uses HTTPS, and endpoint authentication tokens are injected at compile time via option_env!, ensuring no secrets ship inside the binary.

User Control Commands and Erasure

RTK exposes granular control through the telemetry subcommand implemented in [src/core/telemetry_cmd.rs](https://github.com/rtk-ai/rtk/blob/master/src/core/telemetry_cmd.rs).

  • rtk telemetry status: Displays consent state (yes/no/never asked), the enabled flag, and a truncated device_hash (first and last 8 characters) for verification.
  • rtk telemetry enable: Launches an interactive prompt calling save_telemetry_consent(true), which records affirmative consent with a timestamp.
  • rtk telemetry disable: Calls save_telemetry_consent(false), immediately halting data collection without deleting historical data.

Right to Erasure Implementation

The rtk telemetry forget command implements GDPR Article 17 (right to erasure) through the send_erasure_request() function:

  1. Local deletion: Removes ~/.local/share/rtk/.device_salt, the telemetry marker file, and the local tracking.db SQLite database.
  2. Server request: Sends a POST /erasure request containing only the device_hash and action type.
  3. Fallback mechanism: If the server request fails, the CLI prints the device hash and instructs the user to email contact@rtk-ai.app with the hash to complete manual deletion.

# Complete data removal workflow

rtk telemetry forget

# Output:

# • Deleting local telemetry salt... done

# • Removing tracking database... done

# • Sending erasure request to server... done

# If server unreachable:

# "To complete erasure, email contact@rtk-ai.app with your device hash: a3f8c9..."

Data Retention and Compliance Policies

RTK’s retention policies align with GDPR Article 5 (storage limitation) and are documented in docs/TELEMETRY.md:

Data Location Retention Period GDPR Basis
Server-side telemetry records 12 months (automated purge) Article 5(1)(e)
Server erasure audit logs (IP addresses) 6 months then anonymised Article 5(1)(c)
Client-side SQLite (tracking.db) 90 days (configurable in config.toml) User control
Local salt files Until rtk telemetry forget executes Article 17

Contributors adding new telemetry fields must follow the aggregate-only checklist in docs/TELEMETRY.md to prevent accidental collection of personal data.

Summary

  • Opt-in by design: Telemetry requires explicit rtk telemetry enable consent; absence of consent blocks all network activity.
  • Rate limited: The maybe_ping() function enforces a maximum of one ping per 23 hours via marker file checks.
  • Cryptographically anonymous: Device identity is protected via SHA-256 hashing of a local 64-hex salt; no raw identifiers leave the machine.
  • Non-identifiable payloads: Only aggregate counts (commands, tokens saved) and system metadata (OS, arch, version) are transmitted.
  • User sovereignty: rtk telemetry forget triggers automated local deletion and server-side erasure requests, fulfilling GDPR Article 17 requirements.
  • Secure transmission: HTTPS with compile-time injected credentials and strict request timeouts prevent data leakage or CLI blocking.

Frequently Asked Questions

What specific data does RTK collect in its telemetry ping?

The ping contains only aggregate, non-personal metrics such as device_hash (SHA-256 of local salt), RTK version, operating system, architecture, install method, total command counts over 24 hours, top-level command names (e.g., "git", "cargo"), tokens saved, and hook configuration types. According to docs/TELEMETRY.md, RTK never collects command arguments, file paths, repository URLs, or environment variables.

How can I verify that telemetry is completely disabled before running RTK?

You can verify zero network activity by checking rtk telemetry status, which reports the consent state, enabled flag, and environment override status. Additionally, if RTK was compiled without the RTK_TELEMETRY_URL environment variable set, the binary contains no telemetry endpoint at all, as the TELEMETRY_URL constant evaluates to None at compile time in src/core/telemetry.rs.

What happens to my data when I run rtk telemetry forget?

This command triggers a complete erasure workflow: it deletes your local device salt (~/.local/share/rtk/.device_salt), removes the telemetry marker file and local SQLite database (tracking.db), and sends a POST /erasure request to the server containing only your device hash. If the server request fails, the CLI displays your device hash and instructs you to email contact@rtk-ai.app to complete the GDPR Article 17 deletion manually.

How long does RTK retain telemetry data on its servers?

Server-side telemetry records are automatically purged after 12 months. IP addresses in erasure audit logs are retained for 6 months before being anonymised. Client-side usage statistics in tracking.db are retained for 90 days by default, configurable via config.toml.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →