On Android cloud backups

14 June 2026

Wednesday morning started like any other, except I was on-call that week and got pinged to look into a rather strange issue. We had a user who had churned off our premium subscription a few months ago create a new account and use the app again. Nothing weird about that, except that they were seeing data & features from their old premium account in the app! 🤯

Looking at the API traces for the user revealed that we weren’t actually hitting any of the endpoints associated with fetching the data we were seeing. That narrowed the issue down to one possible thing. Somehow, somewhere, we had extremely stale cached data on the user’s device. Data that apparently survived the user reinstalling the app and creating a whole new account several months later.

How we manage & persist state

To understand how this could happen, we first need to go through how we manage app state. Like most React codebases from the 2010s, we overuse Redux for state management. Our store is organised using the ducks pattern where each product area roughly aligns with one redux slice. We then use redux-persist along with mmkv to persist the entire store (bar some sensitive exclusions) to disk periodically. This persisted cache is what’s hydrated into our store on following restarts.

The persisted cache is invalidated by each reducer handling a specific app.logout action, which reverts each slice back to it’s initialState. We then flush the store to disk to overwrite any previously cached data.

So how’d we run into the issue?

Another common thread between the reports was the use of Android. Somehow, our persisted data was surviving app installs, something we hadn’t considered a possibility. It turns out, Android will automatically back up all app files by default unless a specific setting is disabled in the Android manifest or a list of inclusions / exclusions is provided.

Sure enough, we had <application android:allowBackup="true" ... > set in our manifest with no backup rules configured. This meant that when an Android user uninstalled our app, any data that was previously backed up to the Google cloud would be restored when the app was subsequently installed. Our persisted cache is then rehydrated before the user logs in followed by weirdness in the app.

What we did to fix the issue

Initially, we just disabled backups by setting <application android:allowBackup="false" ... > - this stops Android from backing up our app files and doesn’t restore any backed up data when users install the app.

This sorts the issue above but not all Android device manufacturers respect this setting when it comes to device-to-device transfers. For this, we need to specify android:dataExtractionRules that specifically exclude the mmkv directory from cross-platform-transfers.