SDK

Contents

Introduction

Integrate the SDK into your iOS and Android apps to start tracking users and generating events. The SDK abstracts away cross-platform differences between location services on iOS and Android, allowing you to add location context and tracking to your apps with just a few lines of code. You can use the SDK to track the user's location in the foreground, in the background, or both.

In the background, the SDK will wake up while the user is moving (usually every 2-3 minutes), then shut down when the user stops (usually within 3-5 minutes). To save battery, the SDK will not wake up when stopped, and the user must move at least 100 meters from a stop to wake up the SDK.

Radar defaults to a balance of accuracy, reliability, responsiveness, and battery efficiency suitable for most use cases. For most users, background tracking uses less than 2% battery per day.

All geofencing and event generation happens server-side. This allows Radar geofencing to be more powerful than native iOS or Android geofencing, with cross-platform support for unlimited geofences, polygon geofences, stop detection, and accuracy down to 50 meters.

Note that you can use our Toolkit apps for iOS and Android to test Radar before integrating the SDK, or to test your implementation of Radar side-by-side with a complete implementation.

Accuracy and reliability

Smartphone location services are not perfect. On iOS and Android, location services use a combination of GPS, wi-fi scanning, and cell tower scanning to determine the user's location. Accuracy and reliability may be reduced if wi-fi is turned off, especially indoors, or if wi-fi is unavailable, such as in sparse suburban or rural areas.

In addition, accuracy and reliability may be reduced by battery-saving features like iOS Low Power Mode, which restricts background app refresh, and Android Doze Mode and App Standby, which restricts wi-fi scanning and network access, and Android O Background Location Limits, which restricts background location updates.

In general, these restrictions apply to all apps and SDKs using location services on iOS and Android, not just Radar. Radar achieves a balance of accuracy, reliability, responsiveness, and battery efficiency suitable for most use cases.

Have questions or concerns? Click the button on the bottom right of any page to chat with us, or email us at [email protected].

Authentication

Authenticate using your publishable API keys, found on the Settings page. Use your Test Publishable key for testing and non-production environments. Use your Live Publishable key for production environments.

Note that you should always use your publishable API keys, which are restricted in scope, in the SDK. Do not use your secret API keys, which are unrestricted in scope, in any client-side code.

iOS

Learn how to integrate the iOS SDK below. You can also see a detailed SDK reference on GitHub.

Configure project

To track the user's location in the foreground, you must add a string for the NSLocationWhenInUseUsageDescription key in your Info.plist file if you haven't already. This string will be displayed when prompting the user for foreground location permissions.

To track the user's location in the background, you must add a string for the NSLocationAlwaysUsageDescription (iOS 10 and before) and NSLocationAlwaysAndWhenInUseUsageDescription (iOS 11 and later) keys in your Info.plist file if you haven't already. These strings will be displayed when prompting the user for background location permissions.

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Your iOS 11 and higher background location usage description goes here. e.g., "This app uses your location in the background to recommend places nearby."</string>

<key>NSLocationAlwaysUsageDescription</key>
<string>Your iOS 10 and lower background location usage description goes here. e.g., "This app uses your location in the background to recommend places nearby."</string>

<key>NSLocationWhenInUseUsageDescription</key>
<string>Your foreground location usage description goes here. e.g., "This app uses your location in the foreground to recommend places nearby."</string>

Then, in your project settings, go to Capabilities > Background Modes and turn on Background fetch.

For increased reliability and responsiveness in the background, you should also turn on Location updates. Note that this requires additional justification during App Store review. Learn more below.

<key>UIBackgroundModes</key>
<array>
  <string>fetch</string>
  <string>location</string>
</array>

Add SDK to project

The best way to add the SDK to your project is via CocoaPods or Carthage.

CocoaPods

For CocoaPods, add the following to your Podfile:

pod 'RadarSDK', '~> 2.1.0'

Then, run pod install.

Carthage

For Carthage, add the following to your Cartfile:

github "radarlabs/radar-sdk-ios" ~> 2.1.0

Then, run carthage update, drag Build/iOS/RadarSDK.framework into the Linked Frameworks and Libraries section of your target. Do not add the framework as an input to your copy-frameworks run script.

Add manually

You can also add the SDK to your project manually, though this is not recommended. Download the current release, unzip the package, and drag RadarSDK.framework into your Xcode project. It will automatically appear in the Linked Frameworks and Libraries section of your project settings.

Dependencies

The SDK depends on Apple's CoreLocation framework (for location services). In your project settings, go to General > Linked Frameworks and Libraries and add CoreLocation if you haven't already.

The SDK currently supports iOS 9 and higher.

Integrate SDK into app

Initialize SDK

Import the SDK:

Swift Objective-C

import RadarSDK
// modules enabled
@import RadarSDK;

// modules not enabled
#import <RadarSDK/RadarSDK.h>

Initialize the SDK in your AppDelegate class before calling any other Radar methods. In application:didFinishLaunchingWithOptions:application(_:didFinishLaunchingWithOptions:), call:

Swift Objective-C

Radar.initialize(publishableKey: publishableKey)
[Radar initializeWithPublishableKey:publishableKey];

where publishableKey is a string containing your publishable API key.

Enable Places

If you are using Places, you must set Facebook as your place data provider, then install and configure the Facebook SDK if you haven't already. If you are not using Places, you can skip this section.

To set Facebook as your place data provider, call:

Swift Objective-C

Radar.setPlacesProvider(.facebook)
[Radar setPlacesProvider:RadarPlacesProviderFacebook];

Then, install and configure the Facebook SDK if you haven't already. Learn how to install and configure the Facebook SDK here.

Remember that you must also enable Places on the Settings page, under Places.

By default, the Radar SDK links to the Facebook SDK and uses the logged-in user's Facebook access token to make Facebook Places requests. To make Facebook Places requests for logged-out users in addition to logged-in users, go to your Facebook app's dashboard, go to Settings > Advanced, get your Client Token, and add it to your Info.plist file with the rest of your Facebook SDK configuration:

<key>FacebookClientToken</key>
<string>{your-client-token}</string>

Identify user

Until you identify the user, Radar will automatically identify the user by deviceId (IDFV).

To identify the user when logged in, call:

Swift Objective-C

Radar.setUserId(userId)
[Radar setUserId:userId];

where userId is a stable unique ID for the user.

You can also set an optional description for the user, displayed in the dashboard, call:

Swift Objective-C

Radar.setDescription(description)
[Radar setDescription:description];

You only need to call these methods once, as these settings will be persisted across app sessions.

Request permissions

Radar respects standard iOS location permissions. Before tracking the user's location, the user must have authorized location permissions for the app if they haven't already. To track the user's location in the foreground, the app's location authorization status must be kCLAuthorizationStatusAuthorizedWhenInUseauthorizedWhenInUse or kCLAuthorizationStatusAuthorizedAlwaysauthorizedAlways. Learn more about requesting permissions here.

Swift Objective-C

self.locationManager = CLLocationManager()

// foreground
self.locationManager.requestWhenInUseAuthorization()

// background
self.locationManager.requestAlwaysAuthorization()
self.locationManager = [CLLocationManager new];

// foreground
[self.locationManager requestWhenInUseAuthorization];

// background
[self.locationManager requestAlwaysAuthorization];

Foreground tracking

Once you have initialized the SDK, you have identified the user, and the user has authorized foreground permissions, you can track the user's location in the foreground.

To track the user's location in the foreground, call:

Swift Objective-C

Radar.trackOnce(completionHandler: { (status: RadarStatus, location: CLLocation?, events: [RadarEvent]?, user: RadarUser?) in
    // do something with status, location, events, user
})
[Radar trackOnceWithCompletionHandler:^(RadarStatus status, CLLocation *location, NSArray<RadarEvent *> *events, RadarUser *user) {
  // do something with status, location, events, user
}];

You may provide an optional completionHandler that receives the request status, the user's location, the events generated, if any, and the user. The request status can be:

  • RadarStatusSuccesssuccess: the request succeeded
  • RadarStatusErrorPublishableKeyerrorPublishableKey: the SDK was not initialized
  • RadarStatusErrorPermissionserrorPermissions: the app's location authorization status is not kCLAuthorizationStatusAuthorizedWhenInUseauthorizedWhenInUse or kCLAuthorizationStatusAuthorizedAlwaysauthorizedAlways
  • RadarStatusErrorLocationerrorLocation: location services were unavailable, or the location request timed out (after 10 seconds)
  • RadarStatusErrorNetworkerrorNetwork: the network was unavailable, or the network connection timed out
  • RadarStatusErrorUnauthorizederrorUnauthorized: the publishable API key is invalid
  • RadarStatusErrorRateLimiterrorRateLimit: exceeded rate limit of 1 request per second per user or 60 requests per hour per user
  • RadarStatusErrorServererrorServer: an internal server error occurred
  • RadarStatusErrorUnknownerrorUnknown: an unknown error occurred

Background tracking

Once you have initialized the SDK and the user has authorized background permissions, you can start tracking the user's location in the background.

To start tracking the user's location in the background with default tracking options, call:

Swift Objective-C

Radar.startTracking()
[Radar startTracking];

Assuming you have configured your project properly, the SDK will wake up while the user is moving (usually every 2-3 minutes), then shut down when the user stops (usually within 3-5 minutes). To save battery, the SDK will not wake up when stopped, and the user must move at least 100 meters from a stop (sometimes more) to wake up the SDK.

Optionally, you can use RadarTrackingOptions to configure advanced tracking options:

Swift Objective-C

let trackingOptions = RadarTrackingOptions()
trackingOptions.offline = .replayStopped // use .replayOff to disable offline replay (.replayStopped recommended)
trackingOptions.sync = .possibleStateChanges // use .all to sync all location updates (.possibleStateChanges recommended)

Radar.startTracking(trackingOptions)
RadarTrackingOptions *trackingOptions = [RadarTrackingOptions new];
trackingOptions.offline = RadarTrackingOfflineReplayStopped; // use RadarTrackingOfflineReplayOff to disable offline replay
trackingOptions.sync = RadarTrackingSyncPossibleStateChanges; // use RadarTrackingSyncAll to sync all location updates

[Radar startTrackingWithOptions:trackingOptions];

To stop tracking the user's location in the background (e.g., when the user logs out), call:

Swift Objective-C

Radar.stopTracking()
[Radar stopTracking];

You only need to call these methods once, as these settings will be persisted across app sessions.

To listen for events or errors client-side in the background, create a class that implements RadarDelegate, then call setDelegate:setDelegate().

Set your RadarDelegate in a codepath that will be initialized and executed in the background. For example, make your AppDelegate implement RadarDelegate, not a ViewController. AppDelegate will be initialized in the background, whereas a ViewController may not be.

Swift Objective-C

class AppDelegate: UIResponder, UIApplicationDelegate, RadarDelegate {

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    Radar.initialize(publishableKey: publishableKey)
    Radar.setDelegate(self)

    return true
  }

  func didReceiveEvents(_ events: [RadarEvent], user: RadarUser) {
    // do something with events, user
  }

  func didUpdateLocation(_ location: CLLocation, user: RadarUser) {
    // do something with location, user
  }

  func didFail(status: RadarStatus) {
    // do something with status
  }

}
@interface AppDelegate : UIResponder <UIApplicationDelegate, RadarDelegate>

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [Radar initializeWithPublishableKey:publishableKey];
  [Radar setDelegate:self];

  return YES;
}

- (void)didReceiveEvents:(NSArray<RadarEvent *> *)events user:(RadarUser *)user {
  // do something with events, user
}

- (void)didUpdateLocation:(CLLocation *)location user:(RadarUser *)user {
  // do something with location, user
}

- (void)didFailWithStatus:(RadarStatus)status {
  // do something with status
}

@end

To listen for events server-side instead, add a webhook.

Manual tracking

If you want to manage location services yourself, you can manually update the user's location instead by calling:

Swift Objective-C

Radar.updateLocation(location, completionHandler: { (status: RadarStatus, location: CLLocation?, events: [RadarEvent]?, user: RadarUser?) in
    // do something with status, events, user
})
[Radar updateLocation:location withCompletionHandler:^(RadarStatus status, CLLocation *location, NSArray<RadarEvent *> *events, RadarUser *user) {
  // do something with status, events, user
}];

where location is a CLLocation instance with a valid latitude, longitude, and horizontal accuracy. As with trackOnceWithCompletionHandler:trackOnce(completionHandler:), you may provide an optional completionHandler that receives the request status, the user's location, the events generated, if any, and the user.

Verify events

You can accept or reject events after user check-ins or other forms of verification. Event verifications will be used to improve the accuracy and confidence level of future Insights and Places events.

Swift Objective-C

Radar.acceptEventId(event._id, verifiedPlaceId: event.alternatePlaces[0]._id)

Radar.rejectEventId(event._id)
[Radar acceptEventId:event._id withVerifiedPlaceId:event.alternatePlaces[0]._id];

[Radar rejectEventId:event._id];

Submit to App Store

Apple requires that you justify your use of background location. Add something materially similar to the following to the bottom of your App Store description: This app uses background location to (insert use case here). Continued use of background location may decrease battery life.

If you turned on the Location updates background mode, Apple requires additional justification. Add something materially similar to the following to your App Store review notes: This app uses the Radar SDK (https://radar.io) to (insert use case here). The Radar SDK requires the background location mode to support polygon geofences, home and work detection, and nearby place detection, which cannot be accomplished with region monitoring or visit monitoring.

Learn more about this requirement in section 2.5.4 of the App Store Review Guidelines here.

Have questions or concerns? Click the button on the bottom right of any page to chat with us, or email us at [email protected].

Android

Learn how to integrate the Android SDK below. You can also see a detailed SDK reference on GitHub.

Configure project

Radar uses the Play Services Location library. If you haven't already configured your project for Play Services, follow the instructions here.

Radar requires the following permissions, included automatically by the SDK manifest:

  • ACCESS_FINE_LOCATION, for location services
  • INTERNET and ACCESS_NETWORK_STATE, to send API requests
  • RECEIVE_BOOT_COMPLETED, to restore geofences on boot

Add SDK to project

The best way to add the SDK to your project is via Gradle and JCenter in Android Studio. Add the SDK to the dependencies section of your build.gradle file:

dependencies {
  implementation 'io.radar:sdk:2.1.+'
}

The SDK depends on Google's v4 support library version 27.1.1 and higher (to check and request location permissions), Play Services Location library version 11.6.2 and higher (for location services), and Volley library version 1.1.0 and higher (for networking). The newest version of these libraries will be automatically included as transitive dependencies. Learn more about managing dependencies in Gradle here.

You can also add the SDK to your project manually, though this is not recommended. Download the current release and unzip the package. The package contains an aar file. In Android Studio, add the SDK as a module using File > New Module > Import .JAR/.AAR Package.

The SDK currently supports API level 16 and higher.

Integrate SDK into app

Initialize SDK

Import the SDK:

Java Kotlin

import io.radar.sdk.Radar;
import io.radar.sdk.Radar

Initialize the SDK in your Application class before calling any other Radar methods. In onCreate(), call:

Java Kotlin

Radar.initialize(publishableKey);
Radar.initialize(publishableKey)

where publishableKey is a string containing your publishable API key.

Enable Places

If you are using Places, you must set Facebook as your place data provider, then install and configure the Facebook SDK if you haven't already. If you are not using Places, you can skip this section.

To set Facebook as your place data provider, call:

Java Kotlin

Radar.setPlacesProvider(RadarPlacesProvider.FACEBOOK);
Radar.placesProvider = RadarPlacesProvider.FACEBOOK

Then, install and configure the Facebook SDK if you haven't already. Learn how to install and configure the Facebook SDK here.

Remember that you must also enable Places on the Settings page, under Places.

By default, the Radar SDK links to the Facebook SDK and uses the logged-in user's Facebook access token to make Facebook Places requests. To make Facebook Places requests for logged-out users in addition to logged-in users, go to your Facebook app's dashboard, go to Settings > Advanced, get your Client Token, and add a facebook_client_token string resource to your project:

<string name="facebook_client_token">{your-client-token}</string>

Identify user

Until you identify the user, Radar will automatically identify the user by deviceId (Android ID).

To identify the user when logged in, call:

Java Kotlin

Radar.setUserId(userId);
Radar.userId = userId

where userId is a stable unique ID for the user.

To set an optional description for the user, displayed in the dashboard, call:

Java Kotlin

Radar.setDescription(description);
Radar.description = description

You only need to call these methods once, as these settings will be persisted across app sessions.

Request permissions

Radar respects standard Android location permissions. Before tracking the user's location, the user must have granted location permissions for the app if they haven't already. Radar requires ACCESS_FINE_LOCATION permissions. Learn more about requesting permissions here.

Java Kotlin

if (Build.VERSION.SDK_INT >= 23) {
    int requestCode = 0;
    ActivityCompat.requestPermissions(activity, new String[] { Manifest.permission.ACCESS_FINE_LOCATION }, requestCode);
}
if (Build.VERSION.SDK_INT >= 23) {
    val requestCode = 0
    ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), requestCode)
}

Foreground tracking

Once you have initialized the SDK, you have identified the user, and the user has granted permissions, you can track the user's location in the foreground.

To track the user's location in the foreground, call:

Java Kotlin

Radar.trackOnce(new RadarCallback() {
  @Override
  public void onComplete(RadarStatus status, Location location, RadarEvent[] events, RadarUser user) {
    // do something with status, location, events, user
  }
});
Radar.trackOnce { status, location, events, user ->
  // do something with status, location, events, user
}

You may provide an optional instance of RadarCallback with an implementation of onComplete() that receives the request status, the user's location, the events generated, if any, and the user. The request status can be:

  • RadarStatus.SUCCESS: the request succeeded
  • RadarStatus.ERROR_PUBLISHABLE_KEY: the SDK was not initialized
  • RadarStatus.ERROR_PERMISSIONS: the user has not granted location permissions for the app
  • RadarStatus.ERROR_LOCATION: location services were unavailable, or the location request timed out (after 10 seconds)
  • RadarStatus.ERROR_NETWORK: the network was unavailable, or the network connection timed out
  • RadarStatus.ERROR_UNAUTHORIZED: the publishable API key is invalid
  • RadarStatus.ERROR_RATE_LIMIT: exceeded rate limit of 1 request per second per user or 60 requests per hour per user
  • RadarStatus.ERROR_UNKNOWN: an unknown error occurred

Background tracking

Once you have initialized the SDK and the user has granted permissions, you can start tracking the user's location in the background.

To start tracking the user's location in the background with default tracking options, call:

Java Kotlin

Radar.startTracking();
Radar.startTracking()

Assuming you have configured your project properly, the SDK will wake up while the user is moving (usually every 2-3 minutes), then shut down when the user stops (usually within 3-5 minutes). To save battery, the SDK will not wake up when stopped, and the user must move at least 100 meters from a stop (sometimes more) to wake up the SDK.

Optionally, you can use RadarTrackingOptions to configure advanced tracking options. RadarTrackingPriority.RESPONSIVENESS is the default. To guarantee that the SDK never exceeds Android vitals bad behavior thresholds for excessive wakeups or excessive background wi-fi scans, you can use RadarTrackingPriority.EFFICIENCY instead.

Java Kotlin

RadarTrackingOptions trackingOptions = new RadarTrackingOptions.Builder()
      .priority(RadarTrackingPriority.RESPONSIVENESS) // use EFFICIENCY to avoid Android vitals bad behavior thresholds
      .offline(RadarTrackingOffline.REPLAY_STOPPED) // use REPLAY_OFF to disable offline replay (REPLAY_STOPPED recommended)
      .sync(RadarTrackingSync.POSSIBLE_STATE_CHANGES) // use ALL to sync all location updates (POSSIBLE_STATE_CHANGES recommended)
      .build();

Radar.startTracking(trackingOptions);
val trackingOptions : RadarTrackingOptions = RadarTrackingOptions.Builder()
      .priority(RadarTrackingPriority.RESPONSIVENESS) // use EFFICIENCY to avoid Android vitals bad behavior thresholds
      .offline(RadarTrackingOffline.REPLAY_STOPPED) // use REPLAY_OFF to disable offline replay (REPLAY_STOPPED recommended)
      .sync(RadarTrackingSync.STATE_CHANGES_ONLY) // use ALL to sync all location updates (STATE_CHANGES_ONLY recommended)
      .build()

Radar.startTracking(trackingOptions)

To stop tracking the user's location in the background (e.g., when the user logs out), call:

Java Kotlin

Radar.stopTracking();
Radar.stopTracking()

You only need to call these methods once, as these settings will be persisted across app sessions.

To listen for events and errors client-side in the background, create a class that extends RadarReceiver. Then, register the receiver by adding a receiver element to the application element in your manifest:

<application android:label="@string/app_name">
  <receiver
      android:name=".MyRadarReceiver"
      android:enabled="true"
      android:exported="false">
      <intent-filter>
          <action android:name="io.radar.sdk.RECEIVED" />
      </intent-filter>
  </receiver>
</application>

Your receiver should implement the following:

Java Kotlin

public class MyRadarReceiver extends RadarReceiver {

  @Override
  public void onEventsReceived(Context context, RadarEvent[] events, RadarUser user) {
    // do something with context, events, user
  }

  @Override
  public void onLocationUpdated(Context context, Location location, RadarUser user) {
    // do something with context, location, user
  }

  @Override
  public void onError(Context context, RadarStatus status) {
    // do something with context, status
  }

}
class MyRadarReceiver: RadarReceiver() {

  override fun onEventsReceived(context: Context, events: Array<RadarEvent>, user: RadarUser) {
    // do something with context, events, user
  }

  override fun onLocationUpdated(context: Context, location: Location, user: RadarUser) {
    // do something with context, location, user
  }

  override fun onError(context: Context, status: RadarStatus) {
    // do something with context, status
  }

}

To listen for events server-side instead, add a webhook.

Manual tracking

If you want to manage location services yourself, you can manually update the user's location instead by calling:

Java Kotlin

Radar.updateLocation(location, new RadarCallback() {
  @Override
  public void onComplete(RadarStatus status, Location location, RadarEvent[] events, RadarUser user) {
    // do something with status, events, user
  }
});
Radar.updateLocation(location) { status, location, events, user ->
  // do something with status, location, events, user
}

where location is a Location instance with a valid latitude, longitude, and accuracy. As with trackOnce(), you may provide an optional instance of RadarCallback with an implementation of onComplete() that receives the request status, the events generated, if any, and the user.

Verify events

You can accept or reject events after user check-ins or other forms of verification. Event verifications will be used to improve the accuracy and confidence level of future Insights and Places events.

Java Kotlin

Radar.acceptEvent(event.getId(), event.alternatePlaces[0].getId());

Radar.rejectEvent(event.getId());
Radar.acceptEvent(event.id, event.alternatePlaces[0].id)

Radar.rejectEvent(event.id)

React Native

Radar has a React Native module for iOS and Android.

See the full documentation and source on GitHub here. Or, get the react-native-radar package on npm here.

import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
import Radar from 'react-native-radar';

export default class MyComponent extends Component {

  componentDidMount() {
    // identify the user and request permissions
    Radar.setUserId(this.state.userId);
    Radar.requestPermissions(true);

    // track the user's location once in the foreground
    Radar.trackOnce().then((result) => {
      // do something with result.events, result.user.geofences
    }).catch((err) => {
      // optionally, do something with err
    });

    // start tracking the user's location in the background
    Radar.startTracking();
  }

}

// receive events
Radar.on('events', (result) => {
  // do something with result.events, result.user
});

// receive location updates
Radar.on('location', (result) => {
  // do something with result.location, result.user
});

// receive errors
Radar.on('error', (err) => {
  // do something with err
});

Web

Radar also has a JavaScript SDK for web. Unlike the React Native module, the JavaScript SDK is designed for use on desktop and mobile web sites and web apps.

See the full documentation and source on GitHub here. Or, get the radar-sdk-js package on npm here.

<script src="https://js.radar.io/v1-beta/radar.js"></script>

<script type="text/javascript">
  Radar.initialize(publishableKey);
  Radar.trackOnce(function(status, location, user, events) {
    if (status === Radar.STATUS.SUCCESS) {
      if (user.place.chain.slug === 'walmart') {
        // do something
      }
    }
  });
</script>

Support

Have questions after reading the documentation? We're here to help! Click the button on the bottom right of any page to chat with us, or email us at [email protected].