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

# Geofencing

The **Mapbox Maps SDK for iOS**'s [geofencing service](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/geofencingservice/) enables your application to receive events when a device enters, exits, or dwells in your own defined geofences (a virtual fence around a geographic feature). When your application receives these events you can then trigger actions, alerts, and notifications.

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

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

Inactive geofence

The user is outside the geofence.

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

Active geofence

The user is in the geofence.

![The user has left the geofence.](https://docs.mapbox.com/ios/assets/ideal-img/maps-guides-geofencing-exit.20583c3.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 the [User Location](https://docs.mapbox.com/ios/maps/guides/user-location/) section for more details. Additionally, the user must grant background location permission if you need to receive events while the app is in the background.

## Geofencing service

The [GeofencingService](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/geofencingservice/) 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 itself. See [GeofencingOptions](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/geofencingoptions/) for all the available configuration options.

After a user has granted location permission you can create a `GeofencingService` instance, configure it, and start observing geofencing events. One architectural approach is to create a class that will manage the geofencing service. For example, a Swift UI implementation could look like this:

```Swift
class Geofencing: ObservableObject {
  func start(_ completion: @escaping () -> Void) {
    let geofencing = GeofencingFactory.getOrCreate()

    // Optionally, configure the geofencing service here to adjust the maximum number of geofences.
    let geofencingOptions = GeofencingOptions(maximumMonitoredFeatures: 3000)
    geofencing.configure(options: geofencingOptions) { result in
      if case let .failure(error) = result {
        print("Configuring geofencing failed: \(error)")
        return
      }
      // Once the geofencing service is created and configured, you can add observers for geofencing events.
      // Here we add this class as an observer to receive geofencing events.
      geofencing.addObserver(observer: self) { result in
        print("Add observer: \(result)")
      }
      completion()
    }
  }
}

/// Then in your SwiftUI view
struct ContentView: View {
  @ObservedObject private var geofencing = Geofencing()

  var body: some View {
    Map() {
      // Your map code
    }
    .onMapLoaded { _ in
      geofencing.start {
          // You can now add geofences based on Features 
          // and start observing geofencing events.
          print("Geofencing service is ready")  
      }
  }
}
```

If your app uses geofencing while in the background, we recommend adding the observer as part of your application's `AppDelegate`. For a sample implementation of this approach see our [Examples application](https://github.com/mapbox/mapbox-maps-ios/tree/main/Sources/Examples), and specifically the [AppDelegate.swift](https://github.com/mapbox/mapbox-maps-ios/blob/main/Sources/Examples/AppDelegate.swift) class.

## Observing events

Implement the [GeofencingObserver](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/geofencingobserver/) protocol to be notified when the user's device enters, exits, or dwells in geofences.

```Swift
// Extend the Geofencing class created above to conform to the `GeofencingObserver` protocol
// This allows the Geofencing class to receive geofencing events
extension Geofencing: GeofencingObserver {
  // Inside the event you can find the specific geofence feature that was triggered
  func onEntry(event: GeofencingEvent) {
    print("onEntry() called with feature id = \(event.feature.identifier) at \(event.timestamp)")
  }

  func onDwell(event: GeofencingEvent) {
    print("onDwell() called with feature id = \(event.feature.identifier) at \(event.timestamp)")
  }

  func onExit(event: GeofencingEvent) {
    print("onExit() called with feature id = \(event.feature.identifier) at \(event.timestamp)")
  }

  func onError(error: GeofencingError) {
    print("onError() called with: error = \(error)")
  }

  func onUserConsentChanged(isConsentGiven: Bool) {
    print("onUserConsentChanged() called with: isConsentGiven = \(isConsentGiven)")
  }
}
```

> **Note (info): Dwell events**
> 
> For the geofencing service to generate dwell events each geofence feature must define a [dwellTimeKey](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/geofencingpropertieskeys/dwelltimekey) in minutes in its `Feature.properties` (see [GeofencingPropertiesKeys](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/geofencingpropertieskeys/)). After a user dwells in a geofence for the specified time, the geofencing service will trigger a dwell event.
> 
> ```json
> {
>   "type": "Feature",
>   "id": "eiffel_tower",
>   "properties": {
>     ...
>     "MBX_GEOFENCE_DWELL_TIME": 20
>     },
>   "geometry": { ... }
> }
> ```
> 
> You can also set the dwell time for [Features](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/feature/) by setting a property in your Swift code:
> 
> ```swift
> geofencingFeature.properties[GeofencingPropertiesKeys.dwellTimeKey] = 20
> ```

## 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 [pointRadiusKey](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/geofencingpropertieskeys/pointradiuskey/) given in the `Feature.properties` (see [GeofencingPropertiesKeys](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/geofencingpropertieskeys/)).
-   Polygon: the area is described by the polygon.
-   MultiPolygon: events will be triggered whenever the user's device enters or 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/ios/maps/api/latest/documentation/mapboxcommon/geofencingservice/addfeature(feature:callback:)/) method:

```Swift
let featureJSON = """
{
  "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 ]
      ]
    ]
  }
}
"""
if let featureData = featureJSON.data(using: .utf8) {
  let feature = try JSONDecoder().decode(Feature.self, from: featureData)
  geofencing.addFeature(feature: feature) { result in
    print("Add feature result: \(result)")
  }
}
```

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

```Swift
let featureJSON = """
{
  "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 ]
      ]
    ]
  }
}
"""
if let featureData = featureJSON.data(using: .utf8) {
  let feature = try JSONDecoder().decode(Feature.self, from: featureData)
  geofencing.addFeature(feature: feature) { result in
    print("Add feature result: \(result)")
  }
}
```

Later on, you can remove the feature by calling [removeFeature](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/geofencingservice/removefeature(identifier:callback:)/):

```Swift
val id = "eiffel_tower"
geofencing.removeFeature(identifier: id) { result in
  print("Remove feature result: \(result)")
}
```

You can also retrieve geofences directly from the service by their `id`:

```Swift
val id = "eiffel_tower"
geofencing.getFeature(identifier: id) { result in
  switch result {
  case let .success(feature):
    print("Feature found: \(feature)")
  case let .failure(error):
    print("Failed to get feature error: \(error)")
  }
}
```

Further, you can call [clearFeatures](https://docs.mapbox.com/ios/maps/api/latest/documentation/mapboxcommon/geofencingservice/clearfeatures(callback:)/) to remove all geofences:

```Swift
geofencing.clearFeatures { result in
  print("Cleared features: \(result)")
}
```