Every type is a Swift struct decoded from the engine’s dictionaries. Fields
the engine may legitimately omit are optional; fields it always sends are not.
Where a field is optional, that optionality is load-bearing — see the note at
the end.
Location
The payload of onLocation, the return of
getCurrentPosition(), and the record shape in the upload queue.
Field
Type
Notes
uuid
String
Stable per record; the handle destroyLocation() takes.
timestamp
String
ISO 8601, UTC.
age
Double?
Milliseconds between the fix being taken and processed.
odometer
Double
Cumulative metres since the last reset.
coords
Coords
See below.
activity
MotionActivity
Classification at the time of the fix.
battery
Battery
Level and charging state.
isMoving
Bool
The motion machine’s verdict for this fix.
sample
Bool?
true for a getCurrentPosition() sample that was not persisted.
event
String?
"motionchange", "heartbeat", "geofence", or absent for an ordinary fix.
extras
[String: Any]?
Whatever you attached via config or getCurrentPosition(extras = …).
Coords
Field
Type
Notes
latitude
Double
longitude
Double
accuracy
Double
Horizontal radius, metres — the number the accuracy gate filters on.
altitude
Double?
Metres above sea level.
altitudeAccuracy
Double?
speed
Double?
m/s. -1 means “unknown” on some devices; treat negatives as absent.
speedAccuracy
Double?
heading
Double?
Degrees; negative means unknown.
headingAccuracy
Double?
ellipsoidalAltitude
Double?
Height above the WGS84 ellipsoid, where the device reports it.
The engine ignores a classification below minimumActivityRecognitionConfidence
(75 by default) when deciding motion state, so a low-confidence IN_VEHICLE
does not by itself wake tracking.
Battery
Field
Type
Notes
level
Double
0.0–1.0. -1 means unknown — guard before showing a percentage.
isCharging
Bool
State
Returned by ready(), setConfig(), start(), stop() and getState().
Field
Type
Notes
enabled
Bool
Whether tracking is on. This is the persisted intent, not “is a fix arriving right now”.
raw
[String: Any]
Everything else the engine reported.
raw is deliberately untyped: it is a superset of health and diagnostic fields
that grows with the engine, and a typed class would have to be released in
lockstep to stay honest. Read it with state["key"], which returns null for
both an absent key and a JSON null:
let state =await BackgroundGeolocation.getState()
let trackingActive = state["trackingActive"] as?Bool
let lastFixAge = state["lastAcceptedFixAge"] as?Double// seconds, nil until a fix arrives
The two fix ages are in seconds and nil until the first fix — the raw one
is stamped before the location filter runs and the accepted one after, so the
pair separates “CoreLocation stopped delivering” from “the filter is rejecting
everything”. That distinction is the first fork of every field investigation,
and rawFixCount/acceptedFixCount/rejectedFixCount/lastRejectReason
answer the follow-up.
sessionEngineActive tells you which delivery path is live (see
useSessionEngine), and
serviceSessionActive whether the iOS 18+ CLServiceSession is held.
ProviderState
From getProviderState(), and the payload of onProviderChange.
REDUCED when the user granted approximate location only.
Geofence
Field
Type
Notes
identifier
String
Yours; unique. Re-adding the same identifier replaces the fence.
radius
Double
Metres. Under ~100 m, expect the OS to report crossings late.
latitude / longitude
Double
notifyOnEntry
Bool?
Defaults to true engine-side.
notifyOnExit
Bool?
Defaults to true engine-side.
notifyOnDwell
Bool?
Requires loiteringDelay.
loiteringDelay
Double?
Milliseconds inside the radius before DWELL fires.
extras
[String: Any]?
Echoed back on every event for this fence.
Event payloads
MotionChangeEvent
Field
Type
Notes
isMoving
Bool
location
Location?
Nil on the first motionchange of a tracking session — the engine has no accepted fix yet.
GeofenceEvent
Field
Type
Notes
identifier
String
action
GeofenceAction
.enter, .exit, .dwell.
location
Location
The last accepted fix when the OS delivered the transition — not the point where the boundary was crossed.
extras
[String: Any]?
From the geofence definition.
GeofencesChangeEvent
Field
Type
Notes
on
[Geofence]
Now being monitored by the OS.
off
[Geofence]
No longer monitored.
iOS allows 20 monitored regions per app and the engine spends one on its own
wake region, so 19 of yours are armed at a time. It keeps the nearest ones
registered and swaps as you move. This event is how you see that happen; the
fences you added all still exist.
HttpEvent
Field
Type
Notes
success
Bool
2xx.
status
Int
HTTP status; 0 means a network-level failure, not a server response.
responseText
String
Body, truncated to 1024 chars. Logged verbatim — do not put secrets in error bodies.
ConnectivityChangeEvent
Field
Type
connected
Bool
Validated connectivity, not merely “an interface is up” — a captive portal
reads as disconnected.
LocationErrorEvent
Field
Type
Notes
code
String
e.g. LICENSE_MISSING, or a CoreLocation error code.
message
String?
The payload of onLocationError.
code arrives as either a string or a number depending on which engine call
site emitted it, and is normalised to a string here — so a caller can switch on
it without knowing which path produced the failure.
HeartbeatEvent
Field
Type
raw
[String: Any]
Option classes
CurrentPositionOptions
Field
Type
Notes
persist
Bool?
Whether the fix enters the upload queue.
samples
Int?
How many fixes to collect before returning the best.
timeout
Double?
Seconds.
maximumAge
Double?
Milliseconds; accept a cached fix younger than this.
desiredAccuracy
Int?
Overrides config for this call.
extras
[String: Any]?
Attached to the returned record.
WatchPositionOptions
Field
Type
interval
Double?
desiredAccuracy
Int?
persist
Bool?
extras
[String: Any]?
getAuthState()‘s tuple
(accessToken: String?, refreshToken: String?) — a tuple rather than a named
type, because it exists only to answer one question.
The engine’s current token pair after a native refresh — read it with
getAuthState() when your app needs to stay in step with tokens the SDK
rotated on its own. See HTTP & authorization.
LogEntry
Field
Type
Notes
ts
String
ISO 8601.
level
Int
1=ERROR … 5=VERBOSE.
src
String
"native" for engine lines.
event
String
Dot-namespaced (track.start, wake.rearm) for engine diagnostics.
message
String?
data
Any?
Parsed JSON, not a string.
A note on optionality
Optional fields here are not defensive padding. MotionChangeEvent.location
really is absent on the first motion change of a session, and isMoving
arrives as null from the engine while motion is still being probed — up to
stopTimeout minutes after every start().
That last one has history: this SDK originally declared isMoving
non-optional, on the strength of a TypeScript interface that said boolean,
and dropped every location for the first minutes of every session — while
the server received them all, because the upload path never touches the
decoder. If a field is optional in this table, the engine can and does send
nothing for it.