# Location tracking

## How it works[](#how-it-works)

The Location module captures location (with user consent) from your app and attaches it to a person’s profile in Customer.io. You can use this data for geo-aware messaging and audience segmentation with more accuracy than [IP-based geolocation](/journeys/geolocation/).

When you identify a person, the SDK includes the latest location in the identify call. The SDK also sends a `Location Update` event to the person’s activity timeline, which you can use in journeys and segments. To balance location updates with battery and data usage, the SDK limits location updates once a day (at most)—and only sends that update when the person has moved a meaningful distance since the last update.

The SDK does not request location permission on its own—your app must handle the permission flow.

## Install the location module[](#install)

The Location module requires native dependencies on both iOS and Android. Follow the platform-specific steps below.

1.  Add the following property to your project’s `android/gradle.properties` file:
    
    ```properties
    customerio_location_enabled=true
    ```
    

 CocoaPods

#### CocoaPods[](#CocoaPods)

2.  Add the `location` subspec to your Podfile. Open `ios/Podfile` in your Flutter project and add the following line alongside your existing `customer_io` pod:
    
    ```ruby
    pod 'customer_io/location', :path => '.symlinks/plugins/customer_io/ios'
    ```
    

 SPM

#### SPM[](#SPM)

No additional iOS setup is needed. The `customerio_location_enabled` flag you set in `gradle.properties` also controls whether the Location module is included via SPM on iOS.

If the flag isn’t detected (e.g. in Flutter add-to-app modules or some CI environments), you can set the `CIO_LOCATION` environment variable instead:

```bash
CIO_LOCATION=true flutter build ios
```

You can also set this in Android Studio under **Run** > **Edit Configurations** > **Environment variables**.

## Initialize the SDK with the location module[](#initialize-the-sdk-with-the-location-module)

Add a `locationConfig` to your `CustomerIOConfig` to enable the module. The `trackingMode` property controls how and when the SDK captures location.

Option

Type

Default

Description

`trackingMode`

`LocationTrackingMode`

`manual`

Controls how and when the SDK captures location. See [tracking modes](#tracking-modes) below.

### Tracking modes[](#tracking-modes)

Mode

Description

`LocationTrackingMode.manual`

Your app controls when it captures location. Call `setLastKnownLocation()` or `requestLocationUpdate()` to provide location. Use this when your app already has a location-tracking mechanism or you want full control over when you capture location data.

`LocationTrackingMode.onAppStart`

The SDK automatically captures a one-shot location once per app launch when your app enters the foreground. You can still call `setLastKnownLocation()` or `requestLocationUpdate()` alongside automatic capture. Use this for hands-off location tracking with minimal battery impact.

`LocationTrackingMode.off`

Disables location tracking entirely. All location calls become silent and location is not included in identify calls. Use this if you want to register the module but disable it at runtime.

```dart
CustomerIO.initialize(
  config: CustomerIOConfig(
    cdpApiKey: 'YOUR_CDP_API_KEY',
    // ...other config options
    locationConfig: LocationConfig(
      trackingMode: LocationTrackingMode.manual,
    ),
  ),
);
```

## Location APIs[](#location-apis)

The module provides two methods to capture location. You can call either method as often as you like; the SDK always caches the latest coordinates for profile enrichment, but sends a `Location Update` event no more than once a day—and only if the person has moved a meaningful distance since the last update. No matter how frequently you call these methods, the SDK throttles the updates for you so as not to overwhelm your workspace with profile updates.

### `setLastKnownLocation`[](#setlastknownlocation)

Pass coordinates directly from your app’s own location system. This doesn’t require any location permissions from the SDK. Your app manages location access independently of Customer.io.

Parameter

Type

Description

`latitude`

`double`

Latitude in degrees. Must be between -90 and 90.

`longitude`

`double`

Longitude in degrees. Must be between -180 and 180.

```dart
// Pass coordinates from your app's location provider
CustomerIO.location.setLastKnownLocation(
  latitude: 37.7749,
  longitude: -122.4194,
);
```

### `requestLocationUpdate`[](#requestlocationupdate)

Request a one-shot location from the native platform’s location services. Use this if your app doesn’t have its own location system. Your app must request location permission before calling this method—the SDK won’t prompt the user.

If a user doesn’t grant permission or location services are disabled, the request is ignored—no crash or exception. If a request is already in progress, additional calls are ignored until the current request completes.

1.  Add the required key to your `Info.plist`:
    
    ```xml
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>We use your location to personalize your experience.</string>
    ```
    
2.  **(Optional)** If you want more precise location, add `ACCESS_FINE_LOCATION` to your `AndroidManifest.xml`. The SDK already includes `ACCESS_COARSE_LOCATION` when the location module is enabled.
    
    ```xml
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    ```
    
3.  After your app requests and receives permission at runtime, call the SDK:
    
    ```dart
    // After location permission is granted
    CustomerIO.location.requestLocationUpdate();
    ```
    

 We recommend using a package like [geolocator](https://pub.dev/packages/geolocator) or [location](https://pub.dev/packages/location) to handle location permission requests in your Flutter app.

## Profile switch behavior[](#profile-switch-behavior)

When you call `CustomerIO.instance.clearIdentify()`, the SDK clears cached location data so that one person’s location doesn’t carry over to another person’s profile. The next person you identify starts with a clean slate.

Location persists across app restarts. When your app relaunches, the SDK restores the cached location so that the next `identify()` call includes it automatically.