The claim

Our privacy policy states that DocuScanr transmits no data. In July 2026 we verified that claim empirically, at the operating-system level, and this page documents the method and results so you can check our work instead of taking our word for it.

How we measured

Android keeps per-app network byte counters independently of the app itself. We read DocuScanr's counters with the platform's own accounting tool (dumpsys netstats) and snapshotted them at four points: before launching the app; after launch and the Google Play Billing connection; and twice after a complete camera scan with on-device text recognition, several minutes apart. We also watched the system log for any telemetry or upload-scheduler activity across the entire window.

Crash reporting stayed off throughout. That is its default state; it only ever runs if you explicitly opt in.

0 bytes

The app's received and transmitted byte counters were identical at every snapshot. Zero bytes sent, zero bytes received, and zero upload attempts in the system log across launch, billing connect, library browsing, scanning, and sustained text recognition.

The audit caught something. Here is what we did.

A privacy measurement is only worth publishing if it can catch a problem. Ours did. When we re-ran the audit with a much heavier text-recognition workload, a Google SDK component bundled inside the app (the transport layer that ships inside both ML Kit and Play Billing) batched its usage metrics and attempted a real upload to a Google logging endpoint. The attempt failed on our test network and involved no document content, only SDK usage counters. But we do not ship "usually silent".

The same day, we removed that component's upload scheduler from the app entirely, at the manifest level. SDK usage events now have nowhere to go: they are discarded on the device regardless of your settings, your network, or the SDK's intentions. We then re-ran the full measurement with the same heavy workload. The result is the zero above: zero bytes, and just as importantly, zero attempts.

Why does the app hold network permissions at all?

Honest answer: we do not declare the Internet or Network State permissions ourselves. Both arrive through libraries we bundle:

  • Crash reporting (Sentry). The one deliberate network feature in the app. It is opt-in and disabled by default, and when disabled, events are dropped inside the app before anything is even queued.
  • Google Play Billing. Purchases and restores are handled inside the Play Store's own process, not ours. Its traffic never appears under DocuScanr's identity by design.
  • Text recognition (ML Kit). Google's OCR library bundles transport machinery for usage metrics. We disable Firebase analytics with its documented kill-switch flags, remove its auto-initializer, and have removed the transport component's upload scheduler from the app entirely (see above), so its events can never leave the device.

Stripping the permissions outright would break opt-in crash reporting and risk crashes inside the bundled SDKs, for no real privacy gain over a measured zero.

Honest caveats

  • Our test network blocks known telemetry hostnames at the DNS level, which initially made byte counters look cleaner than they deserved. That is exactly why we treat connection attempts in the system log as the primary signal and the byte counters as secondary, and why the upload attempt described above got caught rather than missed.
  • Deferred uploads are no longer a timing question. With the upload scheduler removed from the app, a deferred upload has no mechanism left to run. We still watched the settle window and saw none.
  • The original measurement ran on our development build, which uses the identical dependency set and manifest configuration as the release build. We have since reproduced the result on the production build delivered through Google Play, during closed testing on a real device profile: zero connection attempts across scanning, text recognition, and purchase flows, with the SDK's own discarded-event warnings confirming the removal is active in the shipped app.
  • "Zero bytes" describes DocuScanr's own traffic. Google Play's infrastructure (billing, app updates) runs in its own processes, as it does for every app on Android.

Verify it yourself

Anyone with the Android debug bridge (adb) can reproduce this on their own device. No root, no special build:

# find DocuScanr's app id (uid)
adb shell pm list packages -U com.tothetower.docuscanr

# snapshot the byte counters for that uid
adb shell dumpsys netstats detail

# use the app: scan, run text recognition, browse, export
# then snapshot again and compare. The counters should not move.
adb shell dumpsys netstats detail

Our standing commitment

We re-run this measurement before any release that changes a dependency capable of producing traffic (the text recognition stack, billing, or crash reporting): byte counters, the connection-attempt log scan, and a check that the removed scheduler components stay removed from the built app. The privacy policy's no-transmission claim gets re-verified, never assumed.

Questions about the method? Email us at support@tothetowerlabs.com, or read the formal wording in our privacy policy.