See what your tools send home.
whatleaks runs any command through a local, single-run proxy and shows where its traffic went, which fields it carried, whether any of it is about you, and what it still sends after you opt out.
$npx whatleaks run -- <command>Node ≥ 22.12No accountNothing added to your trust store
$ npx whatleaks compare --no-known-opt-outs --off-env DO_NOT_TRACK=1 -- ./node_modules/.bin/next build whatleaks diff · before "default" (3.7 s, 9 requests) → after "opted-out" (3.1 s, 9 requests) command: ./node_modules/.bin/next build opted out with: DO_NOT_TRACK The telemetry endpoint was still contacted after opting out. Telemetry requests: 8 → 8 · all requests: 9 → 9 STILL SENDING AFTER OPT-OUT ● POST telemetry.nextjs.org/api/v1/record analytics · Next.js telemetry 8 → 8 requests still sent: context.anonymousId, context.projectId, context.sessionId, events[].eventName, meta.agentName, meta.ciName, meta.cpuCount, meta.cpuModel, meta.cpuSpeed, meta.isCI …+81 OTHER TRAFFIC (not identified as telemetry; check it yourself) = POST registry.npmjs.org/-/npm/v1/security/advisories/bulk other 1 → 1 STILL SENT ABOUT YOU ○ Repeated identifiers — 8 requests, in context.anonymousId, context.projectId, context.sessionId PERSISTENT IDENTIFIERS same value in both runs: stored by the app or built into it, so it can link runs together ○ ‹id-1› at context.anonymousId → POST telemetry.nextjs.org/api/v1/record ○ ‹id-2› at context.projectId → POST telemetry.nextjs.org/api/v1/record
$ npx whatleaks run --label next-build -- ./node_modules/.bin/next build … whatleaks · ./node_modules/.bin/next build · 3.7 s · exit 0 9 requests to 2 destinations · ≈10.6 KB sent · 8 to known telemetry endpoints activity | █ ▃ █ ▃▃ | over 3.7 s WHAT IT SENT ABOUT YOU ○ Repeated identifiers: 3 ids reused across requests (‹id-1› ×8, ‹id-2› ×8, ‹id-3› ×8) in context.anonymousId, context.projectId, context.sessionId WHERE IT WENT DESTINATION CATEGORY REQUESTS SENT telemetry.nextjs.org analytics · Next.js telemetry 8 ≈10.3 KB registry.npmjs.org other 1 ≈321 B ENDPOINTS POST telemetry.nextjs.org/api/v1/record analytics · Next.js telemetry 8 requests · first +0.5s · every ~223 ms · ≈10.3 KB · status 204×8 fields: context.anonymousId (id, same in every request), context.projectId (id, same in every request), context.sessionId (id, same in every request), events[].eventName, meta.agentName, meta.ciName, meta.cpuCount, meta.cpuModel …+83 sample (+0.5s): { "context": { "anonymousId": "‹id-1›", "projectId": "‹id-2›", "sessionId": "‹id-3›" }, "meta": { "systemPlatform": "darwin", "systemRelease": "25.6.0", "systemArchitecture": "arm64", "cpuCount": 8, "cpuModel": "Apple M1", "cpuSpeed": 2400, "memoryInMb": 8192, … 55 more lines (see --md)
$ npx whatleaks compare --no-known-opt-outs --off-env NEXT_TELEMETRY_DISABLED=1 --strict -- ./node_modules/.bin/next build whatleaks diff · before "default" (7.2 s, 9 requests) → after "opted-out" (4.3 s, 1 request) command: ./node_modules/.bin/next build opted out with: NEXT_TELEMETRY_DISABLED The telemetry endpoint stopped after opting out. Telemetry requests: 8 → 0 · all requests: 9 → 1 STOPPED ✓ POST telemetry.nextjs.org/api/v1/record analytics · Next.js telemetry 8 → 0 requests OTHER TRAFFIC (not identified as telemetry; check it yourself) = POST registry.npmjs.org/-/npm/v1/security/advisories/bulk other 1 → 1 STILL SENT ABOUT YOU ✓ nothing identifying in the second run's visible traffic no longer sent: stable-id
next build (Next.js 16.4.2, Node 22.23) on 2026-10-21, printed from the saved captures. Next.js documents NEXT_TELEMETRY_DISABLED, not DO_NOT_TRACK.Full transcripts →Find out what it says about you.
Every payload is decoded and every field inventoried. whatleaks searches it for this machine's identifiers, raw and hashed, and flags the ids an app keeps between runs.
It looks for you in every request
- Your username, hostname, home path, MAC address, machine id and git email, raw or as md5, sha1 and sha256 hex or base64.
- Ids that repeat across requests, and ids that stay the same between runs: stored by the app, so they can link your runs together.
- Where each field appeared and how often, with a redacted sample you can post.
In this run Next.js sent none of this machine's identifiers. It sent its own persistent ids, the hardware it ran on, and the AI agent that ran the build.
{
"context": {
"anonymousId": "‹id-1›", // same in a second run
"projectId": "‹id-2›", // same in a second run
"sessionId": "‹id-3›"
},
"meta": {
"systemPlatform": "darwin",
"systemRelease": "25.6.0",
"systemArchitecture": "arm64",
"cpuCount": 8,
"cpuModel": "Apple M1",
"cpuSpeed": 2400,
"memoryInMb": 8192,
"isDocker": false,
"isNowDev": false,
"isWsl": false,
"isCI": false,
"ciName": null,
"nextVersion": "16.4.2",
"agentName": "claude-code_2-1-306_agent"
},
"events": [ … NEXT_CLI_SESSION_STARTED and 39 config fields ]
}
anonymousId and projectId were identical in a second run. Ids are shown as whatleaks's aliases.Opted out? Check.
whatleaks compare runs your command twice in fresh processes, first with defaults and then opted out, and shows what is still sent. The restart is built in, so nobody can say you forgot it.
- Defaults8 requests to telemetry.nextjs.org, 22 events8 requests
DO_NOT_TRACK=1Not a switch Next.js documents. It kept sending.8 → 8 · still sendingNEXT_TELEMETRY_DISABLED=1The switch Next.js documents.8 → 0 · stopped
--strict exits 1 when a known telemetry endpoint is still contactedCI-ready32 documented opt-outs, in one flag
By default the second run sets every opt-out variable whatleaks knows, each with a source. Or test one switch with --no-known-opt-outs --off-env KEY=VALUE.
$ npx whatleaks opt-outs # the list, with the tools each one covers
It catches what other tools miss silently.
46 lab scenarios with exact ground truth: each client writes every attempt to a ledger before making it, and each tool's output is scored per attempt.
of 594 attempts silently missed on macOS, 3.0% of 567 on Linux. Every remaining miss is a Go program whatleaks loads no hook into.
Attempts silently missed
Lower is better. Same scenarios, same ground truth.
mitmproxy 12.2.3 with the same environment whatleaks sets; HTTP Toolkit server 1.27.3 with its own interception.
View as table
| Tool | macOS | Linux |
|---|---|---|
| whatleaks | 3.4% (20 of 594) | 3.0% (17 of 567) |
| mitmproxy | 38% (225 of 594) | 40% (225 of 567) |
| HTTP Toolkit | 67% (399 of 594) | 70% (399 of 567) |
Nothing the app did not send was ever credited to it, in any run.
Every planted identifier was found in every run, including 3 hidden in a WebSocket message. No decoy was flagged.
Matched against each tool's own debug output: Next.js on Node 22 and 20, Turborepo, Astro and Wrangler. HTTP Toolkit matched 4, mitmproxy 3.
Built for the traffic proxies miss.
A proxy sees only what is sent through it. whatleaks also follows the app's processes, hooks the runtimes that ignore proxy settings, and names whatever still goes around.
A CA that lives for one run
Each run makes a fresh certificate authority. Its key stays in memory and its certificate is deleted when the run ends. Your system trust store is never touched.
The whole process tree
Child processes are followed, including detached helpers that keep sending after the app exits. --duration and Ctrl-C stop them all.
Hooks for Node, Python and Ruby
Small preloads route clients that ignore proxy variables, like node:http2 and aiohttp, and report each direct socket as it opens.
Names what goes around
Connections that bypass the proxy are listed by address and process: netstat on macOS, /proc on Linux. Pinned clients are named and counted, never broken into.
Every field, inventoried
JSON, NDJSON, form and binary bodies are decoded. 69 known telemetry hosts carry a source link; keyword guesses are marked ? and never count toward a verdict.
Reports you can post
Your identifiers become labels, secrets become ‹redacted›, ids become aliases. The raw HAR stays on your machine, readable only by you.
What it can't see.
Measured, not guessed. The numbers are in the benchmark.
Apps that refuse the CA
Pinned clients, and Go programs on macOS (they read only the keychain), fail that request. whatleaks names the host and counts it. It never tries to get around pinning.
Very short sockets from native code
Go, Rust or C connections that skip the proxy are found by polling. One reset within about 10 ms is often missed (Go in the lab: caught 10 to 30% of the time), and UDP sent with sendto() is never seen.
Windows
No process-watching backend yet, so it is untested there. macOS and Linux are benchmarked.
Apps you don't launch
Only processes started through whatleaks are watched. GUI apps, Electron apps, browsers and system daemons were not tested.
Exact matching only
Salted hashes of your identifiers can't be recognised. Redaction is pattern-based, so read a report before you post it.
It's our benchmark
We built the lab. Every script and result file is public, and the threats to validity are written down next to the numbers.
Find out what your tools say about you.
Or npm install -g whatleaks. Needs Node ≥ 22.12, on macOS or Linux. Each run saves its capture as a HAR file that only you can read.