Skip to Content
Migrating from FBG

🚀 Migration Guide: flutter_background_geolocation → Tracelet

Switching from flutter_background_geolocation to Tracelet? Great choice! Tracelet is a fully open-source (Apache 2.0) alternative with a 1:1 compatible API — plus extras like Kalman filtering, mock detection, privacy zones, and more. No license keys, no proprietary SDKs, full source code.

💡 This guide always reflects the current release.


⚡ 3-Step Speed Run

Seriously, it’s this fast.

Step 1 — Swap the dependency:

# Before dependencies: flutter_background_geolocation: ^5.x.x

After ✨

dependencies: tracelet: ^3.6.14

Step 2 — Update imports:

// Before import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' as bg; // After — short & sweet ✅ import 'package:tracelet/tracelet.dart' as tl;

Step 3 — Find & replace the class name:

// Before bg.BackgroundGeolocation.ready(bg.Config(...)); // After tl.Tracelet.ready(tl.Config.balanced().copyWith(...));

That’s literally it. Every method, every event, every callback — 1:1 compatible. The rest of this guide is just the cheat sheet for the details.


🏗️ Config: From Flat to Structured

The previous plugin uses a single flat Config() with all fields at one level. Tracelet organizes them into logical sections — making large configs much easier to read and maintain.

// Before — flat config bg.Config( desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH, distanceFilter: 10.0, stopOnTerminate: false, startOnBoot: true, stopTimeout: 5, url: 'https://api.example.com/locations', batchSync: true, autoSync: true, headers: {'Authorization': 'Bearer $token'}, heartbeatInterval: 60, notification: bg.Notification(title: 'Tracking', text: 'Active'), debug: true, logLevel: bg.Config.LOG_LEVEL_VERBOSE, ); // After — organized by section 🏠 tl.Config( geo: tl.GeoConfig( desiredAccuracy: tl.DesiredAccuracy.high, // typed enums! distanceFilter: 10.0, ), app: tl.AppConfig( stopOnTerminate: false, startOnBoot: true, heartbeatInterval: 60, ), android: tl.AndroidConfig( foregroundService: tl.ForegroundServiceConfig( notificationTitle: 'Tracking', notificationText: 'Active', ), ), motion: tl.MotionConfig( stopTimeout: 5, ), http: tl.HttpConfig( url: 'https://api.example.com/locations', batchSync: true, autoSync: true, headers: {'Authorization': 'Bearer $token'}, ), logger: tl.LoggerConfig( debug: true, logLevel: tl.LogLevel.verbose, // readable enum instead of int constants ), );

The config sections at a glance:

  • geoGeoConfig — Accuracy, distance filter, elasticity, periodic mode, Kalman filter, mock detection
  • appAppConfig — Lifecycle, heartbeat, schedule
  • androidAndroidConfig — 🆕 Android-only: foreground service notification, location update intervals, AlarmManager, periodic strategies
  • iosIosConfig — 🆕 iOS-only: activity type, background sessions, prevent suspend
  • motionMotionConfig — Stop timeout, activity recognition, accelerometer-only mode
  • httpHttpConfig — Sync URL, headers, batching, retry backoff, Wi-Fi-only mode
  • loggerLoggerConfig — Log level, max days, debug sounds
  • geofenceGeofenceConfig — Proximity radius, initial trigger, knock-out mode
  • persistencePersistenceConfig — Persist mode, max days/records, templates
  • auditAuditConfig — 🆕 SHA-256 hash chain — because tamper-proof matters
  • privacyZonePrivacyZoneConfig — 🆕 Privacy zone engine — GDPR’s best friend
  • securitySecurityConfig — 🆕 At-rest database encryption (encryptDatabase)
  • attestationAttestationConfig — 🆕 Device attestation / integrity checks

🗺️ The Big Config Cheat Sheet

Don’t worry, every single field has a 1:1 mapping. Here’s your Rosetta Stone.

Location & Tracking → GeoConfig

Before → Tracelet ───────────────────────────────────────────────────────────── desiredAccuracy (int: -2…100) → geo.desiredAccuracy (DesiredAccuracy enum) .high / .medium / .low / .veryLow / .passive distanceFilter → geo.distanceFilter (default 10m) stationaryRadius → geo.stationaryRadius (default 25m) locationTimeout → geo.locationTimeout (default 60s) disableElasticity → geo.disableElasticity elasticityMultiplier → geo.elasticityMultiplier (default 1.0) stopAfterElapsedMinutes → geo.stopAfterElapsedMinutes (-1 = disabled) enableTimestampMeta → geo.enableTimestampMeta maxMonitoredGeofences → geo.maxMonitoredGeofences (-1 = platform default)

Android-specific fields → AndroidConfig:

Before → Tracelet ───────────────────────────────────────────────────────────── locationUpdateInterval → android.locationUpdateInterval (1000ms) fastestLocationUpdateInterval → android.fastestLocationUpdateInterval (500ms) deferTime → android.deferTime allowIdenticalLocations → android.allowIdenticalLocations geofenceModeHighAccuracy → geofence.geofenceModeHighAccuracy (cross-platform; android.* is deprecated) scheduleUseAlarmManager → android.scheduleUseAlarmManager

iOS-specific fields → IosConfig:

Before → Tracelet ───────────────────────────────────────────────────────────── activityType → ios.activityType (LocationActivityType enum) useSignificantChangesOnly → ios.useSignificantChangesOnly showsBackgroundLocationIndicator → ios.showsBackgroundLocationIndicator pausesLocationUpdatesAutomatically → ios.pausesLocationUpdatesAutomatically locationAuthorizationRequest → ios.locationAuthorizationRequest disableLocationAuthorizationAlert → ios.disableLocationAuthorizationAlert preventSuspend → ios.preventSuspend

🆕 Tracelet-exclusive GeoConfig fields:

  • geo.enableAdaptiveMode — Adapts distance filter by activity + battery + speed
  • geo.periodicLocationInterval — Default 900s (15 min)
  • geo.periodicDesiredAccuracy — Default .medium
  • geo.filter (LocationFilter) — Kalman, mock detection, accuracy thresholds

🧹 Location Filter → LocationFilter (Tracelet-exclusive!)

  • 🆕 filter.policyLocationFilterPolicy.adjust / .ignore / .discard
  • 🆕 filter.useKalmanFilter — 4-state Extended Kalman Filter — smooth out GPS noise like a pro
  • 🆕 filter.mockDetectionLevel.disabled / .basic / .heuristic — catch those spoofed locations
  • 🆕 filter.rejectMockLocations — Auto-reject mock locations
  • 🆕 filter.maxImpliedSpeed — Spike filter — “no, the user did NOT teleport”
  • 🆕 filter.trackingAccuracyThreshold — Min accuracy to accept
  • 🆕 filter.odometerAccuracyThreshold — Min accuracy for odometer updates

Motion Detection → MotionConfig

Before → Tracelet ───────────────────────────────────────────────────────────── stopTimeout → motion.stopTimeout (default 5 min) motionTriggerDelay → motion.motionTriggerDelay disableMotionActivityUpdates → motion.disableMotionActivityUpdates (set true for accelerometer-only, no permission!) isMoving → motion.isMoving (initial state) activityRecognitionInterval → motion.activityRecognitionInterval (10000ms) minimumActivityRecognitionConfidence → motion.minimumActivityRecognitionConfidence (75) disableStopDetection → motion.disableStopDetection stopDetectionDelay → motion.stopDetectionDelay stopOnStationary → motion.stopOnStationary triggerActivities → motion.activityTypes (Set<ActivityType>)

🆕 Tracelet-exclusive MotionConfig fields:

  • motion.motionDetectionMode.accelerometer / .speed / .smart — how movement is detected (smart = accelerometer and GPS speed; recommended)
  • motion.shakeThreshold — Accelerometer-only tuning (default 2.5)
  • motion.stillThreshold — Accelerometer-only tuning (default 0.4)
  • motion.stillSampleCount — Accelerometer-only tuning (default 25)
  • motion.speedMovingThreshold / motion.speedStationaryDelay / motion.speedWakeConfirmCount — speed-mode tuning (used by .speed / .smart)
  • motion.stationaryTrackingMode / motion.stationaryPeriodicInterval / motion.stationaryPeriodicAccuracy — what to do once stationary (periodic fixes vs geofences)

Application → AppConfig

Before → Tracelet ───────────────────────────────────────────────────────────── stopOnTerminate → app.stopOnTerminate (default true) startOnBoot → app.startOnBoot (default false) heartbeatInterval → app.heartbeatInterval (default 60s) schedule → app.schedule (cron-like expressions)

Note: scheduleUseAlarmManagerandroid.scheduleUseAlarmManager | preventSuspendios.preventSuspend

🔔 Foreground Service Notification → AndroidConfig.foregroundService

Important (2.x.x change): The foreground service notification is now configured under android.foregroundService (an AndroidConfig), not under app. This is an Android-only concept.

Before (Notification) → Tracelet (AndroidConfig.foregroundService) ───────────────────────────────────────────────────────────── title → android.foregroundService.notificationTitle text → android.foregroundService.notificationText color → android.foregroundService.notificationColor smallIcon → android.foregroundService.notificationSmallIcon largeIcon → android.foregroundService.notificationLargeIcon priority → android.foregroundService.notificationPriority channelName → android.foregroundService.channelName channelId → android.foregroundService.channelId sticky → android.foregroundService.notificationOngoing actions → android.foregroundService.actions enabled → android.foregroundService.enabled

HTTP Sync → HttpConfig

Before → Tracelet ───────────────────────────────────────────────────────────── url → http.url (null = sync disabled) method → http.method (HttpMethod.post / .put) headers → http.headers httpRootProperty → http.httpRootProperty (default 'location') batchSync → http.batchSync maxBatchSize → http.maxBatchSize autoSync → http.autoSync autoSyncThreshold → http.autoSyncThreshold httpTimeout → http.httpTimeout (default 60000ms) params → http.params extras → http.extras locationsOrderDirection → http.locationsOrderDirection (LocationOrder enum)

🆕 Tracelet-exclusive HttpConfig fields:

  • http.disableAutoSyncOnCellular — Wi-Fi-only sync — save that data plan!
  • http.maxRetries — Default 10, with exponential backoff + jitter
  • http.retryBackoffBase — Default 1000ms
  • http.retryBackoffCap — Default 300000ms (5 min)

Geofencing → GeofenceConfig

Before → Tracelet ───────────────────────────────────────────────────────────── geofenceProximityRadius → geofence.geofenceProximityRadius (default 1000m) geofenceInitialTriggerEntry → geofence.geofenceInitialTriggerEntry (default true)
  • 🆕 geofence.geofenceModeKnockOut — Auto-remove geofence after first EXIT — one and done!

Persistence → PersistenceConfig

Before → Tracelet ───────────────────────────────────────────────────────────── persistMode → persistence.persistMode (.all / .location / .geofence / .none) maxDaysToPersist → persistence.maxDaysToPersist (-1 = forever) maxRecordsToPersist → persistence.maxRecordsToPersist (-1 = unlimited) locationTemplate → persistence.locationTemplate (Mustache-style) geofenceTemplate → persistence.geofenceTemplate (Mustache-style) disableProviderChangeRecord → persistence.disableProviderChangeRecord extras → persistence.extras

Logging → LoggerConfig

Before → Tracelet ───────────────────────────────────────────────────────────── logLevel (int const) → logger.logLevel (.verbose / .debug / .info / .warning / .error) logMaxDays → logger.logMaxDays (default 3) debug → logger.debug (alert sounds — fun at demos, terrifying at 3 AM)

🔐 Audit Trail → AuditConfig (Tracelet-exclusive)

  • audit.enabledfalse by default. SHA-256 hash chain on every location — tamper = busted
  • audit.hashAlgorithmHashAlgorithm.sha256
  • audit.includeExtrasInHashfalse by default

🛡️ Privacy Zones → PrivacyZoneConfig (Tracelet-exclusive)

  • privacyZone.enabledfalse by default. Enable privacy zone engine.

🎯 Accuracy Constants — Typed Enums!

Before (int constants) → Tracelet (typed enum) ───────────────────────────────────────────────────────────── Config.DESIRED_ACCURACY_NAVIGATION → DesiredAccuracy.high Config.DESIRED_ACCURACY_HIGH → DesiredAccuracy.high Config.DESIRED_ACCURACY_MEDIUM → DesiredAccuracy.medium Config.DESIRED_ACCURACY_LOW → DesiredAccuracy.low Config.DESIRED_ACCURACY_VERY_LOW → DesiredAccuracy.veryLow Config.DESIRED_ACCURACY_LOWEST → DesiredAccuracy.passive

📡 Events — Same Names, Less Typing

All 14 event streams map 1:1. Just swap the prefix:

Before → Tracelet Callback Type ───────────────────────────────────────────────────────────────────────── onLocation(cb) → onLocation(cb) Location onMotionChange(cb) → onMotionChange(cb) Location onActivityChange(cb) → onActivityChange(cb) ActivityChangeEvent onProviderChange(cb) → onProviderChange(cb) ProviderChangeEvent onGeofence(cb) → onGeofence(cb) GeofenceEvent onGeofencesChange(cb) → onGeofencesChange(cb) GeofencesChangeEvent onHeartbeat(cb) → onHeartbeat(cb) HeartbeatEvent onHttp(cb) → onHttp(cb) HttpEvent onSchedule(cb) → onSchedule(cb) State onPowerSaveChange(cb) → onPowerSaveChange(cb) bool onConnectivityChange(cb) → onConnectivityChange(cb) ConnectivityChangeEvent onEnabledChange(cb) → onEnabledChange(cb) bool onNotificationAction(cb) → onNotificationAction(cb) String onAuthorization(cb) → onAuthorization(cb) AuthorizationEvent N/A → 🆕 onTrip(cb) TripEvent (auto-detected trips!) N/A → 🆕 onRemoteConfig(cb) Config (remote config applied) removeListeners() → removeListeners() Cancels all subscriptions
// Before — so many characters... bg.BackgroundGeolocation.onLocation((bg.Location location) { print('[location] $location'); }); // After — ahh, much better tl.Tracelet.onLocation((tl.Location location) { print('[location] $location'); });

🔧 Methods — The Complete Mapping

Lifecycle

Before → Tracelet ───────────────────────────────────────────────────────────── bg.BackgroundGeolocation.ready(cfg) → tl.Tracelet.ready(cfg) bg.BackgroundGeolocation.start() → tl.Tracelet.start() bg.BackgroundGeolocation.stop() → tl.Tracelet.stop() bg.BackgroundGeolocation.startGeofences() → tl.Tracelet.startGeofences() N/A → 🆕 tl.Tracelet.startPeriodic() bg.BackgroundGeolocation.getState() → tl.Tracelet.getState() bg.BackgroundGeolocation.setConfig() → tl.Tracelet.setConfig() bg.BackgroundGeolocation.reset() → tl.Tracelet.reset() N/A → 🆕 tl.Tracelet.getHealth()

Location

Before → Tracelet ───────────────────────────────────────────────────────────── getCurrentPosition(...) → getCurrentPosition(...) same params: desiredAccuracy, timeout, maximumAge, persist, samples, extras N/A → 🆕 getLastKnownLocation() — zero battery cost! watchPosition(cb, ...) → watchPosition(cb, ...) — returns watchId stopWatchPosition(id) → stopWatchPosition(id) changePace(isMoving) → changePace(isMoving) N/A → 🆕 updateLocationProviderOptions() — live accuracy/filter override, no pipeline restart getOdometer() → getOdometer() setOdometer(value) → setOdometer(value) resetOdometer() → setOdometer(0) — one less method to remember

Geofencing

Before → Tracelet ───────────────────────────────────────────────────────────── addGeofence(g) → addGeofence(g) addGeofences(list) → addGeofences(list) removeGeofence(id) → removeGeofence(id) removeGeofences() → removeGeofences() getGeofences() → getGeofences() N/A → 🆕 getGeofence(id) — get one without fetching all N/A → 🆕 geofenceExists(id) — quick existence check

Persistence & Sync

Before → Tracelet ───────────────────────────────────────────────────────────── getLocations() → getLocations([SQLQuery?]) — optional filtering! getCount() → getCount() destroyLocations() → destroyLocations() destroyLocation(uuid) → destroyLocation(uuid) insertLocation(params) → insertLocation(params) — returns UUID sync() → sync()

Permissions — We’ve Got Helpers for Days

Before → Tracelet ───────────────────────────────────────────────────────────── requestPermission() → requestLocationAuthorization() N/A → 🆕 getLocationAuthorization() N/A → 🆕 hasBackgroundPermission (getter) N/A → 🆕 getNotificationAuthorization() N/A → 🆕 requestNotificationAuthorization() N/A → 🆕 getMotionAuthorization() N/A → 🆕 requestMotionAuthorization() N/A → 🆕 requestTemporaryFullAccuracyAuthorization(purpose) — iOS 14+ N/A → 🆕 canScheduleExactAlarms() — Android 12+ N/A → 🆕 openExactAlarmSettings() N/A → 🆕 openAppSettings() N/A → 🆕 openLocationSettings() N/A → 🆕 openBatterySettings() N/A → 🆕 isIgnoringBatteryOptimizations()

Logging

Before → Tracelet ───────────────────────────────────────────────────────────── getLog() → getLog([SQLQuery?]) — optional filtering destroyLog() → destroyLog() emailLog(email) → emailLog(email) log(level, msg) → log(level, msg)

Scheduling, Background Tasks & Headless

Before → Tracelet ───────────────────────────────────────────────────────────── startSchedule() → startSchedule() stopSchedule() → stopSchedule() startBackgroundTask() → startBackgroundTask() stopBackgroundTask(id) → stopBackgroundTask(id) registerHeadlessTask(cb) → registerHeadlessTask(cb)

Utility

Before → Tracelet ───────────────────────────────────────────────────────────── getProviderState() → getProviderState() getSensors() → getSensors() getDeviceInfo() → getDeviceInfo() playSound(name) → playSound(name) isPowerSaveMode → isPowerSaveMode N/A → 🆕 getSettingsHealth() — detects OEM battery killers N/A → 🆕 openOemSettings(label) — opens OEM settings page N/A → 🆕 requestSettings(action) N/A → 🆕 showSettings(action)

🔐 Audit Trail (Tracelet-only — enterprise-grade integrity)

  • verifyAuditTrail() — Verify SHA-256 hash chain — was anything tampered with?
  • getAuditProof(uuid) — Cryptographic proof for a specific location record

🛡️ Privacy Zones (Tracelet-only — GDPR says thanks)

  • addPrivacyZone(zone) — Add a zone with action: exclude / degrade / event-only
  • addPrivacyZones(list) — Bulk add
  • removePrivacyZone(id) — Remove by identifier
  • removePrivacyZones() — Remove all
  • getPrivacyZones() — List all zones

🎁 Tracelet-Exclusive Features

Features you get with Tracelet that aren’t available in flutter_background_geolocation:

  • Periodic modeTracelet.startPeriodic() — GPS fix every N minutes via WorkManager. No foreground service, no notification, no battery drain.
  • Kalman filtergeo.filter.useKalmanFilter: true — 4-state EKF smooths GPS noise. Your tracks look professional, not drunk.
  • Adaptive samplinggeo.enableAdaptiveMode: true — Auto-adjusts distance filter based on activity + battery + speed.
  • Mock detection (3-level)geo.filter.mockDetectionLevel — Catches GPS spoofing via satellite count, realtime drift, and timestamp analysis.
  • Privacy zonesaddPrivacyZone() — Exclude, degrade, or limit tracking in sensitive areas. GDPR compliance built in.
  • Audit trailverifyAuditTrail() — SHA-256 hash chain. Prove your location data hasn’t been tampered with.
  • Health checkgetHealth() — One call tells you everything: permissions, GPS, battery, OEM issues, 12 auto-warnings.
  • OEM compatibilitygetSettingsHealth() — Detects aggressive battery killers on Huawei, Xiaomi, Samsung, OPPO, and tells users how to fix them.
  • Trip detectiononTrip(cb) — Auto-detects trips with distance, duration, waypoints, and average speed.
  • Polygon geofencesGeofence(vertices: [...]) — Not just circles. Draw any shape with ray-casting polygon support.
  • Geofence knock-outgeofence.geofenceModeKnockOut — Geofence auto-removes after first EXIT. Perfect for one-time alerts.
  • Geofence lookupgetGeofence(id) — Query a single geofence without loading all of them.
  • Permission helpersopenAppSettings(), openBatterySettings() — Direct deeplinks into system settings.
  • Smart retrieshttp.maxRetries + backoff — Exponential backoff with jitter. Your server will thank you.
  • Wi-Fi-only synchttp.disableAutoSyncOnCellular — Save mobile data, sync only on Wi-Fi.
  • Accelerometer-only motionmotion.shakeThreshold — Detect motion without Activity Recognition permission. Zero permission popup.
  • Web support — The same Dart API runs in the browser for foreground (in-tab) tracking. Background tracking and several native features aren’t available — see Web Support.

🤷 Features Not Yet in Tracelet

A few features from the previous plugin aren’t available yet. They’re either planned or easily worked around:

  • Server-side geofence syncPlanned. For now, fetch from your API and call addGeofences().
  • locationTemplate interpolationDeclared, not wired. Transform in onLocation callback or use http.extras.
  • JWT auto-refreshDeclared, not wired. Set http.headers manually; listen to onAuthorization.
  • Demo serverNot planned. Use your own backend — any REST endpoint works.
  • License key activation — 🎉 Not needed! It’s open source.

🛠️ Step-by-Step Migration

Step 1: Update pubspec.yaml

dependencies: tracelet: ^3.6.14

Delete flutter_background_geolocation and any license-key packages. You won’t need them anymore!

Step 2: Android Setup

See INSTALL-ANDROID.md . Key differences:

  • Optional Dependencies — 🆕 Tracelet 2.0.0+ requires you to explicitly add play-services-location to your build.gradle if you want high-accuracy GMS tracking. Otherwise, it falls back to standard AOSP GPS.
  • No license key — remove any BackgroundGeolocation.org config from AndroidManifest.xml
  • Permissions — auto-merged via Gradle, you don’t declare them
  • minSdkVersion — API 21+ (same as before)
  • Kotlin — all native code is Kotlin

Step 3: iOS Setup

See INSTALL-IOS.md . Key differences:

  • No license key — remove previous plugin’s plist entries
  • Background modes — same: Location Updates, Background Fetch, Remote Notifications
  • Info.plist — same usage description keys (NSLocationAlwaysAndWhenInUseUsageDescription, etc.)
  • Podfile — remove previous plugin’s pod sources

Step 4: Update Config

Transform your flat Config() → compound Config(). See the Config: From Flat to Structured section above.

Step 5: Update Event Listeners

Find & replace bg.BackgroundGeolocation.onXxxtl.Tracelet.onXxx:

// Before bg.BackgroundGeolocation.onLocation((bg.Location location) { print('[location] $location'); }); // After tl.Tracelet.onLocation((tl.Location location) { print('[location] $location'); });

Step 6: Update Lifecycle Calls

// Before bg.BackgroundGeolocation.ready(config).then((bg.State state) { if (!state.enabled) bg.BackgroundGeolocation.start(); }); // After tl.Tracelet.ready(config).then((tl.State state) { if (!state.enabled) tl.Tracelet.start(); });

Step 7: Update Headless Task

// Before @pragma('vm:entry-point') void backgroundGeolocationHeadlessTask(bg.HeadlessEvent event) async { switch (event.name) { case bg.Event.LOCATION: bg.Location location = event.event; break; } } void main() { bg.BackgroundGeolocation.registerHeadlessTask(backgroundGeolocationHeadlessTask); runApp(MyApp()); } // After — shorter function name is a bonus 😎 @pragma('vm:entry-point') void headlessTask(tl.HeadlessEvent event) async { switch (event.name) { case 'location': tl.Location location = event.event as tl.Location; break; } } void main() { tl.Tracelet.registerHeadlessTask(headlessTask); runApp(MyApp()); }

📦 HTTP Payload: snake_case → camelCase

Heads up, backend devs! One thing to update on your server.

flutter_background_geolocation sends this:

{ "location": { "coords": { "latitude": 37.42, "longitude": -122.08, "accuracy": 12.3 }, "timestamp": "2026-03-06T10:30:00.000Z", "is_moving": true, "uuid": "abc-123", "odometer": 1234.5, "activity": { "type": "walking", "confidence": 85 }, "battery": { "level": 0.72, "is_charging": false }, "extras": { "custom_key": "custom_value" } } }

Tracelet sends this:

{ "location": { "coords": { "latitude": 37.42, "longitude": -122.08, "accuracy": 12.3 }, "timestamp": "2026-03-06T10:30:00.000Z", "isMoving": true, "uuid": "abc-123", "odometer": 1234.5, "isMock": false, "activity": { "type": "walking", "confidence": 85 }, "battery": { "level": 0.72, "isCharging": false }, "extras": { "custom_key": "custom_value" } } }

TL;DR: is_movingisMoving, is_chargingisCharging, plus a new isMock field. Update your JSON parsing and you’re golden.


🚨 Common Gotchas

Don’t learn these the hard way — we already did:

  • Config is now compound — Wrap fields in GeoConfig(...), AppConfig(...), HttpConfig(...), etc.
  • desiredAccuracy: -1 doesn’t work — Use DesiredAccuracy.high — typed enums, not magic numbers
  • logLevel: 5 doesn’t work — Use LogLevel.verbose
  • Can’t find resetOdometer() — It’s setOdometer(0) now
  • notification: property gone — It’s foregroundService: ForegroundServiceConfig(...) inside android: (AndroidConfig), not app
  • scheduleUseAlarmManager not in AppConfig — It’s now android.scheduleUseAlarmManager
  • preventSuspend not in AppConfig — It’s now ios.preventSuspend
  • Backend can’t parse is_moving — It’s isMoving now (camelCase)
  • Still got license key code? — Delete it — Tracelet doesn’t need one
  • State properties look different — Check the API Reference 
  • HeadlessEvent.event type errors — Cast it: event.event as tl.Location

📚 More Resources


Welcome to the open-source side. We have cookies. 🍪