Evidence capture — Appmiral app cohort: APK harvest + integration & live-config audit (2026-06-28)
Forensic snapshot of every Appmiral / Appstrakt app installed on the investigator’s phone, pulled byte-for-byte from the device as APKs, then statically scanned for the integrations Appmiral advertises on https://appmiral.com/features/integrations, and — for every app carrying the Crowd Connected location SDK — read for its live, server-pushed config: the active geofence km range and whether the remote kill-switch is ON or OFF.
This extends and supersedes the earlier static 114-app inventory and the hand-picked “12-app CrowdConnected club”: the cohort is re-enumerated from the live device (140 apps now installed), complete split-APK sets are pulled, and the tracking analysis is driven by the actual integration scan rather than a preset list.
The APK bytes (375 files, ~7.08 GB) are not committed to this public repo — they live in the companion private repo
GraafG/tt-festival-app-evidenceunderapks_2026-06-28_154246/. Their byte-for-byte integrity is attested here byapk-manifest.sha256, which is identical to the private folder’sSHA256SUMS.txt. This mirrors the repo’s existing two-repo model (see../CONTRIBUTING.md).
Snapshot summary
| Field | Value |
|---|---|
| Captured (local) | 2026-06-28 15:42–15:59 CEST (UTC+02:00) |
| Capture method | adb pull of exact on-device install bytes (no root needed for APKs) |
| Device | Pixel 10a, Android 16, Magisk root, build …/stallion:16/CP1A.260505.005/15081906 |
| ADB serial | 5B161JEA308016 |
| Apps harvested | 140 (appmiral.*, be.appstrakt.*, pl.mysticfestival, com.triple.verstappen) |
| APK files | 375 split-APK files (base + split_config.*) |
| Total APK bytes | ~7.08 GB (private repo) |
| Crowd Connected DBs read (root) | 6 apps with a live, populated config |
Tooling, exact versions, and the full reproduction walk-through:
../../docs/appmiral-comparison/10-apk-harvest-reproduction.md.
What’s in this folder (public)
appmiral-apks_2026-06-28_154246/
├── README.md ← this capture log
├── SHA256SUMS.txt ← SHA-256 of every file in THIS (public) folder
├── apk-manifest.sha256 ← SHA-256 of every harvested APK (== private SHA256SUMS.txt)
├── .capture-timestamp
├── data/ ← machine-readable derived tables (frozen copies)
│ ├── installed_apps_2026-06-28.csv ← 140 installed vs the old 114 inventory (+26 new)
│ ├── apk_files_manifest_2026-06-28.csv ← 375 rows: pkg, versionName/Code, file, size, sha256, on-device path
│ ├── integration_matrix_2026-06-28.csv ← app × 51 integration/SDK presence matrix
│ ├── integration_matrix_2026-06-28.identify.csv ← per-app id: label, versions, minSdk/targetSdk, ABIs, location perms
│ ├── integration_matrix_2026-06-28.json ← matrix + the exact matched byte-patterns (audit trail)
│ ├── cc_live_config_2026-06-28.csv ← 6 apps: kill-switch, km radius, centre, cadences (identifiers redacted)
│ └── cc_live_config_2026-06-28.json
└── logs/
├── tool-versions.txt ← OS, adb, aapt2, Python, androguard, sqlite (captured programmatically)
├── evidence_header_2026-06-28.txt ← device/build/wall-clock header
└── appmiral_packages_2026-06-28.txt ← the raw 140-package list as enumerated on device
The APK bytes (apks_2026-06-28_154246/<pkg>/*.apk) are in the private repo.
The Crowd Connected Room databases (which contain device/account identifiers) are
also private (cc_dbs_2026-06-28_154246/); only the redacted decoded
config is published here in data/cc_live_config_*.
Headline findings
1. Advertised vs. actually-embedded integrations
Static scan of all 140 apps against Appmiral’s published integration catalogue
(byte-scan of DEX + resources + native libs + manifest; presence-only, with the
matched pattern recorded for every hit in the .json). Counts out of 140:
| Integration | Apps /140 | Note |
|---|---|---|
| Instagram, Firebase (Analytics/Messaging/Crashlytics), Google Fused Location | 140 | platform baseline — in every app |
| YouTube, AWS Cognito, CM.com, Beatswitch, AWS Kinesis Firehose, Google Maps SDK | 139 | near-universal |
| Ticketmaster | 137 | |
| Spotify | 128 | |
| Get Moments | 114 | |
| Facebook SDK | 52 | |
| OneTrust (consent) | 40 | |
| Permutive (CDP) | 36 | variable adoption |
| Mapbox | 16 | variable adoption |
| Billetten | 10 | |
| Crowd Connected (literal pkg/host) | 9 | obfuscated away in most — see below |
| Tealium | 2 | |
| TikTok, Azure, Sports Alliance, ShowPass, Eventim, Ticketpay, Tickoweb, Bleep, SeeTickets, WeezEvents, GET, Mobile Locker, Insider, Fanalist, PwC, Halo by CM, Inventis, Jebbit, Komo | 0 | advertised but not present in any installed app |
Two structural facts this exposes:
- Platform baseline vs. per-festival reality. Because every Appmiral app is built from one shared SDK/template, many “integrations” are baked into ~all 140 apps regardless of whether a given festival uses them — so the marketing page over-states per-event usage. The meaningful signal is the variable-adoption integrations (Permutive 36, Mapbox 16, background-location 30, Crowd Connected literal 9, Tealium 2) plus the runtime config.
- The location-tracking capability is bundled almost everywhere. Crowd Connected’s own package string survives in only 9 apps (R8/obfuscation strips it elsewhere), but its AWS pipeline — Cognito 139 + Kinesis Firehose 139 + Fused Location 140 — is near-universal. The capability ships in essentially the whole fleet; only the runtime DB proves it is armed in a given app.
Location permissions: all 140 request fine + coarse location; 30 also request background location.
2. Live config — km range + kill-switch (the 6 apps with a populated CC DB)
Read with root from each app’s CrowdConnected-RoomDatabase (new SDK) or
shared_prefs/CrowdConnected.xml (legacy heartbeat). Identifiers redacted.
| App | Kill-switch | Active km range | Geofence centre | Schema |
|---|---|---|---|---|
com.appmiral.ttfestival |
🔴 ON | 60 km | 52.99, 6.56 (Assen) | new Settings.active=1, Mode=BACKGROUND, SDK 2.1.0 |
com.appmiral.mdlbeast |
OFF | 60 km (armed) | 21.49, 39.19 (Jeddah) | new Settings.active=0 |
com.appmiral.rockforpeople |
OFF | 40 km (armed) | 50.25, 15.84 (CZ) | new Settings.active=0 |
com.appmiral.teamnl |
OFF | 50 km (armed) | 45.45, 9.16 (Milan) | new Settings.active=0 |
com.appmiral.museumnachtamsterdam |
OFF | 80 km (armed) | 52.36, 4.89 (Amsterdam) | legacy activeAPIResponse=120,false,… |
com.appmiral.dutchgp |
OFF | — (no zone cached this run) | — | legacy activeAPIResponse=120,false,… |
Only TT Festival was live (active=1) at capture time, with a 60 km
collection ring centred on Assen — far wider than the festival grounds — and the
SDK in background mode. The kill-switch is server-pushed: every other app
carried an armed geofence (40–80 km) but was toggled OFF by Crowd Connected’s
backend, demonstrating the on/off is a remote decision, not a local one. Config is
fetched by the SDK from its backend during normal polling; we only read the cached
result locally and never contacted Crowd Connected.
Determinism caveat: server-pushed config drifts over time, and only apps that have been launched have a populated DB — so a replicator re-running this later may see different switch states / different apps with cached config. That is expected and itself documents that the operator controls the switch remotely.
Full analysis: 08-integration-matrix
and 09-active-config-km-killswitch.
Verify integrity
This (public) folder:
sha256sum -c SHA256SUMS.txt # Linux/macOS, run inside this folder
Get-Content SHA256SUMS.txt | ForEach-Object { $h,$p = $_ -split ' ',2
if ((Get-FileHash -Algorithm SHA256 -LiteralPath $p).Hash.ToLower() -ne $h) { "MISMATCH: $p" } }
The APK bytes in the private repo, against the public manifest:
# inside the private repo's apks_2026-06-28_154246/ folder
sha256sum -c /path/to/this/folder/apk-manifest.sha256
apk-manifest.sha256 here is byte-for-byte identical to
apks_2026-06-28_154246/SHA256SUMS.txt in the private repo, so this public record
independently attests exactly which APK bytes were captured.
Reproduce
Everything was produced by the documented, parameterized scripts in
../../tools/apk-harvest/ (no hard-coded serial; idempotent).
Follow the step-by-step guide
10-apk-harvest-reproduction.md
— prerequisites, exact commands, expected outputs, checksum verification, and the
determinism caveats above.