> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sequenzy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Geofences

> Start sequences and build segments from visits to your stores and venues, reported by the Sequenzy mobile SDKs

A geofence is a circle around a place you care about: a store, a venue, an
airport. Your app's signed-in users who allow location access report when they
enter, leave or stay in one, and each visit becomes an event on their contact.
Use those events to start sequences, branch them, and build segments.

## Events

| Event | Recorded when |
| - | - |
| `app.geofence_entered` | The phone reports the contact entering the geofence. |
| `app.geofence_exited` | The phone reports the contact leaving it. |
| `app.geofence_dwelled` | The contact stayed inside for the geofence's dwell time. |

Every geofence event carries these properties, taken from the geofence when the
event is recorded:

| Property | Value |
| - | - |
| `geofenceId` | The geofence ID. |
| `geofenceName` | Its name. |
| `geofenceGroup` | Its group, or `null`. |
| `geofenceExternalId` | Your ID for the place, or `null`. |
| `dwellSeconds` | The dwell time (`app.geofence_dwelled` only). |

Events never contain coordinates: they say which of your places the contact
visited, not where they were.

Dwell is worked out by Sequenzy, not the phone: when the dwell time has passed
after an entry with no exit in between, `app.geofence_dwelled` is recorded.
A phone that was offline can report its exit after that point, so a short visit
close to the dwell time can occasionally count as a dwell.

## Set up your app

Each mobile SDK has a geofencing add-on. It watches the geofences nearest to
the user with the phone's region monitoring, so visits are reported also while
the app is in the background or closed. Only identified contacts are tracked:
nothing is watched or sent before `identify` succeeds, and `reset` stops it.
Your app needs "Always" location access with precise location.

> [tab] iOS
>
> Link the `SequenzyGeofences` product of
> `https://github.com/Sequenzy/sequenzy-swift`, and add
> `NSLocationWhenInUseUsageDescription` and
> `NSLocationAlwaysAndWhenInUseUsageDescription` to your Info.plist.
>
> ```swift theme={null}
> import SequenzyGeofences
>
> // application(_:didFinishLaunchingWithOptions:), after Sequenzy.configure
> SequenzyGeofences.shared.start()
>
> // Once the user agreed to location-based messages
> SequenzyGeofences.shared.requestAuthorization()
> SequenzyGeofences.shared.enable()
> ```

> [tab] Android
>
> Add `com.sequenzy:sequenzy-android-geofences`, declare
> `ACCESS_FINE_LOCATION` and `ACCESS_BACKGROUND_LOCATION`, and ask for them
> (background location in a second request on Android 10 and later).
>
> ```kotlin theme={null}
> // Application.onCreate, after Sequenzy.configure(...)
> SequenzyGeofences.start(this)
>
> // Once the user agreed and granted fine and background location
> SequenzyGeofences.enable(context)
> ```

> [tab] React Native
>
> Install `@sequenzy/react-native-geofences`, an Expo module (it needs a
> development build, not Expo Go), and add it to `plugins` in `app.json`
> with your location permission texts.
>
> ```ts theme={null}
> import { SequenzyGeofences } from "@sequenzy/react-native-geofences";
>
> // After Sequenzy.configure
> void SequenzyGeofences.start();
>
> // Once the user agreed to location-based messages
> await SequenzyGeofences.requestAuthorization();
> await SequenzyGeofences.enable();
> ```

> [tab] Flutter
>
> Add `sequenzy_flutter_geofences`, and the two location usage strings to
> `ios/Runner/Info.plist`. The plugin declares the Android permissions.
>
> ```dart theme={null}
> import 'package:sequenzy_flutter_geofences/sequenzy_flutter_geofences.dart';
>
> // After Sequenzy.configure
> await SequenzyGeofences.start();
>
> // Once the user agreed to location-based messages
> await SequenzyGeofences.requestAuthorization();
> await SequenzyGeofences.enable();
> ```

Call `disable()` when the user withdraws consent. On React Native and Flutter,
native code reports visits while your JavaScript or Dart is not running, using
the identity token the SDK last handed it, so configure an
`identityTokenProvider`: tokens that expire within three days, or that are
rejected, are replaced through it. A visit recorded without a connection is
sent with the next visit, or when the app starts or opens, within 24 hours. Google Play asks apps that use background
location for a declaration, and the App Store asks why you need "Always"
access: say that the app tells users about places they arrive at.

Apps that already monitor regions themselves can skip the add-on and call
`fetchNearbyGeofences` and `trackGeofenceTransition` on the core SDK; see the
[client endpoints](https://docs.sequenzy.com/concepts/mobile-sdks.md#client-endpoints).

## Add geofences

Add places under **Settings > Channels > Geofences**: click the map or paste coordinates
or a Google Maps link, then set a radius. You can also import a CSV or GeoJSON
file, or use the [API](https://docs.sequenzy.com/api-reference/geofences/create.md), the CLI
(`sequenzy geofences`) or the MCP server.

| Setting | Range | Notes |
| - | - | - |
| Radius | 100 to 10,000 meters | Phones trigger small regions late or not at all. Use 200 meters or more. |
| Dwell | 1 minute to 4 hours, optional | Without it, no `app.geofence_dwelled` events. |
| Cooldown | 5 minutes to 7 days | A repeat of the same transition by the same contact inside it is ignored. Default 1 hour. |
| Group | Optional label | Lets one trigger or segment cover every store at once. |
| External ID | Optional, unique | Your own ID for the place. Imports update by it. |

A workspace can have up to 10,000 geofences. Pause one to stop it without
losing its history. Adding, editing, pausing or deleting a geofence takes up
to a minute to reach every server, and apps pick up the change on their next
refresh.

## Start a sequence on a visit

Pick **Event received** as the trigger and choose `app.geofence_entered`,
`app.geofence_exited` or `app.geofence_dwelled`. A **Geofence** picker then
lets you limit it to one geofence or a group. Through the API, CLI or MCP, the
same trigger is an event trigger with a property filter, for example
`geofenceGroup equals stores` or `geofenceId one_of ["geo_123"]`.

## Segment by visits

Add a **Geofence** condition to a segment: entered, left or stayed in any
geofence, a group or one geofence, at least or fewer than a number of times,
within a number of days or ever. "Didn't happen" excludes contacts, so you can
find customers who have not been to a store in 30 days. In API filters the
field is `geofence` and the value is `transition:target:timeRange`, or
`transition:target:count:timeRange` for count operators, for example
`entered:group=stores:30d` or `dwelled:id=geo_123:2:90d`.

Time windows count whole days in UTC, so "last 30 days" includes all of the
day 30 days ago. Group conditions use each geofence's current group.

## Privacy

* Geofencing only runs for signed-in users, after your app enables it and the
  user grants location access. Get your users' consent as your local law
  requires.
* To find the nearest geofences, the app sends its position rounded to about
  1 km. Sequenzy does not store or log it.
* Deleting a contact deletes their geofence events and visit counts.

## Limits

To keep battery use and noise down, Sequenzy records at most 100 geofence
transitions per contact per day, and ignores repeats inside a geofence's
cooldown. Phones watch only a few regions per app (20 on iOS, 100 on Android),
so the SDK registers the geofences nearest to the user (19 on iOS, 49 on
Android) plus one region around the device, and fetches the next ones when the
device leaves it. Lower the SDK's `maxRegions` if your app watches regions of
its own.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.