Skip to main content

Traceveil CLI

Run a Traceveil privacy audit on your Android phone from your laptop, and get a JSON report back. Everything goes over USB (adb); nothing is uploaded.

laptop                                   phone (debug build of Traceveil)
  traceveil audit  --adb broadcast-->    DebugAuditReceiver -> runs the normal audit
        ^                                          |
        |  adb shell cat                           v
        +-------- report.json  <--- /sdcard/Android/data/com.dpdpxray.app/files/reports/<id>/
  saves .traceveil/reports/<id>.json

The trigger exists only in debug builds. Release builds have no way to start an audit from adb.

Quick start with pip (no repo checkout)

This is what final.bash does, as plain commands. You need Python 3.11+ and adb (Android platform-tools) on PATH, and the Traceveil debug APK already installed on the phone (it is built from the Traceveil Android app repo; it is not part of the pip package).

# 1. Install the CLI in a clean virtual environment
python3 -m venv .venv
source .venv/bin/activate            # Windows: .venv\Scripts\activate
pip install --upgrade traceveil==0.3.0   # or: pipx install traceveil
traceveil --version

# 2. Check the phone (USB debugging on, Traceveil debug APK installed)
traceveil doctor

# 3. (Optional) install the app you want to audit
adb install -r path/to/your-app-debug.apk

# 4. Audit it and save the JSON report
traceveil audit --package com.example.yourapp --out report.json
echo $?                              # 0 pass, 1 findings, 2 inconclusive, 3 device/trigger, 6 timeout

Useful variations: --plans silent (quick, often inconclusive), --auto-drive (Traceveil taps Accept/Reject), --serial <id> with several phones, --adb <path> to choose the adb binary, traceveil init to create a traceveil.toml. Under WSL2 use the Windows adb (see the WSL2 note in section 1).

From a repo checkout instead (section 1 below also builds the APKs): pip install -e . (then traceveil ... or python3 -m traceveil ...). The examples below use python3 -m traceveil; the installed traceveil command is identical.

1. One-time setup (repo checkout: build the APKs)

You need: Python 3.11+, JDK 17, Android platform-tools (adb), a phone with USB debugging on.

# 1. Build and install the debug app (run from the repo root)
bash ./gradlew :app:assembleDebug :leakyshop:assembleLeakyDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk
adb install -r leakyshop/build/outputs/apk/leaky/debug/leakyshop-leaky-debug.apk   # demo app to audit

# 2. Check the phone is ready
python3 -m traceveil doctor

Under WSL2 the Linux adb cannot see USB phones. Use the Windows one for every command: --adb /mnt/c/Users/<you>/AppData/Local/Android/Sdk/platform-tools/adb.exe (or export ADB=...). Install the APK with that adb too, from a Windows path.

On the phone, once:

  1. Open Traceveil and allow the VPN permission (Android only delivers the trigger to an app that has been opened).
  2. Turn on the Traceveil accessibility service (Settings > Accessibility).
  3. Set Private DNS = Off (otherwise lookups are hidden from the audit).

2. Run an audit

python3 -m traceveil audit --package com.leakyshop.demo

With several phones attached add --serial <serial> (adb devices lists them).

What happens, step by step:

  1. The CLI checks Traceveil is installed and sends the trigger. You see audit started: cli-<time>-<id>.
  2. The phone runs the audit (about 1 to 3 minutes for three plans). By default you tap Accept / Reject on the phone when asked. Add --auto-drive to let Traceveil tap.
  3. The CLI waits (default 15 min, change with --wait <seconds>), then reads report.json from the phone and checks it is valid.
  4. It saves the report to .traceveil/reports/<request_id>.json and prints a summary:
Traceveil audit  LeakyShop (com.leakyshop.demo)  score 21 / AT_RISK  findings 5
  C1   HIGH     Trackers contacted before consent
  ...
  policy: 3 finding(s) at or above high
  report saved: .traceveil/reports/cli-20261010T071219Z-0f9239c5.json

Useful options:

Option What it does
--plans silent,reject,accept Pick plans (default all three; one plan is quick but often gives an inconclusive score)
--json Print the full JSON instead of the summary
--out report.json Also write the JSON to a file you choose
--auto-drive Traceveil taps Accept/Reject itself
--reset Clear the app's data first. Only for your own test apps; needs Shizuku
--resume <request_id> Fetch the result of an earlier run (after a timeout or unplug)

Settings you use often can live in traceveil.toml (python3 -m traceveil init creates it): target.package, audit.fail_on, audit.min_score, output.dir.

3. The report

{
  "schemaVersion": 1,
  "requestId": "cli-20261010T071219Z-0f9239c5",
  "auditId": "audit-1791616339835",
  "target": { "package": "com.leakyshop.demo", "label": "LeakyShop" },
  "device": { "model": "vivo I2501", "androidVersion": "16" },
  "score": 21,
  "band": "AT_RISK",
  "findingCount": 5,
  "findings": [
    { "check": "C1", "severity": "HIGH", "title": "Trackers contacted before consent", "confidence": 1.0 }
  ],
  "sessions": [ { "plan": "REJECT", "netEvents": 12, "consentChoice": "REJECT", "notes": [] } ],
  "observedTrackers": [ { "entity": "AppsFlyer", "category": "ATTRIBUTION", "lookups": 4, "phases": ["AFTER_REJECT", "BEFORE_CONSENT"] } ]
}

score is null (never 0) when the result is inconclusive. The report is a technical assessment, not legal advice. observedTrackers lists every catalogue tracker the app looked up, by consent phase (debug APKs built from this version on; older reports do not have it).

3a. SDK inventory: "SDK found in APK" vs "tracker observed live"

Lists the tracking SDKs bundled in an APK (from the class names in its classes*.dex) and compares them with what an audit actually saw. No phone is needed unless you pass --package.

traceveil sdks --apk app/build/outputs/apk/debug/app-debug.apk                                   # static only
traceveil sdks --apk app-debug.apk --report .traceveil/reports/<request_id>.json                  # compare with an audit
traceveil sdks --apk app-debug.apk --report <request_id> --package com.example.app --fail-on-consent   # + permissions, CI gate
Group Meaning Evidence
in APK + live SDK code is bundled and its hosts were looked up Observed
in APK only SDK code is bundled, no lookup in this audit Not established (may be dormant, consent-gated, or not triggered)
live only Tracker hosts looked up, but no bundled SDK matched Inferred (WebView, custom HTTP code, renamed/obfuscated SDK)

Each row gets next steps: gate the SDK on consent if it was looked up before consent or after Reject; remove it if unused; and, for ad SDKs in an app that requests location (from --package), review the SDK's location defaults. --fail-on-consent exits 1 when a bundled SDK was looked up before consent or after Reject. --json / --out give the JSON inventory. The signature list (src/traceveil/data/sdk_signatures.json) is hand-written from public package names and covers the tracker catalogue's entities. Obfuscated or unlisted SDKs are not recognised; bundled code does not prove it ran; a lookup does not prove what data was sent.

The CLI uses the same deterministic legal lenses as the app (LegalLens, data in core/src/main/resources/law/, copied into the package by tools/sync_law_data.py). Findings and severities never change; each lens marks every check as required by that law, context, or not applicable, with the law's own passages and source links. The lens score is the app's score without the not-applicable findings, so the INDIA lens always equals the app score.

Lens Law
INDIA (in) DPDP Act 2023 + DPDP Rules 2025
EU (eu, gdpr) GDPR + ePrivacy Directive Art 5(3)
UK UK GDPR + PECR reg 6
US_CALIFORNIA (us-ca, ccpa) CCPA/CPRA
US_CHILDREN (coppa) COPPA
BRAZIL (br, lgpd) LGPD
SINGAPORE (sg, pdpa) PDPA
GLOBAL_BASELINE (global) consent-first good practice (not a law)
traceveil audit --package com.example.app                      # summary ends with all 8 lenses
traceveil audit --package com.example.app --lens eu,us-ca --policy eu   # the EU lens decides the exit code
traceveil lens                                                 # re-read the newest saved report, no phone needed
traceveil lens --report <request_id> --lens eu --detail        # relation, the law's note and cited passages per finding
traceveil lens --list

Config: audit.lenses (default "all") and audit.policy (default "INDIA", so exit codes are unchanged). The saved report gains a lenses block. A lens is a reading of the evidence, not a legal verdict.

Colours: severities (CRITICAL, HIGH, MEDIUM, LOW), scores, bands and tracker names are coloured on a terminal. NO_COLOR=1 turns colours off; FORCE_COLOR=1 keeps them in pipes.

4. Exit codes (for scripts and CI)

Code Meaning
0 Finished, policy passed
1 Policy failed (score below min_score, or a finding at/above fail_on)
2 Inconclusive, app-reported failure, or missing/malformed report
3 Device or trigger problem (no phone, app missing, VPN/accessibility off, another audit running)
4 Bad arguments
6 Timed out (the audit keeps running; use --resume)

5. If something goes wrong

  • Phone unplugged mid-audit: the CLI prints a yellow message. Reconnect, unlock the phone, press Enter to retry (or q to quit). The audit keeps running on the phone; --resume <request_id> picks it up later.
  • "no debug trigger answered": install the debug APK and open Traceveil once. A force-stopped app does not receive the trigger.
  • "VPN permission not granted" / "accessibility service is off": do steps 1 and 2 of the phone setup.
  • Timeout: raise --wait, or run again with --resume <id>.
  • Device "unauthorized": unlock the phone and tap Allow on the USB debugging prompt.

Safety: audit only your own test apps (like the LeakyShop demos). The CLI never force-stops anything and never uploads data.

6. Tests

pip install -e . && python3 -m unittest tools.tests.test_traceveil_audit tools.tests.test_traceveil_cli   # CLI, no phone needed
bash ./gradlew :core:test :app:testDebugUnitTest                                       # Android side

More detail (design, limits, device evidence): docs/CLI_AUDIT.md.

Metadata

Release files for traceveil 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for traceveil 0.3.0
File Size Uploaded
traceveil-0.3.0.tar.gz 70.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for traceveil 0.3.0
File Interpreter ABI Platform
traceveil-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 130.4 kB

Release files / traceveil-0.3.0.tar.gz

Download URL traceveil-0.3.0.tar.gz
Size 70.6 kB
Tags Source
SHA-256 checksum
How to use checksums
8448cff9ca832c6aa4e700fffc44496980a778a556672a10c07da801fd3185a3
BLAKE2b-256 checksum
How to use checksums
bb0bef613fc39e8fa8961bc55cf44e9f2f609c3c7a1a5aeba71d9afa2ac264f8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release files / traceveil-0.3.0-py3-none-any.whl

Download URL traceveil-0.3.0-py3-none-any.whl
Size 59.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
14c580fdcabd5ded2d89195134caa7d62f1026233d9a67f5c05e4f8f019571c2
BLAKE2b-256 checksum
How to use checksums
428333c0666ab0a6494583b3fb0f1a6bf1e015e8faab2dd4aa9ad8535179f63b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.7

Release history Release notifications | RSS feed

0.4.1

2 release files

0.4.0

2 release files

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page