TagHistory is an Android app for viewing live and historical locations of your Apple AirTags. It is a Kotlin Multiplatform + Compose rewrite of OpenTagViewer, built on the FindMy.py library.
Warning
This project is not affiliated with Apple Inc. or Google LLC in any capacity.
| ☀️ Light Mode | 🌑 Dark Mode | 🛰️ Satellite |
|---|---|---|
![]() |
![]() |
![]() |
- Live map: all your AirTags on a map, refreshed every 60 seconds.
- Tag cards: swipe through tags at the bottom; cards and map markers stay in sync.
- Location history timeline: scrub through a tag's full position history day by day, Google Maps Timeline style.
- Background sync: configurable automatic refresh interval.
- Light, Dark, Satellite basemap toggle.
- Rename and emoji: give each tag a custom name and emoji.
- Route: tap Route on any card to open your preferred navigation app.
- An Android phone running Android 7.0+ (API 24)
- A free Apple Account with 2FA via SMS or Trusted Device
- One or more AirTags registered to your Apple account via the FindMy app
- A Mac or macOS VM (needed once to export your AirTag data, see below)
- Install the APK from the latest release.
- Log in with your Apple ID inside the app.
- Export your AirTag data. This produces a
.zipfile. Two options:- On a Mac, run the OpenTagViewer macOS Exporter by hand.
- On Linux with KVM, use afm-key-extractor — a Docker image that drives an automated macOS VM end-to-end.
- Import the
.zipin the app. - Your AirTags now appear on the map and update automatically.
See the upstream wiki for detailed setup instructions. The export and login process is unchanged from OpenTagViewer.
A wasmJs build of the app runs in any modern browser:
./scripts/dev-web.sh # dev bundle, serves on :8765
./scripts/dev-web.sh production # wasm-opt-shrunk bundleThe web build is best-effort and ships with caveats:
- Sign-in needs the on-device anisette bridge. The Android app generates anisette headers on-device through Apple's own libCoreADI + the Rust ottjni JNI bridge. The web build does the same with
lbr77/anisette-js— a Unicorn-Engine WASM emulator that runs the same Apple ARM64 libraries inside the browser. Run./scripts/build-web-anisette.shonce to vendor the dist files and copy the Apple libs out of the Apple Music APK that the Android build already extracts. The project will not proxy anisette through any third-party server. - Map + history view render real MapLibre tiles via the JS bridge.
sql.jsDB is backed by IndexedDB so reloads keep imported data.SecureBlobStoreis a pass-through wrapper (browsers have no platform keystore equivalent) — anything storing real key material on web has to gate behind a feature flag first.- BLE / Nearby is unavailable on web; the Nearby button is hidden.
Verified end-to-end: shared compileKotlinWasmJs is green, all 12 crypto primitives (SHA-256, HMAC-SHA-256, PBKDF2, AES-CBC, AES-GCM, secureRng, BigInt round-trip + modPow, P-224 derive + ECDH) pass wasmJsBrowserTest in headless Chromium against NIST/RFC vectors.
PRs are welcome. Things that would be great to have, with up-to-date status as of 2026-05:
🟢 DoableNearby AirTag detection via Bluetooth. FindMy.py's key-rotation derivation was fixed in late 2025 (issue #90); the crypto path (HKDF + P-224) is a few hundred lines to port to pure Kotlin.🟢 Doable"Ring" / Make Noise button. The BLE play-sound characteristic write is fully understood; an experimental ref impl landed in FindMy.py PR #211 and AirGuard does it in production. Mostly Android BLE permissioning + GATT write.🟡 MediumSupport for OpenHaystack tags. Same P-224 ECIES decrypt path as AirTags, additional import flow for OH keys plus a macless-haystack-style relay endpoint.🟠 LargerIntegrate Google Find My Device. Protocol publicly RE'd in 2025 (GoogleFindMyTools, Python). Mostly auth + gRPC port.🟠 LargerIntegrate Samsung SmartTag. uTag already has the Kotlin network/crypto modules; adapting them into a library subproject is the lightest path.🟢 EasyAdditional language translations. Add a newstrings.xmlundercomposeApp/src/commonMain/composeResources/values-<locale>/. English baseline and German live there already.
- OpenTagViewer by Shane B. The original Java app this is based on.
- FindMy.py by malmeloo. The FindMy network library.
- Material Icons by Google.
- MapLibre Android for map rendering.


