Skip to main content

Overview

Radar’s trip tracking feature enables you to track journeys from origin to destination with real-time ETAs, status updates, and approaching/arrival events. Perfect for delivery, ride-sharing, and on-demand services.

Understanding Trips

A trip represents a journey to a destination geofence. Trips include:
  • External ID: Your unique identifier for the trip
  • Destination: A geofence tag or external ID
  • Metadata: Custom key-value pairs
  • Mode: Travel mode (car, bike, foot)
  • Status: Current trip state (started, approaching, arrived, etc.)
  • ETA: Real-time distance and duration to destination
  • Scheduled arrival: Optional expected arrival time
  • Multi-destination support: Multiple legs for complex routes

Trip Lifecycle

Trips progress through the following statuses:
1

Started

Trip has been created and tracking has begun.Status: RadarTripStatusStartedEvent: RadarEventTypeUserStartedTrip
2

Approaching

User is approaching the destination (within threshold).Status: RadarTripStatusApproachingEvent: RadarEventTypeUserApproachingTripDestination
3

Arrived

User has arrived at the destination geofence.Status: RadarTripStatusArrivedEvent: RadarEventTypeUserArrivedAtTripDestination
4

Completed or Canceled

Trip has been completed or canceled.Status: RadarTripStatusCompleted or RadarTripStatusCanceledEvent: RadarEventTypeUserStoppedTrip

Starting a Trip

Start a trip with destination geofence tag or external ID:
let tripOptions = RadarTripOptions(
    externalId: "order-123",
    destinationGeofenceTag: "store",
    destinationGeofenceExternalId: "store-456"
)

tripOptions.mode = .car
tripOptions.metadata = [
    "order_id": "order-123",
    "customer_name": "John Doe"
]

Radar.startTrip(options: tripOptions) { (status, trip, events) in
    if status == .success {
        print("Trip started: \(trip?._id ?? "")")
        print("ETA: \(trip?.etaDuration ?? 0) minutes")
        print("Distance: \(trip?.etaDistance ?? 0) meters")
    }
}
Either destinationGeofenceTag or destinationGeofenceExternalId is required. Both can be provided for additional matching.

Starting with Custom Tracking Options

You can specify custom tracking options for the trip duration:
let tripOptions = RadarTripOptions(
    externalId: "trip-789",
    destinationGeofenceTag: "restaurant",
    destinationGeofenceExternalId: nil
)

let trackingOptions = RadarTrackingOptions.presetContinuous
trackingOptions.desiredMovingUpdateInterval = 30 // 30 seconds

Radar.startTrip(
    options: tripOptions,
    trackingOptions: trackingOptions
) { (status, trip, events) in
    // handle response
}
When you start a trip, Radar automatically starts tracking if not already enabled. You can pass custom tracking options or set startTracking to false to manage tracking separately.

Trip Options Reference

OptionTypeDescription
externalIdStringYour unique identifier for the trip (required).
destinationGeofenceTagString?Tag of the destination geofence.
destinationGeofenceExternalIdString?External ID of the destination geofence.
modeRadarRouteModeTravel mode: .car, .bike, .foot, .truck, .motorbike (default: .car).
metadata[String: Any]?Custom key-value pairs for the trip.
scheduledArrivalAtDate?Expected arrival time.
approachingThresholdUInt16Distance threshold in meters for “approaching” status (default: 0, uses server default).
startTrackingBOOLWhether to automatically start tracking (default: true).
legs[RadarTripLeg]?Array of trip legs for multi-destination trips.

Updating a Trip

Manually update a trip’s options or status:
let tripOptions = RadarTripOptions(
    externalId: "order-123",
    destinationGeofenceTag: "store",
    destinationGeofenceExternalId: "store-789"
)

tripOptions.metadata = ["updated": true]

Radar.updateTrip(
    options: tripOptions,
    status: .unknown // or specify a status to update
) { (status, trip, events) in
    if status == .success {
        print("Trip updated")
    }
}
Pass RadarTripStatusUnknown to avoid updating the trip status when you only want to update other properties.

Completing a Trip

Mark a trip as completed:
Radar.completeTrip { (status, trip, events) in
    if status == .success {
        print("Trip completed")
    }
}

Canceling a Trip

Cancel an active trip:
Radar.cancelTrip { (status, trip, events) in
    if status == .success {
        print("Trip canceled")
    }
}
Completing or canceling a trip does not automatically stop tracking. Call Radar.stopTracking() if you want to stop location updates.

Getting Current Trip

Retrieve the current active trip:
if let trip = Radar.getTrip() {
    print("Trip ID: \(trip._id)")
    print("External ID: \(trip.externalId ?? "")")
    print("Status: \(trip.status)")
    print("ETA: \(trip.etaDuration) minutes")
    print("Distance: \(trip.etaDistance) meters")
}

Trip Events

Receive trip events through the RadarDelegate:
func didReceiveEvents(_ events: [RadarEvent], user: RadarUser?) {
    for event in events {
        switch event.type {
        case .userStartedTrip:
            print("Trip started")
            
        case .userUpdatedTrip:
            if let trip = event.trip {
                print("ETA: \(trip.etaDuration) minutes")
            }
            
        case .userApproachingTripDestination:
            print("User is approaching destination")
            // Send notification to recipient
            
        case .userArrivedAtTripDestination:
            print("User arrived at destination")
            // Complete delivery, notify recipient
            
        case .userStoppedTrip:
            print("Trip stopped (completed or canceled)")
            
        default:
            break
        }
    }
}

Multi-Destination Trips

For trips with multiple stops, use trip legs:

Creating Multi-Destination Trips

let leg1 = RadarTripLeg(
    destinationGeofenceTag: "restaurant",
    destinationGeofenceExternalId: "restaurant-123"
)
leg1.metadata = ["order_id": "order-1"]

let leg2 = RadarTripLeg(
    destinationGeofenceTag: "customer",
    destinationGeofenceExternalId: "customer-456"
)
leg2.metadata = ["order_id": "order-2"]

let tripOptions = RadarTripOptions(
    externalId: "delivery-789",
    destinationGeofenceTag: nil,
    destinationGeofenceExternalId: nil
)
tripOptions.legs = [leg1, leg2]
tripOptions.mode = .car

Radar.startTrip(options: tripOptions) { (status, trip, events) in
    if status == .success {
        print("Multi-destination trip started")
        print("Legs: \(trip?.legs?.count ?? 0)")
        print("Current leg: \(trip?.currentLegId ?? "")")
    }
}

Updating Trip Legs

Update the status of individual legs:
let trip = Radar.getTrip()
if let legId = trip?.legs?.first?._id {
    Radar.updateTripLeg(
        legId: legId,
        status: .arrived
    ) { (status, trip, leg, events) in
        if status == .success {
            print("Leg updated: \(leg?._id ?? "")")
            print("Leg status: \(leg?.status ?? .unknown)")
        }
    }
}

Update Current Leg

Update the current active leg:
Radar.updateCurrentTripLeg(status: .completed) { (status, trip, leg, events) in
    if status == .success {
        print("Current leg completed")
    }
}

Reordering Trip Legs

Reorder legs in a multi-destination trip:
let trip = Radar.getTrip()
if let legIds = trip?.legs?.map({ $0._id }) {
    let reorderedLegIds = [legIds[1], legIds[0]] // swap order
    
    Radar.reorderTripLegs(legIds: reorderedLegIds) { (status, trip, events) in
        if status == .success {
            print("Legs reordered")
        }
    }
}

Trip Properties

Access trip properties from the RadarTrip object:
let trip = Radar.getTrip()

// Identifiers
let radarId = trip?._id
let externalId = trip?.externalId

// Status
let status = trip?.status

// ETA information
let etaDuration = trip?.etaDuration // minutes
let etaDistance = trip?.etaDistance // meters

// Destination
let destinationTag = trip?.destinationGeofenceTag
let destinationExternalId = trip?.destinationGeofenceExternalId
let destinationLocation = trip?.destinationLocation

// Metadata
if let metadata = trip?.metadata {
    print("Metadata: \(metadata)")
}

// Multi-destination trips
if let legs = trip?.legs {
    print("Number of legs: \(legs.count)")
    let currentLegId = trip?.currentLegId
}

Use Cases

Food Delivery

Track delivery driver location and provide customers with real-time ETAs and approaching notifications.

Ride-Sharing

Monitor driver progress to pickup location and notify passengers when the driver is approaching.

Package Delivery

Track couriers across multiple delivery stops with multi-destination trip legs.

Field Services

Track technicians traveling to service appointments with arrival notifications.

Best Practices

1

Use Unique External IDs

Use your own unique identifiers (order IDs, delivery IDs) as the trip’s external ID for easy reference.
2

Set Appropriate Travel Modes

Choose the correct travel mode (car, bike, foot) for accurate ETA calculations.
3

Include Rich Metadata

Store order details, customer information, and other context in trip metadata for personalization.
4

Handle Approaching Events

Listen for approaching events to send timely notifications to recipients.
5

Complete or Cancel Trips

Always complete or cancel trips when finished to maintain clean trip state.
For more details on trip tracking, visit the Radar documentation.