GeofenceKit Start free
Android · Location

Android Geofences That Survive Reboot & App Updates

24 July 2026 · ~6 min read
TL;DR: Android's GeofencingClient keeps your geofences in Google Play services — and that store is wiped on device reboot, app update, and when location is toggled off/on. Nothing warns you. You have to re-register your geofences yourself on BOOT_COMPLETED, on MY_PACKAGE_REPLACED, and on app launch — from a list you persisted locally.

Your Android geofences work perfectly in testing. Then a user reboots their phone — and every geofence is gone, silently, until the next time they open your app. This is expected Android behavior, and it catches almost everyone. Here's precisely when Android drops geofences and how to make them stick.

Where Android keeps geofences (and why they vanish)

When you call GeofencingClient.addGeofences(), the geofences live inside Google Play services, not your app process. That's what lets them fire when your app is closed. But that store isn't permanent — the OS clears it on several everyday events, and it does not restore them or notify you.

When Android silently drops your geofences

The fix: re-register on the right events

The pattern is simple once you know the triggers: keep your geofence definitions in local storage, and re-add them to GeofencingClient whenever one of the "drop" events happens.

  1. Add a BroadcastReceiver for android.intent.action.BOOT_COMPLETED (needs the RECEIVE_BOOT_COMPLETED permission).
  2. Also handle android.intent.action.MY_PACKAGE_REPLACED for app updates.
  3. Re-register on app launch too, as a belt-and-suspenders backstop.
  4. Persist the geofence list locally (e.g. a small store) so you can re-add them offline, without waiting on a network call.

A minimal Kotlin sketch

class BootReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val a = intent.action
        if (a == Intent.ACTION_BOOT_COMPLETED ||
            a == Intent.ACTION_MY_PACKAGE_REPLACED) {
            // Re-add the geofences we persisted locally — no network needed.
            val zones = FenceStore.load(context)
            val client = LocationServices.getGeofencingClient(context)
            client.addGeofences(buildRequest(zones), geofencePendingIntent(context))
        }
    }
}
<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver android:name=".BootReceiver" android:exported="true">
  <intent-filter>
    <action android:name="android.intent.action.BOOT_COMPLETED" />
    <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
  </intent-filter>
</receiver>

Delivering events when the app is dead

Geofence transitions are delivered to a PendingIntent, so your BroadcastReceiver fires even when your app process isn't running. To act on it — show a notification, record the event — do that work in the receiver from locally-cached content. For the upload, hand it to WorkManager with a NetworkType.CONNECTED constraint rather than calling the network inline: the receiver's ~10-second window can't guarantee an HTTP request finishes, but a WorkManager job runs when connectivity returns and survives Doze and reboot. You do not need a persistent foreground service for geofencing.

Gotchas worth handling: request ACCESS_BACKGROUND_LOCATION on Android 10+ (and POST_NOTIFICATIONS on 13+); tune setNotificationResponsiveness() and a loitering delay for dwell; debounce boundary flapping from GPS jitter; and test on OEMs with aggressive battery management (Xiaomi, Huawei, Samsung), where users may need to allow "auto-start".

The short version

Android geofences are not durable — they're wiped on reboot, app update, and location toggles. Persist your zones locally and re-register them on BOOT_COMPLETED, MY_PACKAGE_REPLACED, and app start. Do that and your geofencing survives the real world. (The iOS side has its own trap — the 20-region limit.)

Skip the boilerplate

GeofenceKit re-registers on reboot and app update, uploads events in the background (WorkManager on Android, background URLSession on iOS) so delivery survives app-kill, Doze, and reboot, and fires notifications from cached content — as one SDK for Android, iOS, React Native, and Flutter. You manage zones in a dashboard; the SDK keeps them alive on-device.

Start free — get an API key