Skip to content

PersistenceConfig

class PersistenceConfig

Persistence and storage configuration for the background geolocation SDK.

PersistenceConfig controls how the SDK stores, orders, templates, and purges records in its on-device SQLite database — the durable buffer between data producers (locations, geofences) and consumers (your app and the HTTP service).

Contents

Overview

The SDK maintains an internal SQLite database as a rolling queue. Each recorded Location and geofence event is written immediately, then consumed and deleted by downstream services. The SDK prefers an empty database — records exist only while awaiting upload or retrieval.

Category Properties Notes
Retention maxDaysToPersist, maxRecordsToPersist TTL and count-based purge limits.
Ordering locationsOrderDirection Controls upload and retrieval order.
Templates locationTemplate, geofenceTemplate Custom JSON structure for uploads.
Extras extras Static key/value pairs merged into every record.
Persist mode persistMode Which event types are written to SQLite.
Diagnostics disableProviderChangeRecord Suppress provider-change records.
BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    maxDaysToPersist: 3,
    maxRecordsToPersist: 1000,
    extras: {
      'user_id': 123,
      'appVersion': '1.2.3'
    },
    persistMode: PersistMode.all
  )
));

Storage lifecycle

Records are written to SQLite immediately upon recording and deleted when any of the following occur:

Inspect the pending queue with BackgroundGeolocation.getCount or BackgroundGeolocation.getLocations.


Ordering

locationsOrderDirection controls the order in which records are selected for upload or returned by BackgroundGeolocation.getLocations:

  • "ASC" — oldest first (default)
  • "DESC" — newest first

Templates

By default the SDK serializes locations and geofence events using its standard JSON schema. Use locationTemplate and geofenceTemplate to substitute a custom ERB template that reshapes the JSON to match your backend.

Use extras to merge static key/value metadata into every record at write time, without a custom template.


Persist mode

persistMode controls which event types are written to SQLite. All events are still delivered to their live callbacks (BackgroundGeolocation.onLocation, BackgroundGeolocation.onGeofence) regardless of this setting. Events that are not persisted are not eligible for HTTP uploads via HttpConfig.url.

The persist option on individual API calls can override this setting per-request:

final location = await BackgroundGeolocation.getCurrentPosition({
  persist: true,
  extras: { get_current_position: true },
  samples: 3,
});

Examples
final state = await BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    maxDaysToPersist: 14,
    maxRecordsToPersist: 5000,
    locationsOrderDirection: 'ASC',
    persistMode: PersistMode.all,
    extras: { user_id: 123, appVersion: '1.2.3' },
  ),
  http: HttpConfig(
    url: 'https://example.com/locations',
    autoSync: true,
  )
));
final pending = await BackgroundGeolocation.count;
print('Pending records: ${pending}');

// Purge all records
final ok = await BackgroundGeolocation.destroyLocations();
print('Destroyed all records? ${ok}');
BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    locationTemplate: '{
      "lat": <%= latitude %>,
      "lng": <%= longitude %>,
      "ts": "<%= timestamp %>",
      "meta": <%= JSON.stringify(extras) %>
    }',
    geofenceTemplate: '{
      "id": "<%= identifier %>",
      "action": "<%= action %>",
      "ts": "<%= timestamp %>"
    }',
  ),
));
Configure persistence behavior
final state = await BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    maxDaysToPersist: 14,
    maxRecordsToPersist: 5000,
    locationsOrderDirection: 'ASC',
    persistMode: PersistMode.all,
    extras: { user_id: 123, appVersion: '1.2.3' },
  ),
  http: HttpConfig(
    url: 'https://example.com/locations',
    autoSync: true,
  )
));
Inspect and purge the database
final pending = await BackgroundGeolocation.count;
print('Pending records: ${pending}');

// Purge all records
final ok = await BackgroundGeolocation.destroyLocations();
print('Destroyed all records? ${ok}');
Custom JSON templates
BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    locationTemplate: '{
      "lat": <%= latitude %>,
      "lng": <%= longitude %>,
      "ts": "<%= timestamp %>",
      "meta": <%= JSON.stringify(extras) %>
    }',
    geofenceTemplate: '{
      "id": "<%= identifier %>",
      "action": "<%= action %>",
      "ts": "<%= timestamp %>"
    }',
  ),
));
final pending = await BackgroundGeolocation.count;
print('Pending records: ${pending}');

// Purge all records
final ok = await BackgroundGeolocation.destroyLocations();
print('Destroyed all records? ${ok}');
BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    locationTemplate: '{
      "lat": <%= latitude %>,
      "lng": <%= longitude %>,
      "ts": "<%= timestamp %>",
      "meta": <%= JSON.stringify(extras) %>
    }',
    geofenceTemplate: '{
      "id": "<%= identifier %>",
      "action": "<%= action %>",
      "ts": "<%= timestamp %>"
    }',
  ),
));

Members

disableProviderChangeRecord

bool? disableProviderChangeRecord

Android only Disables the automatic insertion of a synthetic "provider-change" location into the SDK's SQLite database and its subsequent HTTP upload.

By default, when an BackgroundGeolocation.onProviderChange event fires, the Android SDK records a special location documenting when and where the device's location-services state changed (e.g., GPS disabled). This behavior historically existed to support platforms with limited or unreliable Headless Task implementations (e.g., Cordova, Capacitor).

Set this to true if your server-side JSON schema or locationTemplate cannot accommodate the automatically injected provider field.

BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    disableProviderChangeRecord: true
 )
));

extras

Map<String, dynamic>? extras

Optional arbitrary key/value pairs merged into each recorded location at write time.

These values are persisted and included in all HTTP uploads, making them ideal for attaching static contextual metadata such as user_id, route_id, or session_id.

See also - HTTP Guide

BackgroundGeolocation.ready(Config(
  http: HttpConfig(
    url: "https://my-server.com/locations",
    params: {
      device_id: "abc123"  // appended to root JSON of each POST request
    }
  ),
  persistence: PersistenceConfig(
    extras: {
      route_id: 1234       // merged onto each location record
    }
  )
));

The resulting HTTP request body:

POST /locations
{
  "device_id": "abc123",
  "location": {
    "coords": {
      "latitude": 45.51927004945047,
      "longitude": -73.61650072045029
    },
    "extras": {
      "route_id": 1234
    }
  }
}

geofenceTemplate

String? geofenceTemplate

Optional custom ERB template for reshaping GeofenceEvent JSON in HTTP uploads.

Behaves like locationTemplate but includes two additional tags: geofence.identifier and geofence.action. Use Ruby-style ERB tags to interpolate field values:

<%= variable_name %>
BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    geofenceTemplate:
      '{ "lat":<%= latitude %>, "lng":<%= longitude %>, "geofence":"<%= geofence.identifier %>:<%= geofence.action %>" }'
  )
));

// Or a compact Array form:
BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    geofenceTemplate:
      '[<%= latitude %>, <%= longitude %>, "<%= geofence.identifier %>", "<%= geofence.action %>"]'
  )
));

Warning

The SDK does not automatically apply double-quotes around string data. Templates are JSON-encoded exactly as written.

BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    geofenceTemplate: '{"timestamp": <%= timestamp %>}'
  )
));

Produces invalid JSON:

{"timestamp": 2018-01-01T12:01:01.123Z}
BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    geofenceTemplate: '{"timestamp": "<%= timestamp %>"}'
  )
));
{"timestamp": "2018-01-01T12:01:01.123Z"}
Template tags

Identical to locationTemplate with the following additions:

Tag Type Description
geofence.identifier String Identifier of the activated geofence
geofence.action String "ENTER" or "EXIT"
latitude Float
longitude Float
speed Float Meters
heading Float Degrees
accuracy Float Meters
altitude Float Meters
altitude_accuracy Float Meters
timestamp String ISO-8601
uuid String Unique ID
event String motionchange, geofence, heartbeat, providerchange
odometer Float Meters
activity.type String still, on_foot, running, on_bicycle, in_vehicle, unknown
activity.confidence Integer 0–100%
battery.level Float 0–100%
battery.is_charging Boolean Whether device is plugged in
mock Boolean True when location was generated from a mock app
is_moving Boolean True if recorded while in moving state
timestampMeta Object Timestamp metadata; see GeoConfig.enableTimestampMeta

See also - locationTemplate - HttpConfig.rootProperty - HTTP Guide

Incorrect
BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    geofenceTemplate: '{"timestamp": <%= timestamp %>}'
  )
));
Correct
BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    geofenceTemplate: '{"timestamp": "<%= timestamp %>"}'
  )
));

locationTemplate

String? locationTemplate

Optional custom ERB template for reshaping Location JSON in HTTP uploads.

When set, the SDK evaluates the template string against each location record before serializing it. Use Ruby-style ERB tags to interpolate field values:

<%= variable_name %>
BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    locationTemplate:
      '{"lat":<%= latitude %>,"lng":<%= longitude %>,"event":"<%= event %>",isMoving:<%= is_moving %>}'
  )
));

// Or use a compact Array template:
BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    locationTemplate:
      '[<%=latitude%>, <%=longitude%>, "<%=event%>", <%=is_moving%>]'
  )
));

Warning

The SDK does not automatically insert quotes around string values. Templates are JSON-encoded exactly as written.

The following produces invalid JSON because timestamp is a string but is

BackgroundGeolocation.ready(Config(
  persistence: PersistenceConfig(
    locationTemplate: '{"timestamp": <%= timestamp %>}'
  )
));

This renders invalid JSON:

{"timestamp": 2018-01-01T12:01:01.123Z}
BackgroundGeolocation.ready(Config(
 persistence: PersistenceConfig(
  locationTemplate: '{"timestamp": "<%= timestamp %>"}'
 )
));
{"timestamp": "2018-01-01T12:01:01.123Z"}
Configured extras

If extras are configured, the key/value pairs are merged directly into the rendered location JSON.

BackgroundGeolocation.ready(Config(
  http: HttpConfig(
    url: 'https://my.server.com/locations',
    rootProperty: 'data',
  ),
  persistence: PersistenceConfig(
    locationTemplate: '{"lat":<%= latitude %>,"lng":<%= longitude %>}',
    extras: { foo: "bar" }
  )
));

Produces:

{
  "data": {
    "lat": 23.23232323,
    "lng": 37.37373737,
    "foo": "bar"
  }
}
Template tags
Tag Type Description
latitude Float
longitude Float
speed Float Meters
heading Float Degrees
accuracy Float Meters
altitude Float Meters
altitude_accuracy Float Meters
timestamp String ISO-8601
uuid String Unique ID
event String motionchange, geofence, heartbeat, providerchange
odometer Float Meters
activity.type String still, on_foot, running, on_bicycle, in_vehicle, unknown
activity.confidence Integer 0–100%
battery.level Float 0–100%
battery.is_charging Boolean Is device plugged in?
mock Boolean True if generated by mock provider
is_moving Boolean Device was moving when recorded
timestampMeta Object Timestamp metadata; see GeoConfig.enableTimestampMeta

See also - HTTP Guide - geofenceTemplate - HttpConfig.rootProperty

locationsOrderDirection

String? locationsOrderDirection

Sort order used when selecting records for upload or returning them from BackgroundGeolocation.getLocations. Defaults to "ASC" (oldest first).

  • "ASC" — oldest records first
  • "DESC" — newest records first

maxDaysToPersist

int? maxDaysToPersist

Maximum number of days to retain a persisted record in the SDK's on-device SQLite database. Defaults to 1 day.

When your server fails to return a 20x response, the SDK continues retrying uploads. If a record remains unuploaded for longer than maxDaysToPersist days, it is permanently discarded to prevent unbounded database growth.

maxRecordsToPersist

int? maxRecordsToPersist

Maximum number of records the SDK may retain in its on-device SQLite database. Defaults to -1 (no limit).

When a limit is set and the stored record count would exceed it, the oldest records are purged to make room for the newest.

See HttpEvent for details on upload behavior.

persistMode

PersistMode? persistMode

Controls which event types the SDK writes to its internal SQLite database. Defaults to PersistMode.All.

All recorded events are always delivered to their live callbacks (BackgroundGeolocation.onLocation and BackgroundGeolocation.onGeofence). This setting only determines what is written to persistent storage. Events that are not persisted are also not eligible for HTTP uploads via HttpConfig.url.

Value Description
PersistMode.All Default — persist both location and geofence events.
PersistMode.Location Persist location events only.
PersistMode.Geofence Persist geofence events only.
PersistMode.None Persist nothing.

Warning

This setting is intended for specialized cases. For example, if you need continuous location tracking via BackgroundGeolocation.start but only want to store geofence events, configure persistMode: PersistMode.Geofence.