Platforms
Testing Android apps
An Android scan runs your app in a cloud emulator and records what the app sends to analytics and advertising libraries. Mobile Compliance finds the consent dialog in the app and tests it on its own. Mobile Events replay a journey that you record in the app.
This guide covers what to give the scanner, what it does to the app, and where the limits of what it can see are.
Where the scanner gets the app
When you create a test, you have two options:
- Google Play URL. AnalyticsProof tries to download the app itself and fetches the current version before later scans. If the download fails, it offers a file upload instead.
- File upload. An
.apkor.xapkfile up to 200 MB. The uploaded build is scanned unchanged until you replace it. This suits a pre-release build or an internal version that is not in the store.
The scanner reads the package name (for example com.example.app) from the file. If it cannot, you enter it manually.
Upload an app that ships as several APKs (split APKs) as an .xapk, which is a ZIP containing all the .apk files. The scanner installs them together. Other files in the archive, such as OBB data, are not installed. You cannot upload an .aab. If all you have is an app bundle, build a universal APK from it with bundletool:
bundletool build-apks --bundle=app.aab --output=app.apks --mode=universal
unzip app.apks universal.apk
build-apks writes an .apks archive; the file to upload is the universal.apk inside it. Without --ks, bundletool signs the APK with the debug key from ~/.android/debug.keystore if that file exists (Android Studio creates it). If it does not, the APK stays unsigned and will not install, so you need --ks. The debug key is enough, unless the app checks its own signature or uses a service tied to the signing certificate, such as Google sign-in or an API key restricted to your app. If it does, sign it with your own key: add --ks, --ks-key-alias, --ks-pass and --key-pass.
What the scanner does to the app
We install the app exactly as you provide it. We do not repackage or re-sign it, so it keeps your original signature.
Before the scan, the scanner:
- sets the screen orientation, which applies for the whole scan,
- installs the app,
- clears its data, so it starts as on first launch after installation, consent dialog included,
- turns on detailed debug logging on the device for the analytics libraries that support it, for example Google Analytics for Firebase.
The emulator has the certificate of our measurement proxy among its system certificates. That lets the scanner read the traffic to selected servers without modifying the app.
What the scanner sees in the traffic
For every connection, the scanner decides based on the name of the server the app connects to.
- Known analytics servers (for example Meta, Adjust, Amplitude, Mixpanel or Braze): the scanner decrypts the traffic and sees individual requests, events and parameters.
- Google servers (Firebase, Google Analytics, Google ads, Play): the traffic passes through unchanged and the scanner sees only the server name. The content of the batches Google Analytics for Firebase sends, meaning events, parameters and consent signals, is read from the device's debug logs instead.
- Everything else, such as your backend, a CDN or login: passes through unchanged and the scanner sees only the server name. We do not decrypt your own traffic, so login and APIs work as they would on an ordinary phone.
Independently of the traffic, the scanner also inspects the app package, all split APKs included. This way it finds libraries embedded in the app even if they sent nothing during the scan.
Apps with certificate pinning
We do not remove or bypass certificate pinning, whether it lives in OkHttp, in native code or in the app's own network security configuration.
If the app rejects our certificate for a known analytics server, the scanner lets that server through without decryption for the rest of the scan. The connection on which the app rejected the certificate fails; later ones go through normally. For such a server you see that the app connects to it, and we recognise the tool by it. What exactly it sent, you do not see.
Pinning on your own backend has no effect on the result, because the scanner does not decrypt it anyway. The device's debug logs and the package check work the same with or without pinning.
Integrity checks and emulator detection
Because we do not re-sign the app, a check of its own signature will not fail because of us. The app does, however, run in an emulator with administrator (root) access. Apps that check device integrity (for example through Play Integrity), root or an emulator may therefore refuse to start, limit features or show an error.
If the scanner sees in the device logs that the app failed an integrity check or detected root or an emulator, or if the app never shows any content, the scan ends as "Not measured". Such a scan has no score and is not used for comparisons, the baseline or alerts.
For testing, a build with these checks switched off or relaxed works better, such as an internal test version. Upload it as a file.
Recording an in-app journey
You record the journey in the "Record in-app journey" dialog. The app runs in the emulator and the screen is streamed to your browser. Tap or swipe on the screen to record steps. The system buttons Back, Home and Recent apps are available too. Taps are disabled until the app has loaded.
Keep in mind:
- Orientation. You choose portrait or landscape before recording and cannot change it while recording. Replay runs in the same orientation, because steps are positions on the screen.
- Consent. The app starts with its data cleared, so you see the consent dialog as a new user would. Tap the choice you want to test. Replay repeats exactly your tap. Nothing else answers the dialog for you.
- System permissions. During both recording and replay the app gets its permissions granted in advance, so system permission prompts do not appear and you should not record them.
During replay, the scanner looks for the element you tapped by the structure of the screen. If it cannot find it, it taps the recorded coordinates.
How the results differ from the web
- Different evidence. An app has no cookies and no dataLayer. The scanner works with the traffic, the device's debug logs and the content of the package.
- Visibility per server. You see request content only for decrypted servers. For the rest, what you see is that the app connected to the server.
- A different tool list. The list of tools for the web does not apply to Android; detection in apps is separate.
- Steps by screen. Instead of CSS selectors, steps are screen elements and coordinates, which is why orientation matters.
- Country. The device presents itself in the chosen country through its language, time zone and SIM data. The scanner does not fake the GPS location when recording or replaying a journey.