Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/radarlabs/radar-sdk-ios/llms.txt

Use this file to discover all available pages before exploring further.

This guide helps you diagnose and resolve common issues with the Radar iOS SDK.

Quick Diagnostics

Before diving into specific issues, verify these basics:
Ensure you’re calling Radar.initialize() in your AppDelegate’s didFinishLaunchingWithOptions method before any other Radar methods.
AppDelegate.swift
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    Radar.initialize(publishableKey: "prj_test_pk_...")
    return true
}
Verify your publishable key is correct:
  • Starts with prj_test_pk_ (test) or prj_live_pk_ (live)
  • No extra spaces or characters
  • Copied from your Radar dashboard
// Check if initialized
if Radar.isInitialized {
    print("SDK version: \(Radar.sdkVersion)")
}
Check that your app has location permissions:
import CoreLocation

let status = CLLocationManager.authorizationStatus()
switch status {
case .authorizedWhenInUse:
    print("When in use authorization granted")
case .authorizedAlways:
    print("Always authorization granted")
case .denied, .restricted:
    print("Location permission denied or restricted")
case .notDetermined:
    print("Location permission not requested yet")
@unknown default:
    print("Unknown authorization status")
}
Ensure these keys are in your Info.plist:
  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysAndWhenInUseUsageDescription (if using background tracking)
  • Optionally: UIBackgroundModes with location for background tracking

Common Issues

Location Tracking

Location Updates Not Received

1

Enable debug logging

Enable verbose logging to see what the SDK is doing:
// Enable before calling Radar.initialize()
let options = RadarInitializeOptions()
options.logLevel = .debug
Radar.initialize(publishableKey: "prj_test_pk_...", options: options)
2

Implement delegate

Make sure you’ve set a delegate to receive updates:
class MyRadarDelegate: NSObject, RadarDelegate {
    func didUpdateClientLocation(
        _ location: CLLocation,
        stopped: Bool,
        source: RadarLocationSource
    ) {
        print("Location: \(location.coordinate), stopped: \(stopped)")
    }
    
    func didFail(status: RadarStatus) {
        print("Error: \(Radar.stringForStatus(status))")
    }
}

// Set delegate
Radar.setDelegate(MyRadarDelegate())
3

Check tracking status

Verify tracking is actually started:
if Radar.isTracking() {
    let options = Radar.getTrackingOptions()
    print("Tracking with options: \(options)")
} else {
    print("Tracking not started")
    Radar.startTracking(trackingOptions: .presetResponsive)
}
4

Verify location permissions

Background tracking requires “Always” authorization:
let status = CLLocationManager.authorizationStatus()
if status != .authorizedAlways {
    print("Need 'Always' authorization for background tracking")
    // Request always authorization
    let locationManager = CLLocationManager()
    locationManager.requestAlwaysAuthorization()
}
Location updates may be delayed by iOS Low Power Mode, poor connectivity, low battery, or disabled Wi-Fi.

Location Updates Too Infrequent

Symptoms: Location updates happen less often than expected. Solutions:
// Most frequent updates (~30 seconds)
Radar.startTracking(trackingOptions: .presetContinuous)

// Moderate frequency (~2.5 minutes when moving)
Radar.startTracking(trackingOptions: .presetResponsive)

// Least frequent (only on visits)
Radar.startTracking(trackingOptions: .presetEfficient)
let options = RadarTrackingOptions.presetResponsive
options.desiredStoppedUpdateInterval = 120  // 2 minutes when stopped
options.desiredMovingUpdateInterval = 60    // 1 minute when moving
options.desiredAccuracy = .high             // Use best accuracy
Radar.startTracking(trackingOptions: options)
iOS may throttle location updates if:
  • Device is in Low Power Mode
  • Battery is low (< 20%)
  • Poor network connectivity
  • App is in background for extended period
  • Location services are restricted systemwide
These are iOS limitations and cannot be overridden by the SDK.

Tracking Stops When App Backgrounded

Symptoms: Location updates stop when app goes to background. Solutions:
1

Add background location capability

In Xcode, go to your target’s Signing & Capabilities tab:
  1. Click + Capability
  2. Add Background Modes
  3. Enable Location updates
2

Request Always authorization

Background tracking requires “Always” permission:
let locationManager = CLLocationManager()
locationManager.requestAlwaysAuthorization()
3

Add Info.plist key

Add NSLocationAlwaysAndWhenInUseUsageDescription to your Info.plist with a clear explanation of why you need background location access.
4

Don't use continuous with blue bar disabled

If you disable the blue bar indicator:
let options = RadarTrackingOptions.presetContinuous
options.showBlueBar = false  // ⚠️ Not recommended
iOS may still throttle updates. The blue bar is required for guaranteed continuous tracking.

Location Permissions

Permission Prompt Not Showing

Symptoms: Location permission dialog never appears. Solutions:
Ensure you have the correct keys in your Info.plist:
Info.plist
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location to provide nearby recommendations</string>

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We track your location to provide real-time updates and alerts</string>
The description text cannot be empty or the prompt won’t show.
Permission requests must be made on the main thread:
DispatchQueue.main.async {
    let locationManager = CLLocationManager()
    locationManager.requestWhenInUseAuthorization()
}
If the user previously denied permission, the prompt won’t show again:
let status = CLLocationManager.authorizationStatus()
if status == .denied || status == .restricted {
    // Direct user to Settings app
    if let url = URL(string: UIApplication.openSettingsURLString) {
        UIApplication.shared.open(url)
    }
}

Can’t Upgrade from When In Use to Always

Symptoms: Already have “When In Use” permission but can’t get “Always” permission. Solutions:
1

Request in correct order

Request “When In Use” first, then “Always” after the app has been used:
let locationManager = CLLocationManager()

// First request
locationManager.requestWhenInUseAuthorization()

// Later, request Always
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    locationManager.requestAlwaysAuthorization()
}
2

Add both Info.plist keys

You must have both keys in Info.plist to upgrade permissions:
  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysAndWhenInUseUsageDescription
3

Timing matters

iOS may not show the Always prompt immediately. Request it:
  • After the user has used the app a few times
  • When they’re performing an action that benefits from background tracking
  • Not immediately on first launch

Trip Tracking

Trip Not Starting

Symptoms: startTrip() call returns an error or trip doesn’t track. Solutions:
let tripOptions = RadarTripOptions(
    externalId: "trip-123",  // Must be unique
    destinationGeofenceTag: "store",
    destinationGeofenceExternalId: "store-456"
)
tripOptions.mode = .car

Radar.startTrip(options: tripOptions) { (status, trip, events) in
    if status == .success {
        print("Trip started: \(trip?._id ?? "")")
    } else {
        print("Failed to start trip: \(Radar.stringForStatus(status))")
    }
}
The destination geofence must exist in your Radar dashboard:
  1. Go to Geofences
  2. Search for your destinationGeofenceTag or destinationGeofenceExternalId
  3. Ensure the geofence is enabled
Trip tracking requires location tracking to be active:
if !Radar.isTracking() {
    print("Need to start tracking first")
    Radar.startTracking(trackingOptions: .presetResponsive)
}

// Or use automatic tracking
let tripOptions = RadarTripOptions(...)
tripOptions.startTracking = true  // Auto-start tracking
Radar.startTrip(options: tripOptions)

No Trip Events Generated

Symptoms: Trip starts but no approaching/arrival events received. Solutions:
1

Check approaching threshold

Adjust the approaching threshold if events aren’t triggered at the right distance:
let tripOptions = RadarTripOptions(...)
tripOptions.approachingThreshold = 500  // Meters from destination
2

Verify geofence radius

Ensure your destination geofence is large enough. Geofences smaller than 100 meters may have delayed entry detection.
3

Test with manual location

Simulate location updates to test events:
let origin = CLLocation(latitude: 40.7128, longitude: -74.0060)
let destination = CLLocation(latitude: 40.7589, longitude: -73.9851)

Radar.mockTracking(
    origin: origin,
    destination: destination,
    mode: .car,
    steps: 10,
    interval: 3
) { (status, location, events, user) in
    print("Mock update: \(events?.count ?? 0) events")
}

Events and Webhooks

Events Not Received in Delegate

Symptoms: Location updates work but event delegate methods aren’t called. Solutions:
class MyRadarDelegate: NSObject, RadarDelegate {
    func didReceiveEvents(_ events: [RadarEvent], user: RadarUser?) {
        for event in events {
            print("Event: \(RadarEvent.stringForType(event.type) ?? "unknown")")
            if let geofence = event.geofence {
                print("Geofence: \(geofence.tag)")
            }
        }
    }
    
    func didUpdateLocation(_ location: CLLocation, user: RadarUser) {
        print("Location updated, user: \(user._id)")
    }
    
    func didUpdateClientLocation(
        _ location: CLLocation,
        stopped: Bool,
        source: RadarLocationSource
    ) {
        print("Client location updated")
    }
    
    func didFail(status: RadarStatus) {
        print("Error: \(Radar.stringForStatus(status))")
    }
    
    func didLog(message: String) {
        print("Radar log: \(message)")
    }
}
Make sure your delegate isn’t being deallocated:
// ❌ Delegate will be deallocated
Radar.setDelegate(MyRadarDelegate())

// ✅ Keep a strong reference
class MyViewController: UIViewController {
    let radarDelegate = MyRadarDelegate()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        Radar.setDelegate(radarDelegate)
    }
}

Webhooks Not Firing

Symptoms: Events generated but webhooks not received on your server. Solutions:
1

Check webhook configuration

In your Radar dashboard:
  1. Go to SettingsWebhooks
  2. Verify URL is correct and reachable
  3. Ensure event types are enabled
  4. Check webhook signature verification
2

Test endpoint manually

Use the Radar dashboard’s webhook tester to send a test event to your endpoint.
3

Check server logs

Look for incoming requests on your server. Radar webhooks:
  • Use POST method
  • Have Content-Type: application/json
  • Include X-Radar-Signature header
4

Verify event conditions

Some events have conditions:
  • Geofence events require matching tag or metadata
  • Trip events require active trip
  • Dwell events require minimum dwell time

Verified Location

trackVerified() Fails

Symptoms: trackVerified() returns error status. Solutions:
SSL pinning must be configured before calling trackVerified():
// Configure SSL pinning in initialize options
let options = RadarInitializeOptions()
// Add your SSL pinning configuration here
Radar.initialize(publishableKey: "prj_test_pk_...", options: options)

// Then call trackVerified
Radar.trackVerified { (status, token) in
    if let token = token, token.passed {
        print("Location verified: \(token.token)")
    }
}
Location verification requires:
  • SSL pinning configured
  • Valid location with good accuracy
  • Network connectivity
  • Fraud detection enabled in dashboard
Radar.trackVerified(beacons: false, desiredAccuracy: .high) { (status, token) in
    if status != .success {
        print("Verification failed: \(Radar.stringForStatus(status))")
    } else if let token = token {
        print("Passed: \(token.passed)")
        print("Expires: \(token.expiresAt ?? Date())")
    }
}
A failed verification doesn’t mean an error - it might indicate:
  • Location spoofing detected
  • Proxy/VPN usage
  • Location mismatch with expected jurisdiction
Radar.trackVerified { (status, token) in
    guard status == .success else {
        // Handle API error
        return
    }
    
    if token?.passed == true {
        // Verification passed
        sendTokenToServer(token?.token)
    } else {
        // Verification failed - may indicate fraud
        showErrorMessage("Location verification failed")
    }
}

Performance Issues

High Battery Usage

Symptoms: App drains battery faster than expected. Solutions:
// ⚡ Highest battery usage
Radar.startTracking(trackingOptions: .presetContinuous)

// ⚡⚡ Moderate battery usage (recommended)
Radar.startTracking(trackingOptions: .presetResponsive)

// ⚡⚡⚡ Lowest battery usage
Radar.startTracking(trackingOptions: .presetEfficient)
let options = RadarTrackingOptions.presetResponsive
options.desiredMovingUpdateInterval = 300  // 5 minutes
options.desiredStoppedUpdateInterval = 0   // Shut down when stopped
options.desiredAccuracy = .low             // Use lower accuracy
Radar.startTracking(trackingOptions: options)
let options = RadarTrackingOptions.presetResponsive
options.beacons = false          // Disable beacon ranging
options.useIndoorScan = false    // Disable indoor positioning
options.syncGeofences = false    // Disable geofence sync
Radar.startTracking(trackingOptions: options)

App Launch Time Increased

Symptoms: App takes longer to launch after adding Radar SDK. Solutions:
func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    // Initialize Radar first (required)
    Radar.initialize(publishableKey: "prj_test_pk_...")
    
    // Defer tracking start until after UI loads
    DispatchQueue.main.async {
        if CLLocationManager.authorizationStatus() == .authorizedAlways {
            Radar.startTracking(trackingOptions: .presetResponsive)
        }
    }
    
    return true
}
Disable features you don’t need:
let options = RadarInitializeOptions()
options.autoLogNotificationConversions = false  // If not using notifications
options.autoHandleNotificationDeepLinks = false
Radar.initialize(publishableKey: "prj_test_pk_...", options: options)

Debugging Tools

Logging

Enable different log levels to see SDK activity:
let options = RadarInitializeOptions()
options.logLevel = .debug  // .none, .error, .warning, .info, or .debug

Radar.initialize(publishableKey: "prj_test_pk_...", options: options)
Log Levels:
  • .none - No logs
  • .error - Only errors
  • .warning - Warnings and errors
  • .info - Info, warnings, and errors (default)
  • .debug - Verbose logging including all SDK operations
Implement log delegate:
class MyRadarDelegate: NSObject, RadarDelegate {
    func didLog(message: String) {
        print("[Radar] \(message)")
        // Send to your analytics service
    }
}

Testing with Mock Locations

Test tracking without moving:
let sanFrancisco = CLLocation(latitude: 37.7749, longitude: -122.4194)
let newYork = CLLocation(latitude: 40.7128, longitude: -74.0060)

Radar.mockTracking(
    origin: sanFrancisco,
    destination: newYork,
    mode: .car,
    steps: 20,       // Number of location updates
    interval: 2      // Seconds between updates
) { (status, location, events, user) in
    print("Mock location: \(location?.coordinate ?? CLLocationCoordinate2D())")
    print("Events: \(events?.count ?? 0)")
}

Manual Tracking

Test with a manual location:
let testLocation = CLLocation(
    coordinate: CLLocationCoordinate2D(latitude: 40.7589, longitude: -73.9851),
    altitude: 10,
    horizontalAccuracy: 5,
    verticalAccuracy: 5,
    timestamp: Date()
)

Radar.trackOnce(location: testLocation) { (status, location, events, user) in
    print("Status: \(Radar.stringForStatus(status))")
    print("Events: \(events?.count ?? 0)")
    print("User: \(user?._id ?? "")")
}

Check SDK State

Get current SDK configuration:
// Version and initialization
print("SDK Version: \(Radar.sdkVersion)")
print("Is Initialized: \(Radar.isInitialized)")

// Tracking status
print("Is Tracking: \(Radar.isTracking())")
if Radar.isTracking() {
    let options = Radar.getTrackingOptions()
    print("Tracking Options: \(options.dictionaryValue)")
}

// Verified tracking
print("Is Tracking Verified: \(Radar.isTrackingVerified())")

// User info
if let userId = Radar.getUserId() {
    print("User ID: \(userId)")
}
if let metadata = Radar.getMetadata() {
    print("Metadata: \(metadata)")
}

// Trip info
if let trip = Radar.getTrip() {
    print("Active Trip: \(trip._id)")
    print("Status: \(trip.status)")
}

Common Error Codes

Understand error status codes:
switch status {
case .success:
    print("Operation succeeded")
    
case .errorPublishableKey:
    print("SDK not initialized or invalid API key")
    
case .errorPermissions:
    print("Location permissions not granted")
    
case .errorLocation:
    print("Location services error or timeout (20 seconds)")
    
case .errorBluetooth:
    print("Beacon ranging error or timeout (5 seconds)")
    
case .errorNetwork:
    print("Network error or timeout (10 seconds)")
    
case .errorBadRequest:
    print("Bad request - check parameters")
    
case .errorUnauthorized:
    print("Invalid API key")
    
case .errorPaymentRequired:
    print("Organization disabled or usage exceeded")
    
case .errorForbidden:
    print("Insufficient permissions or no beta access")
    
case .errorNotFound:
    print("Resource not found")
    
case .errorRateLimit:
    print("Too many requests - rate limit exceeded")
    
case .errorServer:
    print("Internal server error")
    
case .errorUnknown:
    print("Unknown error")
    
default:
    print("Unhandled error: \(status.rawValue)")
}

Still Having Issues?

If you’re still experiencing problems:

Contact Support

Email support@radar.com with:
  • SDK version
  • iOS version
  • Device model
  • Detailed description
  • Relevant logs

GitHub Issues

Search existing issues or create a new one with:
  • Steps to reproduce
  • Expected behavior
  • Actual behavior
  • Code samples

Documentation

Review the complete documentation for detailed API references and guides

Dashboard

Check your Radar dashboard for:
  • Event logs
  • Webhook logs
  • API usage
  • Configuration

Build docs developers (and LLMs) love