> For the complete documentation index, see [llms.txt](https://docs.mapbox.com/android/maps/llms.txt)

# Geofencing

The Mapbox Maps SDK for Android's [geofencing service](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.common.geofencing/) enables your application to observe when a device enters, exits, or remains within your own defined geofences (a virtual fence around a geographic feature).

You can use these monitored events to trigger actions, alerts, and notifications.

> **Related content (example): [See Geofencing Examples](https://docs.mapbox.com/android/maps/examples/android-view/simple-geofencing/)**
> 
> See how the `GeofencingService` is used to execute actions when a device enters, exits, or remains within the geofences.

![The user is outside the geofence.](https://docs.mapbox.com/android/assets/ideal-img/maps-guides-geofencing-inactive.1abc602.480.png)

Inactive geofence

The user is outside the geofence.

![The user is in the geofence.](https://docs.mapbox.com/android/assets/ideal-img/maps-guides-geofencing-active.e873f8d.480.png)

Active geofence

The user is in the geofence.

![The user has left the geofence.](https://docs.mapbox.com/android/assets/ideal-img/maps-guides-geofencing-exit.5a7b4d9.480.png)

Exit geofence

The user has left the geofence.

Before you can use the geofencing component, users must grant your application permission to access their location. See sections [Step 2: (Optional) Configure permissions](https://docs.mapbox.com/android/maps/guides/install/) and [Permission handling](https://docs.mapbox.com/android/maps/guides/user-location/permissions/) for more details. Moreover, the user must grant background location permission if you need to observe events while the app is in the background.

## Geofencing service

The [GeofencingService](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.common.geofencing/-geofencing-service/) is the main entry point to the Mapbox geofencing component. It allows you to manage geofences, start/stop observing events and configure the geofencing service.

After user has granted location permission you can get a `GeofencingService` instance and configure it:

```Kotlin
if (PermissionsManager.areLocationPermissionsGranted(context)
  && PermissionsManager.isBackgroundLocationPermissionGranted(context)) {

  // Permissions are granted, we can use GeofencingService
  val geofencing: GeofencingService = GeofencingFactory.getOrCreate()

  // Optionally, configure geofencing service. For example, increase maximum number of geofences:
  val geofencingOptions = geofencingOptions { maximumMonitoredFeatures = 300_000 }
  geofencing.configure(geofencingOptions) { result ->
    result.onError { geofenceError ->
      Log.d(TAG, "geofence.configure() error $geofenceError")
    }
  }
}
```

Check [GeofencingOptions.Builder](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.common.geofencing/-geofencing-options/-builder/) for all the available configuration options.

Once the geofencing service is created and configured, you can add observers for geofencing events.

## Observing events

Use the [GeofencingObserver](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.common.geofencing/-geofencing-observer/) to be notified when user's device enters, exits, or remains within geofences.

```Kotlin
// Build your GeofencingObserver
private val observer: GeofencingObserver = object : GeofencingObserver {
  override fun onEntry(event: GeofencingEvent) {
    // Inside the event you can find the geofence feature triggered
    val feature: Feature = event.feature
    Log.d(TAG, "onEntry() called with: feature id = ${feature.id()} at ${event.timestamp}")
  }

  override fun onDwell(event: GeofencingEvent) {
    Log.d(TAG, "onDwell() called with:  feature id = ${event.feature.id()} at ${event.timestamp}")
  }

  override fun onExit(event: GeofencingEvent) {
    Log.d(TAG, "onExit() called with:  feature id = ${event.feature.id()} at ${event.timestamp}")
  }

  override fun onError(error: GeofencingError) {
    Log.d(TAG, "onError() called with: error = $error")
  }

  override fun onUserConsentChanged(isConsentGiven: Boolean) {
    Log.d(TAG, "onUserConsentChanged() called with: isConsentGiven = $isConsentGiven")
  }
}

// Then, add it to the geofencing service
geofencing.addObserver(observer) { result: Expected<GeofencingError, Unit> ->
  if (result.isError) {
    logD(TAG, "addObserver() failed: ${result.error}")
  } else {
    logD(TAG, "Geofencing observer added successfully")
  }
}
```

If your app uses geofencing while in the background, we recommend adding the observer as part of the `Application.onCreate`.

## Geofences management

You must provide a [GeoJSON](https://docs.mapbox.com/help/glossary/geojson/) feature for each geofence you want to create. The following geoJSON geometries are supported:

-   Point: the monitored area is a circle around the point defined by the radius given in the `Feature.properties` (see [GeofencingPropertiesKeys](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.common.geofencing/-geofencing-properties-keys/)).
-   Polygon: the area is described by the polygon.
-   MultiPolygon: events will be triggered whenever user's device enters/exits any of the multiple polygons defined in the geometry.

> **Note (info): Quickly create GeoJSON features**
> 
> You can visit [geojson.io](https://geojson.io/) to create and edit GeoJSON features.

Each feature must define a unique string identifier (`id`). For example:

```json
{
  "type": "Feature",
  "id": "eiffel_tower",
  "properties": {
    "name": "Eiffel Tower"
   },
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [2.291903984967945, 48.85772344046961],
        [2.293390631169075, 48.85669301371263],
        [2.296888622230682, 48.859015366890844],
        [2.2952747763545176, 48.860087588194006],
        [2.291903984967945, 48.85772344046961]
      ]
    ]
  }
}
```

To add above GeoJSON feature to the geofencing service you must call the [addFeature](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.common.geofencing/-geofencing-service/add-feature.html) method:

```kotlin
val feature:Feature = Feature.fromJson(
"""
{
  "type": "Feature",
  "id": "eiffel_tower",
  "properties": {
    "name": "Eiffel Tower"
    },
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [ 2.291903984967945, 48.85772344046961 ],
        [ 2.293390631169075, 48.85669301371263 ],
        [ 2.296888622230682, 48.859015366890844 ],
        [ 2.2952747763545176, 48.860087588194006 ],
        [ 2.291903984967945, 48.85772344046961 ]
      ]
    ]
  }
}
""".trimIndent())
geofencing.addFeature(feature) { result ->
  if (result.isError) {
    Log.e(TAG, "Failed to add feature error: ${result.error}")
  } else {
    Log.d(TAG, "Feature [${result.value}] added successfully")
  }
}
```

To update a geofence you need to call `addFeature` again with the same feature identifier. For example, let's add a new property `rating`:

```Kotlin
val updatedFeature:Feature = Feature.fromJson(
"""
{
  "type": "Feature",
  "id": "eiffel_tower",
  "properties": {
    "name": "Eiffel Tower",
    "rating": 4.5
   },
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [ 2.291903984967945, 48.85772344046961 ],
        [ 2.293390631169075, 48.85669301371263 ],
        [ 2.296888622230682, 48.859015366890844 ],
        [ 2.2952747763545176, 48.860087588194006 ],
        [ 2.291903984967945, 48.85772344046961 ]
      ]
    ]
  }
}
""".trimIndent())
geofencing.addFeature(updatedFeature) { result ->
  if (result.isError) {
    Log.e(TAG, "Failed to add feature error: ${result.error}")
  } else {
    Log.d(TAG, "Feature [${result.value}] added successfully")
  }
}
```

Later on, you can remove the feature by calling [removeFeature](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.common.geofencing/-geofencing-service/remove-feature.html):

```Kotlin
val id = "eiffel_tower"
geofencing.removeFeature(id) { result ->
  if (result.isError){
    Log.e(TAG, "Failed to remove feature error: ${result.error}")
  } else {
    Log.d(TAG, "Feature [$id] removed successfully")
  }
}
```

You can also retrieve geofences directly from the service by their `id` using [getFeature()](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.common.geofencing/-geofencing-service/get-feature.html):

```Kotlin
val id = "eiffel_tower"
geofencing.getFeature(id) { result ->
  if (result.isError) {
    Log.e(TAG, "Failed to get feature error: ${result.error}")
  } else {
    val eiffelTowerFeature = result.value!!.feature
    Log.d(TAG, "Feature [$id] found: $eiffelTowerFeature")
  }
}
```

You can call [clearFeatures](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.common.geofencing/-geofencing-service/clear-features.html) to remove all geofences:

```Kotlin
geofencing.clearFeatures { result ->
  if (result.isError) {
    Log.e(TAG, "Failed to clear features error: ${result.error}")
  } else {
    Log.d(TAG, "All features removed successfully")
  }
}
```

> **Note (info): Dwell events**
> 
> For the geofencing service to generate dwell events each geofence feature must define a dwell time in minutes in its `Feature.properties` (see [GeofencingPropertiesKeys](https://docs.mapbox.com/android/maps/api/latest/mapbox-maps-android/com.mapbox.common.geofencing/-geofencing-properties-keys/)):
> 
> ```json
> {
>   "type": "Feature",
>   "id": "eiffel_tower",
>   "properties": {
>     ...
>     "MBX_GEOFENCE_DWELL_TIME": 20
>     },
>   "geometry": { ... }
> }
> ```