Skip to content

Setup

React Native

Installation

npm install react-native-background-geolocation
yarn add react-native-background-geolocation

Configure your license

Purchase a license

The SDK requires a license for release builds. Debug builds work without one. Purchase at transistorsoft.com.

iOS — Info.plist

<key>TSLocationManagerLicense</key>
<string>YOUR_LICENSE_KEY_JWT</string>

Android — AndroidManifest.xml

<application>
    <meta-data
        android:name="com.transistorsoft.locationmanager.license"
        android:value="YOUR_LICENSE_KEY_JWT" />
</application>

iOS Setup

CocoaPods

cd ios && pod install

Background Modes

In Xcode, select your target → Signing & Capabilities+ CapabilityBackground Modes. Enable:

  • [x] Location updates
  • [x] Background fetch
  • [x] Audio (optional — enables debug sound FX)

Info.plist

<!-- License key -->
<key>TSLocationManagerLicense</key>
<string>YOUR_LICENSE_KEY_JWT</string>

<!-- Background modes -->
<key>UIBackgroundModes</key>
<array>
    <string>location</string>
    <string>fetch</string>
    <string>processing</string>
    <string>audio</string>
</array>

<!-- Background task identifier -->
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
    <string>com.transistorsoft.fetch</string>
</array>

<!-- Location usage descriptions -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>App requires location access at all times for background tracking.</string>

<key>NSLocationWhenInUseUsageDescription</key>
<string>App requires location access while in use.</string>

<key>NSMotionUsageDescription</key>
<string>Motion detection helps determine when the device is stationary.</string>

AppDelegate

import TSBackgroundFetch

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    TSBackgroundFetch.sharedInstance()?.didFinishLaunching()
    return true
}
#import <TSBackgroundFetch/TSBackgroundFetch.h>

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [[TSBackgroundFetch sharedInstance] didFinishLaunching];
    return YES;
}

Android Setup

Gradle ext vars

The plugin reads two optional ext vars from your root project. Set them in android/build.gradle to pin specific versions:

ext {
    playServicesLocationVersion = "21.3.0"
    tslocationmanagerVersion    = "4.0.+"
}
Variable Default Description
playServicesLocationVersion 21.3.0 com.google.android.gms:play-services-location version. Versions ≥ 21 use tslocationmanager; versions < 21 use tslocationmanager-gms20. Browse: maven.google.com
tslocationmanagerVersion 4.0.+ Transistor Android SDK version. Browse: central.sonatype.com

android/app/build.gradle

android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources false   // required
        }
    }
}

AndroidManifest.xml

<application>
    <meta-data
        android:name="com.transistorsoft.locationmanager.license"
        android:value="YOUR_LICENSE_KEY_JWT" />
</application>

Example

import React, { useEffect, useRef } from 'react';
import { Button, View } from 'react-native';
import BackgroundGeolocation, {
  Subscription,
} from 'react-native-background-geolocation';

export default function App() {
  const subscriptions = useRef<Subscription[]>([]);

  useEffect(() => {
    const subs = subscriptions.current;

    // Register event listeners *before* calling ready()
    subs.push(
      BackgroundGeolocation.onLocation(location => {
        console.log('[onLocation]', location);
      })
    );

    // ready() configures the SDK and restores persisted state.
    // It does NOT start tracking — call start()/stop() separately.
    BackgroundGeolocation.ready({
      {{> ts-ready-config.md}}
    });

    return () => subs.forEach(s => s.remove());
  }, []);

  // e.g. a toggle-button handler in your UI
  const onToggleTracking = async () => {
    const state = await BackgroundGeolocation.getState();
    if (state.enabled) {
      BackgroundGeolocation.stop();
    } else {
      BackgroundGeolocation.start();
    }
    console.log('[state]', state.enabled, state.trackingMode);
  };

  return (
    <View>
      <Button title="Toggle Tracking" onPress={onToggleTracking} />
    </View>
  );
}

Expo

Installation

npx expo install react-native-background-geolocation

The SDK ships an Expo Config Plugin — it handles all native configuration automatically during expo prebuild. No manual edits to Info.plist, AndroidManifest.xml, or Gradle files are required.

Configure your license

Purchase a license

The SDK requires a license for release builds. Debug builds work without one. Purchase at transistorsoft.com.

app.json / app.config.js

{
  "expo": {
    "plugins": [
      [
        "react-native-background-geolocation",
        {
          "license": "YOUR_ANDROID_LICENSE_KEY_JWT"
        }
      ],
      [
        "expo-gradle-ext-vars",
        {
          "googlePlayServicesLocationVersion": "21.3.0",
          "tslocationmanagerVersion": "4.0.+"
        }
      ]
    ],
    "ios": {
      "infoPlist": {
        "TSLocationManagerLicense": "YOUR_IOS_LICENSE_KEY_JWT",
        "UIBackgroundModes": ["location", "fetch", "processing", "audio"],
        "BGTaskSchedulerPermittedIdentifiers": [
          "com.transistorsoft.fetch"
        ],
        "NSLocationAlwaysAndWhenInUseUsageDescription": "App requires location access at all times for background tracking.",
        "NSLocationWhenInUseUsageDescription": "App requires location access while in use.",
        "NSMotionUsageDescription": "Motion detection helps determine when the device is stationary."
      }
    }
  }
}

expo-gradle-ext-vars

Install the companion package to control the Google Play Services location version:

npx expo install expo-gradle-ext-vars

Prebuild

After configuring app.json, regenerate native projects:

npx expo prebuild

Then build as normal:

npx expo run:ios
npx expo run:android

Example

The JavaScript API is identical to React Native.

import React, { useEffect, useRef } from 'react';
import { Button, View } from 'react-native';
import BackgroundGeolocation, {
  Subscription,
} from 'react-native-background-geolocation';

export default function App() {
  const subscriptions = useRef<Subscription[]>([]);

  useEffect(() => {
    const subs = subscriptions.current;

    // Register event listeners *before* calling ready()
    subs.push(
      BackgroundGeolocation.onLocation(location => {
        console.log('[onLocation]', location);
      })
    );

    // ready() configures the SDK and restores persisted state.
    // It does NOT start tracking — call start()/stop() separately.
    BackgroundGeolocation.ready({
      {{> ts-ready-config.md}}
    });

    return () => subs.forEach(s => s.remove());
  }, []);

  // e.g. a toggle-button handler in your UI
  const onToggleTracking = async () => {
    const state = await BackgroundGeolocation.getState();
    if (state.enabled) {
      BackgroundGeolocation.stop();
    } else {
      BackgroundGeolocation.start();
    }
    console.log('[state]', state.enabled, state.trackingMode);
  };

  return (
    <View>
      <Button title="Toggle Tracking" onPress={onToggleTracking} />
    </View>
  );
}

Capacitor

Installation

npm install @transistorsoft/capacitor-background-geolocation
npx cap sync

Requires Capacitor 5 or higher.

Configure your license

Purchase a license

The SDK requires a license for release builds. Debug builds work without one. Purchase at transistorsoft.com.

iOS — Info.plist

<key>TSLocationManagerLicense</key>
<string>YOUR_LICENSE_KEY_JWT</string>

Android — AndroidManifest.xml

<application>
    <meta-data
        android:name="com.transistorsoft.locationmanager.license"
        android:value="YOUR_LICENSE_KEY_JWT" />
</application>

iOS Setup

Background Modes

In Xcode, select your target → Signing & Capabilities+ CapabilityBackground Modes. Enable:

  • [x] Location updates
  • [x] Background fetch
  • [x] Audio (optional — enables debug sound FX)

Info.plist

<!-- License key -->
<key>TSLocationManagerLicense</key>
<string>YOUR_LICENSE_KEY_JWT</string>

<!-- Location usage descriptions -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>App requires location access at all times for background tracking.</string>

<key>NSLocationWhenInUseUsageDescription</key>
<string>App requires location access while in use.</string>

<key>NSMotionUsageDescription</key>
<string>Motion detection helps determine when the device is stationary.</string>

Android Setup

Gradle ext vars

The plugin reads two optional ext vars from your root project. Set them in android/variables.gradle:

ext {
    minSdkVersion               = 24
    compileSdkVersion           = 35
    targetSdkVersion            = 35
    playServicesLocationVersion = '21.3.0'
    tslocationmanagerVersion    = '4.0.+'
}
Variable Default Description
playServicesLocationVersion 21.3.0 com.google.android.gms:play-services-location version. Versions ≥ 21 use tslocationmanager; versions < 21 use tslocationmanager-gms20. Browse: maven.google.com
tslocationmanagerVersion 4.0.+ Transistor Android SDK version. Browse: central.sonatype.com

android/app/build.gradle

android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources false   // required
        }
    }
}

AndroidManifest.xml

<application>
    <meta-data
        android:name="com.transistorsoft.locationmanager.license"
        android:value="YOUR_LICENSE_KEY_JWT" />
</application>

Example

import { Injectable, OnDestroy } from '@angular/core';
import BackgroundGeolocation, {
  Subscription,
} from '@transistorsoft/capacitor-background-geolocation';

@Injectable({ providedIn: 'root' })
export class BackgroundGeolocationService implements OnDestroy {
  private subscriptions: Subscription[] = [];

  init() {
    // Register event listeners *before* calling ready()
    this.subscriptions.push(
      BackgroundGeolocation.onLocation(location => {
        console.log('[onLocation]', location);
      })
    );

    // ready() configures the SDK and restores persisted state.
    // It does NOT start tracking — call start()/stop() separately.
    BackgroundGeolocation.ready({
      {{> ts-ready-config.md}}
    });
  }

  // e.g. wired to a toggle button in your template
  async onToggleTracking() {
    const state = await BackgroundGeolocation.getState();
    if (state.enabled) {
      await BackgroundGeolocation.stop();
    } else {
      await BackgroundGeolocation.start();
    }
    console.log('[state]', state.enabled, state.trackingMode);
  }

  ngOnDestroy() {
    this.subscriptions.forEach(s => s.remove());
  }
}
import React, { useEffect, useRef } from 'react';
import BackgroundGeolocation, {
  Subscription,
} from '@transistorsoft/capacitor-background-geolocation';

export default function App() {
  const subscriptions = useRef<Subscription[]>([]);

  useEffect(() => {
    const subs = subscriptions.current;

    // Register event listeners *before* calling ready()
    subs.push(
      BackgroundGeolocation.onLocation(location => {
        console.log('[onLocation]', location);
      })
    );

    // ready() configures the SDK and restores persisted state.
    // It does NOT start tracking — call start()/stop() separately.
    BackgroundGeolocation.ready({
      {{> ts-ready-config.md}}
    });

    return () => subs.forEach(s => s.remove());
  }, []);

  // e.g. a toggle-button handler in your UI
  const onToggleTracking = async () => {
    const state = await BackgroundGeolocation.getState();
    if (state.enabled) {
      BackgroundGeolocation.stop();
    } else {
      BackgroundGeolocation.start();
    }
    console.log('[state]', state.enabled, state.trackingMode);
  };

  return (
    <IonButton onClick={onToggleTracking}>Toggle Tracking</IonButton>
  );
}
<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue';
import BackgroundGeolocation, {
  Subscription,
} from '@transistorsoft/capacitor-background-geolocation';

const subscriptions: Subscription[] = [];

onMounted(() => {
  // Register event listeners *before* calling ready()
  subscriptions.push(
    BackgroundGeolocation.onLocation(location => {
      console.log('[onLocation]', location);
    })
  );

  // ready() configures the SDK and restores persisted state.
  // It does NOT start tracking — call start()/stop() separately.
  BackgroundGeolocation.ready({
    {{> ts-ready-config.md}}
  });
});

// e.g. a toggle-button handler in your template
async function onToggleTracking() {
  const state = await BackgroundGeolocation.getState();
  if (state.enabled) {
    await BackgroundGeolocation.stop();
  } else {
    await BackgroundGeolocation.start();
  }
  console.log('[state]', state.enabled, state.trackingMode);
}

onUnmounted(() => {
  subscriptions.forEach(s => s.remove());
});
</script>