Why a repeatable device state matters
Investigating an app's API is a sequence of sessions, and each session depends on the state left by the one before it. A reproduced request is only reproducible while the conditions that produced it hold: the same install, the same stored credentials, the same set of derived identifiers, the same server side session. When any of those move, a working client starts failing in ways that look like a code defect.
Keeping one device for the work and changing it deliberately is what makes results comparable. A device that is also used for other installs, other accounts and automatic updates introduces changes you did not make and cannot easily unwind.
Install bound identifiers and what changes between installs
The values that break a reproduction often are created at install time and tied to the package instance rather than to the hardware. Uninstalling and reinstalling the app commonly produces a new set, and an app update can reset some of them while leaving others intact.
- A key pair generated in the platform keystore belongs to the install. Clear the app data or remove the package and the key is gone, along with anything encrypted under it and any signature the server has learned to expect.
- An app instance identifier stored in the app's private directory is created on first run. A reinstall produces a different value, and a server that has bound an account or a session to the old one rejects requests that carry the new one.
- A verification or attestation result is issued for a particular package and signing certificate. Rebuilding the app with a different signing key changes the result even when the code is identical.
- A server side session survives on the server rather than the device. The device can be perfectly preserved and the session still expire, which is why a reproduction plan records both.
Advertising identifiers and other resettable values behave differently again, since they can change without an install. Any value that the client reads and sends falls into one of these categories, and knowing which one tells you what survives an update.
Recording the state a client was validated against
A note that says the client worked is not enough to rebuild the conditions later. Record the state precisely at the moment a run succeeds, because the record is what you compare against when it stops working.
The device record covers the model, the Android version, the security patch level, whether the build is a user or userdebug build, and whether the bootloader state and root status are the ones the app expects. The app record covers the version name and version code, the signing certificate digest, the install time and the installer package, because an app that installed from a store can behave differently from one installed from a file.
The session record covers the account used, the time of the run, the tokens in play at that moment and which of them came from an interactive login rather than a refresh. Keep the captured requests from the successful run with the record, since they are the ground truth the next run is compared against.
Keeping the state long enough to be useful
Disable automatic updates for the app and for anything it depends on. Hold the device on a network you control, and keep a second device or emulator that stays on the old app version so a comparison is possible after an update lands.
Back up the app's private data with the keystore considerations in mind, because a data backup does not carry hardware backed keys, and restoring it onto a device with a different keystore does not restore the identifiers the server knows. Prefer to keep the original install alive over rebuilding it from a backup, and take a snapshot of the whole device state before any experiment that could change it, such as running a tool that writes to the app's directory.
When a device has to be wiped or replaced, plan the revalidation as its own task. The client will need its stored identifiers refreshed, and the server side session recreated, so the run that follows is a fresh validation rather than a continuation.
Where isolation fits the delivery
Device state is what separates a demonstration from a client the customer can run. The Python or TypeScript client is built to derive its own values rather than carry the ones observed on one handset, so it stops depending on the state of the phone it was validated on. SReverse recovers the signing scheme behind those derived values, and the client is delivered through APK to callable API with the device requirements written down, so a change of phone is a known step rather than a mystery.
Related work
Reviewed 28 September 2026 · SReverse research desk