TrackerControl

trackercontrol.org
TrackerControl

Monitor and control hidden data collection in mobile apps about user behavior/ tracking. Get from F-Droid

Open Source

TrackerControl Source Code

Author

TrackerControl

Description

TrackerControl Android: monitor and control trackers and ads.

#android#privacy#tracking-protection

Homepage

https://trackercontrol.org/

Repository

  • LicenseGPL-3.0
  • Created10 Nov 19
  • Primary languageJava
  • Size47,178 KB
  • Stars2,665
  • Forks136
  • Watchers2,665

Language Usage

Language Usage

Project Health

Recent Commits

  • Konrad Kollnig(19 Sept 26)

    Remove obsolete legacy watchdog (#967)

  • Konrad Kollnig(19 Sept 26)

    Check for a killed VPN from outside the service (#966) * Restart the VPN after a teardown the app cannot otherwise see Every recovery path in ServiceSinkhole is registered by the service itself — the Doze-exit reload, the connectivity receiver, the network callbacks — so all of them go away with it. Once the system revokes the tunnel or kills the service while the device is idle, nothing in the app is left to notice, and protection stays off until the user opens the app or reboots. The revoke notification meanwhile promises that TrackerControl "will reconnect automatically when possible", which nothing delivered. The only retry that outlives the service is an alarm, so a teardown that leaves protection enabled now arms one: setAndAllowWhileIdle, because Doze defers every other kind of alarm for exactly as long as the window this has to fire in. The ladder backs off 1 → 5 → 15 → 30 minutes and then holds, and its rung is persisted, so a device that refuses the background service start is not woken on the shortest delay forever. A running tunnel, a switch-off, or a temporary stop for a phone call retires the alarm instead. The watchdog alarm covers the remaining case, a kill with no onDestroy. It only ever helped when the user found it in the advanced settings, so it now runs by default on a half-hour period. It stays inexact and non-wakeup, so it costs no extra wakeups: the Doze window is the restart ladder's job. Refs #954 Claude-Session: https://claude.ai/code/session_01MpSLy3Az7op3W93RS15DkY * Check for a killed VPN from outside the service, as AppTP does The alarm ladder this replaces was out of line with how comparable apps handle the same failure. WireGuard and Mullvad do nothing at all: they react to the system restarting them for always-on and otherwise leave it to the OS. DuckDuckGo's App Tracking Protection is the one that solves it, and it does so with a 15-minute WorkManager check against a heartbeat the service writes, restarting only when the service died without saying so. None of the three wakes the device for this. So the check is periodic work now. Doze defers it to the maintenance window instead of waking the device, which is what the battery constraint in AGENTS.md asks for, and the cost is latency in a state the user would otherwise sit in until they next opened the app. Telling a kill from a deliberate teardown needs the same discriminator AppTP has. The service records a stop it performed itself — a switch-off, the pause for a phone call, a revoke — and a kill records nothing, so the absence of that mark is what the worker acts on. A static flag says whether a tunnel is up, and a killed process takes it down with it. A revoke is now terminal, as it is in AppTP and Mullvad: the system said the tunnel is gone on purpose, and coming back from one is the OS's job through the always-on designation. The revoke notification no longer promises an automatic reconnection it does not deliver, and points at the app instead. Refs #954 Claude-Session: https://claude.ai/code/session_01MpSLy3Az7op3W93RS15DkY * Say what the established flag actually tracks It is set when a tun is established and cleared on a teardown the service performs, so it does not follow a tunnel that failed underneath the service - those windows belong to the in-service recovery paths. The comment claimed more than that. Claude-Session: https://claude.ai/code/session_01MpSLy3Az7op3W93RS15DkY --------- Co-authored-by: Claude <[email protected]>

  • Claude(19 Sept 26)

    fix: record the app version in ACRA crash reports The report whitelist never requested APP_VERSION_NAME or APP_VERSION_CODE, so the version could only ever reach a report inside the BUILD_CONFIG dump. That dump was itself missing from most builds: ACRA resolves the BuildConfig class from the runtime package name unless it is named explicitly, and every flavour but the GitHub release carries an applicationIdSuffix, so the lookup missed the class sitting at the namespace and the collector dropped the whole block. F-Droid and Play reports therefore carried no version at all. Name the BuildConfig class explicitly and add the two version fields, plus PACKAGE_NAME (the only field that reveals flavour and build type, since the suffix is not in BuildConfig), BRAND/PHONE_MODEL and THREAD_DETAILS. Logcat, shared preferences and device identifiers stay off the list. Claude-Session: https://claude.ai/code/session_011GwW8sWZDwptms371192Td

  • Konrad Kollnig(19 Sept 26)

    Compare search domains and excluded routes in Builder.equals (#965) Builder.equals decides whether reload() replaces the live tun or takes the "Native restart" shortcut, so any field it does not capture cannot reach a running interface. Two were still missing after #960 fixed the metered flag: - search domains (addSearchDomain); - the carrier ePDG exclusions (excludeRoute, API 33+). These are re-resolved on every rebuild behind a 1.5s timeout, so a first establish whose lookup timed out was never replaced by a later rebuild that resolved them, and Wi-Fi calling stayed broken until some unrelated change forced a real replacement. Both are now recorded by overriding the corresponding Builder methods and compared like the existing lists. Also: two offline builders (both networkInfo null) now compare equal instead of forcing a needless replacement on every reload while there is no active network, and the cast to Builder is guarded by an instanceof check rather than relying on a following null check. The extra interface replacements this produces go through VpnReplacementSequencer, which was not in place when the issue was first triaged. Refs #763 Claude-Session: https://claude.ai/code/session_016eKiHiWiQwMQosDXj8qY4s Co-authored-by: Claude <[email protected]>

  • dependabot[bot](19 Sept 26)

    deps: bump the gradle-minor-patch group across 1 directory with 3 updates (#957) Bumps the gradle-minor-patch group with 3 updates in the / directory: [org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin](https://github.com/JetBrains/kotlin), androidx.compose:compose-bom and [org.robolectric:robolectric](https://github.com/robolectric/robolectric). Updates `org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin` from 2.4.10 to 2.4.20 - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.4.10...v2.4.20) Updates `androidx.compose:compose-bom` from 2026.08.00 to 2026.09.00 Updates `org.robolectric:robolectric` from 4.16.1 to 4.17 - [Release notes](https://github.com/robolectric/robolectric/releases) - [Commits](https://github.com/robolectric/robolectric/compare/robolectric-4.16.1...robolectric-4.17) --- updated-dependencies: - dependency-name: androidx.compose:compose-bom dependency-version: 2026.09.00 dependency-type: direct:production dependency-group: gradle-minor-patch - dependency-name: org.jetbrains.kotlin.plugin.compose:org.jetbrains.kotlin.plugin.compose.gradle.plugin dependency-version: 2.4.20 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: gradle-minor-patch - dependency-name: org.robolectric:robolectric dependency-version: '4.17' dependency-type: direct:production update-type: version-update:semver-minor dependency-group: gradle-minor-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

  • Konrad Kollnig(19 Sept 26)

    Remove the DHCP responder that hijacks tethered leases (#964) * Remove the DHCP responder that hijacks tethered leases (#962) check_dhcp() answered any packet reaching the tun with source port 68 or destination port 67, replying with a hard-coded lease of 10.1.10.2/24, gateway 10.1.10.1 and DNS 9.9.9.9 instead of forwarding it. Nothing on the tun is a DHCP client, so that reply is never right; a tethered peer that receives it is configured onto a subnet with no route off the device. The default route set keeps the responder out of reach: 224.0.0.0/3 covers the 255.255.255.255 broadcast and 192.168.0.0/16 is excluded, so no DHCP packet enters the tun. Tethering compatibility mode installs a plain 0.0.0.0/0 default route and deliberately puts both back inside the tunnel, which arms the responder for exactly the users being told to enable that mode to get tethering working again. The function also wrote through its own const pointer, inet_pton(AF_INET, "10.1.10.1", (void *) &u->saddr); overwriting the live session's stored source address -- four bytes into a union that holds 16 for IPv6, and into the tuple the session table matches on. Drop the responder rather than gate it. Forwarding is the correct handling for a DHCP packet that does reach the tun: the broadcast has nowhere to go through a UDP socket and is discarded, leaving the on-link DHCP server (Android's own, for a tethering downstream) to answer. dhcp_options.c existed only to serve it, and its test was never wired into run_defensive_tests.sh. The checked-in Doxygen output under docs/html/ still documents the removed structs; it is generated and left to the next regeneration. Claude-Session: https://claude.ai/code/session_01BEU2NQ6M7Zwgwpvn7Vsv5P * Drop the DHCP option test step from the test workflow The removal missed this call site: test.yml compiles dhcp_options_test.c and dhcp_options.c in a step of its own, separately from run_defensive_tests.sh, so the `test` job failed on the two source files no longer being there. Claude-Session: https://claude.ai/code/session_01BEU2NQ6M7Zwgwpvn7Vsv5P --------- Co-authored-by: Claude <[email protected]>

  • Claude(19 Sept 26)

    test: move unit tests to Robolectric 4.17 and drop the SDK pin 4.17 supports Android API 37, which the app already compiles and targets, so robolectric.properties no longer has to hold the framework-backed tests back on API 36: without the file Robolectric follows targetSdk. Neither half works alone. 4.16 stops at API 36, so unpinning under 4.16.1 would fail every framework-backed test with an unsupported-SDK error, and 4.17 needs the --add-opens flags added in the previous commit. Taking the Robolectric third of the gradle-minor-patch group here leaves that Dependabot PR (#957) to Kotlin and the Compose BOM alone. Claude-Session: https://claude.ai/code/session_019dRHAPyWPcJZyko41E4YWS

  • Konrad Kollnig(19 Sept 26)

    test: open JDK internals for the unit test JVM (#963) Robolectric reflects into JDK internals that the module system closes from Java 17 onwards. 4.16.1 still gets away with it, but 4.17 does not: on the CI JDK 21 every framework-backed test dies in AndroidInterceptors with an IllegalAccessException (267 of 491 failed in the 4.17 bump). Add the --add-opens flags Robolectric documents for Java 17+ so the bump can land. The flags are harmless on 4.16.1, so this goes in ahead of the bump rather than on top of the Dependabot branch, which Dependabot would rebase away. Claude-Session: https://claude.ai/code/session_019dRHAPyWPcJZyko41E4YWS

  • Konrad Kollnig(18 Sept 26)

    Stop marking unmetered networks as metered while the VPN runs (#960) Android defaults a VPN network to metered, so the metered flag has to be set explicitly. We passed a snapshot of Util.isMeteredNetwork(), which is wrong twice over: - ConnectivityManager.isActiveNetworkMetered() returns true when there is no active network at all, so a tunnel established before Wi-Fi associates (boot start, always-on VPN) is born metered; - the flag only reaches apps through establish(), and Builder.equals() never compared it, so a metered reload took the "Native restart" shortcut and the stale value survived for the life of the tunnel. Apps that ask the system whether the current network is metered — K-9 Mail, Syncthing — then hold back on any Wi-Fi for as long as TC runs (#959). Pass false instead, which does not force the network unmetered: it tells the platform to inherit meteredness from the underlying networks, so the VPN tracks the physical network as it changes, with no snapshot to go stale. Also track the flag in Builder and compare it, so a future change of the value does force a real re-establish (part of #763). Closes #959 Claude-Session: https://claude.ai/code/session_01184pQBPQMMwWef1H7DmgJA Co-authored-by: Claude <[email protected]>

  • github-actions[bot](18 Sept 26)

    Update translations from Crowdin (#958) Co-authored-by: Crowdin Bot <[email protected]>

  • Konrad Kollnig(17 Sept 26)

    Bump Android NDK to 29.0.14206865 (r29) Verified libwgbridge.so cross-compile (all 4 ABIs), assembleGithubDebug (native CMake + Rust builds), and testGithubDebugUnitTest all pass. Co-Authored-By: Claude Sonnet 5 <[email protected]>

  • github-actions[bot](14 Sept 26)

    Update translations from Crowdin (#955) Co-authored-by: Crowdin Bot <[email protected]>

  • github-actions[bot](11 Sept 26)

    New Crowdin translations (#951) * Update translations from Crowdin * Update translations from Crowdin --------- Co-authored-by: Crowdin Bot <[email protected]>

  • github-actions[bot](09 Sept 26)

    Update translations from Crowdin (#950) Co-authored-by: Crowdin Bot <[email protected]>

  • Konrad Kollnig(09 Sept 26)

    Localise tracker categories in timeline

  • Konrad Kollnig(09 Sept 26)

    Remove unused Android resources (#949)

  • Konrad Kollnig(09 Sept 26)

    Resolve existing locale lint warnings (#944)

  • Konrad Kollnig(09 Sept 26)

    Complete missing translations for all locales (#940) * Complete locale translation coverage (#875) * Resolve lint warnings in completed translations

  • Konrad Kollnig(09 Sept 26)

    Resolve layout and accessibility lint findings (#947)

  • Konrad Kollnig(09 Sept 26)

    Preserve TCP app ownership across WireGuard policy reloads (#933) Retain bounded numeric owner state independently of route and blocking verdict generations. Revalidate policy against the original connection owner, reject ambiguous uncached established UID zero, and resolve fresh SYN tuples anew. Keep cache resets atomic and preserve the established route fast path. Add production-bound attribution, root UID, tuple reuse, expiry, collision and bridge-call regressions.

  • Konrad Kollnig(09 Sept 26)

    Remove obsolete Android API compatibility paths (#948)

  • Konrad Kollnig(09 Sept 26)

    Document lifecycle-safe lint exceptions (#943)

  • Konrad Kollnig(09 Sept 26)

    Make displayed values locale-safe (#945)

  • Konrad Kollnig(09 Sept 26)

    Fix TCP close handling and TUN failure recovery qualification (#942) * Release finished TCP sockets without resetting retransmitted FINs Include the socket-release fix from #941 and retain normal FIN/ACK handling for already-consumed retransmitted payload after the upstream descriptor is released. New payload and conflicting FIN sequences remain rejected. Exercise both close orderings and delayed final ACKs with real epoll, plus queued data, sequence wraparound and duplicate payload/FIN regressions. Validated the native suites on an isolated Android emulator with UBSan; the epoll regression fails before #941 and the retransmission regression fails with #941 alone. * Qualify TUN recovery across one uninterrupted failure run Use the existing total-minus-streak identity to detect successful writes between connectivity polls. Separate failure bursts start a fresh persistence window instead of falsely triggering tunnel recovery. Sustained failures still qualify even when handshakes and receive counters advance. Cover hidden resets, growing bursts, resumed persistent failure and invalid samples. All 40 connectivity checker and monitor tests pass.

  • github-actions[bot](09 Sept 26)

    New Crowdin translations (#938) * Update translations from Crowdin * Update translations from Crowdin --------- Co-authored-by: Crowdin Bot <[email protected]>

  • Konrad Kollnig(09 Sept 26)

    Keep concurrent ICMP echo identifiers in separate sessions (#939)

  • Konrad Kollnig(09 Sept 26)

    Improve DoH setup and recover immediately after endpoint changes (#936) * Improve DoH endpoint validation and recovery after edits * Update DoH instrumentation test for endpoint state

  • Konrad Kollnig(09 Sept 26)

    Guard main-screen autofill lookup against missing descriptors (#934)

  • github-actions[bot](08 Sept 26)

    Update translations from Crowdin (#920) Co-authored-by: Crowdin Bot <[email protected]>

  • Konrad Kollnig(08 Sept 26)

    Guard against RejectedExecutionException in teardown-racing receivers (#930) interactiveStateReceiver (SCREEN_ON/SCREEN_OFF) and packageChangedReceiver call executor.submit() without catching RejectedExecutionException. A broadcast already queued for delivery on the main Handler can still reach onReceive after onDestroy() unregisters the receiver and calls executor.shutdownNow(), so the uncaught exception crashes the app. Mirror the existing catch already used by the network-validation submit site. Claude-Session: https://claude.ai/code/session_01GM9qWQ9etUyxx5yicdN4ze Co-authored-by: Claude <[email protected]>

TrackerControl Website

Website

TrackerControl for Android | Monitor and control trackers and ads.

TrackerControl allows you to monitor and control the widespread, ongoing, hidden data collection in mobile apps about user behaviour (tracking).

Redirects

Does not redirect

Security Checks

All 65 security checks passed

Server Details

  • IP Address185.199.110.153
  • Hostnamecdn-185-199-110-153.github.com
  • LocationFrancisco,Indiana,United States of America,NA
  • ISPGitHub Inc.
  • ASNAS54113

Associated Countries

  • USUS

Safety Score

Website marked as safe

100%

Blacklist Check

trackercontrol.org was found on 0 blacklists

  • AntiSocial Blacklist
  • Artists Against 419
  • Badbitcoin
  • Bambenek Consulting
  • CERT Polska
  • CoinBlockerLists
  • CRDF
  • CryptoScamDB
  • EtherAddressLookup
  • EtherScamDB
  • Fake Website Buster
  • MetaMask EthPhishing
  • NABP Not Recommended Sites
  • OpenPhish
  • PetScams
  • PhishFeed
  • PhishFort
  • Phishing.Database
  • PhishStats
  • PhishTank
  • Phishunt
  • RPiList Not Serious
  • Scam.Directory
  • SecureReload Phishing List
  • Spam404
  • StopGunScams
  • Suspicious Hosting IP
  • ThreatFox
  • ThreatLog
  • TweetFeed
  • URLhaus
  • ViriBack C2 Tracker

Website Preview

Website preview

TrackerControl Android App

APK Info

Trackers

  • ACRA

Permissions

  • Access Network State
  • Access Wifi State
  • Foreground Service
  • Internet
  • Query All Packages
  • Read Phone State
  • Receive Boot Completed
  • Vibrate
  • Wake Lock
  • Write External Storage
  • Admin

TrackerControl Reviews

More Mobile Apps

About the Data: TrackerControl

Change History

  • Amended (androidApp)

Edit TrackerControl Data

You can edit TrackerControl's entry in this section of awesome-privacy.yml by submitting a PR to our GitHub repo.
Note that some of the information shown above has been aggregated from external sources, a list of these can be found data documentation.

Origin Data

Modify Data

API

You can access TrackerControl's data programmatically via our API. Simply make a GET request to:

https://api.awesome-privacy.xyz/v1/services/trackercontrol

The REST API is free, no-auth and CORS-enabled. To learn more, view the API Docs or read the API Usage Guide.

Share TrackerControl

Help your friends compare Mobile Apps, and pick privacy-respecting software and services.
Share TrackerControl and Awesome Privacy with your network!