Skip to main content
Skip to main content

Telemetry

CDK Insights ships with optional, aggregate-only telemetry that helps us prioritise rules and grow auto-fix coverage. It is off by default and only sends data when you explicitly opt in and have a license key configured (free-tier keys are enough). This page documents exactly what does and does not leave your machine.

The privacy posture in four lines

  • Off by default. Nothing is sent until you set telemetry.enabled: true in .cdk-insights.json.
  • License key required. Telemetry only fires when both the opt-in flag is on and a license key is configured. Without a license, the CLI has no hashed identifier to send and skips the call entirely โ€” no per-machine UUIDs are ever generated. Free-tier keys count.
  • License ID is hashed. The CLI computes sha256(licenseKey) locally and only sends the first 32 hex chars. The backend cannot reverse the hash.
  • Aggregates only. Counts, severity buckets, and rule-id histograms โ€” never code, resource names, file paths, or fingerprints.
  • Fire-and-forget. Sends are bounded to a 1.5-second timeout and never block, slow, or fail your run. If the network is down the event is dropped silently.

How to opt in (or out)

During cdk-insights init

When you run init in an interactive terminal, the CLI prompts you after the license-key step:

๐Ÿ“Š Anonymous Telemetry
   Sending aggregate counts (severities, rule histograms, fix activity) helps us
   prioritise rules and improve auto-fix coverage. The license ID is sha256-hashed
   before transmission. No resource names, file paths, or code ever leave the machine.

   Enable telemetry? (y/N): 

The default is no โ€” pressing Enter declines. Your answer is written to .cdk-insights.json and you can change it any time.

By editing .cdk-insights.json

Add (or remove) the telemetry block at the top level of the config:

{
  "output": "table",
  "failOnCritical": true,
  "telemetry": {
    "enabled": true
  }
}

Set enabled: false (or remove the block entirely) to turn telemetry off. Commit the file to git so the choice is versioned with your project.

What is collected

Every telemetry event is wrapped in the same envelope. The envelope itself plus the event-specific payload are the only things transmitted.

hashedLicenseId

sha256(licenseKey) truncated to 32 hex characters. The backend can count unique customers but cannot reverse-map back to a key.

tier

free, pro, team, or trial. Lets us segment usage analytics by tier without correlating individual users.

cliVersion

The cdk-insights CLI version (e.g. 1.24.0). Used to deprecate old releases responsibly.

platform

Coarse OS family โ€” darwin, linux, win32. No hostnames or usernames.

emittedAt

ISO 8601 timestamp the CLI generated when sending the event.

event

The aggregate payload โ€” see the three event shapes below. Never contains code, resource names, file paths, or fingerprints.

What is NOT collected

The local-first principle still holds with telemetry on. None of the following ever leaves your machine:

  • โ€ขResource names (bucket names, table names, function names)
  • โ€ขAWS account IDs, region names, or stack ARNs
  • โ€ขFile paths or directory structure
  • โ€ขCode snippets, props values, or any source content
  • โ€ขConstruct paths or fingerprints from .cdk-insights-baseline.json
  • โ€ขIP addresses (beyond what API Gateway logs operationally)
  • โ€ขLicense keys (only the sha256 prefix)
  • โ€ขHostnames, usernames, or git author info

Sensitive-data findings (hardcoded credentials etc.) are already filtered out of the analysis pipeline before any backend call regardless of telemetry โ€” see the static analysis docs for that boundary.

The three event types

baseline_written

When: After cdk-insights scan --writeBaseline finishes successfully.

{
  type: 'baseline_written',
  totalFindings: number,             // count of fingerprints written
  severityCounts: { CRITICAL, HIGH, MEDIUM, LOW },
  ruleHistogram: { 'AwsSolutions-S10': 4, 'CDKI-S3-ENCRYPTION': 2, ... },
  uniqueServices: number             // distinct AWS::<Service>::* counts
}

Why we want it: Lets us understand which rules fire most often across the user base and how big a typical baseline is.

diff_run

When: After cdk-insights scan --diff completes (regardless of exit code).

{
  type: 'diff_run',
  newFindings: number,               // count of issues new since baseline
  existingSuppressed: number,        // count of issues filtered by baseline
  newSeverities: { CRITICAL, HIGH, MEDIUM, LOW },
  baselineGeneratedAt?: string,      // ISO timestamp of the baseline
  failedOnCritical: boolean          // true if exit code was 1
}

Why we want it: Drives the "ratchet working" trend: how often diff runs fail on new criticals vs pass cleanly, and how stale typical baselines get.

fix_run

When: After cdk-insights fix completes (dry-run or --apply).

{
  type: 'fix_run',
  mode: 'dry-run' | 'apply',
  applied: number,
  skipped: number,
  errored: number,
  rulesFixed: { 'AwsSolutions-DDB3': 1, 'CDKI-S3-ENCRYPTION': 2, ... },
  ruleFilter?: string                // value of --rule, if any
}

Why we want it: Tells us which rules are landing fixes successfully vs being skipped/errored โ€” the signal we need to grow auto-fix coverage.

Where things stand today

  • Phase 1: collect-only. Events are persisted to a backend table, but there is no dashboard yet. Phase 2 will surface a Pro-tier trend view once we have enough signal.
  • Anonymous endpoint. The telemetry route accepts unauthenticated POSTs because the fix command does not run the auth/login flow. The hashed license ID is the only customer identifier on the row. We may tighten this to require a JWT in a later phase.
  • 365-day TTL. Raw events are auto-deleted after a year. Aggregates derived from them (Phase 2) will be retained longer, but those aggregates are by their nature impossible to attribute to an individual run.
  • You can audit the code. The CLI is open on GitHub โ€” the entire telemetry path is in src/shared/telemetry/telemetryClient.ts.

Related

Telemetry primarily reflects activity from the diff and auto-fix flows: