Skip to content

Geofences

Learn how to set up geofences for the Braze SDK. A geofence is a virtual geographic area that forms a circle around a specific global position, and is represented by combining latitude, longitude, and a radius.

Prerequisites

Before you can use this feature, you’ll need to integrate the Android Braze SDK. Additionally, you’ll need to set up silent push notifications.

Setting up geofences

Step 1: Update build.gradle

Add android-sdk-location to your app-level build.gradle. Also, add the Google Play Services location package using the Google Play Services setup guide:

1
2
3
4
dependencies {
  implementation "com.braze:android-sdk-location:+"
  implementation "com.google.android.gms:play-services-location:${PLAY_SERVICES_VERSION}"
}

Step 2: Update the manifest

Add boot, fine location, and background location permissions to your AndroidManifest.xml:

1
2
3
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

Add the Braze boot receiver to the application element of your AndroidManifest.xml:

1
2
3
4
5
<receiver android:name="com.braze.BrazeBootReceiver">
  <intent-filter>
    <action android:name="android.intent.action.BOOT_COMPLETED" />
  </intent-filter>
</receiver>

Step 3: Enable Braze location collection

If you have not yet enabled Braze location collection, update your braze.xml file to include com_braze_enable_location_collection and confirm its value is set to true:

1
<bool name="com_braze_enable_location_collection">true</bool>

Braze geofences are enabled if Braze location collection is enabled. If you would like to opt-out of our default location collection but still want to use geofences, it can be enabled selectively by setting the value of key com_braze_geofences_enabled to true in braze.xml, independently of the value of com_braze_enable_location_collection:

1
<bool name="com_braze_geofences_enabled">true</bool>

Step 4: Obtain location permissions from the end user

For Android M and higher versions, you must request location permissions from the end user before gathering location information or registering geofences.

Add the following call to notify Braze when a user grants the location permission to your app:

1
Braze.getInstance(context).requestLocationInitialization();
1
Braze.getInstance(context).requestLocationInitialization()

This will cause the SDK to request geofences from Braze servers and initialize geofence tracking.

See RuntimePermissionUtils.java in our sample application for an example implementation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class RuntimePermissionUtils {
  private static final String TAG = BrazeLogger.getBrazeLogTag(RuntimePermissionUtils.class);
  public static final int DROIDBOY_PERMISSION_LOCATION = 40;

  public static void handleOnRequestPermissionsResult(Context context, int requestCode, int[] grantResults) {
    switch (requestCode) {
      case DROIDBOY_PERMISSION_LOCATION:
        // In Android Q, we require both FINE and BACKGROUND location permissions. Both
        // are requested simultaneously.
        if (areAllPermissionsGranted(grantResults)) {
          Log.i(TAG, "Required location permissions granted.");
          Toast.makeText(context, "Required location permissions granted.", Toast.LENGTH_SHORT).show();
          Braze.getInstance(context).requestLocationInitialization();
        } else {
          Log.i(TAG, "Required location permissions NOT granted.");
          Toast.makeText(context, "Required location permissions NOT granted.", Toast.LENGTH_SHORT).show();
        }
        break;
      default:
        break;
    }
  }

  private static boolean areAllPermissionsGranted(int[] grantResults) {
    for (int grantResult : grantResults) {
      if (grantResult != PackageManager.PERMISSION_GRANTED) {
        return false;
      }
    }
    return true;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
object RuntimePermissionUtils {
  private val TAG = BrazeLogger.getBrazeLogTag(RuntimePermissionUtils::class.java!!)
  val DROIDBOY_PERMISSION_LOCATION = 40

  fun handleOnRequestPermissionsResult(context: Context, requestCode: Int, grantResults: IntArray) {
    when (requestCode) {
      DROIDBOY_PERMISSION_LOCATION ->
        // In Android Q, we require both FINE and BACKGROUND location permissions. Both
        // are requested simultaneously.
        if (areAllPermissionsGranted(grantResults)) {
          Log.i(TAG, "Required location permissions granted.")
          Toast.makeText(context, "Required location permissions granted.", Toast.LENGTH_SHORT).show()
          Braze.getInstance(context).requestLocationInitialization()
        } else {
          Log.i(TAG, "Required location permissions NOT granted.")
          Toast.makeText(context, "Required location permissions NOT granted.", Toast.LENGTH_SHORT).show()
        }
      else -> {
      }
    }
  }

  private fun areAllPermissionsGranted(grantResults: IntArray): Boolean {
    for (grantResult in grantResults) {
      if (grantResult != PackageManager.PERMISSION_GRANTED) {
        return false
      }
    }
    return true
  }
}

Using the preceding sample code is done via:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    boolean hasAllPermissions = PermissionUtils.hasPermission(getApplicationContext(), Manifest.permission.ACCESS_BACKGROUND_LOCATION)
        && PermissionUtils.hasPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION);
    if (!hasAllPermissions) {
      // Request both BACKGROUND and FINE location permissions
      requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION},
          RuntimePermissionUtils.DROIDBOY_PERMISSION_LOCATION);
    }
  } else {
    if (!PermissionUtils.hasPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION)) {
      // Request only FINE location permission
      requestPermissions(new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION},
          RuntimePermissionUtils.DROIDBOY_PERMISSION_LOCATION);
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    val hasAllPermissions = PermissionUtils.hasPermission(applicationContext, Manifest.permission.ACCESS_BACKGROUND_LOCATION)
        && PermissionUtils.hasPermission(applicationContext, Manifest.permission.ACCESS_FINE_LOCATION)
    if (!hasAllPermissions) {
      // Request both BACKGROUND and FINE location permissions
      requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION),
          RuntimePermissionUtils.DROIDBOY_PERMISSION_LOCATION)
    }
  } else {
    if (!PermissionUtils.hasPermission(applicationContext, Manifest.permission.ACCESS_FINE_LOCATION)) {
      // Request only FINE location permission
      requestPermissions(arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
          RuntimePermissionUtils.DROIDBOY_PERMISSION_LOCATION)
    }
  }
}

Step 5: Enable geofences on the dashboard

Android only allows up to 100 geofences to be stored for a given app. Braze locations products will use up to 20 geofence slots if available. To prevent accidental or unwanted disruption to other geofence-related functionality in your app, location geofences must be enabled for individual apps on the dashboard.

For Braze locations products to work correctly, confirm that your app is not using all available geofence spots.

Enable geofences from the locations page

The geofence options on the Braze locations page.

Enable geofences from the settings page

The geofence checkbox located on the Braze settings pages.

Step 6: Manually request geofence updates (optional)

By default, Braze automatically retrieves the device’s location and requests geofences based on that collected location. However, you can manually provide a GPS coordinate that will be used to retrieve proximal Braze geofences instead. To manually request Braze Geofences, you must disable automatic Braze geofence requests and provide a GPS coordinate for requests.

Step 6.1: Disable automatic geofence requests

Automatic Braze geofence requests can be disabled in your braze.xml file by setting com_braze_automatic_geofence_requests_enabled to false:

1
<bool name="com_braze_automatic_geofence_requests_enabled">false</bool>

This can additionally be done at runtime via:

1
2
3
BrazeConfig.Builder brazeConfigBuilder = new BrazeConfig.Builder()
    .setAutomaticGeofenceRequestsEnabled(false);
Braze.configure(getApplicationContext(), brazeConfigBuilder.build());
1
2
3
val brazeConfigBuilder = BrazeConfig.Builder()
    .setAutomaticGeofenceRequestsEnabled(false)
Braze.configure(applicationContext, brazeConfigBuilder.build())

Step 6.2: Manually request Braze geofence with GPS coordinate

Braze Geofences are manually requested via the requestGeofences() method:

1
Braze.getInstance(getApplicationContext()).requestGeofences(latitude, longitude);
1
Braze.getInstance(applicationContext).requestGeofences(33.078947, -116.601356)

Enabling push-to-sync

Note that Braze syncs geofences to devices using background push. In most cases, this will involve no code changes, as this feature requires no further integration on the part of the app.

However, note that if your application is stopped, receiving a background push will launch it in the background and its Application.onCreate() method will be called. If you have a custom Application.onCreate() implementation, you should defer automatic server calls and any other actions you would not want to be triggered by background push.

Prerequisites

Before you can use this feature, you’ll need to integrate the Swift Braze SDK. Additionally, you’ll need to set up silent push notifications.

Setting up geofences

Step 1: Enable location services

Braze location services must be enabled through the SDK. They are not enabled by default.

Step 2: Enable geofences

Enable geofences by setting location.geofencesEnabled to true on the configuration object that initializes theBraze instance. For other location configuration options, see Braze Swift SDK reference.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let configuration = Braze.Configuration(
  apiKey: "<BRAZE_API_KEY>",
  endpoint: "<BRAZE_ENDPOINT>"
)
configuration.location.brazeLocationProvider = BrazeLocationProvider()
configuration.location.automaticLocationCollection = true
configuration.location.geofencesEnabled = true
configuration.location.automaticGeofenceRequests = true

// Configurations for background geofence reporting with `When In Use` authorization.
configuration.location.allowBackgroundGeofenceUpdates = true
configuration.location.distanceFilter = 8000

let braze = Braze(configuration: configuration)
AppDelegate.braze = braze
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
BRZConfiguration *configuration =
    [[BRZConfiguration alloc] initWithApiKey:brazeApiKey
                                    endpoint:brazeEndpoint];
configuration.logger.level = BRZLoggerLevelInfo;
configuration.location.brazeLocationProvider = [[BrazeLocationProvider alloc] init];
configuration.location.automaticLocationCollection = YES;
configuration.location.geofencesEnabled = YES;
configuration.location.automaticGeofenceRequests = YES;

// Configurations for background geofence reporting with `When In Use` authorization.
configuration.location.allowBackgroundGeofenceUpdates = YES;
configuration.location.distanceFilter = 8000;

Braze *braze = [[Braze alloc] initWithConfiguration:configuration];
AppDelegate.braze = braze;

Configuring geofences for background reporting

By default, geofences are only monitored if your app is in the foreground, or it has Always authorization (which monitors all application states).

However, you can choose to monitor geofence events when your app is in the background or when it has the When In Use authorization by adding the Background Mode -> Location updates capability to your Xcode project and enabling allowBackgroundGeofenceUpdates. This let’s Braze extend your app’s “in use” status by continuously monitoring location updates.

allowBackgroundGeofenceUpdates only works when your app is in the background. When it re-opens, it’s existing background processes are paused, so foreground processes can be prioritized instead.

Step 3: Verify background push

Braze syncs geofences to devices using background push notifications. Follow the ignoring silent push article to ensure that your application does not take any unwanted actions upon receiving Braze geofence sync notifications.

Step 4: Update your Info.plist

Add the key NSLocationAlwaysUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription or NSLocationWhenInUseUsageDescription to your info.plist with a String value that has a description of why your application needs to track location.

This description will be shown when the system location prompt requests authorization and should clearly explain the benefits of location tracking to your users.

Step 5: Request authorization

When requesting authorization from a user, you can request When In Use or Always authorization.

To request When In Use authorization, use the requestWhenInUseAuthorization() method:

1
2
var locationManager = CLLocationManager()
locationManager.requestWhenInUseAuthorization()
1
2
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
[locationManager requestWhenInUseAuthorization];

By default, requestAlwaysAuthorization() only grants your app When In Use authorization and will re-prompt your user for Always authorization after some time has passed. However, you can choose to immediately prompt your user by first calling requestWhenInUseAuthorization(), then calling requestAlwaysAuthorization() after receiving your initial When In Use authorization.

1
2
var locationManager = CLLocationManager()
locationManager.requestAlwaysAuthorization()
1
2
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
[locationManager requestAlwaysAuthorization];

Step 6: Configure the dashboard

iOS only allows up to 20 geofences to be stored for a given app. With geofences enabled, Braze will use up some of these 20 available slots. To prevent accidental or unwanted disruption to other geofence-related functionality in your app, location geofences must be enabled for individual apps on the dashboard. For our location services to work correctly, check that your app is not using all available geofence spots.

There are two ways to enable geofences for a particular app: from the Locations page or from the Manage Settings page.

Enable geofences on the Locations page of the dashboard.

  1. Go to Audience > Locations.
  2. The number of apps in your workspace that currently have geofences enabled is displayed beneath the map, for example: 0 of 1 Apps with Geofences enabled. Click this text.
  3. Select the app to enable geofences. Click Done. The geofence options on the Braze locations page.

Enable geofences from your app’s settings.

  1. Go to Settings > App Settings.
  2. Select the app for which you wish to enable geofences.
  3. Select the Geofences Enabled checkbox. Click Save.

The geofence checkbox located on the Braze settings pages.

Disabling automatic geofence requests

Step 1: Set automaticGeofenceRequests to false

You can disable automatic geofence requests in your configuration object passed to init(configuration). Set automaticGeofenceRequests to false. For example:

1
2
3
4
5
6
7
let configuration = Braze.Configuration(
  apiKey: "{BRAZE_API_KEY}",
  endpoint: "{BRAZE_ENDPOINT}"
)
configuration.automaticGeofencesRequest = false
let braze = Braze(configuration: configuration)
AppDelegate.braze = braze
1
2
3
4
5
6
BRZConfiguration *configuration =
  [[BRZConfiguration alloc] initWithApiKey:{BRAZE_API_KEY}
                                  endpoint:{BRAZE_ENDPOINT}];
configuration.automaticGeofencesRequest = NO;
Braze *braze = [[Braze alloc] initWithConfiguration:configuration];
AppDelegate.braze = braze;

Step 2: Manually request geofences

When the Braze SDK requests geofences to monitor from the backend, it reports the user’s current location and receives geofences that are determined to be optimally relevant based on the location reported. There is a rate limit of one geofence refresh per session.

To control the location that the SDK reports for the purposes of receiving the most relevant geofences, you can manually request geofences by providing the latitude and longitude of a location. It is recommended to disable automatic geofence requests when using this method. To do so, use the following code:

1
AppDelegate.braze?.requestGeofences(latitude: latitude, longitude: longitude)
1
2
[AppDelegate.braze requestGeofencesWithLatitude:latitude
                                      longitude:longitude];
HOW HELPFUL WAS THIS PAGE?
New Stuff!