BGGeo¶
classBGGeo
Primary SDK API — the single entry point for all geolocation, geofencing, HTTP sync, and configuration operations.
Contents¶
Overview¶
The SDK operates around a motion-based state machine: it tracks aggressively while the device is moving and pauses location services when stationary, delivering high-quality background tracking with minimal battery impact.
| Area | Key methods |
|---|---|
| Lifecycle | ready, start, stop, setConfig, reset |
| Location | getCurrentPosition, watchPosition, getOdometer |
| Geofencing | addGeofence, startGeofences, onGeofence |
| Events | onLocation, onMotionChange, onHttp, onProviderChange |
| Persistence | getLocations, getCount, sync, destroyLocations |
| Background tasks | startBackgroundTask, stopBackgroundTask |
Lifecycle¶
Think of the SDK like a stereo receiver:
-
Wiring the speakers — Register event listeners (
onLocation,onGeofence, etc.) before callingready. The SDK buffers events untilreadyresolves, so listeners registered afterward may miss them. You do not need to remove listeners when you callstop— the SDK simply stops emitting events when it isn't running. -
Plugging in the power cord —
readyinitializes the SDK, restores persisted state, and applies your configuration. Call it once per launch, before any method that acquires a location or requests permissions. Your config is not applied untilreadyresolves. -
The power button —
startandstopbegin and halt location tracking. The SDK persists its enabled state across launches. If the app is terminated while tracking is active, the next call toreadywill automatically resume tracking — you do not need to callstartagain.
Always call ready on every launch — no exceptions. The SDK buffers all events from the
moment the app starts, and holds them until ready is called. If your app launches and
never calls ready, the SDK sits silently waiting: no events fire, no locations are
recorded, no uploads are attempted. It does not matter whether tracking was already active
from a previous session — ready is the signal that tells the SDK your app is alive and
listening. This is why the method is named ready.
Calling methods before ready resolves is perfectly fine, provided they do not request
a location or trigger a permission dialog. Methods that only read from the SDK's SQLite
database are safe — for example getState, getLocations, getGeofences,
removeGeofences. Avoid start, requestPermission, getCurrentPosition, and
watchPosition until after ready resolves. The SDK defaults apply until your config
arrives — calling a permission-sensitive method too early will use those defaults, not
your configured values.
Configuration¶
The SDK uses a compound-configuration model. Options are grouped into typed sub-interfaces (GeolocationConfig, HttpConfig, AppConfig, etc.) passed as a single Config object. All SDK constants are available as strongly-typed enum namespaces on the default export:
Events¶
Each onX method returns a Subscription that must be removed when
no longer needed:
These can also be imported individually¶
// Within a coroutine scope
val bgGeo = BGGeo.instance
bgGeo.ready {
logger.logLevel = LogLevel.DEBUG
}
Examples¶
Compound configuration¶
// Within a coroutine scope
val bgGeo = BGGeo.instance
bgGeo.ready {
geolocation.desiredAccuracy = DesiredAccuracy.HIGH
geolocation.distanceFilter = 20f
http.url = "https://example.com/locations"
http.autoSync = true
persistence.maxDaysToPersist = 7
}
Event listeners¶
val bgGeo = BGGeo.instance
bgGeo.onLocation { location ->
Log.d(TAG, "New location: $location")
}
bgGeo.onMotionChange { event ->
Log.d(TAG, "Device is moving? ${event.isMoving}")
}
Removing event listeners¶
Getting started¶
// Within a coroutine scope
val bgGeo = BGGeo.instance
bgGeo.ready {
geolocation.distanceFilter = 10f
http.url = "https://example.com/locations"
http.autoSync = true
}
if (!bgGeo.enabled) {
bgGeo.start()
}
Events¶
onActivityChange¶
fun onActivityChange(callback: (ActivityChangeEvent) -> Unit): EventSubscription
Subscribe to motion-activity changes.
Fires each time the activity-recognition system reports a new activity
(still, on_foot, in_vehicle, on_bicycle, running).
Android¶
ActivityChangeEvent.confidence always reports 100.
val bgGeo = BGGeo.instance
val subscription = bgGeo.onActivityChange { event ->
Log.d(TAG, "[onActivityChange] ${event.activity} (${event.confidence}%)")
}
activitychange
onAuthorization¶
fun onAuthorization(callback: (AuthorizationEvent) -> Unit): EventSubscription
Subscribe to Config.authorization events.
Fires when AuthorizationConfig.refreshUrl responds, either
successfully or not. On success, AuthorizationEvent.success is
true and AuthorizationEvent.response contains the decoded JSON
response. On failure, AuthorizationEvent.error contains the error
message.
val bgGeo = BGGeo.instance
val subscription = bgGeo.onAuthorization { event ->
if (event.isSuccess) {
Log.d(TAG, "[authorization] SUCCESS: ${event.response}")
} else {
Log.d(TAG, "[authorization] ERROR: ${event.error}")
}
}
authorization
onConnectivityChange¶
fun onConnectivityChange(callback: (ConnectivityChangeEvent) -> Unit): EventSubscription
Subscribe to network connectivity changes.
Fires when the device's network connectivity transitions between connected
and disconnected. By default, the SDK also fires this event at
start time with the current connectivity state. When connectivity
is restored and the SDK has queued locations, it automatically initiates
an upload to HttpConfig.url.
val bgGeo = BGGeo.instance
val subscription = bgGeo.onConnectivityChange { event ->
Log.d(TAG, "[onConnectivityChange] isConnected: ${event.isConnected}")
}
connectivitychange
onEnabledChange¶
Subscribe to changes in plugin State.enabled.
Fires when State.enabled changes. Calling start or
stop triggers this event.
val bgGeo = BGGeo.instance
val subscription = bgGeo.onEnabledChange { event ->
Log.d(TAG, "[onEnabledChange] isEnabled? ${event.enabled}")
}
enabledchange
onGeofence¶
fun onGeofence(callback: (GeofenceEvent) -> Unit): EventSubscription
Subscribe to geofence transition events.
Fires when any monitored geofence crossing occurs.
See also
- 📘 Geofencing Guide
val bgGeo = BGGeo.instance
val subscription = bgGeo.onGeofence { event ->
Log.d(TAG, "[onGeofence] $event")
}
geofence
onGeofencesChange¶
fun onGeofencesChange(callback: (GeofencesChangeEvent) -> Unit): EventSubscription
Subscribe to changes in the set of actively monitored geofences.
Fires when the SDK's active geofence set changes. The SDK can monitor any number of geofences in its database — even thousands — despite native platform limits (20 for iOS; 100 for Android). It achieves this with a geospatial query that activates only the geofences nearest to the device's current location (see GeolocationConfig.geofenceProximityRadius). When the device is moving, the query runs periodically and the active set may change — that change triggers this event.
See also
- 📘 Geofencing Guide
val bgGeo = BGGeo.instance
val subscription = bgGeo.onGeofencesChange { event ->
val on = event.on // new geofences activated
val off = event.off // geofences that were just de-activated
// Create map circles
on.forEach { geofence ->
Log.d(TAG, "activated: ${geofence.identifier}")
}
// Remove map circles
off.forEach { identifier ->
Log.d(TAG, "deactivated: $identifier")
}
}
geofenceschange
onHeartbeat¶
fun onHeartbeat(callback: (HeartbeatEvent) -> Unit): EventSubscription
Subscribe to periodic heartbeat events.
Fires at each AppConfig.heartbeatInterval while the device is in
the stationary state. On iOS, AppConfig.preventSuspend must
also be true to receive heartbeats in the background.
Note
The LocationEvent provided by the HeartbeatEvent is only the
last-known location — the heartbeat does not engage location services. To
fetch a fresh location inside your callback, call getCurrentPosition.
// Within a coroutine scope
val bgGeo = BGGeo.instance
bgGeo.config.edit {
app.heartbeatInterval = 60.0
}
val subscription = bgGeo.onHeartbeat { event ->
Log.d(TAG, "[onHeartbeat] $event")
// You could request a new location if you wish.
kotlinx.coroutines.runBlocking {
val location = bgGeo.getCurrentPosition(samples = 1, persist = true)
Log.d(TAG, "[getCurrentPosition] $location")
}
}
heartbeat
onHttp¶
fun onHttp(callback: (HttpEvent) -> Unit): EventSubscription
Subscribe to HTTP responses from your server HttpConfig.url.
See also
- HTTP Guide
val bgGeo = BGGeo.instance
val subscription = bgGeo.onHttp { response ->
val status = response.statusCode
val success = response.isSuccess
val responseText = response.responseText
Log.d(TAG, "[onHttp] $response")
}
http
onLocation¶
fun onLocation(callback: (LocationEvent) -> Unit): EventSubscription
Subscribe to location events.
Every location recorded by the SDK is delivered to your callback, including
locations from onMotionChange, getCurrentPosition, and
watchPosition.
Error Codes¶
If the native location API fails, the error callback receives a
LocationError code.
Note
During onMotionChange and getCurrentPosition, the SDK
requests multiple location samples to find the most accurate fix. These
intermediate samples are not persisted, but are delivered to this
callback with LocationEvent.sample set to true. Filter out sample
locations before manually posting to your server.
val bgGeo = BGGeo.instance
val subscription = bgGeo.onLocation { location ->
Log.d(TAG, "[onLocation] success: $location")
}
location
onMotionChange¶
fun onMotionChange(callback: (LocationEvent) -> Unit): EventSubscription
Subscribe to motion-change events.
Fires each time the device transitions between the moving and stationary states.
Warning
When a motion-change event fires, HttpConfig.autoSyncThreshold is ignored — all queued locations are uploaded immediately. The SDK flushes eagerly before going dormant (moving→stationary) and immediately after waking up (stationary→moving).
See also - GeolocationConfig.stopTimeout
val bgGeo = BGGeo.instance
val subscription = bgGeo.onMotionChange { event ->
if (event.isMoving) {
Log.d(TAG, "[onMotionChange] Device has just started MOVING ${event.location}")
} else {
Log.d(TAG, "[onMotionChange] Device has just STOPPED: ${event.location}")
}
}
motionchange
onNotificationAction¶
Android only Subscribe to button-click actions on the Android foreground-service notification.
Fires when the user taps a button defined in a custom NotificationConfig.layout.
onPowerSaveChange¶
Subscribe to OS power-saving mode changes.
Fires when the operating system's power-saving mode is enabled or disabled. Power-saving mode can throttle background services such as GPS and HTTP uploads.
See also
- isPowerSaveMode
iOS¶
Power Saving mode is enabled manually in Settings → Battery or via an automatic OS prompt.

Android¶
Battery Saver is enabled manually in Settings → Battery → Battery Saver or automatically when the battery drops below a configured threshold.

val bgGeo = BGGeo.instance
val subscription = bgGeo.onPowerSaveChange { event ->
Log.d(TAG, "[onPowerSaveChange] isPowerSaveMode: ${event.isPowerSaveMode}")
}
powersavechange
onProviderChange¶
fun onProviderChange(callback: (ProviderChangeEvent) -> Unit): EventSubscription
Subscribe to location-services authorization changes.
Fires whenever the state of the device's location-services authorization
changes (e.g. GPS enabled, WiFi-only, permission revoked). The SDK also
fires this event immediately after ready completes, so you always
receive the current authorization state on each app launch.
See also
- getProviderState
val bgGeo = BGGeo.instance
val subscription = bgGeo.onProviderChange { event ->
Log.d(TAG, "[onProviderChange] $event")
when (PermissionStatus.fromValue(event.status)) {
PermissionStatus.DENIED ->
Log.d(TAG, "- Location authorization denied")
PermissionStatus.ALWAYS ->
Log.d(TAG, "- Location always granted")
PermissionStatus.WHEN_IN_USE ->
Log.d(TAG, "- Location WhenInUse granted")
}
}
providerchange
onSchedule¶
Subscribe to AppConfig.schedule events.
Fires each time a schedule event activates or deactivates tracking.
Check state.enabled in your callback to determine whether tracking
was started or stopped.
val bgGeo = BGGeo.instance
val subscription = bgGeo.onSchedule { event ->
if (event.state["enabled"] == true) {
Log.d(TAG, "[onSchedule] scheduled start tracking")
} else {
Log.d(TAG, "[onSchedule] scheduled stop tracking")
}
}
schedule
Methods¶
changePace¶
Manually toggle the SDK's motion state between stationary and moving.
Passing true immediately engages location services and begins tracking,
bypassing stationary monitoring. Passing false turns off location
services and returns the SDK to the stationary state.
Use this in workout-style apps where you want explicit start/stop control independent of the device's motion sensors.
val bgGeo = BGGeo.instance
bgGeo.changePace(true) // <-- Location-services ON ("moving" state)
bgGeo.changePace(false) // <-- Location-services OFF ("stationary" state)
getCurrentPosition¶
suspend fun getCurrentPosition( timeout: Int = 30, desiredAccuracy: Double = 0.0, maximumAge: Long = 0, samples: Int = 3, persist: Boolean = true, extras: Map<String, Any>? = null )
Retrieve the current LocationEvent.
Instructs the SDK to fetch a single location at maximum power and
accuracy. The location is persisted to SQLite and posted to
HttpConfig.url just like any other recorded location. If an error
occurs, the promise rejects with a LocationError.
Options¶
See CurrentPositionRequest.
Error Codes¶
See LocationError.
Note
The SDK requests multiple location samples internally to find the best
fix. All intermediate samples are delivered to onLocation with
LocationEvent.sample set to true. Filter these out if you are
manually posting locations to your server.
// Within a coroutine scope
val bgGeo = BGGeo.instance
val location = bgGeo.getCurrentPosition(
timeout = 30,
maximumAge = 5000L,
desiredAccuracy = 10.0,
samples = 3,
extras = mapOf("route_id" to 123)
)
ready¶
suspend fun ready( reset: Boolean = true, transistorAuthorizationToken:TransistorToken? = null, configure: ConfigEditor.() -> Unit )
Signal to the SDK that your app is launched and ready, supplying the default Config.
Call ready exactly once per app launch, before calling start.
The SDK applies your configuration, restores persisted state, and prepares
for tracking. On subsequent launches after first install, it loads the
persisted configuration and merges your supplied Config on top.
See Config.reset for finer control over this behaviour.
Warning
Call ready once per app launch from your application root — not inside a
component or behind a UI action. On iOS, the OS can relaunch your app in
the background when the device starts moving; if ready is not called in
that path, tracking will not resume.
See also
- Config.reset
- setConfig
// Within a coroutine scope
val bgGeo = BGGeo.instance
bgGeo.ready {
geolocation.desiredAccuracy = DesiredAccuracy.HIGH
geolocation.distanceFilter = 10f
app.stopOnTerminate = false
app.startOnBoot = true
http.url = "http://your.server.com"
http.headers = mapOf("my-auth-token" to "secret-token")
}
Log.d(TAG, "[ready] success")
// Within a coroutine scope
val bgGeo = BGGeo.instance
bgGeo.config.reset()
// Reset to documented default-values with overrides
bgGeo.config.edit {
geolocation.distanceFilter = 10f
}
removeListeners¶
Remove all event listeners.
Calls Subscription.remove on all active subscriptions.
resetOdometer¶
Reset the odometer to 0.
Internally performs a getCurrentPosition to record the exact
location where the odometer was reset. Equivalent to
.setOdometer(0).
// Within a coroutine scope
val bgGeo = BGGeo.instance
val location = bgGeo.setOdometer(0.0)
Log.d(TAG, "[setOdometer] success: $location")
setOdometer¶
Set the odometer to an arbitrary value.
Internally performs a getCurrentPosition to record the exact
location where the odometer was set.
// Within a coroutine scope
val bgGeo = BGGeo.instance
val location = bgGeo.setOdometer(1234.56)
Log.d(TAG, "[setOdometer] success: $location")
start¶
Enable location and geofence tracking.
This is the SDK's power ON switch. The SDK enters its stationary state, acquires an initial location, then turns off location services until motion is detected. On Android, the Activity Recognition System monitors for motion; on iOS, a stationary geofence is created around the current location.
Note
If a AppConfig.schedule is configured, start overrides the
schedule and begins tracking immediately.
See also
- stop
- startGeofences
startGeofences¶
Switch to geofences-only tracking mode.
In this mode no active location tracking occurs — only geofences are
monitored. Use the usual stop method to exit geofences-only mode.
start and startGeofences are mutually exclusive — call one or the
other, never both. start enables full tracking: location recording and
geofence monitoring run together. startGeofences enables geofence monitoring
only, with no continuous location recording. Calling start while already
in geofences-only mode (or vice versa) switches modes; there is no need to call
stop first.
See also
- stop
- 📘 Geofencing Guide
// Within a coroutine scope
val bgGeo = BGGeo.instance
// Add a geofence.
bgGeo.geofences.add(
Geofence.Builder()
.setIdentifier("ZONE_OF_INTEREST")
.setLatitude(37.234232)
.setLongitude(42.234234)
.setRadius(200f)
.setNotifyOnExit(true)
.build()
)
// Listen to geofence events.
bgGeo.onGeofence { event ->
Log.d(TAG, "[onGeofence] - $event")
}
// Configure the plugin
bgGeo.config.edit {
http.url = "http://my.server.com"
http.autoSync = true
}
// Start monitoring geofences.
bgGeo.startGeofences()
startSchedule¶
Activate the configured AppConfig.schedule.
Initiates the schedule defined in AppConfig.schedule. The SDK
automatically starts or stops tracking according to the schedule. To halt
scheduled tracking, call stopSchedule.
See also
- AppConfig.schedule
- stopSchedule
stop¶
Disable location and geofence monitoring.
This is the SDK's power OFF switch.
Note
If a AppConfig.schedule is configured, stop does not halt
the scheduler. Call stopSchedule explicitly if you also want to
stop scheduled tracking (for example, on user logout).
// Later when you want to stop the Scheduler (e.g., user logout)
val bgGeo = BGGeo.instance
bgGeo.stopSchedule()
stopSchedule¶
Halt scheduled tracking.
Warning
stopSchedule does not call stop if the SDK is currently
tracking. Call stop explicitly if you also want to end the current
tracking session.
See also
- startSchedule
// Within a coroutine scope
// Later when you want to stop the Scheduler (e.g., user logout)
val bgGeo = BGGeo.instance
bgGeo.stopSchedule()
if (bgGeo.enabled) {
bgGeo.stop()
}
watchPosition¶
fun watchPosition( interval: Long = 1000, timeout: Int = 60, persist: Boolean = false, extras: Map<String, Any>? = null, success: (LocationEvent) -> Unit, failure: (Int) -> Unit )
Start a continuous stream of location updates.
Each location is persisted to SQLite (when the SDK is State.enabled)
and posted to HttpConfig.url if HTTP is configured. Returns a
Subscription that must be retained to halt the stream.
Warning
watchPosition is designed for foreground use only — not for long-term
background monitoring. The SDK's motion-based tracking model does not
require it.
iOS¶
watchPosition continues running in the background, preventing iOS from
suspending your app. Remove the subscription in your app's suspend handler
to avoid draining the battery.
val bgGeo = BGGeo.instance
var watchSubscription: EventSubscription? = null
fun onResume() {
watchSubscription = bgGeo.watchPosition(
interval = 1000L,
persist = false,
extras = mapOf("foo" to "bar"),
success = { location ->
Log.d(TAG, "[watchPosition] - $location")
},
failure = { errorCode ->
Log.d(TAG, "[watchPosition] ERROR - $errorCode")
}
)
}
fun onSuspend() {
watchSubscription?.close()
watchSubscription = null
}
Properties¶
app¶
App API — background-task and power-save utilities.
authorization¶
Authorization API — request and monitor location permissions.
config¶
Config API — read and update the SDK configuration.
deviceSettings¶
DeviceSettings API
geofences¶
Access to the GeofenceManager — add, remove, and query geofences.
logger¶
Logger API
sensors¶
Sensors API — query the device motion hardware.
state¶
val state:State
Read-only snapshot of the SDK's current runtime state.
val state = bgGeo.state
if (state.enabled && state.isMoving) {
Log.d(TAG, "Tracking in motion, odometer: ${state.odometer}")
}
store¶
DataStore API — query, upload, and destroy persisted location records.