APKRadar
APKRadar is a command-line tool that audits Android apps (.apk, .xapk,
.apkm) for GDPR-relevant findings: third-party tracking SDKs, sensitive
permissions and SDK vendors located outside the EU. It gives each app a
score from 0 to 100. It can also check the publisher's email security, SSL
certificate and cookie consent behaviour, and prepare a formal GDPR letter to
the publisher's Data Protection Officer (DPO).
pip install apkradar
apkradar audit app.apk
Contents
- Why it matters for the GDPR
- What APKRadar is and is not
- Installation
- Commands
- Usage
- Reading the results
- Supported formats
- Full stack analysis with MailRadar and CookieRadar
- Known limitations
- Development
- License
Why it matters for the GDPR
A mobile app is often the main way a company collects personal data, and much of that collection is done by code the company did not write: analytics, advertising and crash-reporting SDKs bundled into the app. Many of these send data to their vendors, often outside the EU. APKRadar makes those components visible by reading the app file itself, without running the app and without relying on what the privacy policy says.
Each type of finding relates to a specific GDPR obligation. The same mapping is
used in the DPO letter generated by apkradar send:
| Finding | What APKRadar reports | GDPR provisions |
|---|---|---|
| Tracking SDKs | Known analytics, advertising and crash-reporting SDKs found in the app | Art. 5(1)(a) lawfulness and transparency, art. 13 information to the data subject |
| Sensitive permissions | Permissions that give access to location, contacts, camera, microphone, SMS, call log, biometrics and similar data | Art. 5(1)(c) data minimisation, art. 9 special categories |
| Extra-EU transfers | Code from vendors headquartered outside the EU (for example Google, Meta, ByteDance, Yandex) | Art. 44–49 transfers to third countries |
Technical measures (--full, send) |
Publisher email security score, SSL certificate status, trackers active before or after cookie consent | Art. 32 security of processing |
What APKRadar is and is not
APKRadar performs static analysis: it inspects the contents of the app file. Its results are technical indicators. They are not proof that personal data is actually processed or transferred.
- A detected SDK shows that the code is present in the app. It does not show whether the SDK is active, what data it sends, or whether consent was collected first.
- A sensitive permission shows that the app declares it may ask for that access. It does not show that the user granted it or that the data is used.
- An extra-EU transfer shows that the app contains code published by a non-EU company. It does not show that data leaves the EU, or which safeguards (such as Standard Contractual Clauses) are in place.
The findings are a good basis for questions to a controller, which is how
apkradar send uses them. They do not replace legal assessment or dynamic
testing (observing the app's network traffic).
Installation
APKRadar requires Python 3.11 or later.
pip install apkradar
playwright install chromium
pip install apkradar installs everything needed for audit, batch,
batch-excel, search and send, including
MailRadar and
CookieRadar.
playwright install chromium downloads the headless browser that CookieRadar
uses. It is only needed for the cookie check in audit --full. On a fresh Linux
system Chromium may also need system libraries; install them with:
playwright install --with-deps chromium
Check the installation:
$ apkradar --version
APKRadar 2026.09.29
Commands
| Command | Purpose |
|---|---|
apkradar audit <file> |
Audit one app file |
apkradar audit <file> --full |
Audit the app, then check the publisher and SDK domains with MailRadar, SSL and CookieRadar |
apkradar batch <list.txt> |
Audit every app file listed in a text file |
apkradar batch-excel <file.xlsx> |
Audit the apps listed in an Excel sheet and write the results to Excel |
apkradar search <package> |
Look up an app on Google Play by package name |
apkradar send <file> ... |
Audit an app and send a GDPR letter to the publisher's DPO |
apkradar --version |
Print the installed version |
Run apkradar <command> --help for the full list of options.
Usage
The examples below are real output from APKRadar 2026.09.29, captured on 18 September 2026 with public builds of Bitwarden (GitHub release), Wikipedia and Nextcloud (F-Droid). Results for third-party apps and domains change over time. Colours are not shown.
Audit an app
$ apkradar audit bitwarden.apk
Auditing bitwarden.apk...
📱 APKRadar Report — com.x8bit.bitwarden
Score: 80/100 — GOOD
App: Bitwarden
Version: 2026.9.0 (21909)
SDK: min=29 target=37
Format: APK
SHA256: 954967bb3c9b940c...
✅ No trackers detected
⚠️ Sensitive Permissions (3)
╭─────────────────┬──────────────╮
│ Permission │ GDPR Concern │
├─────────────────┼──────────────┤
│ USE_BIOMETRIC │ biometrics │
│ USE_FINGERPRINT │ fingerprint │
│ CAMERA │ camera │
╰─────────────────┴──────────────╯
🌍 Extra-EU Transfers (1)
╭──────────────────┬────────────────╮
│ Entity │ Package Prefix │
├──────────────────┼────────────────┤
│ Google LLC (USA) │ com.google │
╰──────────────────┴────────────────╯
Score: 100 − 3 permissions × 5 − 1 transfer × 5 = 80. The Google LLC entry comes from Google components that are not on the tracker list: Firebase Cloud Messaging (push notifications), ML Kit and Play Core. For more on this, see Reading the results.
The command exits with code 1 if the file cannot be analysed.
Full stack analysis
$ apkradar audit wikipedia.apk --full
...
✅ No extra-EU transfers detected
🔗 Full stack analysis — 1 domains
Publisher + SDK domains detected
🔗 wikipedia.org
📡 MailRadar: 49/100 — POOR
🔒 SSL: valid until 03/11/2026
🍪 CookieRadar: 0 pre-consent trackers, none persist
Add --verbose (-v) to print each step as it runs. See
Full stack analysis for
what each line means.
Audit several apps
Create a text file with one app file path per line. Empty lines and lines
starting with # are ignored.
# apks.txt
wikipedia.apk
bitwarden.apk
nextcloud.apk
$ apkradar batch apks.txt
Loaded 3 APKs from apks.txt
Auditing wikipedia.apk...
🟡 MODERATE — 70/100 — 0 trackers, 6 sensitive permissions
Auditing bitwarden.apk...
🟢 GOOD — 80/100 — 0 trackers, 3 sensitive permissions
Auditing nextcloud.apk...
🟠 POOR — 55/100 — 0 trackers, 9 sensitive permissions
The list must contain paths to app files on disk, not URLs or package names. If any app fails to scan, the command prints how many failed and exits with code 1.
Audit apps from an Excel sheet
batch-excel reads the first sheet of an .xlsx file. The first row must be a
header. Column names are case-insensitive:
| Column | Accepted names | Required |
|---|---|---|
| App file path | APK Path, APK, Path, File |
Yes, for the app to be audited |
| Package name | Package Name, Package, PackageName, Pkg |
No |
| App name | App Name, App, Name, Title |
No |
Example input (apps.xlsx):
| App Name | Package Name | APK Path |
|---|---|---|
| Wikipedia | org.wikipedia | wikipedia.apk |
| Bitwarden | com.x8bit.bitwarden | bitwarden.apk |
| Coin Master | com.moonactive.coinmaster |
$ apkradar batch-excel apps.xlsx --output report.xlsx
Reading apps.xlsx...
Found 3 apps to audit
Auditing Wikipedia...
🟡 MODERATE — 70/100 — 0 trackers
Auditing Bitwarden...
🟢 GOOD — 80/100 — 0 trackers
Auditing Coin Master...
⏭️ SKIPPED — no APK path
Writing results to report.xlsx...
✅ Report saved to report.xlsx
⏭️ 1/3 skipped — no APK path
Without --output, the report is written next to the input file as
<name>_report.xlsx (here apps_report.xlsx).
APKRadar does not download apps. Rows that have a package name but no file
path are marked SKIPPED, with an empty score.
The output workbook contains these columns: App Name, Package Name, Format, Version, Score, Grade (colour-coded), Trackers, Sensitive Permissions, Extra-EU Transfers, Tracker Names and SHA256 (first 16 characters).
With --augment (-a), the result columns (Score, Grade, Trackers,
Permissions, Extra-EU, Tracker Names) are appended to the input sheet instead.
The file is written to --output if given, otherwise the input file is
overwritten.
Every text value APKRadar writes (app names, package names, versions, tracker names) is stored as text, never as a formula. A crafted app name or input row therefore cannot inject a formula into the report.
Look up an app on Google Play
$ apkradar search org.wikipedia
Looking up org.wikipedia...
📱 Wikipedia
Package: org.wikipedia
Developer: Wikimedia Foundation
Category: Books & Reference
Installs: 50,000,000+
Rating: 4.3/5.0
The best Wikipedia experience on your Mobile device. Ad-free and free of charge, forever.
...
If the package is not on Google Play, APKRadar searches the web (DuckDuckGo) for a possible removal reason:
$ apkradar search com.example.doesnotexist.app
Looking up com.example.doesnotexist.app...
⚠️ App not found on Google Play
Package: com.example.doesnotexist.app
No removal reason found — app may have been removed or never published.
Only package names are supported. If you pass an app name such as
"Wikipedia", APKRadar prints instructions for finding the package name on
Google Play.
Send a GDPR letter to the DPO
send audits the app, checks the publisher domain with MailRadar and SSL, and
writes a formal letter to the publisher's DPO. The letter asks for the legal
basis, purposes and safeguards for each finding, and exercises the data
subject's rights of access (art. 15), information (art. 13), erasure (art. 17)
and objection (art. 21). It also states that a complaint to the supervisory
authority (art. 77) may follow if there is no reply within 30 days.
Always preview first with --dry-run. Nothing is sent, and no SMTP password
is asked for.
$ apkradar send wikipedia.apk \
--to dpo@example.org \
--publisher "Example Publisher" \
--from jane@example.org \
--name "Jane Doe" \
--smtp-host smtp.example.org \
--smtp-user jane \
--noyb \
--dry-run
...
Running MailRadar on wikipedia.org...
📡 MailRadar — wikipedia.org: 49/100 — POOR
Checking SSL on wikipedia.org...
🔒 SSL valid until 03/11/2026
--- DPO Letter Preview ---
Oggetto: Esercizio diritti GDPR — Wikipedia (org.wikipedia) — Audit tecnico indipendente
Spettabile Example Publisher,
All'attenzione del Responsabile della Protezione dei Dati
...
2. PERMESSI SENSIBILI — art. 5(1)(c), 9 GDPR
L'applicazione dichiara i seguenti permessi con rilevanza GDPR:
→ ACCESS_COARSE_LOCATION: approximate location
→ ACCESS_FINE_LOCATION: precise GPS location
...
The letter has six sections:
- Third-party trackers and SDKs (art. 5(1)(a), 13), with the SHA-256 hash of the audited file
- Sensitive permissions (art. 5(1)(c), 9)
- Extra-EU transfers (art. 44–49), with a request to state the art. 46 safeguards
- Technical measures (art. 32): the MailRadar score, described as inadequate below 60, and the SSL certificate if it is expired, self-signed or issued by an unknown authority
- Formal requests (art. 15, 13, 17, 21)
- Escalation (art. 77, and optionally NOYB)
Options:
| Option | Meaning |
|---|---|
--to |
DPO email address (required) |
--publisher |
Publisher name used in the salutation (required) |
--from |
Sender email (required) |
--name |
Sender full name (required) |
--org |
Sender organisation |
--smtp-host, --smtp-user |
SMTP server and username (required) |
--smtp-port |
SMTP port. Default 465 (implicit TLS). Any other port uses STARTTLS. |
--noyb |
Add a reference to NOYB in the escalation section |
--noyb-id |
Add a reference to NOYB with your supporter number (implies --noyb) |
--dry-run |
Print the letter without sending it |
Without --dry-run, the SMTP password is asked for interactively and is never
passed on the command line. APKRadar verifies the SMTP server's certificate
before logging in. No letter is sent if the scan fails.
The letter is currently available in Italian only. --lang is accepted,
but no other template exists yet, so the Italian letter is always used.
Reading the results
Score
Every app starts at 100 points. Points are deducted for each finding:
| Finding | Deduction |
|---|---|
| Tracker SDK | −10 each |
| Sensitive permission | −5 each |
| Extra-EU vendor | −5 each |
The score never goes below 0. It maps to a grade:
| Score | Grade |
|---|---|
| 80–100 | 🟢 GOOD |
| 60–79 | 🟡 MODERATE |
| 40–59 | 🟠 POOR |
| 0–39 | 🔴 CRITICAL |
A file that cannot be analysed scores 0 and is shown with an error. In
batch-excel, rows without an app file are shown as SKIPPED.
The score is a way to compare and sort apps. It is not a legal assessment: one tracker without a valid legal basis can matter more than several permissions that are justified.
Trackers
APKRadar recognises 43 SDKs, including Google Analytics, Firebase Analytics,
Google Ads, Facebook App Events, Facebook Audience Network, AppsFlyer, Adjust,
Amplitude, Branch, Mixpanel, Segment, OneSignal, AppLovin, Unity Ads,
IronSource, TikTok SDK, Yandex Metrica, Crashlytics, Sentry and Huawei
Analytics. The full list is TRACKER_SIGNATURES in
apkradar/scanner.py.
An SDK is detected in two ways:
- Manifest: the app declares a component (activity, service, receiver, provider) that belongs to the SDK's package.
- Code: the SDK's classes are found in the app's compiled code (DEX files). This finds SDKs that declare no manifest component, such as Firebase Analytics, AppsFlyer and Facebook App Events.
Each SDK is listed once, with the package that identified it.
Sensitive permissions
APKRadar flags 23 Android permissions that give access to personal data. Each one is shown with a short description in the "GDPR Concern" column:
| Area | Permissions |
|---|---|
| Location | ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION, ACCESS_BACKGROUND_LOCATION |
| Communications | READ_CONTACTS, WRITE_CONTACTS, READ_CALL_LOG, WRITE_CALL_LOG, READ_SMS, RECEIVE_SMS, PROCESS_OUTGOING_CALLS |
| Device identity | READ_PHONE_STATE, READ_PHONE_NUMBERS, GET_ACCOUNTS |
| Camera and microphone | CAMERA, RECORD_AUDIO |
| Body and biometrics | BODY_SENSORS, ACTIVITY_RECOGNITION, USE_BIOMETRIC, USE_FINGERPRINT |
| Storage and calendar | READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE, READ_CALENDAR, WRITE_CALENDAR |
These are permissions the app declares. Whether a permission is justified
depends on what the app does. A password manager needs CAMERA to scan QR
codes, and USE_BIOMETRIC to unlock with a fingerprint.
Extra-EU transfers
APKRadar lists a vendor when the app contains code from that vendor's namespace. It knows 13 vendors:
| Package prefix | Entity as reported |
|---|---|
com.google |
Google LLC (USA) |
com.facebook |
Meta Platforms Inc. (USA) |
com.amazon |
Amazon Web Services (USA) |
com.microsoft |
Microsoft Corporation (USA) |
com.appsflyer |
AppsFlyer Ltd. (USA/Israel) |
com.adjust |
Adjust GmbH (Germany) → USA |
com.amplitude |
Amplitude Inc. (USA) |
com.mixpanel |
Mixpanel Inc. (USA) |
com.tiktok |
ByteDance Ltd. (China/USA) |
com.yandex |
Yandex LLC (Russia) |
com.huawei |
Huawei Technologies (China) |
com.xiaomi |
Xiaomi Corporation (China) |
com.baidu |
Baidu Inc. (China) |
A vendor is listed if the app declares a component under its prefix, or if a tracker from that vendor was detected. This is broader than the tracker list. Any Google component counts, including push notifications, Play Services and ML Kit, as in the Bitwarden example above. Treat this finding as "code from this vendor is present, so ask how transfers to it are governed". It does not show that data is transferred.
Supported formats
| Format | Source | How it is analysed |
|---|---|---|
.apk |
Standard Android package | Analysed directly |
.xapk |
APKPure bundle | The base APK is extracted to a temporary folder and analysed |
.apkm |
APKMirror bundle | The base APK is extracted to a temporary folder and analysed |
The format is detected from the file extension, or from the file contents if
the extension is missing or different. For bundles, APKRadar takes the base APK
and ignores split APKs (files named split_* or config.*). See
Known limitations.
APKRadar computes the SHA-256 hash of the file as supplied. The console and Excel reports show its first 16 characters, and the DPO letter includes it in full. This lets you show later exactly which file was audited.
Full stack analysis with MailRadar and CookieRadar
apkradar audit <file> --full also looks at the websites behind the app. It
collects these domains:
- the publisher domain, inferred from the package name
(
org.wikipedia→wikipedia.org; generic segments are skipped, socom.game.asteroids_revenge→asteroids-revenge.com) - the known domains of every detected tracker SDK, for example
appsflyer.comfor AppsFlyer, orgoogleadservices.comanddoubleclick.netfor Google Ads
For each domain it runs three checks:
| Line | Tool | What it checks |
|---|---|---|
| 📡 MailRadar | MailRadar | Email security of the domain, as a score from 0 to 100 with a grade. unavailable if the check could not run. |
| 🔒 SSL | Built in | The HTTPS certificate on port 443, using TLS 1.2 or later. Possible results: valid until <date>, EXPIRED, self-signed certificate, unknown certificate authority, hostname mismatch, certificate verification failed, timeout, check failed. |
| 🍪 CookieRadar | CookieRadar | Loads the website in a headless browser and records trackers before consent and after the cookie banner is rejected. |
The CookieRadar line reads:
N pre-consent trackers, none persist: N trackers loaded before any choice was made, and none of them was still present after rejection.VIOLATION — N tracker(s) post-rejection, followed by the tracker domains: these trackers loaded before consent and stayed after the user rejected cookies.error: ...: the browser could not run. Usually this meansplaywright install chromiumhas not been run, or system libraries are missing (see Installation).
send also runs the MailRadar and SSL checks on the publisher domain, and
includes the results in the technical measures section of the letter. It does
not run CookieRadar.
Known limitations
- Code obfuscation (R8/ProGuard). Release builds are usually minified, and R8 can rename or move SDK classes. Code detection looks for the SDK's original package names. An SDK whose classes were renamed, and that declares no manifest component, is not detected. "No trackers detected" therefore means "none of the known SDKs was found". It does not mean the app contains no trackers.
- Split APKs. For
.xapkand.apkmbundles only the base APK is analysed. Code and permissions that exist only in feature splits (split_*) or configuration splits (config.*) are not seen. Plain.apkfiles downloaded from a split install have the same limitation, because only that one file is analysed. - Static analysis only. APKRadar does not run the app or observe its network traffic. It cannot tell whether an SDK is active, what it sends, or whether consent is collected first.
- Declared permissions, not effective ones. Permissions are counted as
declared in the manifest. Restrictions such as
maxSdkVersionare not taken into account. For example, the Wikipedia app declaresGET_ACCOUNTSonly up to Android 5.1 (maxSdkVersion="22") but itself requires Android 6.0 or later, so the permission is never requested. APKRadar still counts it. - Extra-EU detection is namespace-based. Any component under a listed prefix counts, including infrastructure libraries that are not trackers (see Extra-EU transfers). Vendors outside the 13 listed prefixes are not reported.
- Fixed signature lists. Only the 43 trackers, 23 permissions and 13 vendors listed in the code are recognised.
- Publisher domain is a guess. It is inferred from the package name and
can be wrong. For example,
com.x8bit.bitwardengivesx8bit.com, notbitwarden.com. Check the domain before relying on--fullresults, or before sending a letter that quotes them. The letter does not state an SSL hostname mismatch as an issue for this reason. - Google Play lookup by package name only. Search by app name is not supported. The removal-reason search depends on DuckDuckGo having a summary for the package, and often returns nothing.
- DPO letter in Italian only (see Send a GDPR letter).
- Options not yet implemented. Some options are accepted but have no
effect:
audit --outputandaudit --lang,batch --outputandbatch --full, andsearch --audit. For full stack analysis, useaudit --fullon each app. - Log noise. Androguard, the APK parsing library, may print
WARNINGlines on standard error for some apps. They do not affect the results.
Development
git clone https://github.com/maksimtech/apkradar.git
cd apkradar
pip install -e ".[dev]"
pytest
The changes in each release are listed in CHANGELOG.md. Security issues: see SECURITY.md.
License
MIT. See LICENSE.
Release files for apkradar 2026.9.31
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| apkradar-2026.9.31.tar.gz | 104.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| apkradar-2026.9.31-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 148.8 kB
Release files / apkradar-2026.9.31.tar.gz
| Download URL | apkradar-2026.9.31.tar.gz |
|---|---|
| Size | 104.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d09e0809683db3e55e0a324d95566f8324b924321112eada3f3a5dcbfe671f68
|
|
BLAKE2b-256 checksum How to use checksums |
b6a24b5af5fbffa81e064e61a483e2a34794baf580975bac5994d9d123e69781
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.
Transparency logRelease files / apkradar-2026.9.31-py3-none-any.whl
| Download URL | apkradar-2026.9.31-py3-none-any.whl |
|---|---|
| Size | 44.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b2c2613db116ba3725971f7d8795ef90fbe014d15c12ae675599fb12ea5e35f1
|
|
BLAKE2b-256 checksum How to use checksums |
3e5af199f5ce3b212b7d9c62a38155a0e4260f7809ea01339c6effa7e28bdab1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.
Transparency log