A tiny Android app that exists for one reason: to let you see what AppInspect does, on a real device, in about five minutes.
Clone it, run the debug build, tap a few buttons to generate data, then open the inspector and look at what it captured. Every AppInspect touch point in the code is small and commented, so the app also works as a copy-paste reference for wiring the library into your own project.
AppInspect in one line: a full-screen inspector inside your own debug/internal builds — OkHttp traffic with per-endpoint API analytics, response mocking, SharedPreferences / DataStore / SQLite / Room, WorkManager jobs, crashes and ANRs, a live logcat tail and runtime metadata — with no proxy, no certificate, no desktop client and no adb connection.
- Docs: https://app-inspect-doc.vercel.app/
- Maven Central: https://central.sonatype.com/artifact/io.github.appinspect/appinspect/overview
- The version this sample builds against is pinned in
gradle/libs.versions.toml
- Android Studio (any recent version) or just the command line with JDK 17+
- A device or emulator on Android 7.0 (API 24) or newer
- ANR and native-crash reporting need Android 11 (API 30)+
- Notifications need the Android 13+ runtime permission, which the app asks for on launch
git clone https://github.com/appinspect/AppInspect-Sample-App.git
cd AppInspect-Sample-App
# build + install the debug variant on a connected device/emulator
./gradlew :app:installDebugOr open the project in Android Studio, pick the debug variant, and hit Run.
The dependency is resolved from Maven Central, so the first build needs an internet connection.
Any of these work, and none of them need extra host code:
| How | Notes |
|---|---|
| Open inspector button | Calls AppInspect.open(context) |
| Shake the device | Firm, deliberate shake (default threshold 2.7 g) |
| Long-press the header card | Long-press gesture wired to open() |
| Launcher shortcut | Long-press the app icon on the home screen → Inspect |
| Tap a network notification | Appears after an API call, if the notification permission was granted |
The inspector opens as its own task, so it gets a separate card in Recents and can be used in split-screen next to the app.
The demo screen is one list of buttons grouped by the panel they feed.
- Network — tap Run 3 calls in a row, then open the inspector → Network. You get request
and response headers, bodies, formatted JSON, cURL copy, and
.txt/.harexport. Unreachable host shows how a transport failure is recorded differently from an HTTP error. - API Analytics — with a few calls captured, tap the Insights icon in the Network panel's top bar. Endpoints are grouped and graded by latency percentiles and error rate, with charts and a ranked list of findings. The sample is frozen when you open it, so percentiles do not shift while you read; new calls surface as a banner. Nothing is computed until you open it, so an unopened panel costs the host app nothing.
- Mocks — open Mocks, enable Catalog — empty state, then tap GET catalog again. The
response is served from the device and the request never leaves it. The rules come from
app/src/debug/assets/appinspect/mocks.jsonand all ship disabled. - Logcat — tap One line per level, then open Logcat (top bar). Filter by level, tag, text or regex; expand the stack trace from Exception with a cause; toggle Redact after tapping Lines with fake secrets.
- Storage — tap Write SharedPreferences and Seed SQLite database, then open Storage.
Preferences are editable; the database shows schema and paged rows. The long
cached_profilevalue opens in the full-screen JSON tree viewer. - Background work — tap Enqueue delayed sync job, then open Work. The job sits in
ENQUEUEDwith its constraints and input data visible. - Crashes — tap Crash on main thread. The app dies, which is the point. Relaunch it and open Crashes. Freeze main thread (ANR) works the same way on Android 11+.
- Runtime — open it any time (top bar) for app, device and session metadata, including the custom entries this sample registers.
Three places. That is all of it.
| File | What it does |
|---|---|
app/build.gradle.kts |
debugImplementation(appinspect) + releaseImplementation(appinspect-no-op), and a commented staging build type |
SampleApi.kt |
.addAppInspectInterceptor() — the one line that enables network capture |
AppInspectBridge.kt |
Optional configuration + AppInspect.open() |
Everything else in the app (SampleLogs, SampleStorage, SampleWork, SampleCrashes) is
ordinary Android code with no reference to AppInspect at all — the panels pick that data up on their
own. That is worth noticing: apart from the interceptor, the library observes your app rather than
being called by it.
AppInspect.open() and updateConfiguration() exist only in the full appinspect artifact. The
release build depends on appinspect-no-op, which does not contain them. So those calls live behind
one small object with two copies:
app/src/debug/java/.../inspector/AppInspectBridge.kt— the real callsapp/src/release/java/.../inspector/AppInspectBridge.kt— same signatures, does nothing
The rest of the app is variant-agnostic and the release build compiles cleanly. The OkHttp
interceptor is the exception: the no-op artifact ships the same extension as a pass-through, so
addAppInspectInterceptor() can sit in src/main unguarded.
| Variant | AppInspect artifact | Inspector |
|---|---|---|
debug |
appinspect |
On. isDebuggable = true → DEBUG tier, everything enabled, nothing to configure |
release |
appinspect-no-op |
Not present. ~8 KB pass-through interceptor, no UI, no capture, no manifest entries |
staging / uat |
commented out in app/build.gradle.kts |
See below |
AppInspect never sees your Gradle variant names. It resolves a build to a tier from two inputs:
FLAG_DEBUGGABLE, and the boolean resource appinspect_enabled_in_non_debuggable_build.
- debuggable → DEBUG, everything on
- not debuggable + resource
true→ STAGING, everything on - not debuggable + resource absent (the default) → PRODUCTION, everything off
So a non-debuggable staging/uat build opts in with one resource line. The commented staging block
in app/build.gradle.kts shows the whole thing — including matchingFallbacks, which any custom
build type needs because the AppInspect artifacts publish only debug and release variants. This
sample keeps it commented so there are just two variants to think about; uncomment it (plus the
stagingImplementation line) if you want to try it.
Two independent layers keep the inspector out of production: the release APK contains the no-op
artifact, and even the full library disables itself when FLAG_DEBUGGABLE is false. There is no
runtime switch that can turn it on in production.
- A crash record shows up only after you relaunch. The record is written before the process dies; the panel reads it on the next start.
- ANRs and native crashes need Android 11+ and are also reported on the next launch.
- No notifications? The Android 13+
POST_NOTIFICATIONSgrant is required. AppInspect declares the permission but has no Activity, so the host app must request it — seeMainActivity. - A network call is missing. Only clients that added
addAppInspectInterceptor()are captured. WebView traffic and other HTTP stacks are not visible. - Add the interceptor last on the OkHttp builder. A
SHORT_CIRCUITmock returns without callingproceed(), so anything registered after it is skipped. - Debug builds show real secrets — auth headers, tokens, database contents. That is intentional, and it is why exports should be redacted before being attached to a ticket.
- Full documentation: https://app-inspect-doc.vercel.app/
- Install guide: https://app-inspect-doc.vercel.app/install.html
- Builds and environments: https://app-inspect-doc.vercel.app/environments.html
- Configuration reference: https://app-inspect-doc.vercel.app/configuration.html
- QA checklist: https://app-inspect-doc.vercel.app/qa-checklist.html
Apache License 2.0 — see LICENSE. The wiring code in this sample is intended to be copy-pasted into your own project.