# API Reference Source: https://docs.radar.com/api Reference for Radar's REST API, including tracking, geofences, trips, events, users, geocoding, search, and routing endpoints. Use Radar APIs as [building blocks for location-based products and services](#building-blocks) like pickup and delivery tracking, location-triggered notifications, location verification, store locators, address autocomplete, and more. Or, use Radar APIs to [manage your Radar data](#manage-your-radar-data), including users, geofences, and events. The API is RESTful, with predictable, resource-oriented URLs. All responses, including errors, return JSON. `POST` and `PUT` request body parameters may be sent as `application/json` or `application/x-www-form-urlencoded`. ## Authentication All requests must be authenticated. Authenticate using your API keys, found on the [Settings](https://dashboard.radar.com/settings) page. Include your API key in the `Authorization` header. API endpoints with authentication level `Publishable` are safe to call client-side (e.g., [from the SDK](/sdk#authentication)). You should use your publishable API keys to call these endpoints. Use your `Test Publishable` key for testing and non-production environments. Use your `Live Publishable` key for production environments. API endpoints with authentication level `Secret` are only safe to call server-side. You should use your secret API keys to call these endpoints. Use your `Test Secret` key for testing and non-production environments. Use your `Live Secret` key for production environments. Include your API key in the `Authorization` header. **Sample request** ```sh theme={null} curl https://api.radar.io/v1/users \ -H "Authorization: prj_live_sk_..." ``` ## Errors The API uses standard HTTP response codes. **Response codes** * **`200`**: Success * **`202`**: Accepted * **`400`**: Bad request (missing or invalid params) * **`401`**: Unauthorized (invalid API key) * **`402`**: Payment required (organization disabled or usage exceeded) * **`403`**: Forbidden (insufficient permissions) * **`404`**: Not found * **`409`**: Conflict * **`429`**: Too many requests (rate limit exceeded, no state change, or selective throttling) * **`451`**: Unavailable for legal reasons (country blocklisted) * **`500`**: Internal server error * **`503`**: Service temporarily unavailable **Sample error response** ```sh theme={null} { "meta": { "code": 400, "param": "latitude", "message": "latitude: Invalid latitude. Valid range: [-90, 90]." } } ``` ## Request IDs Every API response includes an `X-Radar-Request-ID` header with a unique identifier for the request. **Sample response header** ```sh theme={null} X-Radar-Request-ID: 01890a5d-ac96-774b-bcce-b302099a8057 ``` If you contact support about a specific API call, include the request ID. The request ID allows us to quickly find and debug the exact request. ## Building blocks Use these endpoints as building blocks for location-based products and services like delivery tracking, store locators, address autocomplete, location-based content and notifications, and more. ### Track Tracks a location update. Returns the user and the events generated, depending on project settings. On iOS and Android, use the [SDK](/sdk/sdk) to track user locations in the foreground or in the background. `deviceId` is used to identify logged out users. `userId` and `deviceId` are used to identify logged in users. If a matching user already exists, it will be updated. If not, a new user will be created. Do not send any PII, like names, email addresses, or publicly available IDs, for `userId`. See [privacy best practices](/faqs#what-are-privacy-best-practices-for-radar) for more information. **Definition** `POST` `https://api.radar.io/v1/track` **Body parameters** * **`deviceId`** (string, required): A device ID for the user. Used to identify logged out users. * **`userId`** (string, optional): A stable unique ID for the user. Used with `deviceId` to identify logged in users. Not required for logged out users. * **`latitude`** (number, required): The user's current latitude. A number between -90 and 90. * **`longitude`** (number, required): The user's current longitude. A number between -180 and 180. * **`accuracy`** (number, required): The accuracy of the user's current latitude and longitude, in meters. A number greater than 0. Used when evaluating the [confidence](/geofencing/geofences#confidence-and-accuracy) of geofence events. * **`foreground`** (boolean, optional): `true` if the client is in the foreground, `false` if the client is in the background. * **`stopped`** (boolean, optional): `true` if the user is stopped, `false` if the user is moving. * **`description`** (string, optional): An optional description for the user, displayed in the dashboard. * **`metadata`** (dictionary, optional): An optional dictionary of custom metadata for the user. Up to 32 keys and values of type string, boolean, or number. * **`deviceType`** (string, optional): The user's device type, one of `iOS`, `Android`, or `Web`. * **`updatedAt`** (datetime, optional): The client timestamp or historical timestamp when the user's location was updated. Historical data must be upserted in chronological order. Optional, defaults to the current server timestamp if not provided or not in chronological order. A date or valid ISO date string. * **`replayed`** (boolean, optional): `true` if the location is replayed, `false` if the location is not replayed. Defaults to `false`. * **`deviceOS`** (string, optional): The operating system of the device. * **`deviceMake`** (string, optional): The manufacturer of the device. * **`deviceModel`** (string, optional): The model of the device. * `altitude` (number, optional): An altitude in meters. * `verticalAccuracy` (number, optional): A vertical accuracy in meters. **Authentication level** Publishable **Rate limits** 1 request per second per device **Sample request** ```sh theme={null} curl "https://api.radar.io/v1/track" \ -H "Authorization: prj_live_pk_..." \ -X POST \ -d "deviceId=C305F2DB-56DC-404F-B6C1-BC52F0B680D8" \ -d "userId=1" \ -d "latitude=40.78382" \ -d "longitude=-73.97536" \ -d "accuracy=65" ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "events": [ { "_id": "56db1f4613012711002229f6", "type": "user.entered_geofence", "createdAt": "2018-06-12T13:44:10.535Z", "live": true, "user": { "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", "metadata": { "customId": "abc", "customFlag": false } }, "geofence": { "tag": "store", "externalId": "123", "description": "Store #123", "metadata": { "parking": false } }, "location": { "type": "Point", "coordinates": [ -73.977797, 40.783826 ] }, "locationAccuracy": 5, "confidence": 3 }, { "_id": "56db1f4613012711002229f7", "type": "user.entered_place", "createdAt": "2018-06-12T13:44:10.535Z", "live": true, "user": { "_id": "56db1f4613012711002229f4", "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", "metadata": { "customId": "abc", "customFlag": false } }, "place": { "name": "Starbucks", "chain": { "name": "Starbucks", "slug": "starbucks", "externalId": "123", "metadata": { "customFlag": true } }, "categories": [ "food-beverage", "coffee-shop" ], "location": { "type": "Point", "coordinates": [ -73.977797, 40.783826 ] } }, "location": { "type": "Point", "coordinates": [ -73.977797, 40.783826 ] }, "locationAccuracy": 5, "confidence": 2 } ], "user": { "_id": "56db1f4613012711002229f4", "live": true, "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", "metadata": { "customId": "abc", "customFlag": false }, "updatedAt": "2018-06-12T13:44:10.535Z", "createdAt": "2018-06-10T11:23:58.741Z", "location": { "type": "Point", "coordinates": [ -73.977797, 40.783826 ] }, "locationAccuracy": 5, "stopped": true, "foreground": false, "deviceType": "iOS", "ip": "173.14.0.1", "geofences": [ { "tag": "store", "externalId": "123", "description": "Store #123", "metadata": { "parking": false } } ], "place": { "name": "Starbucks", "chain": { "name": "Starbucks", "slug": "starbucks" }, "categories": [ "food-beverage", "coffee-shop" ], "location": { "type": "Point", "coordinates": [ -73.977797, 40.783826 ] } }, "country": { "code": "US", "name": "United States", "flag": "🇺🇸" }, "state": { "code": "MD", "name": "Maryland" }, "dma": { "code": "26", "name": "Baltimore" }, "postalCode": { "code": "21014", "name": "21014" }, "beacons": [ { "type": "ibeacon", "uuid": "b9407f30-f5f8-466e-aff9-25556b57fe6d", "major": "100", "minor": "1", "description": "Store #123 - Register #1", "tag": "store-register", "externalId": "123-1", "enabled": true } ], "fraud": { "verified": true, "passed": false, "bypassed": false, "blocked": false, "mocked": true, "jumped": false, "compromised": false, "inaccurate": false, "proxy": false, "sharing": false "lastMockedAt": "2023-07-27T17:18:28.536Z", "lastJumpedAt": "2023-07-27T17:18:28.536Z", "lastCompromisedAt": null, "lastInaccurateAt": null, "lastProxyAt": null, "lastSharingAt": null }, "segments": [ { "description": "Starbucks Visitors", "externalId": "starbucks-visitors" } ], "topChains": [ { "name": "Starbucks", "slug": "starbucks", "externalId": "123" }, { "name": "Walmart", "slug": "walmart", "externalId": "456" } ], "fraud": { "proxy": false, "mocked": false } } } ``` ### Geocoding #### **Forward geocode** Geocodes an address, converting address to coordinates. This endpoint is best for complete addresses. For partial addresses or place names, call the [autocomplete](#autocomplete) endpoint instead. Returns a confidence level indicating the certainty of the result's latitude and longitude: * **`exact`**: Precise coordinates for a known address location. * **`interpolated`**: Estimated coordinates between two known address points when an exact address location is unavailable. * **`fallback`**: Coarse coordinates (e.g., postal code/city) for the containing region when no precise location is available. **Definitions** `GET` `https://api.radar.io/v1/geocode/forward` **Query parameters** * **`query`** (string, required): The address to geocode. * **`layers`** (string, optional): Optional layer filters. A string, comma-separated, including one or more of `place`, `address`, `postalCode`, `locality`, `county`, `state`, `country`, `coarse`, and `fine`. Note that `coarse` includes all of `postalCode`, `locality`, `county`, `state`, and `country`, whereas `fine` includes `address` and `place`. If not provided, results from `address` and `coarse` layers will be returned. * **`country`** (string, optional): An optional countries filter. A string of comma-separated countries, the unique 2-letter [country code](/regions/countries). * **`lang`** (string, optional): Specifies the language for the results. A string, one of `ar`, `de`, `en`, `es`, `fr`, `ja`, `ko`, `pt`, `ru`, `zh`. Defaults to `en`. **Authentication level** Publishable **Default rate limit** 100 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/geocode/forward?query=20+jay+st+brooklyn+ny" \ -H "Authorization: prj_live_pk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "addresses": [ { "latitude": 40.7041, "longitude": -73.9867, "geometry": { "type": "Point", "coordinates": [-73.9867,40.7041] }, "country": "United States", "countryCode": "US", "countryFlag": "🇺🇸", "county": "Kings County", "confidence": "exact", "borough": "Brooklyn", "city": "Brooklyn", "number": "20", "neighborhood": "DUMBO", "postalCode": "11201", "stateCode": "NY", "state": "New York", "street": "Jay St", "layer": "address", "formattedAddress": "20 Jay St, Brooklyn, New York, NY 11201 USA", "addressLabel": "20 Jay St", "timeZone": { "id": "America/New_York", "name": "Eastern Daylight Time", "code": "EDT", "currentTime": "2024-04-09T10:12:00-04:00", "utcOffset": -14400, "dstOffset": 3600 } } ] } ``` #### **Reverse geocode** Reverse geocodes a location, converting coordinates to address. **Definitions** `GET` `https://api.radar.io/v1/geocode/reverse` **Query parameters** * `coordinates` (string, required): The coordinates to reverse geocode. A string in the format `latitude,longitude`. * `layers` (string, optional): Optional layer filters. A string, comma-separated, including one or more of `place`, `address`, `postalCode`, `locality`, `county`, `state`, `country`, `coarse`, and `fine`. Note that `coarse` includes all of `postalCode`, `locality`, `county`, `state`, and `country`, whereas `fine` includes `address` and `place`. If not provided, results from `address` and `coarse` layers will be returned. **Authentication level** Publishable **Default rate limit** 100 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/geocode/reverse?coordinates=40.70390,-73.98670" \ -H "Authorization: prj_live_pk_..." ``` **Sample responses** ```json theme={null} { "meta": { "code": 200 }, "addresses": [ { "latitude": 40.70390, "longitude": -73.98670, "geometry": { "type": "Point", "coordinates": [-73.98670, 40.70390] }, "addressLabel": "20 Jay Street", "formattedAddress": "20 Jay Street, Brooklyn, New York, NY 11201 USA", "country": "United States", "countryCode": "US", "countryFlag": "🇺🇸", "state": "New York", "stateCode": "NY", "postalCode": "11201", "city": "New York", "borough": "Brooklyn", "county": "Kings County", "neighborhood": "DUMBO", "timeZone": { "id": "America/New_York", "name": "Eastern Daylight Time", "code": "EDT", "currentTime": "2024-04-09T10:12:00-04:00", "utcOffset": -14400, "dstOffset": 3600 }, "number": "20", "distance": 5, "layer": "address" } ] } ``` #### **IP geocode** Geocodes the requester's IP, converting IP address to city, state, and country. **Definitions** `GET` `https://api.radar.io/v1/geocode/ip` **Authentication level** Publishable **Default rate limit** 100 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/geocode/ip" \ -H "Authorization: prj_live_pk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "address": { "latitude": 40.70390, "longitude": -73.98670, "geometry": { "type": "Point", "coordinates": [-73.98670, 40.70390] }, "country": "United States", "countryCode": "US", "countryFlag": "🇺🇸", "state": "New York", "stateCode": "NY", "postalCode": "11201", "city": "New York", "timeZone": { "id": "America/New_York", "name": "Eastern Daylight Time", "code": "EDT", "currentTime": "2024-04-09T10:12:00-04:00", "utcOffset": -14400, "dstOffset": 3600 }, }, "proxy": false, "ip": "107.77.199.117" } ``` ### **Search** #### **Autocomplete** Autocompletes partial addresses and place names, sorted by relevance and proximity. **Definitions** `GET https://api.radar.io/v1/search/autocomplete` **Query parameters** * `query` (string, required): The partial address or place name to autocomplete. * `near` (string, optional): The location to prefer search results near. A string in the format `latitude,longitude`. If not provided, the request IP geolocation will be used to anchor the search. * `layers` (string, optional): Optional layer filters. A string, comma-separated, including one or more of `place`, `address`, `postalCode`, `locality`, `county`, `state`, `country`, `coarse`, and `fine`. Note that `coarse` includes all of `postalCode`, `locality`, `county`, `state`, and `country`, whereas `fine` includes `address` and `place`. If not provided, results from `address` and `coarse` layers will be returned. * `limit` (number, optional): The max number of addresses to return. A number between 1 and 100. Defaults to 10. * `countryCode` (string, optional): An optional countries filter. A string of comma-separated countries, the unique 2-letter [country code](/regions/countries). **Query best practices** **US/CA:** For customers using autocomplete for full address completion (i.e. checkout page), pass in `layers`: `address`, `countryCode`: `US, CA`. **International:** For customers implementing autocomplete for international address completion use cases, contact your solutions engineer for best practices based on your use case. **Authentication level** Publishable **Default rate limit** 100 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/search/autocomplete?query=brooklyn+roasting&layers=place&near=40.70390,-73.98670" \ -H "Authorization: prj_live_pk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "addresses": [ { "latitude": 40.695779, "longitude": -73.991489, "geometry": { "type": "Point", "coordinates": [-73.991489,40.695779] }, "country": "United States", "countryCode": "US", "countryFlag": "🇺🇸", "county": "Kings County", "distance": 990, "borough": "Brooklyn", "city": "Brooklyn", "number": "1", "neighborhood": "Brooklyn Heights", "postalCode": "11201", "stateCode": "NY", "state": "New York", "street": "Clinton St", "layer": "place", "formattedAddress": "1 Clinton St, Brooklyn, New York, NY 11201 USA", "placeLabel": "Brooklyn Roasting Company" } ] } ``` #### **Search users** Searches for users near a location, sorted by distance. **Definitions** `GET https://api.radar.io/v1/search/users` **Query parameters** * `near` (string, required): A location for the search. A string in the format `latitude,longitude`. * `radius` (number, optional): The radius to search, in meters. A number between 100 and 10000. Defaults to 1000. If `mode` is specified, the `radius` is the travel duration in minutes. * `mode` (string, optional): The [travel mode](https://docs.radar.com/api#distance). A string, one of `car`, `truck`, `foot`, or `bike`. * `metadata[key]` (string, optional): Optional metadata filters. Values may be of type string. Type will be automatically inferred. For example, to match on `working == true`, use `&metadata[working]=true`. * `limit` (number, optional): The max number of users to return. A number between 1 and 100. Defaults to 10. **Authentication level** Secret **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/search/users?near=40.78382,-73.97536&radius=1000&limit=10" \ -H "Authorization: prj_live_sk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "users": [ { "_id": "56db1f4613012711002229f4", "live": true, "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", ... }, ... ] } ``` #### **Search geofences** Searches for geofences near a location, sorted by distance. **Definitions** `GET https://api.radar.io/v1/search/geofences` **Query parameters** * `near` (string, required): A location for the search. A string in the format `latitude,longitude`. * `limit` (number, optional): The max number of geofences to return. A number between 1 and 1000. Defaults to 100. * `radius` (number, optional): Optional radius to search, in meters. * `tags` (string, optional): Optional tag filters. A string, comma-separated. * `metadata[key]` (string, optional): Optional metadata filters. Values may be of type string. Type will be automatically inferred. For example, to match on `offers == true`, use `&metadata[offers]=true`. * `includeGeometry` (boolean, optional): Include geofence geometries in the response. Defaults to `true`. **Note:** To retrieve more than 100 results, `includeGeometries` must be set to `false`. **Authentication level** Publishable **Default rate limit** 50 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/search/geofences?tags=store&metadata%5Boffers%5D=true&near=40.783826,-73.975363&radius=1000&limit=10" \ -H "Authorization: prj_live_pk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "geofences": [ { "_id": "56db1f4613012711002229f5", "createdAt": "2016-06-10T13:44:10.535Z", "live": true, "tag": "store", "externalId": "123", "description": "Store #123", "metadata": { "rating": "4.5" }, "geometryCenter": { "type": "Point", "coordinates": [-73.97536, 40.78382] }, ... }, ... ] } ``` #### **Search places** Searches for places near a location, sorted by distance. **Definitions** `GET https://api.radar.io/v1/search/places` **Query parameters** * `chains` (string, optional): [Chain slug](/places/chains) filters. A string, comma-separated. If your project has a [chain mapping](/geofencing/places#mappings), the mapped ID can be used in place of the chain slug. If not provided, `categories` must be provided. * `categories` (string, optional): [Category](/places/categories) filters. A string, comma-separated. If not provided, `chains` must be provided. * `iataCode` (string, optional): The 3-letter IATA code for the airport to search. If provided, no other parameters are required. * `chainMetadata[key]` (optional): Optional [chain metadata](/geofencing/places#metadata) filters. Values may be of type string, boolean, or number. Type will be automatically inferred. For example, to match on `offers == true`, use `&chainMetadata[offers]=true`. * `near` (string, required): A location for the search. A string in the format `latitude,longitude`. * `radius` (number, optional): The radius to search, in meters. A number between 1 and 10000. Defaults to 1000. * `limit` (number, optional): The max number of places to return. A number between 1 and 100. Defaults to 10. **Authentication level** Publishable **Default rate limit** 50 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/search/places?chains=starbucks&near=40.78382,-73.97779&radius=1000&limit=10" \ -H "Authorization: prj_live_pk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "places": [ { "name": "Starbucks", "chain": { "name": "Starbucks", "slug": "starbucks", "externalId": "123", "metadata": { "customFlag": true } }, "categories": [ "food-beverage", "coffee-shop" ], "location": { "type": "Point", "coordinates": [ -73.97779, 40.78382 ] } }, ... ] } ``` #### **Validate an address** Validates an address. Currently only available for US and Canada addresses for enterprise customers. This endpoint is best for validating complete structured addresses. For partial addresses or place names, call the [autocomplete](/api#autocomplete) endpoint instead. Returns a `verificationStatus` as part of the `result`, as defined below: * `verified`: The input has a complete and unique match with a result. * `partially verified`: The input has a partial match with a result. * `ambiguous`: The input closely matches multiple results. * `unverified`: Unable to verify the input address. Returns a `recordType` value in the `metadata` field as part of the `result`, values are defined below according to USPS standards: * `S`: Street Address * `P`: Post Office Box * `R`: Rural Route * `H`: High-rise * `F`: Firm * `G`: General Delivery On US addresses, an `analysis` field may be returned, which contains the following fields: * `unit:missing`: Radar detected units at the address, but no unit was specified. * `unit:invalid`: Radar detected units at the address, but the unit specified doesn't exist. **Definitions** `GET https://api.radar.io/v1/addresses/validate` **Query parameters** * `city` (string, required): The city name. * `stateCode` (string, required): The 2-letter state abbreviation (e.g., `NY`). * `postalCode` (string, required): The postal or zip code. Plus 4 codes are accepted but not required. * `countryCode` (string, required): The unique 2-letter [country code](/regions/countries) (e.g., `US`). * `number` (string, optional): The building or P.O. box number. If not provided, `addressLabel` must be provided. * `street` (string, optional): The street name. If not provided, `addressLabel` must be provided. * `unit` (string, optional): The unit number, such as apartment or suite (e.g., `Apt 3`). * `addressLabel` (string, optional): The first line of the address, including the building number, street name, and unit number if applicable (e.g., `20 Jay St Apt 3`). If not provided, `number` and `street` must be provided. **Authentication level** Publishable **Default rate limit** 25 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/addresses/validate?countryCode=US&stateCode=NY&city=New%20York&number=841&postalCode=10003&street=Broadway&unit=Fl%7" \ -H "Authorization: prj_live_pk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "address": { "addressLabel": "841 BROADWAY FL 7", "unit": "FL 7", "number": "841", "street": "BROADWAY", "city": "NEW YORK", "stateCode": "NY", "postalCode": "10003", "plus4": "4704", "county": "NEW YORK", "countryCode": "US", "formattedAddress": "841 BROADWAY FL 7, NEW YORK, NY 10003-4704 US", "metadata": { "recordType": "H", "propertyType": "commercial" } }, "result": { "verificationStatus": "verified" } } ``` ### **Routing** #### **Distance** Calculates the travel distance and duration between an origin and a destination. **Definitions** `GET https://api.radar.io/v1/route/distance` **Query parameters** * `origin` (string, required): The origin. A string in the format `latitude,longitude`. * `destination` (string, required): The destination. A string in the format `latitude,longitude`. * `modes` (string, required): The travel modes. A string, comma-separated, including one or more of `car`, `truck`, `foot`, or `bike`. * `units` (string, optional): The distance units. A string, `metric` or `imperial`. Defaults to `imperial` if not provided. In the response, `distance.value` will be in meters for `metric` and in feet for `imperial`. * `avoid` (string, optional): The features that calculated routes should avoid. A string, comma-separated, including one or more of `tolls`, `highways`, `ferries` and `borderCrossings`. No features are avoided if not provided. * `geometry` (string, optional): The format of the `geometry` in the response. Valid values are `linestring`, `polyline5` and `polyline6`. `linestring` returns a GeoJSON `LineString`, `polyline5` returns a polyline with 5 decimal places of precision (compatible with other mapping providers) and `polyline6` returns a polyline with 6 decimal places of precision. Defaults to none if not provided. * `departureTime` (string, optional): The date and time of the route provided as an ISO 8601 date string (e.g., `2025-01-01T14:30:00Z`) which will be used for historical traffic times. If not provided, the current date and time will be used. **Authentication level** Publishable **Default rate limit** 50 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/route/distance?origin=40.78382,-73.97536&destination=40.70390,-73.98690&modes=foot,car&units=imperial" \ -H "Authorization: prj_live_pk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "routes": { "geodesic": { "distance": { "value": 29333.03, "text": "5.6 mi" } }, "foot": { "distance": { "value": 54596.46, "text": "10.3 mi", }, "duration": { "value": 98.48, "text": "1 hr 38 min" } }, "car": { "distance": { "value": 42480.31, "text": "8.0 mi" }, "duration": { "value": 19.9, "text": "20 mins" } } } } ``` #### **Matrix** Calculates the travel distances and durations between multiple origins and destinations for up to 625 routes. **Definitions** `GET https://api.radar.io/v1/route/matrix` **Query parameters** * `origins` (string, required): A list of origins. A pipe-delimited string in the format `latitude0,longitude0|latitude1,longitude1|...`. * `destinations` (string, required): A list of destinations. A pipe-delimited string in the format `latitude0,longitude0|latitude1,longitude1|...`. * `mode` (string, required): The travel mode. A string, one of `car`, `truck`, `foot`, or `bike`. * `units` (string, optional): The distance units. A string, `metric` or `imperial`. Defaults to `imperial` if not provided. * `avoid` (string, optional): The features that calculated routes should avoid. A string, comma-separated, including one or more of `tolls`, `highways` and `ferries`. No features are avoided if not provided. **Authentication level** Publishable **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/route/matrix?origins=40.78382,-73.97536&destinations=40.70390,-73.98690|40.73237,-73.94884&mode=car&units=imperial" \ -H "Authorization: prj_live_pk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "origins": [ { "latitude": 40.78382, "longitude": -73.97536 } ], "destinations": [ { "latitude": 40.70390, "longitude": -73.98670 }, { "latitude": 40.73237, "longitude": -73.94884 } ], "matrix": [ [ { "distance": { "value": 42480.31, "text": "8.0 mi" }, "duration": { "value": 19.9, "text": "20 mins" }, "originIndex": 0, "destinationIndex": 0 }, { "distance": { "value": 31108.92, "text": "5.8 mi" }, "duration": { "value": 17.13, "text": "17 mins" }, "originIndex": 0, "destinationIndex": 1 } ] ] } ``` #### **Route match** Snaps points collected along a route to roads that were most likely traveled on. Returns the matched path and road information. For best results, the sample rate should be less than 10 seconds between points. **Definitions** `POST https://api.radar.io/v1/route/match` **JSON payload** * `path` (array, required): A list of coordinate objects along a route to be snapped. * Each object in the list should be of the form `{"coordinates": "latitude,longitude"}` * Objects may optionally include either or both an ISO date string and an accuracy value in meters for that coordinate `{"coordinates": "latitude,longitude", "createdAt": "iso date string", "accuracy": value}` * `mode` (string, optional): The travel mode. A string, one of `car`, `truck`, `foot`, or `bike`. Defaults to `car`. * `roadAttributes` (string, optional): Attributes of matched roads to be included in the response. A string, comma-separated, including one or more of `speedLimit`, `names`, and `roadClass`. * `roadClass` return values will be one of: * `motorway` * `trunk` * `primary` * `secondary` * `tertiary` * `unclassified` * `residential` * `service_other` * `units` (string, optional): The distance and speed units. A string, `metric` or `imperial`. Defaults to `imperial` if not provided. * `geometry` (string, optional): The format of the `geometry` in the response. Valid values are `linestring`, `polyline5` and `polyline6`. `linestring` returns a GeoJSON `LineString`, `polyline5` returns a polyline with 5 decimal places of precision (compatible with other mapping providers) and `polyline6` returns a polyline with 6 decimal places of precision. Defaults to `polyline6` if not provided. **Authentication level** Publishable **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/route/match" \ -H "Authorization: prj_live_pk_..." \ -H "Content-Type: application/json" \ -X POST \ -d '{"path": [{"coordinates": "40.754231505412264,-73.98465161242224", "createdAt": "2024-03-29T20:47:49Z", "accuracy": 23}, {"coordinates": "40.73988226756973,-73.9950818342906", "createdAt": "2024-03-29T20:49:02Z", "accuracy": 27}], "mode": "car", "roadAttributes": "speedLimit,names,roadClass"}' ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "matchedPath": [ { "latitude": 40.754233, "longitude": -73.984727, "originalIndex": 0 }, { "latitude": 40.739919, "longitude": -73.995156, "originalIndex": 1 } ], "roadAttributes": [ { "roadClass": "residential", "speedLimit": { "value": 25, "text": "25 mph" }, "names": [ "West 41st Street" ], "startLocation": { "latitude": 40.754233, "longitude": -73.984728 }, "endLocation": { "latitude": 40.754464, "longitude": -73.985276 }, "originalIndex": 0 }, { "roadClass": "secondary", "speedLimit": { "value": 25, "text": "25 mph" }, "names": [ "7th Avenue" ], "startLocation": { "latitude": 40.755373, "longitude": -73.987447 }, "endLocation": { "latitude": 40.75532, "longitude": -73.987485 } }, { "roadClass": "residential", "speedLimit": { "value": 25, "text": "25 mph" }, "names": [ "West 18th Street" ], "startLocation": { "latitude": 40.741056, "longitude": -73.997862 }, "endLocation": { "latitude": 40.740997, "longitude": -73.997721 } }, { "roadClass": "residential", "speedLimit": { "value": 25, "text": "25 mph" }, "names": [ "West 18th Street" ], "startLocation": { "latitude": 40.740997, "longitude": -73.997721 }, "endLocation": { "latitude": 40.739919, "longitude": -73.995157 }, "originalIndex": 1 } ], "geometry": { "polyline": "qbmvlAnltblCmMfa@Wx@mApDYz@s@xBcZd_Ag@|Aw@fCc@vA{AvE}Lba@cBrFhBjAbQ|KtLvHnBnAlBnAl]vTbC|AtClBj]jUdDzB|AbAt]nUjCdBhBlA`^vUnBrA`CxAl^hUzBvAlBpAz^lVhDzBnEvCz^dVhBnAjCbB~AdA`ZxRTNrCjBxA`At@d@n\\tTxBvA`C|Az]hUpChBlBtAh]pVpBpAjCdBvOhJrFdDxErCPLrBrAnBpAvQtL|JvGlCdBnBpAhUhOvGjEvBxAvBtA~]hUbC|AfBjAxUrOdG|DjCfBrBrAlD|BtJpGjMjI`EjCbEnCFDnO~JlNfJzBxAzBtAb^vUvBtAfBjAtTvNxFxDtBvAjBnA`\\bTdC`BbBfArTrN`G`ExBxAtByGjbAg_D" }, "distance": { "value": 7439.501747250396, "text": "1.4 mi" } } ``` **Response Definitions** `roadClass` values, in descending order of size: * `motorway`: Major divided highway, normally with 2 or more running lanes plus emergency hard shoulder. * `trunk`: Arterial roads meant to support large amounts of traffic. * `primary`: Large sized roads. * `secondary`: Medium sized roads. * `tertiary`: Small roads that often connect `residential` roads. * `residential`: Roads which serve as an access to housing. * `unclassified`: Minor roads that don't provide access to housing. * `service_other`: For access roads to, or within an industrial estate, camp site, business park, car park, alleys, etc. #### **Directions** Calculates the most efficient route between two or more locations to visit in order. **Definitions** `GET https://api.radar.io/v1/route/directions` **Query parameters** * `locations` (string, required): A list of up to 25 coordinates to visit in order. A pipe-delimited string in the format `latitude0,longitude0|latitude1,longitude1|...`. * `mode` (string, optional): The travel mode. A string, one of `car`, `truck`, `foot`, or `bike`. Defaults to `car`. * `units` (string, optional): The distance units. A string, `metric` or `imperial`. Defaults to `imperial`. * `avoid` (string, optional): The features that calculated routes should avoid. A string, comma-separated, including one or more of `tolls`, `highways`, `ferries` and `borderCrossings`. No features are avoided if not provided. * `geometry` (string, optional): The format of the `geometry` in the response. Valid values are `linestring`, `polyline5` and `polyline6`. `linestring` returns a GeoJSON `LineString`, `polyline5` returns a polyline with 5 decimal places of precision (compatible with other mapping providers) and `polyline6` returns a polyline with 6 decimal places of precision. Defaults to `polyline6` if not provided. * `departureTime` (string, optional): The date and time of the route provided as an ISO 8601 date string (e.g., `2025-01-01T14:30:00Z`) which will be used for historical traffic times. If not provided, the current date and time will be used. * `heading` (number, optional): Initial heading of travel where north is 0°, east is 90°, south is 180°, and west is 270°. If not provided, no initial heading will be used. **Turn by Turn** Additionally you can modify the turn-by-turn directions response by specifying additional query parameters. * `alternatives` (boolean, optional): Specifies whether to try to return alternative routes. This feature is available if only two locations are specified. Defaults to `false`. * `lang` (string, optional): Specifies the language for the results. A string, one of `de`, `en`, `es`, `fr`, `ja`, `ko`, `pt`, `ru`. Defaults to `en`. Each turn-by-turn step includes `maneuver`, a string describing the maneuver type (for example, `start`, `left`, or `destination`). **Authentication level** Publishable **Default rate limit** 20 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/route/directions?locations=40.734250,-73.990934|40.712971,-73.951385|40.745580,-73.903162|40.774419,-73.872746&mode=car&units=imperial" \ -H "Authorization: prj_live_pk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "routes": [ { "duration": { "value": 52.07845, "text": "52 mins" }, "distance": { "value": 62683.72904, "text": "11.9 mi" }, "legs": [ { "startLocation": { "latitude": 40.73425, "longitude": -73.990934 }, "endLocation": { "latitude": 40.712971, "longitude": -73.951385 }, "duration": { "value": 20.394166666666667, "text": "20 mins" }, "distance": { "value": 19639.10824, "text": "3.7 mi" }, "geometry": { "polyline": "kafulAnn`clCfKxAhCF`CJdg@vGtB\\|BZfJrAh[lEhC^dBThMjBjRjCdBZn@Pd@Nh@PzAuE|EoO`HqT`CuHl@mBbCkHxBkGhYk}@v@oCfBuFvB_H~c@avAbLm^ZgAj@kB`BmFlBnAvYlRjAv@nBrAdC~AvVdPdEnCfBhAtBvAj^~UrBtAlBnAn\\dTbBfAtBtAl^zUzAbAjCfBv]tUbBfAjBlAf^pUhBlAnBnAfSzMhLxHrBrAlBrAlFnDzXnRnBrAtBxAjFfDtFx@jEZ|BRzDh@xFtAjD`AvAj@|Ap@lQnH~ZjMhIhDzAl@bBp@nBt@pAh@l{@r]xAf@rBr@xAf@vAd@xItDbVrKvVjKz@^hBr@rEdBzGlC`AwEX}AnG}Zd@}B~@uEj@uCtKyh@XsAh@gCd@yBbJ{c@\\aBr@iD~AeIz@yDn@wCpD}PVmAf@eCf@eC`Joc@VsAf@aCd@}BpHm^r@kDXoAfAkFbA{EtIsb@Z}A`@uBR_AXeAd@}A`AwCtEsNrAsEjAeEb@aBd@aBr@sCz@cDjBcHbIoY|@kD\\qAXkAxDgRzAmHzSgdA~J_g@|\\gcBpb@_uB|U{kAlDqUxWysA`~DirRd_@ufBrJk^ts@spDzH{TrEcU`AoFjCkOd@yC`@}CToCTwChAeTx@}PRkCb@eDd@gCn@sCrP_r@\\wAjAsEmCuAsP}I}KsG}@i@kAq@QeFo@uTAMiBy_@wBac@KkBOkBQiDk@mIs@{Io@aMmBs]{AmXS}EQ{CoBac@OeDeA{ScAoTUmEUeEsA{X}@yPoAcW_Cef@WkF}AcPScFG}AUkFaDXg[dCmKx@aCRec@hD_CP{CZo]bD" }, "steps": [ { "distance": { "value": 931.75856, "text": "0.2 mi" }, "duration": { "value": 1.4142833333333333, "text": "1 min" }, "start_location": { "latitude": 40.734246, "longitude": -73.990904 }, "end_location": { "latitude": 40.731744, "longitude": -73.991464 }, "bearing_before": 0, "bearing_after": 189, "instructions": "Drive south on Broadway. Then, in 300 meters, Turn left onto East 10th Street.", "banner_instructions": "Drive south on Broadway.", "voice_instructions": "Drive south on Broadway.", "geometry": { "polyline": "kafulAnn`clCfKxAhCF`CJdg@vGtB\\|BZfJrAh[lEhC^dBThMjBjRjCdBZn@Pd@Nh@P" }, "mode": "car", "maneuver": "start", "street_name": "Broadway" }, { "distance": { "value": 1473.09716, "text": "0.3 mi" }, "duration": { "value": 2.5110666666666663, "text": "3 mins" }, "start_location": { "latitude": 40.731744, "longitude": -73.991464 }, "end_location": { "latitude": 40.729779, "longitude": -73.986812 }, "bearing_before": 197, "bearing_after": 119, "instructions": "Turn left onto East 10th Street.", "banner_instructions": "Turn left onto East 10th Street.", "voice_instructions": "Turn left onto East 10th Street.", "geometry": { "polyline": "_eaulAnqaclCzAuE|EoO`HqT`CuHl@mBbCkHxBkGhYk}@v@oCfBuFvB_H~c@avAbLm^ZgAj@kB`BmF" }, "mode": "car", "maneuver": "left", "street_name": "East 10th Street" }, { "distance": { "value": 3992.78228, "text": "0.8 mi" }, "duration": { "value": 4.9593, "text": "5 mins" }, "start_location": { "latitude": 40.729779, "longitude": -73.986812 }, "end_location": { "latitude": 40.719911, "longitude": -73.992948 }, "bearing_before": 118, "bearing_after": 208, "instructions": "Turn right onto 2nd Avenue.", "banner_instructions": "Turn right onto 2nd Avenue.", "voice_instructions": "Turn right onto 2nd Avenue.", "geometry": { "polyline": "ej}tlAvnxblClBnAvYlRjAv@nBrAdC~AvVdPdEnCfBhAtBvAj^~UrBtAlBnAn\\dTbBfAtBtAl^zUzAbAjCfBv]tUbBfAjBlAf^pUhBlAnBnAfSzMhLxHrBrAlBrAlFnDzXnRnBrAtBxAjFfDtFx@jEZ|BRzDh@xFtAjD`AvAj@|Ap@lQnH~ZjMhIhDzAl@bBp@nBt@pAh@l{@r]xAf@rBr@xAf@vAd@xItDbVrKvVjKz@^hBr@rEdBzGlC" }, "mode": "car", "maneuver": "right", "street_name": "2nd Avenue" }, { "distance": { "value": 4215.8794, "text": "0.8 mi" }, "duration": { "value": 5.349966666666666, "text": "5 mins" }, "start_location": { "latitude": 40.719911, "longitude": -73.992948 }, "end_location": { "latitude": 40.715536, "longitude": -73.978895 }, "bearing_before": 200, "bearing_after": 111, "instructions": "Turn left onto Delancey Street.", "banner_instructions": "Turn left onto Delancey Street.", "voice_instructions": "Turn left onto Delancey Street.", "geometry": { "polyline": "majtlAfndclC`AwEX}AnG}Zd@}B~@uEj@uCtKyh@XsAh@gCd@yBbJ{c@\\aBr@iD~AeIz@yDn@wCpD}PVmAf@eCf@eC`Joc@VsAf@aCd@}BpHm^r@kDXoAfAkFbA{EtIsb@Z}A`@uBR_AXeAd@}A`AwCtEsNrAsEjAeEb@aBd@aBr@sCz@cDjBcHbIoY|@kD\\qAXkAxDgRzAmHzSgdA~J_g@|\\gcBpb@_uB|U{kA" }, "mode": "car", "maneuver": "left", "street_name": "Delancey Street" }, { "distance": { "value": 5000.00016, "text": "0.9 mi" }, "duration": { "value": 1.6442666666666668, "text": "2 mins" }, "start_location": { "latitude": 40.715536, "longitude": -73.978895 }, "end_location": { "latitude": 40.710451, "longitude": -73.962137 }, "bearing_before": 111, "bearing_after": 107, "instructions": "Keep left to take Interstate 2 78 East toward Queens, Bronx.", "banner_instructions": "Keep left to take I 278 East toward Queens/Bronx.", "voice_instructions": "Keep left to take I 278 East toward Queens/Bronx.", "geometry": { "polyline": "_patlA|_iblClDqUxWysA`~DirRd_@ufBrJk^ts@spD" }, "mode": "car", "maneuver": "stay-left", "street_name": "Williamsburg Bridge" }, { "distance": { "value": 213.2546, "text": "213.3 ft" }, "duration": { "value": 0.07093333333333333, "text": "0.1 min" }, "start_location": { "latitude": 40.710451, "longitude": -73.962137 }, "end_location": { "latitude": 40.710187, "longitude": -73.961433 }, "bearing_before": 111, "bearing_after": 120, "instructions": "Keep right toward Interstate 2 78 West, Broadway West. Then Keep left toward Broadway East.", "banner_instructions": "Keep right toward I 278 West/Broadway West.", "voice_instructions": "Keep right toward I 278 West/Broadway West.", "geometry": { "polyline": "erwslAphhalCzH{TrEcU" }, "mode": "car", "maneuver": "stay-right", "street_name": "I 278 West/Broadway West" }, { "distance": { "value": 757.87404, "text": "757.9 ft" }, "duration": { "value": 0.6236166666666667, "text": "1 min" }, "start_location": { "latitude": 40.710187, "longitude": -73.961433 }, "end_location": { "latitude": 40.709554, "longitude": -73.95886 }, "bearing_before": 111, "bearing_after": 109, "instructions": "Keep left toward Broadway East, South 5th Street.", "banner_instructions": "Keep left toward Broadway East/South 5th Street.", "voice_instructions": "Keep left toward Broadway East/South 5th Street.", "geometry": { "polyline": "uawslAp|falC`AoFjCkOd@yC`@}CToCTwChAeTx@}PRkCb@eDd@gCn@sCrP_r@\\wAjAsE" }, "mode": "car", "maneuver": "stay-left", "street_name": "Broadway East/South 5th Street" }, { "distance": { "value": 259.18636, "text": "259.2 ft" }, "duration": { "value": 0.5566333333333334, "text": "1 min" }, "start_location": { "latitude": 40.709554, "longitude": -73.95886 }, "end_location": { "latitude": 40.710183, "longitude": -73.958458 }, "bearing_before": 115, "bearing_after": 24, "instructions": "Turn left onto Havemeyer Street. Then Turn right onto Borinquen Place.", "banner_instructions": "Turn left onto Havemeyer Street.", "voice_instructions": "Turn left onto Havemeyer Street.", "geometry": { "polyline": "czuslAv{aalCmCuAsP}I}KsG}@i@kAq@" }, "mode": "car", "maneuver": "left", "street_name": "Havemeyer Street" }, { "distance": { "value": 2050.525, "text": "0.4 mi" }, "duration": { "value": 1.8798333333333335, "text": "2 mins" }, "start_location": { "latitude": 40.710183, "longitude": -73.958458 }, "end_location": { "latitude": 40.710961, "longitude": -73.951119 }, "bearing_before": 26, "bearing_after": 84, "instructions": "Turn right onto Borinquen Place.", "banner_instructions": "Turn right onto Borinquen Place.", "voice_instructions": "Turn right onto Borinquen Place.", "geometry": { "polyline": "mawslArbaalCQeFo@uTAMiBy_@wBac@KkBOkBQiDk@mIs@{Io@aMmBs]{AmXS}EQ{CoBac@OeDeA{ScAoTUmEUeEsA{X}@yPoAcW_Cef@WkF}AcPScFG}AUkF" }, "mode": "car", "maneuver": "right", "street_name": "Borinquen Place" }, { "distance": { "value": 734.90816, "text": "734.9 ft" }, "duration": { "value": 1.3842166666666667, "text": "1 min" }, "start_location": { "latitude": 40.710961, "longitude": -73.951119 }, "end_location": { "latitude": 40.712967, "longitude": -73.951428 }, "bearing_before": 82, "bearing_after": 353, "instructions": "Turn left onto Union Avenue.", "banner_instructions": "Turn left onto Union Avenue.", "voice_instructions": "Turn left onto Union Avenue.", "geometry": { "polyline": "arxslA|wr`lCaDXg[dCmKx@aCRec@hD_CP{CZo]bD" }, "mode": "car", "maneuver": "left", "street_name": "Union Avenue" }, { "distance": { "value": 0, "text": "0.0 ft" }, "duration": { "value": 0, "text": "0 min" }, "start_location": { "latitude": 40.712967, "longitude": -73.951428 }, "end_location": { "latitude": 40.712967, "longitude": -73.951428 }, "bearing_before": 352, "bearing_after": 0, "instructions": "You have arrived at your destination.", "banner_instructions": "You have arrived at your destination.", "voice_instructions": "You have arrived at your destination.", "geometry": { "polyline": "mo|slAfks`lC" }, "mode": "car", "maneuver": "destination" } ] }, { "startLocation": { "latitude": 40.712971, "longitude": -73.951385 }, "endLocation": { "latitude": 40.74558, "longitude": -73.903162 }, "duration": { "value": 20.06063333333333, "text": "20 mins" }, "distance": { "value": 21571.523, "text": "4.1 mi" }, "geometry": { "polyline": "mo|slAfks`lCyGn@wk@tGgIz@}CTwDVuVnByXvB_DX}CwDqNeTkt@yhAkKiR}BoDiBeDsZoj@oY}f@cBaDqBkDsVyc@y^mo@_B_DsAmCqJcRuKiTaV{`@oBwC}AuCoc@}{@{CsGeBgDkm@wnA{AsCaB_DkJySiCsFiCuFuBgEYk@iBmDyAyC{AgC_CqDsLaRyG}KmDeGmDwFgC_EiNyTcCuDcCeEyC_GwCoGsSse@_DwGsBmEsBoEsHePaCoFgBsEiBgFqBmFcB}FsAsFyAgGyAmGoAmG{AmHqAyGeFwX{@yEkCcPuBsMyBkOqSstAsDgWgKos@aAuGcC{NeA_GuAeHqAoGqAeG}A}GcBwG_KoU_CcH}BsGiBeFuCeHmCiG{CwGoCsFkCkFwCkFqCmE{CaFwCmE{CiEqEeGocBctBiI_KcHuIiGsHuEaFeFuFcEgEoEkE{FoFkFuEmGaFwEoD}EoDqFaE{GyEoFoDuEuCgEmCoaAwk@ef@qVam@o]oFeDyEsC}DkCsDiCqFiEgFwE}E}E}DmEiD}DuDwE}DsF{DiGoDiGuCsFcDyGgEwJ_MiYy@gCyDqMcDyLgEwMqBoJmB_JkBsImAcHaBiJmAoHiA{GcAwG}@iGu@uFw@{Gw@mGu@qHs@sH_A{L{@uQeAcQy@yPo@qPi@iQ_Bml@[aPu@kQ_AiP}}@s{McB}Wi@mHs@qHu@wHm@eFy@uG{@eGaAsGaAeGkAoGkAcGuAoGuAeGsAuFaBeGaByFcBuFmB}Fwd@{sAqEqM}E_OsE_OwDoM_@wAcCiJy@{CSw@uBcIcHmXwEo_@yEcZgAeF{AwFuAmEqAyDsPad@iC{GuHwRiCyLsFsP[_Cq@kFwCQySeBiU{B_DSmHw@kHu@{BW{Ek@sEk@oDe@mEk@}BW{AQwJiAcq@{HoYkD{m@uHuCa@w@~DWpAsDrRkFbYu@jDq@pCyGvWmGxYwB|H{DlNY`Ai@pBkGrWmHdYiEfWiIhf@sD~Tk@bDeDaAq]kKcFiBUiEYgG" }, "steps": [ { "distance": { "value": 757.87404, "text": "757.9 ft" }, "duration": { "value": 1.42635, "text": "1 min" }, "start_location": { "latitude": 40.712967, "longitude": -73.951428 }, "end_location": { "latitude": 40.715031, "longitude": -73.951773 }, "bearing_before": 0, "bearing_after": 352, "instructions": "Drive north on Union Avenue. Then, in 200 meters, Turn right onto Meeker Avenue.", "banner_instructions": "Drive north on Union Avenue.", "voice_instructions": "Drive north on Union Avenue.", "geometry": { "polyline": "mo|slAfks`lCyGn@wk@tGgIz@}CTwDVuVnByXvB_DX" }, "mode": "car", "maneuver": "start", "street_name": "Union Avenue" }, { "distance": { "value": 5150.9188, "text": "1.0 mi" }, "duration": { "value": 5.7953, "text": "6 mins" }, "start_location": { "latitude": 40.715031, "longitude": -73.951773 }, "end_location": { "latitude": 40.723834, "longitude": -73.937366 }, "bearing_before": 352, "bearing_after": 41, "instructions": "Turn right onto Meeker Avenue.", "banner_instructions": "Turn right onto Meeker Avenue.", "voice_instructions": "Turn right onto Meeker Avenue.", "geometry": { "polyline": "mp`tlAx`t`lC}CwDqNeTkt@yhAkKiR}BoDiBeDsZoj@oY}f@cBaDqBkDsVyc@y^mo@_B_DsAmCqJcRuKiTaV{`@oBwC}AuCoc@}{@{CsGeBgDkm@wnA{AsCaB_DkJySiCsFiCuFuBgEYk@iBmDyAyC{AgC_CqDsLaRyG}KmDeGmDwFgC_EiNyTcCuDcCeEyC_GwCoGsSse@_DwGsBmEsBoEsHePaCoFgBsEiBgFqBmFcB}FsAsFyAgGyAmGoAmG{AmHqAyG" }, "mode": "car", "maneuver": "right", "street_name": "Meeker Avenue" }, { "distance": { "value": 4366.79804, "text": "0.8 mi" }, "duration": { "value": 2.5965, "text": "3 mins" }, "start_location": { "latitude": 40.723834, "longitude": -73.937366 }, "end_location": { "latitude": 40.731092, "longitude": -73.92567 }, "bearing_before": 69, "bearing_after": 69, "instructions": "Take the Interstate 2 78 East ramp on the left toward Brooklyn-Queens Expressway, Queens.", "banner_instructions": "Take the I 278 East ramp on the left toward Brooklyn-Queens Expressway/Queens/Bronx.", "voice_instructions": "Take the I 278 East ramp on the left toward Brooklyn-Queens Expressway/Queens/Bronx.", "geometry": { "polyline": "svqtlAj|w_lCeFwX{@yEkCcPuBsMyBkOqSstAsDgWgKos@aAuGcC{NeA_GuAeHqAoGqAeG}A}GcBwG_KoU_CcH}BsGiBeFuCeHmCiG{CwGoCsFkCkFwCkFqCmE{CaFwCmE{CiEqEeGocBctBiI_KcHuIiGsHuEaFeFuFcEgEoEkE{FoFkFuEmGaFwEoD}EoDqFaE{GyEoFoDuEuCgEmCoaAwk@" }, "mode": "car", "maneuver": "ramp-left", "street_name": "I 278 East/Brooklyn-Queens Expressway" }, { "distance": { "value": 7165.35456, "text": "1.4 mi" }, "duration": { "value": 5.1314166666666665, "text": "5 mins" }, "start_location": { "latitude": 40.731092, "longitude": -73.92567 }, "end_location": { "latitude": 40.738404, "longitude": -73.902957 }, "bearing_before": 27, "bearing_after": 24, "instructions": "Keep left to stay on Interstate 2 78 East, Brooklyn-Queens Expressway.", "banner_instructions": "Keep left to stay on I 278 East/Brooklyn-Queens Expressway.", "voice_instructions": "Keep left to stay on I 278 East/Brooklyn-Queens Expressway.", "geometry": { "polyline": "g|_ulAjaa_lCef@qVam@o]oFeDyEsC}DkCsDiCqFiEgFwE}E}E}DmEiD}DuDwE}DsF{DiGoDiGuCsFcDyGgEwJ_MiYy@gCyDqMcDyLgEwMqBoJmB_JkBsImAcHaBiJmAoHiA{GcAwG}@iGu@uFw@{Gw@mGu@qHs@sH_A{L{@uQeAcQy@yPo@qPi@iQ_Bml@[aPu@kQ_AiP}}@s{McB}Wi@mHs@qHu@wHm@eFy@uG{@eGaAsGaAeGkAoGkAcGuAoGuAeGsAuFaBeGaByFcBuFmB}Fwd@{sAqEqM}E_OsE_OwDoM_@wAcCiJy@{CSw@uBcIcHmX" }, "mode": "car", "maneuver": "stay-left", "street_name": "I 278 East/Brooklyn-Queens Expressway" }, { "distance": { "value": 961.28612, "text": "0.2 mi" }, "duration": { "value": 0.62875, "text": "1 min" }, "start_location": { "latitude": 40.738404, "longitude": -73.902957 }, "end_location": { "latitude": 40.739523, "longitude": -73.899832 }, "bearing_before": 64, "bearing_after": 74, "instructions": "Take exit 39 onto 65th Place.", "banner_instructions": "Take exit 39 onto 65th Place.", "voice_instructions": "Take exit 39 onto 65th Place.", "geometry": { "polyline": "genulAxut}kCwEo_@yEcZgAeF{AwFuAmEqAyDsPad@iC{GuHwRiCyLsFsP[_Cq@kF" }, "mode": "car", "maneuver": "exit-right", "street_name": "Laurel Hill Boulevard", "exit_name": "39" }, { "distance": { "value": 1459.9738, "text": "0.3 mi" }, "duration": { "value": 1.9234166666666668, "text": "2 mins" }, "start_location": { "latitude": 40.739523, "longitude": -73.899832 }, "end_location": { "latitude": 40.743487, "longitude": -73.899074 }, "bearing_before": 74, "bearing_after": 5, "instructions": "Turn left onto 65th Place.", "banner_instructions": "Turn left onto 65th Place.", "voice_instructions": "Turn left onto 65th Place.", "geometry": { "polyline": "ekpulAnrn}kCwCQySeBiU{B_DSmHw@kHu@{BW{Ek@sEk@oDe@mEk@}BW{AQwJiAcq@{HoYkD{m@uHuCa@" }, "mode": "car", "maneuver": "left", "street_name": "65th Place" }, { "distance": { "value": 1374.67196, "text": "0.3 mi" }, "duration": { "value": 1.9673666666666667, "text": "2 mins" }, "start_location": { "latitude": 40.743487, "longitude": -73.899074 }, "end_location": { "latitude": 40.744914, "longitude": -73.903687 }, "bearing_before": 9, "bearing_after": 291, "instructions": "Turn left onto Woodside Avenue.", "banner_instructions": "Turn left onto Woodside Avenue.", "voice_instructions": "Turn left onto Woodside Avenue.", "geometry": { "polyline": "}bxulAbcm}kCw@~DWpAsDrRkFbYu@jDq@pCyGvWmGxYwB|H{DlNY`Ai@pBkGrWmHdYiEfWiIhf@sD~Tk@bD" }, "mode": "car", "maneuver": "left", "street_name": "Woodside Avenue" }, { "distance": { "value": 262.4672, "text": "262.5 ft" }, "duration": { "value": 0.4638, "text": "0.5 min" }, "start_location": { "latitude": 40.744914, "longitude": -73.903687 }, "end_location": { "latitude": 40.7456, "longitude": -73.903403 }, "bearing_before": 289, "bearing_after": 16, "instructions": "Turn right onto 61st Street. Then Turn right onto Roosevelt Avenue.", "banner_instructions": "Turn right onto 61st Street.", "voice_instructions": "Turn right onto 61st Street.", "geometry": { "polyline": "c|zulAlcv}kCeDaAq]kKcFiB" }, "mode": "car", "maneuver": "right", "street_name": "61st Street" }, { "distance": { "value": 65.6168, "text": "65.6 ft" }, "duration": { "value": 0.12766666666666668, "text": "0.1 min" }, "start_location": { "latitude": 40.7456, "longitude": -73.903403 }, "end_location": { "latitude": 40.745624, "longitude": -73.90317 }, "bearing_before": 19, "bearing_after": 81, "instructions": "Turn right onto Roosevelt Avenue. Then You will arrive at your destination.", "banner_instructions": "Turn right onto Roosevelt Avenue.", "voice_instructions": "Turn right onto Roosevelt Avenue.", "geometry": { "polyline": "_g|ulAtqu}kCUiEYgG" }, "mode": "car", "maneuver": "right", "street_name": "Roosevelt Avenue" }, { "distance": { "value": 0, "text": "0.0 ft" }, "duration": { "value": 0, "text": "0 min" }, "start_location": { "latitude": 40.745624, "longitude": -73.90317 }, "end_location": { "latitude": 40.745624, "longitude": -73.90317 }, "bearing_before": 82, "bearing_after": 0, "instructions": "You have arrived at your destination.", "banner_instructions": "You have arrived at your destination.", "voice_instructions": "You have arrived at your destination.", "geometry": { "polyline": "oh|ulAbcu}kC" }, "mode": "car", "maneuver": "destination" } ] }, { "startLocation": { "latitude": 40.74558, "longitude": -73.903162 }, "endLocation": { "latitude": 40.774419, "longitude": -73.872746 }, "duration": { "value": 11.62365, "text": "12 mins" }, "distance": { "value": 21473.0978, "text": "4.1 mi" }, "geometry": { "polyline": "oh|ulAbcu}kCqEg_AwDiz@QaEOoCwDmu@ScEOyCkD{r@[oGQoDyAwXsAcX{Dkv@}Dew@wC\\ea@vEwAPgBTc_@jEqBTgCXg@Fef@pF_@D}C~@M}Cc@{Ke@}IoAqC_AaBeAy@kAm@oBg@s@UiAQcA?g@Pk@@_AZaAXu@\\qG~Cq^dRgHrDgHjDoI|D}G~CeGnCaDfA{DhAaE`AiEx@sNzFsHl@aVnAm_@nD}ShDaQ`EiQfIs~@vg@mc@|V}CfBkZbJaa@pM_UlGwWpFkGxAe^|GkS`BaMz@qLQuM{@wQeDwM}DeNeFqQkGwg@q[e^_Ti_C}wA}l@i`@sE_DuDsCsDaDyDeEwCkDuCyD_DwEkLqRmCwDuDuEoDeE{CuC{CoC}EkDaAm@wBsAmF_CuDcAwEuAyQkEoEuAsDoAeD}A}CsBkCsByCyC}DqEiCyD}BsEuBwEeBmFkAkEeAaFs@_Gg@kG[sFSsHaAyh@c@eRm@cRcCyl@kAcVqIqs@{A_Q_B{PaBgPgBwPmBoPuBkPwBcPiCoQsBuMeCwOoC}OyCiPqCyO{C_PcDaPcDsOiDoOqDoOuDkO_EqOiEaOcEaOoE_OuE_O}E{N{EqNgFkNiFgNoFcNuF_NwFuMgGcNw{@glB_GiMeGyMsFmM}BuFuBkFuBwFoBqFqBuFmB}FcBqFgBcG{AyFcBgG}AkG{AaGuAkGqA_GqAqGoAoG{@kEqCq_@IgA}B_]UeEe@}Ic@}Ke@kL[yLKuMAwPBsNHkMH}K|D_oBHkED{ECuEM{FUuF]sF}@iJeFgi@[iDYwDIwDBmENeEb@gEd@gDv@wDr@kCfAaDfK_Y`Lq_@pw@g_BdTkc@t_@yq@fBaDz@iBh@sAf@_Bb@yATsARaBJgBFsBA}BK}BSuB]{Bo@yB}@}BeAmBoAaBiAmAuAeAqAs@sAc@_B]wAMyAEaBD}AX_Bd@uAp@}AbAoAdA_AbAw@bAmO|T{Rt[eHbMoAnC_AfCcB~EaBjFcAvDs@`Da@|B]bD]zDYjEUxEeDnr@[vE_@tEi@hEu@bFeAbFaAhEw@tCgAfD{BhGkBbEkDdH{GtNiH`OyLjVcC|GqCdIkCpI}CfKaB`GyA~FcBjH_BhIgA~GoAzIkAjJy@`Hu@fIm@hH]~F]|GWjIOhHIdHEtH?Z" }, "steps": [ { "distance": { "value": 1909.44888, "text": "0.4 mi" }, "duration": { "value": 2.5659, "text": "3 mins" }, "start_location": { "latitude": 40.745624, "longitude": -73.90317 }, "end_location": { "latitude": 40.746333, "longitude": -73.896325 }, "bearing_before": 0, "bearing_after": 82, "instructions": "Drive east on Roosevelt Avenue.", "banner_instructions": "Drive east on Roosevelt Avenue.", "voice_instructions": "Drive east on Roosevelt Avenue.", "geometry": { "polyline": "oh|ulAbcu}kCqEg_AwDiz@QaEOoCwDmu@ScEOyCkD{r@[oGQoDyAwXsAcX{Dkv@}Dew@" }, "mode": "car", "maneuver": "start", "street_name": "Roosevelt Avenue" }, { "distance": { "value": 777.55908, "text": "777.6 ft" }, "duration": { "value": 1.1424999999999998, "text": "1 min" }, "start_location": { "latitude": 40.746333, "longitude": -73.896325 }, "end_location": { "latitude": 40.748433, "longitude": -73.896754 }, "bearing_before": 82, "bearing_after": 351, "instructions": "Turn left onto 69th Street.", "banner_instructions": "Turn left onto 69th Street.", "voice_instructions": "Turn left onto 69th Street.", "geometry": { "polyline": "yt}ulAhwg}kCwC\\ea@vEwAPgBTc_@jEqBTgCXg@Fef@pF_@D}C~@" }, "mode": "car", "maneuver": "left", "street_name": "69th Street" }, { "distance": { "value": 127.95276, "text": "128.0 ft" }, "duration": { "value": 0.27251666666666663, "text": "0.3 min" }, "start_location": { "latitude": 40.748433, "longitude": -73.896754 }, "end_location": { "latitude": 40.748477, "longitude": -73.896294 }, "bearing_before": 342, "bearing_after": 83, "instructions": "Turn right onto 37th Avenue. Then Turn left to take the Interstate 2 78 East ramp.", "banner_instructions": "Turn right onto 37th Avenue.", "voice_instructions": "Turn right onto 37th Avenue.", "geometry": { "polyline": "axavlAbrh}kCM}Cc@{Ke@}I" }, "mode": "car", "maneuver": "right", "street_name": "37th Avenue" }, { "distance": { "value": 2388.45152, "text": "0.5 mi" }, "duration": { "value": 0.9872, "text": "1 min" }, "start_location": { "latitude": 40.748477, "longitude": -73.896294 }, "end_location": { "latitude": 40.754551, "longitude": -73.898787 }, "bearing_before": 81, "bearing_after": 54, "instructions": "Turn left to take the Interstate 2 78 East ramp toward Brooklyn Queens Expressway, LaGuardia.", "banner_instructions": "Turn left to take the I 278 East ramp toward Brooklyn Queens Expressway/LaGuardia/Robert F. Kennedy Bridge.", "voice_instructions": "Turn left to take the I 278 East ramp toward Brooklyn Queens Expressway/LaGuardia/Robert F. Kennedy Bridge.", "geometry": { "polyline": "yzavlAjug}kCoAqC_AaBeAy@kAm@oBg@s@UiAQcA?g@Pk@@_AZaAXu@\\qG~Cq^dRgHrDgHjDoI|D}G~CeGnCaDfA{DhAaE`AiEx@sNzFsHl@aVnAm_@nD}ShDaQ`EiQfIs~@vg@mc@|V}CfB" }, "mode": "car", "maneuver": "ramp-left", "street_name": "I 278 East/Brooklyn-Queens Expressway" }, { "distance": { "value": 4025.59068, "text": "0.8 mi" }, "duration": { "value": 1.3148833333333334, "text": "1 min" }, "start_location": { "latitude": 40.754551, "longitude": -73.898787 }, "end_location": { "latitude": 40.764487, "longitude": -73.894912 }, "bearing_before": 333, "bearing_after": 342, "instructions": "Keep right to take exit 42 to stay on Brooklyn-Queens Expressway East toward La Guardia Airport.", "banner_instructions": "Keep right to take exit 42 to stay on Brooklyn-Queens Expressway East toward La Guardia Airport.", "voice_instructions": "Keep right to take exit 42 to stay on Brooklyn-Queens Expressway East toward La Guardia Airport.", "geometry": { "polyline": "mvmvlAdql}kCkZbJaa@pM_UlGwWpFkGxAe^|GkS`BaMz@qLQuM{@wQeDwM}DeNeFqQkGwg@q[e^_Ti_C}wA}l@i`@sE_DuDsCsDaDyDeEwCkDuCyD_DwEkLqRmCwDuDuEoDeE{CuC{CoC}EkDaAm@wBsAmF_C" }, "mode": "car", "maneuver": "stay-right", "street_name": "Brooklyn-Queens Expressway East", "exit_name": "42" }, { "distance": { "value": 5774.2784, "text": "1.1 mi" }, "duration": { "value": 2.5493333333333337, "text": "3 mins" }, "start_location": { "latitude": 40.764487, "longitude": -73.894912 }, "end_location": { "latitude": 40.771256, "longitude": -73.876885 }, "bearing_before": 22, "bearing_after": 15, "instructions": "Keep left to take GCP, Grand Central Parkway.", "banner_instructions": "Keep left to take GCP/Grand Central Parkway.", "voice_instructions": "Keep left to take GCP/Grand Central Parkway.", "geometry": { "polyline": "mcawlA~~d}kCuDcAwEuAyQkEoEuAsDoAeD}A}CsBkCsByCyC}DqEiCyD}BsEuBwEeBmFkAkEeAaFs@_Gg@kG[sFSsHaAyh@c@eRm@cRcCyl@kAcVqIqs@{A_Q_B{PaBgPgBwPmBoPuBkPwBcPiCoQsBuMeCwOoC}OyCiPqCyO{C_PcDaPcDsOiDoOqDoOuDkO_EqOiEaOcEaOoE_OuE_O}E{N{EqNgFkNiFgNoFcNuF_NwFuMgGcNw{@glB_GiMeGyMsFmM}BuFuBkFuBwFoBqFqBuFmB}FcBqFgBcG{AyFcBgG}AkG{AaGuAkGqA_GqAqGoAoG{@kE" }, "mode": "car", "maneuver": "stay-left", "street_name": "GCP/Grand Central Parkway" }, { "distance": { "value": 2906.82424, "text": "0.6 mi" }, "duration": { "value": 1.0503500000000001, "text": "1 min" }, "start_location": { "latitude": 40.771256, "longitude": -73.876885 }, "end_location": { "latitude": 40.770136, "longitude": -73.867012 }, "bearing_before": 68, "bearing_after": 79, "instructions": "Take exit 7 toward LaGuardia Airport, Terminals B-C.", "banner_instructions": "Take exit 7 toward LaGuardia Airport/Terminals B-C.", "voice_instructions": "Take exit 7 toward LaGuardia Airport/Terminals B-C.", "geometry": { "polyline": "ojnwlAhxa|kCqCq_@IgA}B_]UeEe@}Ic@}Ke@kL[yLKuMAwPBsNHkMH}K|D_oBHkED{ECuEM{FUuF]sF}@iJeFgi@[iDYwDIwDBmENeEb@gEd@gDv@wDr@kCfAaDfK_Y`Lq_@pw@g_B" }, "mode": "car", "maneuver": "exit-right", "street_name": "LaGuardia Road", "exit_name": "7" }, { "distance": { "value": 1489.50136, "text": "0.3 mi" }, "duration": { "value": 0.5813166666666666, "text": "1 min" }, "start_location": { "latitude": 40.770136, "longitude": -73.867012 }, "end_location": { "latitude": 40.770698, "longitude": -73.865902 }, "bearing_before": 127, "bearing_after": 127, "instructions": "Take the exit on the left toward Terminal B, Parking B.", "banner_instructions": "Take the exit on the left toward Terminal B/Parking B/Rental Car Return.", "voice_instructions": "Take the exit on the left toward Terminal B/Parking B/Rental Car Return.", "geometry": { "polyline": "odlwlAfon{kCdTkc@t_@yq@fBaDz@iBh@sAf@_Bb@yATsARaBJgBFsBA}BK}BSuB]{Bo@yB}@}BeAmBoAaBiAmAuAeAqAs@sAc@_B]wAMyAEaBD}AX_Bd@uAp@}AbAoAdA_AbAw@bAmO|T{Rt[eHbMoAnC_AfC" }, "mode": "car", "maneuver": "exit-left", "street_name": "Terminal B/Parking B/Rental Car Return" }, { "distance": { "value": 2066.9292, "text": "0.4 mi" }, "duration": { "value": 1.1596, "text": "1 min" }, "start_location": { "latitude": 40.770698, "longitude": -73.865902 }, "end_location": { "latitude": 40.772666, "longitude": -73.872746 }, "bearing_before": 301, "bearing_after": 300, "instructions": "Keep right to take Terminal B Arrivals toward Terminal B Arrivals.", "banner_instructions": "Keep right to take Terminal B Arrivals toward Terminal B Arrivals.", "voice_instructions": "Keep right to take Terminal B Arrivals toward Terminal B Arrivals.", "geometry": { "polyline": "sgmwlAzil{kCcB~EaBjFcAvDs@`Da@|B]bD]zDYjEUxEeDnr@[vE_@tEi@hEu@bFeAbFaAhEw@tCgAfD{BhGkBbEkDdH{GtNiH`OyLjVcC|GqCdIkCpI}CfKaB`GyA~FcBjH_BhIgA~GoAzIkAjJy@`Hu@fIm@hH]~F]|GWjIOhHIdHEtH?Z" }, "mode": "car", "maneuver": "stay-right", "street_name": "Terminal B Arrivals" }, { "distance": { "value": 0, "text": "0.0 ft" }, "duration": { "value": 0, "text": "0 min" }, "start_location": { "latitude": 40.772666, "longitude": -73.872746 }, "end_location": { "latitude": 40.772666, "longitude": -73.872746 }, "bearing_before": 270, "bearing_after": 0, "instructions": "Your destination is on the right.", "banner_instructions": "Your destination is on the right.", "voice_instructions": "Your destination is on the right.", "geometry": { "polyline": "sbqwlAruy{kC" }, "mode": "car", "maneuver": "destination-right" } ] } ], "geometry": { "polyline": "kafulAnn`clCfKxAhCF`CJdg@vGtB\\|BZfJrAh[lEhC^dBThMjBjRjCdBZn@Pd@Nh@PzAuE|EoO`HqT`CuHl@mBbCkHxBkGhYk}@v@oCfBuFvB_H~c@avAbLm^ZgAj@kB`BmFlBnAvYlRjAv@nBrAdC~AvVdPdEnCfBhAtBvAj^~UrBtAlBnAn\\dTbBfAtBtAl^zUzAbAjCfBv]tUbBfAjBlAf^pUhBlAnBnAfSzMhLxHrBrAlBrAlFnDzXnRnBrAtBxAjFfDtFx@jEZ|BRzDh@xFtAjD`AvAj@|Ap@lQnH~ZjMhIhDzAl@bBp@nBt@pAh@l{@r]xAf@rBr@xAf@vAd@xItDbVrKvVjKz@^hBr@rEdBzGlC`AwEX}AnG}Zd@}B~@uEj@uCtKyh@XsAh@gCd@yBbJ{c@\\aBr@iD~AeIz@yDn@wCpD}PVmAf@eCf@eC`Joc@VsAf@aCd@}BpHm^r@kDXoAfAkFbA{EtIsb@Z}A`@uBR_AXeAd@}A`AwCtEsNrAsEjAeEb@aBd@aBr@sCz@cDjBcHbIoY|@kD\\qAXkAxDgRzAmHzSgdA~J_g@|\\gcBpb@_uB|U{kAlDqUxWysA`~DirRd_@ufBrJk^ts@spDzH{TrEcU`AoFjCkOd@yC`@}CToCTwChAeTx@}PRkCb@eDd@gCn@sCrP_r@\\wAjAsEmCuAsP}I}KsG}@i@kAq@QeFo@uTAMiBy_@wBac@KkBOkBQiDk@mIs@{Io@aMmBs]{AmXS}EQ{CoBac@OeDeA{ScAoTUmEUeEsA{X}@yPoAcW_Cef@WkF}AcPScFG}AUkFaDXg[dCmKx@aCRec@hD_CP{CZo]bDyGn@wk@tGgIz@}CTwDVuVnByXvB_DX}CwDqNeTkt@yhAkKiR}BoDiBeDsZoj@oY}f@cBaDqBkDsVyc@y^mo@_B_DsAmCqJcRuKiTaV{`@oBwC}AuCoc@}{@{CsGeBgDkm@wnA{AsCaB_DkJySiCsFiCuFuBgEYk@iBmDyAyC{AgC_CqDsLaRyG}KmDeGmDwFgC_EiNyTcCuDcCeEyC_GwCoGsSse@_DwGsBmEsBoEsHePaCoFgBsEiBgFqBmFcB}FsAsFyAgGyAmGoAmG{AmHqAyGeFwX{@yEkCcPuBsMyBkOqSstAsDgWgKos@aAuGcC{NeA_GuAeHqAoGqAeG}A}GcBwG_KoU_CcH}BsGiBeFuCeHmCiG{CwGoCsFkCkFwCkFqCmE{CaFwCmE{CiEqEeGocBctBiI_KcHuIiGsHuEaFeFuFcEgEoEkE{FoFkFuEmGaFwEoD}EoDqFaE{GyEoFoDuEuCgEmCoaAwk@ef@qVam@o]oFeDyEsC}DkCsDiCqFiEgFwE}E}E}DmEiD}DuDwE}DsF{DiGoDiGuCsFcDyGgEwJ_MiYy@gCyDqMcDyLgEwMqBoJmB_JkBsImAcHaBiJmAoHiA{GcAwG}@iGu@uFw@{Gw@mGu@qHs@sH_A{L{@uQeAcQy@yPo@qPi@iQ_Bml@[aPu@kQ_AiP}}@s{McB}Wi@mHs@qHu@wHm@eFy@uG{@eGaAsGaAeGkAoGkAcGuAoGuAeGsAuFaBeGaByFcBuFmB}Fwd@{sAqEqM}E_OsE_OwDoM_@wAcCiJy@{CSw@uBcIcHmXwEo_@yEcZgAeF{AwFuAmEqAyDsPad@iC{GuHwRiCyLsFsP[_Cq@kFwCQySeBiU{B_DSmHw@kHu@{BW{Ek@sEk@oDe@mEk@}BW{AQwJiAcq@{HoYkD{m@uHuCa@w@~DWpAsDrRkFbYu@jDq@pCyGvWmGxYwB|H{DlNY`Ai@pBkGrWmHdYiEfWiIhf@sD~Tk@bDeDaAq]kKcFiBUiEYgGqEg_AwDiz@QaEOoCwDmu@ScEOyCkD{r@[oGQoDyAwXsAcX{Dkv@}Dew@wC\\ea@vEwAPgBTc_@jEqBTgCXg@Fef@pF_@D}C~@M}Cc@{Ke@}IoAqC_AaBeAy@kAm@oBg@s@UiAQcA?g@Pk@@_AZaAXu@\\qG~Cq^dRgHrDgHjDoI|D}G~CeGnCaDfA{DhAaE`AiEx@sNzFsHl@aVnAm_@nD}ShDaQ`EiQfIs~@vg@mc@|V}CfBkZbJaa@pM_UlGwWpFkGxAe^|GkS`BaMz@qLQuM{@wQeDwM}DeNeFqQkGwg@q[e^_Ti_C}wA}l@i`@sE_DuDsCsDaDyDeEwCkDuCyD_DwEkLqRmCwDuDuEoDeE{CuC{CoC}EkDaAm@wBsAmF_CuDcAwEuAyQkEoEuAsDoAeD}A}CsBkCsByCyC}DqEiCyD}BsEuBwEeBmFkAkEeAaFs@_Gg@kG[sFSsHaAyh@c@eRm@cRcCyl@kAcVqIqs@{A_Q_B{PaBgPgBwPmBoPuBkPwBcPiCoQsBuMeCwOoC}OyCiPqCyO{C_PcDaPcDsOiDoOqDoOuDkO_EqOiEaOcEaOoE_OuE_O}E{N{EqNgFkNiFgNoFcNuF_NwFuMgGcNw{@glB_GiMeGyMsFmM}BuFuBkFuBwFoBqFqBuFmB}FcBqFgBcG{AyFcBgG}AkG{AaGuAkGqA_GqAqGoAoG{@kEqCq_@IgA}B_]UeEe@}Ic@}Ke@kL[yLKuMAwPBsNHkMH}K|D_oBHkED{ECuEM{FUuF]sF}@iJeFgi@[iDYwDIwDBmENeEb@gEd@gDv@wDr@kCfAaDfK_Y`Lq_@pw@g_BdTkc@t_@yq@fBaDz@iBh@sAf@_Bb@yATsARaBJgBFsBA}BK}BSuB]{Bo@yB}@}BeAmBoAaBiAmAuAeAqAs@sAc@_B]wAMyAEaBD}AX_Bd@uAp@}AbAoAdA_AbAw@bAmO|T{Rt[eHbMoAnC_AfCcB~EaBjFcAvDs@`Da@|B]bD]zDYjEUxEeDnr@[vE_@tEi@hEu@bFeAbFaAhEw@tCgAfD{BhGkBbEkDdH{GtNiH`OyLjVcC|GqCdIkCpI}CfKaB`GyA~FcBjH_BhIgA~GoAzIkAjJy@`Hu@fIm@hH]~F]|GWjIOhHIdHEtH?Z" } } ] } ``` #### **Optimize route** Calculates the optimal ordering and route to visit a list of locations. **Definitions** `GET https://api.radar.io/v1/route/optimize` **Query parameters** * `locations` (string, required): A list of up to 10 coordinates to visit. A pipe-delimited string in the format `latitude0,longitude0|latitude1,longitude1|...`. The first location should be the origin of the route, and the last location should be the final destination. * `mode` (string, optional): The travel mode. A string, one of `car`, `truck`, `foot`, or `bike`. Defaults to `car`. * `units` (string, optional): The distance units. A string, `metric` or `imperial`. Defaults to `imperial`. * `geometry` (string, optional): The format of the `geometry` in the response. Valid values are `linestring`, `polyline5` and `polyline6`. `linestring` returns a GeoJSON `LineString`, `polyline5` returns a polyline with 5 decimal places of precision (compatible with other mapping providers) and `polyline6` returns a polyline with 6 decimal places of precision. Defaults to none if not provided. **Authentication level** Publishable **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/route/optimize?locations=40.7343164,-73.995688|40.6396701,-73.9257626|40.6390023,-73.9975035|40.7227423,-73.9983234|40.6410279,-73.7746107&mode=car&units=imperial" \ -H "Authorization: prj_live_pk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "route": { "distance": { "value": 137388.45584, "text": "26.0 mi" }, "duration": { "value": 49.1802166667, "text": "49 mins" }, "legs": [ { "startLocation": { "latitude": 40.7343164, "longitude": -73.995688 }, "endLocation": { "latitude": 40.7227423, "longitude": -73.9983234 }, "startIndex": 0, "endIndex": 3, "distance": { "value": 9137.1394, "text": "1.7 mi" }, "duration": { "value": 5.2633833333333335, "text": "5 mins" }, "geometry": { "polyline": "kefulAxyiclCg_AlxCiBzFmBjGa}@`uC_AxCsAhEeBvEhJrEd^fQj@XfClAvAr@lHlD~BlAfFfClCpAtLjG~Av@vBfAp[lOpI`EjB|@tBbAdF`CtIbE`JfEjD`BhBz@lCnAlEtB|L|FnB~@xCvA|SzJ~E~BfK~EvJtE`Ab@~@d@fFbCjNvGl]lPlKbFxCvAdBx@bPvHhD`B~At@tPdIdCjAlBbAr\\lQdNvFhDvAvBXjEj@d[dChJt@dBNhCN~CNl_@zCjCTXsGzJc{BZgHmC{@oOwEmEsFaDaB}@eAe@yA\\gDvA_FvHsR~@aC~@cCjH}QzH_Sv@sBjAuChRef@`AeC|@}BhP}a@rAmDtAqD~Tkk@jTkj@`AcC|@_CzG}PxHwRbAkCnAaDjNg^bBqHBG~@mFfCrB~LzJvq@zi@xAjAbAx@fM`Kpw@xn@|AnAjAmDFShJ_Z" } }, { "startLocation": { "latitude": 40.7227423, "longitude": -73.9983234 }, "endLocation": { "latitude": 40.6390023, "longitude": -73.9975035 }, "startIndex": 3, "endIndex": 2, "distance": { "value": 44586.6156, "text": "8.4 mi" }, "duration": { "value": 15.074816666666667, "text": "15 mins" }, "geometry": { "polyline": "{uotlAt{nclCjEeNt@aCh@aBdQci@hBwFnApFre@h]`CdBnAqFbCcKn@oCj@aClM{i@FUf@yBl@eCjMwi@p@sCh@yBtLug@DQh@}Bh@yBDQjLmf@h@}BFW`AaEjEjAtIbCxGMzWjIlCz@fBj@ju@nUnCz@bC|@LFvRnIfUpJlV~KtBbAlB~@hc@tUhR|J|DrBzDAbBOvAWjAg@|Y{PfHsF`B}AhBsBfByBnFkH|AiBzAeBzAcB|A{AdB}ApBwAhCyAbCqAtVqKzq[o~N`UoK|@a@rNaDtCcA|Bi@pCYnAKbBLxAb@rAbA~@pA`AzAt@tB\\lCJtCClCYvBg@nBw@~AkAnAqAlAmLnAgFKmIOmg@kAyDh@BcBd@oYHsDB{ANoJr@_[`Cu`@~Bop@z@gGdAiIh@cEv@uGt@yE~@cF`A_Ez@cDjA}B~@wAbBaBzAaAjA]`B]rA@|AVlA^jAt@x@bAx@bBp@zBT~BC~CQbDg@|BcA~BkLlOoV|Y{PzRcRvTsE`G{EpH{FjKiChFuDfIcCfHwCbJaBfGiBzHgBzIgAhIy@|HqBxSeBnScBzR}Drf@iAnM}Etn@iAfP{Cxk@Y|Qi@nSWjOWfUHfJT|LPvH^xMj@hHdA`Ix@rFpAbIjBhJnB`KrB|IjD|LrJzZnLfZvH~TvL|VhJ`NdL~NzNfMzOvJhVhKtt@xXf`@rNvl@fUrcAt_@hyAxi@da@jNfPhEbRrG~MxDjLpBnMz@vOBhJi@pU{Cld@cOnc@kO~KqC~KeBvLu@lGCjGZlNbClN|DnNpErxMpcFv\\~Nr`@lOdb@lMfPhDzNnAfXa@vSkDjJaDbHaDpIcFrI_Gdx@mr@~V{R`g@g_@fn@ec@z`Li~FtQgJdVgJfTeJjH}AbD}@`D}ArF{DxBoBzBmC|EaH`GiLpIeQhOyX`J{Q~JuQzt@m{A~Ow[no@apAzZyk@tBoD~DsG|CkFvCuEtCaEfFwG`OqPlJ{J~HaHjS{O|dBmhAr[mT`U_ShVoXhPmUtRw\\rS{`@`k@shAvCyFln@g~@lk@}~@`Te\\zCeAbCfCxAxA~XxYfBn@tJu@l{@wIxJkAv]wDto@wHx{@oIpCk@|X}Cx_BkQfEe@xC]pgByRzC[pBrGvAzHj[llAzAlCzBdClCdJjArDnQzn@bXv_AbCnInUpx@dAdDbAlDvA~E`BvF`GbU`h@jhBjGpTlEjOjAxChAnCbGfLpMxUdB`D~ArChGbK~Q~ZdHtL|HzM|IhOtHnMlItNtE|H`BrCnAtBpZ`h@~GnLfJzOpHhMzJvPbQdZlDbGhCjEpHjMpIvNrIzNfChEfNtUlHbMdIdNfIjN|\\xk@cm@dkAeC|Eb]f^|CbDbZ}k@l@kA" } }, { "startLocation": { "latitude": 40.6390023, "longitude": -73.9975035 }, "endLocation": { "latitude": 40.6396701, "longitude": -73.9257626 }, "startIndex": 2, "endIndex": 1, "distance": { "value": 28047.90116, "text": "5.3 mi" }, "duration": { "value": 13.328916666666666, "text": "13 mins" }, "geometry": { "polyline": "{glolAjcmclCtKaTzBmEaBqC{EgIeIgNwHsM}\\yk@gIkNeIeNmHcMgNuUgCiEsI{NqIwNqHkMiCkEmDcGcQeZ{JwPqHiMgJ{O_HoLqZah@oAuBaBsCuE}HmIuNuHoM}IiO}H{MeHuL_R_[iGcK_BsCeBaDqMyUcGgLiAoCkAyCmEkOkGqTah@khBaGcUaBwFwA_FcAmDeAeDoUqx@cCoIcXw_AoQ{n@kAsDmCeJcDqNm@oD]yC{@aQ[yEoD_q@[uG]oG{@sOgA_TaBcZaB}ZgBc]mEyx@qEyx@mDwr@MmH@mCHqCbBm[FaATqCVkDzAqT|D}k@VoDFuEOyEg@uDaCaJqL}`@kAwD_AgDgDmLuIc[u@uHs@oHsKu_@cV}y@_AaD{@sCoSir@}Rmq@}@{Co@uBoS{r@wRgq@_AaDw@oC{Rqq@iN_e@s@aCwDsMmUax@mIiY}D_N{HsVaWa~@eWu{@}Usy@OuHmE_pBH_I~@oHxQsb@|ByAjB]lJg@|BeAxBuDOsRkA}EC_Fk@qXsDujB{@qb@w@g`@oH}sDu@c_@aEaqBAYy@_a@aAw`@s@wYi@aSc@_Qi@kSsBo{@k@aUc@wQg@_SsBey@g@sRc@oQg@gSsBky@c@mQi@aTi@cTi@aTmAqf@]yMu@wYa@yOuBs{@g@kSi@kTe@{QsBiy@e@}Pi@mSm@mUg@iTe@wRc@sRuBey@e@mQg@qSo@wVi@gVc@kSc@oRyBgy@g@eRi@wSi@qSuBy{@i@eSc@kQg@uRuBo{@i@eTkAqf@[sLG_DGsBa@sOe@mR_Ag[IqCIsCYiJvErArA`@h]vJzZvIrYjIvUxGxTzFdOxDbXhHjRnFhOdE~Ab@pRjFdVdGf_AtWpX`F~CTzDZ`D\\lEd@tJdAtfAfLzJdAfE`@pD^lC\\xGt@bHv@ph@|Ft]pCjQvA|D`@dFf@`QlBzaBdRbPhBvD^hDZvP`A|YfBrkA`M`UnA|SbB" } }, { "startLocation": { "latitude": 40.6396701, "longitude": -73.9257626 }, "endLocation": { "latitude": 40.6410279, "longitude": -73.7746107 }, "startIndex": 1, "endIndex": 4, "distance": { "value": 55616.79968, "text": "10.5 mi" }, "duration": { "value": 15.5131, "text": "16 mins" }, "geometry": { "polyline": "qjmolAbia_lC}ScBaUoAskAaM}YgBwPaAiD[wD_@cPiB{aBeRaQmBeFg@}Da@kQwAu]qCqh@}FcHw@yGu@mC]qD_@gEa@{JeAufAgLuJeAmEe@aD]{D[_DUqXaFg_AuWeVeGqRkF_Bc@iOeEkRoFcXiHeOyDyT{FwUyGsYkIe`@uUwF}AmP_FqA_@cF{A[gOK_IK_IGwQfAoy@z@iy@BaGHeG^_[j@kh@HwILuH~@es@b@{T`@uTXuTVcWtAamAZ}R?}GPkMV_VXe\\JeLKcXMiM]i[W_U_@uIi@iHiAqNeDwa@_Giu@mD_e@eEii@]oEaDua@aGot@gRq~Bw@mJqA_P_AkLcBgJeDwK}CyHyFcLyI_P_h@o_A{EeH{HeIsSgToFcIaC}H_AaKcB_UiCu]G{@m@}Hc@aHsA_TaDsg@wAgSyDid@oDic@w@sJWyHJsK|@qPnFaq@lEcj@nCi_@PiHKaGa@iFcBmIiCwJsR{l@{P{h@}EeOkDmKsF}PwBuGaCoHq[{`AiJcYc\\wbAgQki@kYs{@{Km\\ea@}nAaJuXi]seA{IiX}J}Z}Tar@aKa[{Yu|@iPke@qBgG{Oef@kCeIePsi@eRek@qKg\\ic@esAuWix@ePch@_\\idAeAsCgE}KeKySyHoO{KsQyKkQmTe\\uQkXyRmYcHcLcDcIiDuMqAeMYuDuBsXa@mFsCc`@_Qi}B_@wE_@}EMiBuHabA{B_ZcCq[gDkc@eC{]_Eok@qDmh@{O_oBeIodAgBkU_CgZ}G_|@sDyh@{Fut@mXukDKqAqC}`@a@kI?uDBoBfa@mdBl\\k`BP_AvFsX~SmdAbHk]vE_c@tFon@|Dm_@tFgZ|Gs]vHa^jAiFfI{^jJm[`L}[zNa]bc@ibArKgX`IqUxHg[vHaYnI}n@p~@uwGtLqeAnGcm@~WsqDlJkoApX_gDtEoi@zBqVpAuNzRapCjf@atIz@sPbAyTXeXYiY{A}[mCwXuDiY}EaVcG_UkHoUgZa{@wNgb@_Lia@yJce@_Hod@}G_k@}BmUo@iHg@cGk@wGg@}Ge@{Gc@kGe@iHa@yGsAecACeE?cEFoDRkD^oDb@gDr@kD`AkDbA{CnAyCvAkC~AcChByBlBqBhB}A|BwA`CkAbC_A`Cs@jCi@jCUdCKnCBrCRhCZzBl@~Bx@pBbAvBpAjBlAhFnD~BzAnCzArCjAvIzC|B`Cna@n^dlAxfArDfDdJfInD`DxDdDrD|CvDxCzDzCrDpCzDtC~DpCxDfCfEhC`EbC|DzBfDjBf@V|DtBzBhAfAh@fErBbEjBlEpBnEjBlEdBjE`BpE`BhExAnExArEtArEpAnElApEfAtEdApE`A`FbApEx@tEx@tEr@pEp@vBVdBRrEh@hAJrCVxE`@xE\\zE\\rETbFTpEN|EJtEHbFDvE@vECbFEzEIxEOtEQvESxEYvE[tE_@|Ee@tEg@`Fk@tEm@xEu@rEs@rEy@xE_AnE_AvEeApEgAtEiApEoAlEoAtEyAlE{AhEyAnE_BpEiBhEgBlEmBbEiBhKcFxKwFdKuFlK_GbK_GfKcG~JeGfKsGzJoG`KwG|JwGzJ}GvJaHxJgHvJmHrJkHlJmHrJ{HlJyHnJ}HdJ_IlJkI`JeIfJoI|IoIdJ}I~IwIxI{IpDsDvIaJxIgJzIuJjIcJpIsJjIyJbIcKzCeEzCsEtCoEfHqLnGsLjGmMxFyMlFeN|EqNlE}N`EiOlDuOhDqPfC}N~BoPjBkP~AuPjAsP|@}Pf@aQNcHHgGDwG@gHEuHC}GKaHQaHQiHy@qYuByv@u@yWe@{Pg@wQ]oLa@{P_@yPwBsxA@{GByGJeHNcHNaHdAsa@PmHL}GFwGBaHAeHEwGKeHQaHSaHY{G]kG[aFKuAi@sGsDoa@yDo]}J}a@kIwVaHkU}Nkd@oNyc@sRgn@_Ogd@sFaOwEqRoAqIUsH`A{LzBwKjEqMpCwFzDoGlFkGlMqLd_@kUfH{EvGeGrE}FxDwJ`AuFz@}IjEqi@d@aFj@iEr@cDv@wClNmd@b@wBZ{BRiCJiCAiCIwC]iDa@sC?A" } } ] } } ``` ## **Manage your Radar data** Use these endpoints to manage your Radar data, including users, geofences, and events. ### **Users** A user represents a user tracked in your project. Users can be referenced by Radar `_id`, `userId`, or `deviceId`. **Object fields** * `_id` (string): A unique ID for the user, provided by Radar. An alphanumeric string. * `live` (boolean): `true` if the user was created with your `live` API key, `false` if the user was created with your `test` API key. * `userId` (string): A stable unique ID for the user. * `deviceId` (string): A device ID for the user. * `description` (string): An optional description for the user. * `metadata` (dictionary): An optional dictionary of custom metadata for the user. * `location` (point): The user's current location, a `Point` in [GeoJSON](http://geojson.org/) format. * `locationAccuracy` (number): The accuracy of the user's current location in meters. * `foreground` (boolean): `true` if the user's current was updated in the foreground, `false` if the user's current location was updated in the background. * `stopped` (boolean): `true` if the user's current location was updated while stopped, `false` if the user's current location was updated while moving. * `deviceType` (string): The user's device type, one of `iOS`, `Android`, or `Web`. * `createdAt` (datetime): The datetime when the user was created. * `updatedAt` (datetime): The datetime when the user's location was last updated. * `geofences` (array): An array of the user's current geofences. * `trip` (dictionary): When a [Trip](/geofencing/trips) has been started, the user's current trip. Present when the trip has a `status` of `started`, `approaching`, or `arrived`. * `place` (dictionary): When [Places](/geofencing/places) is enabled, the user's current place. * `country` (dictionary): When [Regions](/geofencing/regions) is enabled, the user's current country. * `state` (dictionary): When [Regions](/geofencing/regions) is enabled, the user's current state. US-only. * `dma` (dictionary): When [Regions](/geofencing/regions) is enabled, the user's current DMA (market area). US-only. * `postalCode` (dictionary): When [Regions](/geofencing/regions) is enabled, the user's current postal code. US-only. * `beacons` (array): When [Beacons](/geofencing/beacons) have been created, an array of the user's current beacons. * `fraud` (object): When [Fraud](/geofencing/fraud) is enabled, indicates whether the user passed fraud checks. * `expectedAddress` (object): When an [expected address](/geofencing/fraud#setting-expected-address) is set, the result of comparing the user's location to that address, including `expectedAddress`, `formattedAddress`, `latitude`, `longitude`, `atAddress`, `distance`, and `confidence`. **Sample object** ```json theme={null} { "_id": "56db1f4613012711002229f4", "live": true, "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", "metadata": { "customId": "123", "customFlag": false }, "location": { "type": "Point", "coordinates": [-73.97536, 40.78382] }, "locationAccuracy": 5, "foreground": true, "stopped": true, "deviceType": "iOS", "updatedAt": "2016-06-10T13:44:10.535Z", "geofences": [ { "_id": "56db1f4613012711002229f5", "tag": "neighborhood", "externalId": "1", "description": "Upper West Side", ... }, ... ], "trip:": { "_id": "5f3e50491c2b7d005c81f5d9", "live": true, "status": "started", "externalId": "299", "metadata": { "Customer Name": "Jacob Pena", "Car Model": "Green Honda Civic" }, "mode": "car", "destinationGeofenceTag": "store", "destinationGeofenceExternalId": "123", "destinationLocation": { "coordinates": [ -105.061198, 39.779366 ], "type": "Point" }, "eta": { "duration": 5.5, "distance": 1331 }, ... }, "place": { "_id": "56db1f4613012711002229f7", "facebookId": "37965424481", "name": "Starbucks", "categories": [ "food-beverage", "cafe", "coffee-shop" ], "chain": { "name": "Starbucks", "slug": "starbucks" } }, "country": { "name": "United States", "code": "US" }, "state": { "name": "New Jersey", "code": "NJ" }, "dma": { "name": "New York", "code": "501" }, "postalCode": { "code": "07302" }, "beacons": [ { "type": "ibeacon", "uuid": "b9407f30-f5f8-466e-aff9-25556b57fe6d", "major": "100", "minor": "1", "description": "Store #123 - Register #1", "tag": "store-register", "externalId": "123-1", "enabled": true } ], "fraud": { "verified": true, "passed": false, "bypassed": false, "blocked": false, "mocked": true, "jumped": false, "compromised": false, "inaccurate": false, "proxy": false, "sharing": false "lastMockedAt": "2023-07-27T17:18:28.536Z", "lastJumpedAt": "2023-07-27T17:18:28.536Z", "lastCompromisedAt": null, "lastInaccurateAt": null, "lastProxyAt": null, "lastSharingAt": null } } ``` #### **Create a user** To create a user, call the [track](/api#track) endpoint. On iOS and Android, use the [SDK](/sdk/sdk) to track users. #### **List users** Lists users. Users are sorted descending by `updatedAt`. **Definition** **GET**`https://api.radar.io/v1/users` **Query parameters** * `limit` (number, optional): The max number of users to return. A number between 1 and 1000. Defaults to 100. * `updatedBefore` (datetime, optional): A cursor for use in pagination. Retrieves users updated before the specified datetime. A date or valid ISO date string. * `updatedAfter` (datetime, optional): A cursor for use in pagination. Retrieves users updated after the specified datetime. A date or valid ISO date string. **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/users" \ -H "Authorization: prj_live_sk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200, "hasMore": true }, "users": [ { "_id": "56db1f4613012711002229f4", "live": true, "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", ... }, ... ] } ``` #### **Get a user** Gets a user. The user can be referenced by Radar `_id`, `userId`, or `deviceId`. **Definition** `GET https://api.radar.io/v1/users/:id` **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/users/56db1f4613012711002229f4" \ -H "Authorization: prj_live_sk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "user": { "_id": "56db1f4613012711002229f4", "live": true, "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", ... } } ``` #### **Delete a user** Deletes a user. The user can be referenced by Radar `_id`, `userId`, or `deviceId`. **Definition** `DELETE https://api.radar.io/v1/users/:id` **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/users/56db1f4613012711002229f4" \ -H "Authorization: prj_live_sk_..." \ -X DELETE ``` **Sample response** ```json theme={null} { "meta": { "code": 200 } } ``` #### **Send remote track requests to users** Sends a remote track request to a list of users via silent push notifications. **Definition** `POST https://api.radar.io/v1/users/refresh` **Body parameters** * `userIds` (array, required): An array of user IDs to send the track request to. Limit to a maximum of 10 users per request. * `type` (string, optional): Choose which type of notification is used, one of `silentPush` or `pushExtension`. **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/users/refresh" \ -H "Authorization: prj_test_sk_..." \ -H "Content-Type: application/json" \ -X POST \ -d '{"userIds": ["userId1", "userId2", "userId3"]}' ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "sent": [{"userId": "userId1"}, {"userId": "userId2"}], "failed": [{"userId": "userId3", "reason": "Rate limit exceeded"}] } ``` ### **Trips** A trip is a sequence of location updates with metadata and a unique ID, optionally with an ETA to a destination geofence. Depending on your use case, a trip may represent a pickup, a delivery, or something else. **Object fields** * `_id` (string): The unique ID for the trip, provided by Radar. An alphanumeric string. * `live` (boolean): `true` if the user was created with your `live` API key, `false` if the user was created with your `test` API key. * `externalId` (string): A stable unique ID for the trip. Depending on your use case, may represent an order ID, a delivery ID, or something else. * `metadata` (dictionary): An optional set of custom key-value pairs for the trip, displayed in the trip tracking dashboard. * `mode` (string): The [travel mode](#distance) for the trip. A string, one of `foot`, `bike`, and `car`. * `destinationGeofenceTag` (string): For trips with a destination, the tag of the destination geofence. * `destinationGeofenceExternalId` (string): For trips with a destination, the external ID of the destination geofence. * `destinationLocation` (point): For trips with a destination, the location of the destination geofence. * `eta` (dictionary): For trips with a destination, the ETA to the destination geofence based on the travel mode for the trip, including `duration` in minutes and `distance` in meters. * `approachingThreshold` (number): For trips with a destination, the [trip approaching threshold](/geofencing/trips#trip-events) setting for the trip (in minutes). Overrides the geofence-level and project-level trip approaching threshold settings. * `createdAt` (datetime): The datetime when the trip was started. * `updatedAt` (datetime): The datetime when the trip's location was last updated. * `scheduledArrivalAt` (datetime): Required for the [Olo order firing integration](/integrations/olo#order-firing), the backstop datetime when the device on the trip is expected to arrive. The order will be fired `approachingThreshold` minutes before `scheduledArrivalAt`. * `orderFiredAt` (datetime): From the [Olo integration](/integrations/olo), the datetime when the order associated with the trip was fired. * `arrivedAt` (datetime): For trips with a destination, the datetime when the user arrived at the trip destination (entered the destination geofence). * `completedAt` (datetime): The datetime when the trip was stopped. * `status` (string): The status of the trip, one of `pending`, `started`, `approaching`, `arrived`, `expired`, `completed`, or `canceled`. * `user` (dictionary): The [user](#users) for which the trip is being tracked. * `userId` (string): The external ID of the [user](#users) for which the trip is being tracked. * `locations` (array): The location updates tracked while the trip was active. An array of `Point`s in [GeoJSON](http://geojson.org/) format. * `delay` (dictionary): The predicted delay for the trip, including a `delayed` boolean flag and a `scheduledArrivalTimeDelay` with the delay amount in minutes. **Sample object** ```json theme={null} { "_id": "5f3e50491c2b7d005c81f5d9", "live": true, "status": "started", "externalId": "299", "metadata": { "Customer Name": "Jacob Pena", "Car Model": "Green Honda Civic" }, "mode": "car", "destinationGeofenceTag": "store", "destinationGeofenceExternalId": "123", "destinationLocation": { "coordinates": [ -105.061198, 39.779366 ], "type": "Point" }, "approachingThreshold": 3, "eta": { "duration": 5.5, "distance": 1331 }, "createdAt": "2020-08-20T10:27:55.830Z", "updatedAt": "2020-08-20T10:30:55.837Z", "user": { "_id": "56db1f4613012711002229f4", "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8" }, "userId": "1", "locations": [ { "type": "Point", "coordinates": [ -105.062645, 39.766059819860864 ], "updatedAt": "2020-08-20T10:29:55.897Z" }, { "type": "Point", "coordinates": [ -105.06267319809022, 39.769057068070715 ], "updatedAt": "2020-08-20T10:30:55.837Z" } ], "delay": { "delayed": false, "scheduledArrivalTimeDelay": 0 } } ``` #### **Get a trip** Gets a trip. The trip can be referenced by Radar `_id` or `externalId`. **Definition** **GET**`https://api.radar.io/v1/trips/:id`\ **GET**`https://api.radar.io/v1/trips/:externalId` **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/trips/299/route" \ -H "Authorization: prj_live_sk_..." ``` **Authentication level** Secret **Sample response** ```json theme={null} { "distance": { "value": 1077.1173573024, "text": "0.2 mi" }, "geometry": { "polyline": "waczjAhnokgEia@BcXXga@Ri|@KmIDsIDyD@mD@" } } ``` #### **List trips** **Definition** Lists trips. Trips are sorted descending by `updatedAt`. **GET**`https://api.radar.io/v1/trips` **Query parameters** * `status` (string, optional): Retrieves trips by status. A string, comma-separated including one or more of `pending`, `started`, `approaching`, `arrived`, `completed`, `canceled`, `expired`. * `destinationGeofenceTag` (string, optional): Retrieves trips with the destination geofence tag. * `destinationGeofenceExternalId` (string, optional): Retrieves trips with the destination geofence external ID. * `externalId` (string, optional) Retrieves trips by unique IDs. A string, comma-separated including one or more IDs. * `userId` (string, optional): The Radar `_id` of the [user](https://docs.radar.com/api#users) for which the trip is being tracked. * `includeLocations` (boolean, optional): Whether to include locations on trips. Defaults to `false`. * `createdAfter` (datetime, optional): A cursor for use in pagination. Retrieves trips created after the specified datetime. A date or valid ISO date string. * `createdBefore` (datetime, optional): A cursor for use in pagination. Retrieves trips created before the specified datetime. A date or valid ISO date string. * `sortBy` (string, optional): Sorts trips by the specified field in descending order. A string, one of `createdAt` or `updatedAt`. Defaults to `updatedAt`. * `delayed` (boolean, optional): Retrieves trips that matches specified delayed state. * `limit` (number, optional): The max number of addresses to return. A number between 1 and 1000. Defaults to 500. **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/trips?status=started&destinationGeofenceTag=store&destinationGeofenceExternalId=123&externalId=123,456,789" \ -H "Authorization: prj_live_sk_..." ``` **Authentication level** Secret **Sample response** ```json theme={null} { "meta": { "code": 200 }, "trips": [ { "_id": "5f3e50491c2b7d005c81f5d9", "live": true, "status": "started", "externalId": "299", "metadata": { "Customer Name": "Jacob Pena", "Car Model": "Green Honda Civic" }, "mode": "car", "destinationGeofenceTag": "store", "destinationGeofenceExternalId": "123", "destinationLocation": { "coordinates": [ -105.06119826017914, 39.7793665 ], "type": "Point" }, "eta": { "duration": 5.5, "distance": 1331 }, "createdAt": "2020-08-20T10:27:55.830Z", "updatedAt": "2020-08-20T10:30:55.837Z", "endedAt": "2020-08-20T10:30:55.837Z" ... }, ... ] } ``` #### **Create a new trip** Use the [SDK](/sdk/sdk) to start trips and track users for most use cases. Trips can also be created server-side or through integrations (e.g., Olo). Location updates with the specified `userId` from the [SDK](/sdk/sdk) will update the trip for that user. **Definition** Creates a new trip. **POST**`https://api.radar.io/v1/trips` **Body parameters** * `externalId` (string, required): A stable unique ID for the trip. Depending on your use case, it may represent an order ID, a delivery ID, or something else. * `destinationGeofenceTag` (string, optional): For trips with a destination, the tag of the destination geofence. * `destinationGeofenceExternalId` (string, optional): For trips with a destination, the external ID of the destination geofence. * `userId` (string, optional): The external ID of the [user](#users) for which the trip is being tracked. * `mode` (string, optional): The [travel mode](#distance) for the trip. A string, one of `foot`, `bike`, and `car`. Defaults to `car`. * `approachingThreshold` (number, optional): For trips with a destination, the [trip approaching threshold](/geofencing/trips#trip-events) setting for the trip (in minutes). Overrides the geofence-level and project-level trip approaching threshold settings. * `scheduledArrivalAt` (datetime): Required for the [Olo order firing integration](/integrations/olo#order-firing), the backstop datetime when the device on the trip is expected to arrive. The order will be fired `approachingThreshold` minutes before `scheduledArrivalAt`. * `metadata` (dictionary, optional): An optional set of custom key-value pairs for the trip. **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/trips" \ -H "Authorization: prj_test_pk_..." \ -X POST \ -d "externalId=123" \ -d "mode=car" \ -d "destinationGeofenceTag=store" \ -d "destinationGeofenceExternalId=1" \ -d "userId=001" \ -d "approachingThreshold=3" \ -d "metadata={\"foo\": \"bar\"}" ``` **Authentication level** Publishable **Sample response** ```json theme={null} { "meta": { "code": 200, }, "trip": { "_id": "6334960ad9735600116b7ab5", "live": false, "externalId": "123", "userId": "001", "mode": "car", "status": "pending", "destinationGeofenceTag": "store", "destinationGeofenceExternalId": "1", "destinationLocation": { "type": "Point", "coordinates": [ -73.977797, 40.783826 ] }, "metadata": { "foo": "bar" }, "approachingThreshold": 3, "user": { "_id": "56db1f4613012711002229f4", "userId": "001", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8" }, "locations": [], } } ``` #### **Update a trip** Updates a trip. The trip can be referenced by Radar `_id` or `externalId`. On iOS and Android, use the [SDK](https://docs.radar.com/sdk) to update trips. **Definition** **PATCH**`https://api.radar.io/v1/trips/:id/update`\ **PATCH**`https://api.radar.io/v1/trips/:externalId/update` **Body parameters** * `status` (string, required): The new status of the trip, one of `pending`,`started`, `approaching`, `arrived`, `completed`, or `canceled`. * `mode` (string, optional): The [travel mode](#distance) for the trip. A string, one of `foot`, `bike`, and `car`. * `destinationGeofenceTag` (string, optional): For trips with a destination, the tag of the destination geofence. * `destinationGeofenceExternalId` (string, optional): For trips with a destination, the external ID of the destination geofence. * `approachingThreshold` (number, optional): For trips with a destination, the [trip approaching threshold](/geofencing/trips#trip-events) setting for the trip (in minutes). Overrides the geofence-level and project-level trip approaching threshold settings. * `scheduledArrivalAt` (datetime, optional): Required for the [Olo order firing integration](/integrations/olo#order-firing), the backstop datetime when the device on the trip is expected to arrive. The order will be fired `approachingThreshold` minutes before `scheduledArrivalAt`. * `metadata` (dictionary, optional): An optional set of custom key-value pairs for the trip. **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/trips/299/update" \ -H "Authorization: prj_live_sk_..." -X PATCH -d "status=completed" ``` **Authentication level** Publishable **Sample response** ```json theme={null} { "meta": { "code": 200 }, "trip": { "_id": "6334960ad9735600116b7ab5", "live": false, "externalId": "123", "userId": "001", "mode": "car", "status": "completed", "destinationGeofenceTag": "store", "destinationGeofenceExternalId": "1", "destinationLocation": { "type": "Point", "coordinates": [ -73.977797, 40.783826 ] }, "metadata": { "foo": "bar" }, "approachingThreshold": 3, "user": { "_id": "56db1f4613012711002229f4", "userId": "001", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8" }, "locations": [], } } ``` #### **Delete a trip** Deletes a trip. The trip can be referenced by Radar `_id` or `externalId`. **Definition** **DELETE**`https://api.radar.io/v1/trips/:id` **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/trips/56db1f4613012711002229f4" \ -H "Authorization: prj_live_sk_..." \ -X DELETE ``` **Sample response** ```json theme={null} { "meta": { "code": 200 } } ``` ### **Geofences** A geofence represents a custom region or place monitored in your project. Geofences can be uniquely referenced by Radar `_id` or by `tag` and `externalId`. **Object fields** * `_id` (string): The unique ID for the geofence, provided by Radar. An alphanumeric string. * `createdAt` (datetime): The datetime when the geofence was created. * `updatedAt` (datetime): The datetime when the geofence was last updated. * `live` (boolean): `true` if the geofence was created with your `live` API key, `false` if the user was created with your `test` API key. * `tag` (string): A group for the geofence. * `externalId` (string): An external ID for the geofence that maps to your internal database. * `description` (string): A description for the geofence. * `type` (string): The type of geofence geometry, one of `circle`, `polygon`, or `isochrone`. * `geometry` (polygon): The geometry of the geofence. Coordinates for type `polygon`. A calculated polygon approximation for type `circle` and `isochrone`. A `Polygon` in [GeoJSON](http://geojson.org/) format. * `geometryCenter` (point): The center for type `circle`. The calculated centroid of the polygon for type `polygon`. The destination for type `isochrone`. A `Point` in [GeoJSON](http://geojson.org/) format. * `geometryRadius` (number): The radius in meters for type `circle`. The calculated approximate radius of the polygon for type `polygon`. The travel duration in minutes for type `isochrone`. * `mode` (string): The [travel mode](#distance) for type `isochrone`. * `metadata` (dictionary): An optional set of custom key-value pairs for the geofence. * `userId` (string, optional): An optional user restriction for the geofence. If set, the geofence will only generate events for the specified user. If not set, the geofence will generate events for all users. **Deprecated.** * `userIds` (string, optional): An optional user restriction for the geofence. A string of comma-separated user IDs. If set, the geofence will only generate events for the specified users. If not set, the geofence will generate events for all users. * `ip` (string, optional): An optional IP address restriction for the geofence. A string of comma-separated IP address ranges, each of which could be a single IP (`8.8.8.8`), wildcard notation (`8.8.8.*`), or CIDR notation (`8.8.8.8/24`). If set, the geofence will only generate events for requests from the specified IP address. If not set, the geofence will generate events for all requests. * `tripApproachingThreshold` (number): The [trip approaching threshold](/geofencing/trips#trip-events) setting for the geofence (in minutes). Overrides the project-level trip approaching threshold setting. * `dwellThreshold` (number): An optional field to trigger dwell events. If set and `user.dwelled_in_geofence` is enabled in settings, an event is triggered when a user dwells in the geofence longer than the threshold (in minutes). * `enabled` (boolean): If `true`, the geofence will generate events. If `false`, the geofence will not generate events. Defaults to `true`. * `operatingHours` (dictionary): An optional set of key-value pairs restricting the [operating hours of the geofence](/geofencing/geofences#operating-hours). Each key is a day of the week, and each value is a list of pairs, where a pair indicates one opening and closing time for that day in `HH:mm` format. **Sample object** ```json theme={null} { "_id": "56db1f4613012711002229f5", "createdAt": "2016-06-10T13:44:10.535Z", "updatedAt": "2016-06-10T14:40:10.535Z", "live": true, "tag": "venue", "externalId": "2", "description": "Coffee Shop", "type": "circle", "geometry": { "type": "Polygon", "coordinates": [[...]] }, "geometryCenter": { "type": "Point", "coordinates": [-73.97536, 40.78382] }, "geometryRadius": 50, "metadata": { ... }, "enabled": true } ``` #### **List geofences** **Definition** Lists geofences. Geofences are sorted descending by `updatedAt`. **GET**`https://api.radar.io/v1/geofences` **Query parameters** * `limit` (number, optional): The max number of geofences to return. A number between 1 and 1000. Defaults to 100. * `createdBefore` (datetime, optional): Retrieves geofences created before the specified datetime. A date or valid ISO date string. * `createdAfter` (datetime, optional): Retrieves geofences created after the specified datetime. A date or valid ISO date string. * `updatedBefore` (datetime, optional): A cursor for use in pagination. Retrieves geofences updated before the specified datetime. A date or valid ISO date string. * `updatedAfter` (datetime, optional): A cursor for use in pagination. Retrieves geofences updated after the specified datetime. A date or valid ISO date string. * `tag` (string, optional): Retrieves geofences with the specified `tag`. * `externalId` (string, optional): Retrieves geofences with the specified `externalId`. * `metadata[key]` (string, optional): Optional metadata filters. Values may be of type string. Type will be automatically inferred. For example, to match on `offers == true`, use `&metadata[offers]=true`. **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/geofences" \ -H "Authorization: prj_live_sk_..." ``` **Authentication level** Secret **Sample response** ``` { "meta": { "code": 200, "hasMore": true }, "geofences": [ { "_id": "56db1f4613012711002229f5", "createdAt": "2016-06-10T13:44:10.535Z", "live": true, "tag": "venue", "externalId": "2", "description": "Coffee Shop", "type": "circle", ... }, ... ] } ``` #### **Get a geofence** Gets a geofence. The geofence can be uniquely referenced by Radar `_id` or by `tag` and `externalId`. **Definition** **GET**`https://api.radar.io/v1/geofences/:id`\ **GET**`https://api.radar.io/v1/geofences/:tag/:externalId` **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/geofences/56db1f4613012711002229f5" \ -H "Authorization: prj_live_sk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "geofence": { "_id": "56db1f4613012711002229f5", "createdAt": "2016-06-10T13:44:10.535Z", "live": true, "tag": "venue", "externalId": "2", "description": "Coffee Shop", "type": "circle", ... } } ``` #### **Upsert a geofence** Upserts a geofence. The geofence can be uniquely referenced by `tag` and `externalId` or by the Radar `_id`. If a geofence with the specified `tag` and `externalId` already exists, it will be updated. If not, it will be created. **Definition** **PUT**`https://api.radar.io/v1/geofences/:tag/:externalId`\ **PUT**`https://api.radar.io/v1/geofences/:id` **Body parameters** * `description` (string, required): A description for the geofence. * `type` (string, required): The type of geofence geometry. A string, one of `circle`, `polygon`, or `isochrone`. * `coordinates` (array, required if `address` and `placeId` are not included): An array or JSON string representing a center for type `circle` or a destination for type `isochrone` in the format `[longitude,latitude]`. A two-dimensional array or JSON string representing a closed ring of between 4 and 2,000 coordinates in the format `[[longitude0, latitude0],[longitude1,latitude1],[longitude2,latitude2],...,[longitude0,latitude0]]` for type `polygon`. **Note that longitude comes before latitude, a GeoJSON convention.** * `address` (string, required if `coordinates` and `placeId` are not included): An address to search for, and if found, will represent the center for type `circle` or `isochrone`. If `address` and `coordinates` are both provided, they must be nearby, and `coordinates` will take precedent. Ignored for type `polygon`. * `radius` (number, required for type `circle` and `isochrone`): The radius in meters for type `circle`, a number between `10` and `10000`. The travel duration in minutes for type `isochrone`. Ignored for type `polygon`. * `metadata` (dictionary, optional): An optional set of custom key-value pairs for the geofence. A dictionary or JSON string with up to 16 keys and values of type string, boolean, or number. * `userId` (string, optional): An optional user restriction for the geofence. If set, the geofence will only generate events for the specified user. If not set, the geofence will generate events for all users. **Deprecated.** * `userIds` (string, optional): An optional user restriction for the geofence. A string of comma-separated user IDs. If set, the geofence will only generate events for the specified users. If not set, the geofence will generate events for all users. * `ip` (string, optional): An optional IP address restriction for the geofence. A string of comma-separated IP address ranges, each of which could be a single IP (`8.8.8.8`), wildcard notation (`8.8.8.*`), or CIDR notation (`8.8.8.8/24`). If set, the geofence will only generate events for requests from the specified IP address. If not set, the geofence will generate events for all requests. * `enabled` (boolean, optional): If `true`, the geofence will generate events. If `false`, the geofence will not generate events. Defaults to `true`. * `disableAfter` (datetime, optional): Use to create temporary geofences. If set, the geofence will be disabled after the specified datetime. A date or valid ISO date string. * `deleteAfter` (datetime, optional): Use to create temporary geofences. If set, the geofence will be deleted after the specified datetime. A date or valid ISO date string. * `stopDetection` (boolean, optional): The [stop detection](/geofencing/geofences#stop-detection) setting for the geofence. Overrides the project-level stop detection setting. * `mode` (string, required for type `isochrone`): The [travel mode](#routing) for type `isochrone`. * `tripApproachingThreshold` (number, optional): The [trip approaching threshold](/geofencing/trips#trip-events) setting for the geofence (in minutes). Overrides the project-level trip approaching threshold setting. * `dwellThreshold` (number, optional): An optional field to trigger dwell events. If set and `user.dwelled_in_geofence` is enabled in settings, an event is triggered when a user dwells in the geofence longer than the threshold (in minutes). * `placeId` (string, required if `coordinates` and `address` are not included): For [place matching](/geofencing/places#place-matching), an optional `id` of the Radar [place](/geofencing/places) to match to the geofence. If provided and found, the place centroid will override `coordinates` and `address`. * `operatingHours` (dictionary, optional): An optional set of key-value pairs restricting the [operating hours of the geofence](/geofencing/geofences#operating-hours). Each key is a day of the week (e.g., `Sunday`) or the three letter abbreviation of the day (e.g., `Sun`), case insensitive. Each value is a list of pairs, where a pair indicates one opening and closing time for that day. For example, a restaurant only open for lunch and dinner on Sundays would be `{ Sunday: [["11:00", "14:00"], ["19:00", "22:00"]] }`. Accepted time formats include `h:mm aa` (e.g., `12:45 AM`) and `HH:mm` (e.g., `00:45`). If not set, the geofence will always be open. **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/geofences/venue/2" \ -H "Authorization: prj_live_sk_..." \ -X PUT \ -d "description=Coffee Shop" \ -d "type=circle" \ -d "coordinates=[-73.97536,40.78382]" \ -d "radius=50" ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "geofence": { "_id": "56db1f4613012711002229f5", "createdAt": "2016-06-10T13:44:10.535Z", "live": true, "tag": "venue", "externalId": "2", "description": "Coffee Shop", "type": "circle", ... } } ``` #### **Delete a geofence** Deletes a geofence. The geofence can be uniquely referenced by Radar `_id` or by `tag` and `externalId`. **Definition** **DELETE**`https://api.radar.io/v1/geofences/:id`\ **DELETE**`https://api.radar.io/v1/geofences/:tag/:externalId` **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/geofences/56db1f4613012711002229f5" \ -H "Authorization: prj_live_sk_..." \ -X DELETE ``` **Sample response** ```json theme={null} { "meta": { "code": 200 } } ``` #### **Get users in a geofence** Gets users currently in a geofence. **Definition** **GET**`https://api.radar.io/v1/geofences/:tag/:externalId/users` **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/geofences/venue/2/users" \ -H "Authorization: prj_live_sk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200, "hasMore": false }, "users": [ { "_id": "611ace2eb08f300047c904e9", "location": { "type": "Point", "coordinates": [ 73.97536, 40.78382 ] }, ... } ... ] } ``` ### **Events** An event represents a change in user state. Events can be uniquely referenced by Radar `_id`. **Object fields** * `_id` (string): The unique ID for the event, provided by Radar. An alphanumeric string. * `createdAt` (datetime): The datetime when the event was created on the mobile client. * `actualCreatedAt` (datetime): The datetime when the event was created on the server. Mobile operating systems can deliver location updates on a delay, resulting in a delta between this field and `createdAt`. * `live` (boolean): `true` if the event was generated for a user and geofence created with your `live` API key, `false` if the event was generated for a user and geofence created with your `test` API key. * `type` (string): The type of event. By default, events are generated when a user enters a geofence (type `user.entered_geofence`) or exits a geofence (type `user.exited_geofence`). [Places](/geofencing/places) and [Regions](/geofencing/regions) also generate events. * `user` (dictionary): The user for which the event was generated. * `geofence` (dictionary): For `user.entered_geofence` and `user.exited_geofence` events, the geofence for which the event was generated, including `description`, `tag`, and `externalId`. * `place` (dictionary): For `user.entered_place` and `user.exited_place` events, the place for which the event was generated, including `name`, `categories`, `chain`, and `facebookId`. * `alternatePlaces` (array): For `user.entered_place` events, alternate place candidates. * `verifiedPlace` (dictionary): For verified `user.entered_place` events, the verified place. * `location` (point): The location of the user at the time of the event, a `Point` in [GeoJSON](http://geojson.org/) format. * `locationAccuracy` (number): The accuracy of the user's location at the time of the event in meters. * `confidence` (number): The confidence level of the event, one of `3` (high), `2` (medium), or `1` (low). * `duration` (number): On exit events, the duration between entry and exit events, in minutes. **Sample object** ```json theme={null} { "_id": "56db1f4613012711002229f6", "createdAt": "2016-06-10T13:44:10.535Z", "live": true, "type": "user.exited_geofence", "location": { "type": "Point", "coordinates": [-73.97779, 40.78382] }, "locationAccuracy": 5, "confidence": 3, "duration": 48.38920, "user": { "_id": "56db1f4613012711002229f4", "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", ... }, "geofence": { "_id": "56db1f4613012711002229f5", "tag": "venue", "externalId": "2", "description": "Coffee Shop", ... } } ``` #### **Generate an entry or exit event** To generate an entry or exit event, call the [track](#track) endpoint to trigger an event. For example, specify a `latitude` and `longitude` to enter a geofence that you have created. On iOS and Android, use the [SDK](/sdk/sdk) to track users. #### **Log a conversion** > [!NOTE] > > Conversions are available on the [**Enterprise plan**](https://radar.com/pricing). Logs a conversion to analyze alongside other location activity in your app. This can represent anything from a purchase or signup to engagement with an in-app feature. **Definition** **POST**`https://api.radar.io/v1/events` **Body parameters** * `name` (string, required): The name of the conversion. Should be generic (e.g., `in_app_purchase`). Only alphanumeric characters and underscores are supported. * `metadata` (dictionary, optional): The metadata of the conversion. This data cannot contain any sensitive or personally identifiable information. * `revenue` (number, optional): The revenue of the conversion. Used to associate an amount with a transactional conversion such as a purchase or coupon redemption. * `userId` (string, optional): The stable unique ID for the user. Used to identify logged in users. * `deviceId` (string, optional): A device ID for the user. Used to identify logged out users. * `installId` (string, optional): An install ID for the user. Used to identify users who have opted out of location permissions. Can be a random alphanumeric string for users that don't exist in Radar. * `createdAt` (string, optional): The datetime when the conversion occurred. * `duration` (number, optional): The duration of the conversion in minutes. **Authentication level** Publishable **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Sample request** ``` curl "https://api.radar.io/v1/events" \ -H "Authorization: prj_live_pk_..." \ -X POST \ -d "name=conversion" \ -d "userId=user123" ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "event": { "_id": "56db1f4613012711002229f6", "createdAt": "2016-06-10T13:44:10.535Z", "live": true, "type": "conversion", "confidence": 3, "user": { "_id": "56db1f4613012711002229f4", "userId": "user123", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", ... } } } ``` ### **Beacons** A beacon represents a Bluetooth beacon monitored in your project. Beacons can be uniquely referenced by Radar `_id` or by `tag` and `externalId`. **Object fields** * `_id` (string): A unique ID for the beacon, provided by Radar. An alphanumeric string. * `createdAt` (datetime): The datetime when the beacon was created. * `updatedAt` (datetime): The datetime when the beacon was last updated. * `live` (boolean): `true` if the beacon was created with your `live` API key, `false` if the beacon was created with your `test` API key. * `description` (string): A display name for the beacon. * `tag` (string): A group for the beacon. * `externalId` (string): An external ID for the beacon. * `type` (string, required): The type of beacon, one of `ibeacon` (supported on iOS and Android) or `eddystone` (supported on Android only). * `uuid` (string, required for `ibeacon`): For iBeacons, the UUID of the beacon. * `major` (string, required for `ibeacon`): For iBeacons, the major ID of the beacon. * `minor` (string, required for `ibeacon`): For iBeacons, the minor ID of the beacon. * `uid` (string, required for `eddystone`): For Eddystone beacons, the UID of the beacon. * `instance` (string, required for `eddystone`): For Eddystone beacons, the instance ID of the beacon. * `geometry` (point): The approximate location of the beacon, used to sync nearby beacons (within 1 kilometer) to the SDK. Coordinates for type `point` in `[longitude,latitude]` format. * `enabled` (boolean): If true, the beacon will generate events. If false, the beacon will not generate events. * `metadata` (dictionary): A set of custom key-value pairs for the beacon. A JSON string representing a dictionary with up to 16 keys and values of type string, boolean, or number. **Sample object** ```json theme={null} { "_id": "60f6da60cf4cc0a72a6c070b", "createdAt": "2021-07-20T14:27:22.283Z", "updatedAt": "2021-07-20T14:27:22.283Z", "live": false, "description": "Store #123 - Register #1", "tag": "store-register", "externalId": "123-1", "type": "ibeacon", "uuid": "b9407f30-f5f8-466e-aff9-25556b57fe6d", "major": "100", "minor": "1", "geometry": { "type": "Point", "coordinates": [ -73.975384, 40.783747 ] }, "enabled": true, "metadata": { "supportsContactlessPayments": true } } ``` #### **List beacons** Lists beacons. Beacons are sorted descending by `createdAt`. **Definition** **GET**`https://api.radar.io/v1/beacons` **Query parameters** * `limit` (number, optional): The max number of beacons to return. A number between 1 and 1000. Defaults to 100. * `createdBefore` (datetime, optional): A cursor for use in pagination. Retrieves beacons updated before the specified datetime. A date or valid ISO date string. * `createdAfter` (datetime, optional): A cursor for use in pagination. Retrieves beacons updated after the specified datetime. A date or valid ISO date string. * `tag` (string, optional): Retrieves beacons with the specified `tag`. * `externalId` (string, optional): Retrieves beacons with the specified `externalId`. **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/beacons" \ -H "Authorization: prj_live_sk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200, "hasMore": true }, "beacons": [ { "_id": "6109a4b16dbfe3de2cb03924", "createdAt": "2021-08-03T20:18:57.888Z", "updatedAt": "2021-08-03T20:18:57.888Z", "live": true, "description": "Store #123 - Register #1", ... }, ... ] } ``` #### **Get a beacon** Gets a beacon. The beacon can be uniquely referenced by Radar `_id` or by `tag` and `externalId`. **Definition** **GET**`https://api.radar.io/v1/beacons/:id`\ **GET**`https://api.radar.io/v1/beacons/:tag/:externalId` **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/beacons/6109a4b16dbfe3de2cb03924" \ -H "Authorization: prj_live_sk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "beacon": { "_id": "6109a4b16dbfe3de2cb03924", "createdAt": "2021-08-03T20:18:57.888Z", "updatedAt": "2021-08-03T20:18:57.888Z", "live": true, "description": "Store #123 - Register #1", "tag": "store-register", "externalId": "123-1", ... } } ``` #### **Create a beacon** Creates a beacon. **Definition** **POST**`https://api.radar.io/v1/beacons` **Body parameters** * `description` (string, required): A display name for the beacon. * `tag` (string, required): A group for the beacon. * `externalId` (string, required): An external ID for the beacon. * `type` (string, required): The type of beacon, one of `ibeacon` (supported on iOS and Android) or `eddystone` (supported on Android only). * `uuid` (string, required for `ibeacon`): For iBeacons, the UUID of the beacon. * `major` (string, required for `ibeacon`): For iBeacons, the major ID of the beacon. * `minor` (string, required for `ibeacon`): For iBeacons, the minor ID of the beacon. * `uid` (string, required for `eddystone`): For Eddystone beacons, the UID of the beacon. * `instance` (string, required for `eddystone`): For Eddystone beacons, the instance ID of the beacon. * `coordinates` (point, required): The approximate location of the beacon, used to sync nearby beacons (within 1 kilometer) to the SDK. Coordinates in `[longitude,latitude]` format. * `enabled` (boolean, optional): If true, the beacon will generate events. If false, the beacon will not generate events. * `metadata` (dictionary, optional): A set of custom key-value pairs for the beacon. A JSON string representing a dictionary with up to 16 keys and values of type string, boolean, or number. **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/beacons" \ -H "Authorization: prj_live_sk_..." \ -X POST \ -d "description=Store 123 - Register 1" \ -d "tag=store-register" \ -d "tag=123-1" \ -d "type=ibeacon" \ -d "uuid=b9407f30-f5f8-466e-aff9-25556b57fe6d" \ -d "major=100" \ -d "minor=1" -d "coordinates=[-105.94653744704361,35.70654086799666]" \ -d "enabled=true" ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "beacon": { "_id": "6116d947049aee0089a682a2", "createdAt": "2021-08-13T20:42:47.711Z", "updatedAt": "2021-08-13T20:42:47.711Z", "live": true, "description": "Store #123 - Register #1", "tag": "store-register", "externalId": "123-1", ... } } ``` #### **Upsert a beacon** Upserts a beacon. The beacon can be uniquely referenced by Radar `_id` or by `tag` and `externalId`. If a beacon with the specified `tag` and `externalId` already exists, it will be updated. If not, it will be created. **Definition** **PUT**`https://api.radar.io/v1/beacons/:id`\ **PUT**`https://api.radar.io/v1/beacons/:tag/:externalId` **Body parameters** * `description` (string, required): A display name for the beacon. * `type` (string, required): The type of beacon, one of `ibeacon` (supported on iOS and Android) or `eddystone` (supported on Android only). * `uuid` (string, required for `ibeacon`): For iBeacons, the UUID of the beacon. * `major` (string, required for `ibeacon`): For iBeacons, the major ID of the beacon. * `minor` (string, required for `ibeacon`): For iBeacons, the minor ID of the beacon. * `uid` (string, required for `eddystone`): For Eddystone beacons, the UID of the beacon. * `instance` (string, required for `eddystone`): For Eddystone beacons, the instance ID of the beacon. * `coordinates` (point, required): The approximate location of the beacon, used to sync nearby beacons (within 1 kilometer) to the SDK. Coordinates in `[longitude,latitude]` format. * `metadata` (dictionary, optional): An optional set of custom key-value pairs for the beacon. A JSON string representing a dictionary with up to 16 keys and values of type string, boolean, or number. * `enabled` (boolean, optional): If `true`, the beacon will generate events. If `false`, the beacon will not generate events. Defaults to `true`. **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/beacons/store-register/123-1" \ -H "Authorization: prj_live_sk_..." \ -X PUT \ -d "description=Store 123 - Register 1" \ -d "tag=store-register" \ -d "externalId=123-1" \ -d "type=ibeacon" \ -d "uuid=b9407f30-f5f8-466e-aff9-25556b57fe6d" \ -d "major=100" \ -d "minor=1" \ -d "coordinates=[-105.94653744704361,35.70654086799666]" \ -d "enabled=true" ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "beacon": { "_id": "6116d947049aee0089a682a2", "createdAt": "2021-08-13T20:42:47.711Z", "updatedAt": "2021-08-13T20:42:47.711Z", "live": true, "description": "Store #123 - Register #1", "tag": "store-register", "externalId": "123-1", ... } } ``` #### **Delete a beacon** Deletes a beacon. The beacon can be uniquely referenced by Radar `_id` or by `tag` and `externalId`. **Definition** **DELETE**`https://api.radar.io/v1/beacons/:id`\ **DELETE**`https://api.radar.io/v1/beacons/:tag/:externalId` **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/beacons/56db1f4613012711002229f4" \ -H "Authorization: prj_live_sk_..." \ -X DELETE ``` **Sample response** ``` { "meta": { "code": 200 } } ``` ### **Fraud** Block or unblock users and devices for [Fraud](/geofencing/fraud). These endpoints must be enabled for your project. Contact your customer success manager for access. #### **Block users and devices** Creates block rules for existing users or devices. Each item targets exactly one user or device. By default, blocking a user does not block their devices, and blocking a device does not block its users. Set `includeAssociations` to `true` to also block associated devices or users. Each successful block creates a new rule, even if the target is already blocked. If a user or device does not exist in the project and environment associated with your API key, the item succeeds without creating a rule. **Definition** **POST**`https://api.radar.io/v1/fraud/block` **Body parameters** * `items` (array, required): An array of items to block, with at least 1 item and a default maximum of 500 items. Each item accepts: * `userId` (string): The `userId` of the user to block. Specify exactly one of `userId` or `deviceId`, as a non-empty string. * `deviceId` (string): The `deviceId` of the device to block. Specify exactly one of `userId` or `deviceId`, as a non-empty string. * `includeAssociations` (boolean, optional): Set to `true` to also block associated devices for a user, or immediately associated users for a device, asynchronously. Defaults to `false`. * `durationMs` (number, optional): The duration of the block in milliseconds, starting when the rule is created. Must be non-negative. If omitted, the block has no expiration. * `description` (string, optional): A description of the block rule. * `label` (string, optional): Either `fraud` or `not_fraud`. Requires fraud labels to be enabled for your project. * `fraudType` (string, optional): A fraud category, up to 100 characters. Allows alphanumeric characters, dashes, underscores, spaces, periods, and commas. Requires `label`. * `incidentTime` (string, optional): The time of the incident as an ISO 8601 datetime with a timezone, for example, `2026-10-21T12:00:00Z`. Requires `label`. **Default rate limit** 5 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ```bash theme={null} curl "https://api.radar.io/v1/fraud/block" \ -H "Authorization: prj_live_sk_..." \ -H "Content-Type: application/json" \ -X POST \ -d '{"items":[{"userId":"user-123","description":"Confirmed fraudulent activity"},{"deviceId":"device-456","includeAssociations":true}]}' ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "responses": [ { "index": 0, "target": { "userId": "user-123" }, "meta": { "code": 200 }, "action": { "changedBlockCount": 1, "affected": { "userIds": ["user-123"], "deviceIds": [] }, "configuration": { "description": "Confirmed fraudulent activity", "expiresAt": null } } }, { "index": 1, "target": { "deviceId": "device-456" }, "meta": { "code": 202 }, "action": { "changedBlockCount": 1, "affected": { "userIds": [], "deviceIds": ["device-456"] }, "statusUrl": "/v1/fraud/actions/act_123", "configuration": { "description": null, "expiresAt": null } } } ] } ``` **Response fields** * `responses` (array): One result per request item, in request order. * `index` (number): The zero-based index of the request item. * `target` (object): The requested `userId` or `deviceId`. * `meta.code` (number): `200` when the direct action succeeded and no association processing was requested, including when no rule was created; `202` when the direct action succeeded and association processing was accepted; or `500` if the item failed. * `action.changedBlockCount` (number): The number of block rules created for the item. `0` if the target does not exist. * `action.affected` (object): Arrays of affected `userIds` and `deviceIds`. Both arrays are empty if no rule was created. * `action.statusUrl` (string): The relative URL for [checking the asynchronous action](#get-fraud-action-status), for example, `/v1/fraud/actions/act_123`. Included when association processing is accepted. * `action.configuration` (object): Included when a rule is created. Contains `description` and `expiresAt`, an ISO 8601 datetime. These fields are `null` when no description or expiration was specified. An HTTP `200` response can contain failed items. Check each item's `meta.code`; failed items do not include `action`. Invalid request bodies return `400`. These endpoints return `404` if access is not enabled. Supplying a label when fraud labels are not enabled returns `403`. Optional labels are delivered asynchronously for successful actions on existing users. An item's success does not confirm label delivery. Labels are not submitted for unknown users. #### **Unblock users and devices** Disables block rules for the specified users or devices. Each item targets exactly one user or device. By default, unblocking a user does not unblock their devices, and unblocking a device does not unblock its users. Set `includeAssociations` to `true` to also unblock associated devices or users. If a target does not exist or has no block rules to disable, the item succeeds with `changedBlockCount` set to `0`. **Definition** **POST**`https://api.radar.io/v1/fraud/unblock` **Body parameters** * `items` (array, required): An array of items to unblock, with at least 1 item and a default maximum of 500 items. Each item accepts: * `userId` (string): The `userId` of the user to unblock. Specify exactly one of `userId` or `deviceId`, as a non-empty string. * `deviceId` (string): The `deviceId` to unblock. Specify exactly one of `userId` or `deviceId`, as a non-empty string. * `includeAssociations` (boolean, optional): Set to `true` to also unblock associated devices for a user, or immediately associated users for a device, asynchronously. Defaults to `false`. * `label` (string, optional): Either `fraud` or `not_fraud`. Requires fraud labels to be enabled for your project. * `fraudType` (string, optional): A fraud category, up to 100 characters. Allows alphanumeric characters, dashes, underscores, spaces, periods, and commas. Requires `label`. * `incidentTime` (string, optional): The time of the incident as an ISO 8601 datetime with a timezone, for example, `2026-10-21T12:00:00Z`. Requires `label`. Unlike blocking, unblocking does not accept `durationMs` or `description`. **Default rate limit** 5 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ```bash theme={null} curl "https://api.radar.io/v1/fraud/unblock" \ -H "Authorization: prj_live_sk_..." \ -H "Content-Type: application/json" \ -X POST \ -d '{"items":[{"userId":"user-123"},{"deviceId":"device-456","includeAssociations":true}]}' ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "responses": [ { "index": 0, "target": { "userId": "user-123" }, "meta": { "code": 200 }, "action": { "changedBlockCount": 1, "affected": { "userIds": ["user-123"], "deviceIds": [] } } }, { "index": 1, "target": { "deviceId": "device-456" }, "meta": { "code": 202 }, "action": { "changedBlockCount": 1, "affected": { "userIds": [], "deviceIds": ["device-456"] }, "statusUrl": "/v1/fraud/actions/act_123" } } ] } ``` **Response fields** * `responses` (array): One result per request item, in request order. * `index` (number): The zero-based index of the request item. * `target` (object): The requested `userId` or `deviceId`. * `meta.code` (number): `200` when the direct action succeeded and no association processing was requested, including when no rules were disabled; `202` when the direct action succeeded and association processing was accepted; or `500` if the item failed. * `action.changedBlockCount` (number): The number of block rules disabled for the item. Can be greater than `1` if the target had multiple block rules. * `action.affected` (object): Arrays of affected `userIds` and `deviceIds`. Both arrays are empty if no rules were disabled. * `action.statusUrl` (string): The relative URL for [checking the asynchronous action](#get-fraud-action-status), for example, `/v1/fraud/actions/act_123`. The same partial failure, request error, and asynchronous label delivery behavior described for [blocking](#block-users-and-devices) applies to unblocking. Unblock responses do not include `action.configuration`. #### **Get fraud action status** Gets the status of an asynchronous block or unblock action. Use the `action.statusUrl` returned by [blocking](#block-users-and-devices) or [unblocking](#unblock-users-and-devices) with `includeAssociations` set to `true` to poll for completion. An authorized lookup returns HTTP `200`. Check `operation.meta.code` for the action's status: `202` means association processing is pending or in progress, and `200` means the full discovered scope has succeeded. **Definition** **GET**`https://api.radar.io/v1/fraud/actions/:actionId` **Path parameters** * `actionId` (string, required): The action ID in the `action.statusUrl` returned by the block or unblock request. **Authentication level** Secret **Sample request** ```bash theme={null} curl "https://api.radar.io/v1/fraud/actions/act_123" \ -H "Authorization: prj_live_sk_..." ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "operation": { "actionId": "act_123", "meta": { "code": 202 }, "acceptedAt": "2026-10-01T19:00:00.000Z", "directAction": { "changedBlockCount": 1, "affected": { "userIds": [], "deviceIds": ["device-456"] } }, "associations": { "discoveryComplete": true, "processedCount": 20, "processedEntityCount": 20, "skippedEntityCount": 0, "changedBlockCount": 20 } } } ``` **Response fields** * `operation` (object): The asynchronous action and its progress. * `actionId` (string): The action ID. * `meta.code` (number): `202` while association processing is pending or in progress, or `200` after the full discovered scope succeeds. * `acceptedAt` (string): The time the action was accepted. * `directAction` (object): The result for the explicit target. * `associations` (object): Progress for associated entities. * `discoveryComplete` (boolean): Whether all immediate associations have been discovered. * `processedCount` (number): The number of associated entities processed. * `processedEntityCount` (number): The number of associated entities whose processing has completed. * `skippedEntityCount` (number): The number of associated entities skipped. * `changedBlockCount` (number): The number of block rules created or disabled for associated entities. ## Manage your Radar project settings ### **Places settings** Places settings represents your current project settings for [Places](/geofencing/places). **Object fields** * `chainMetadata` (dictionary): Current metadata associated with each Radar chain. * `chainMappings` (dictionary): Current mapping associated with each Radar chain. * `placeFilters` (dictionary): Current chains and category filtering for place entry and exit event generation. #### **Get Places settings** Gets your current Places settings. **Definition** **GET**`https://api.radar.io/v1/settings` **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/settings" \ -H "Authorization: prj_live_sk_..." \ -X GET ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "chainMetadata": { "mcdonalds": { "availableDeals": true, }, "starbucks": { "availableDeals": true, } }, "chainMappings": { "mcdonalds": "retailer1", "starbucks": "retailer2" }, "placeFilters": { "chain": [ "mcdonalds", "starbucks" ], "category": [ "restaurant" ] } } ``` #### **Update Places settings** Updates your Places settings. **Definition** **PATCH**`https://api.radar.io/v1/settings` **Default rate limit** 10 requests per second (contact your customer success manager to increase rate limit) **Authentication level** Secret **Sample request** ``` curl "https://api.radar.io/v1/settings" \ -H "Authorization: prj_live_sk_..." \ -H "Content-Type: application/json" \ -X PATCH \ -d '{"chainMetadata":{"mcdonalds":{"availableDeals":false}},"chainMappings":{"mcdonalds":"retailer1"},"placeFilters":{"chain":["mcdonalds"]}}' ``` **Sample response** ```json theme={null} { "meta": { "code": 200 }, "chainMetadata": { "mcdonalds": { "availableDeals": false } }, "chainMappings": { "mcdonalds": "retailer1" }, "placeFilters": { "chain": [ "mcdonalds" ] } } ``` # FAQs Source: https://docs.radar.com/faqs Answers to common questions about Radar, covering testing, battery drain, privacy, security, and location permissions. ## Testing ### How should I test Radar battery drain? To test battery drain attributable to Radar background tracking in your iOS or Android app, you must isolate battery drain attributable Radar's usage of location services. This means that you must control for confounding variables: * In the context of your app, you must control for battery drain attributable to other code and other SDKs running in your app, having the app foregrounded, and notifications. * In the context of your device, you must control for battery drain attributable to other apps, the OS, and your device state, including having the screen turned on. Often, having the screen turned on and the app foregrounded are bigger sources of battery drain than usage of location services. To isolate battery drain attributable Radar's usage of location services in your app, there are two ways to test: 1. Install two builds of your app, one with Radar running background tracking and one without. Use your phone for a period of time, ideally a full day, and avoid opening either app (to avoid the confounding variables described above). At the end of the period, compare battery blame for each app on the Battery screen in the device settings. 2. Install the [Radar Waypoint app](/waypoint), a sample app that does nothing but run Radar. Use your phone for a period of time, ideally a full day, and avoid opening the app (to avoid the confounding variables described above). At the end of the period, inspect battery blame for the app on the Battery screen in the device settings. Note that the Battery screen on iOS and Android shows battery drain attributable to each app not as an absolute percentage, but as a percentage of the absolute battery drain in the battery session. For example, if the iOS Battery screen shows 2% battery blame attributable to your app and shows that your phone has drained 50% of its battery in the battery session, the absolute percentage attributable to your app is actually 2% \* 50% = 1%. When using the efficient and responsive tracking presets, the SDK will wake up while the user is moving (usually every few minutes), then shut down when the user stops. To save battery, the SDK will not wake up when stopped. For most users, background tracking with these presets uses only 1-2% battery per day (measured in absolute percentage). See the [SDK documentation](/sdk/sdk) and [Navigating location services tradeoffs between accuracy, frequency, and battery efficiency](https://radar.com/blog/navigating-location-services-tradeoffs-between-accuracy-frequency-battery-efficiency) for more information. ### Can I test Radar side-by-side with another location SDK? Many developers switch to Radar from other location SDKs. You can test Radar side-by-side with another location SDK, but keep in mind that there may be side effects on iOS. On iOS, significant location change events, `CLRegion` events, and `CLVisit` events may be sent to all `CLLocationManager` instances in the app. This may cause the Radar SDK to receive client-side location updates triggered by other SDKs even if you have not called `Radar.trackOnce()` or `Radar.startTracking()`. On Android, this is not an issue. ## Product ### Is Radar still able to track location in the background if the app is killed? Yes, if background location permissions have been granted. On iOS, if the app is killed (e.g., swiped up from the App Switcher), the SDK is able to wake up and start collecting locations again if it receives certain types of location updates from the OS. These services can be activated on iOS by enabling the [location updates background mode](/sdk/ios#background-modes) and using at least one of following [tracking options](/sdk/tracking#ios-options): * `syncGeofences` * `useStoppedGeofence` * `useMovingGeofence` * `useSignificantLocationChanges` * `useVisits` On Android, Radar will continue to receive location updates if the app is swiped out of the Recent Apps list. Radar will not receive location updates if the phone manufacturer aggressively kills background services or the user presses *Force stop*. ### If a user backgrounds my app, do I need to request background location permissions to access location? With just foreground location permissions, you can leverage the [background location indicator](https://developer.apple.com/documentation/corelocation/cllocationmanager/2923541-showsbackgroundlocationindicator) on iOS or a [foreground service](https://developer.android.com/guide/components/foreground-services) on Android to continue to receive location updates in the background. These are activated via the `showBlueBar` [tracking option](/sdk/tracking#ios-options) on iOS or the `foregroundService` [tracking option](/sdk/tracking#android-options) on Android. iOS devices will display a blue location icon when activated, and Android devices will display a persistent notification. Use of these visual indicators is common for operational use cases such as fleet tracking and delivery. On Android, Google Play does not accept geofencing as a foreground service use case. See [foreground services and Google Play policy](/sdk/android#foreground-services-and-google-play-policy). ### What are the different event listeners and how should I use them? Each listener can support different use cases and exposes different data to take actions. The client location listener (`onClientLocationUpdated` on Android, `didUpdateClientLocation` on iOS) is fired whenever the Radar SDK receives a location update from the device. It can be used to collect a stream of location updates before they hit Radar servers. The location updated listener (`onLocationUpdated` on Android, `didUpdateLocation` on iOS) delivers location updates processed by Radar servers and will return refreshed user context. This listener can be used to deliver in-app experiences based on user context, including when `Radar.trackOnce()` is called on application launch. The Radar events listener (`didReceiveEvents` on Android and iOS) can be used to listen for Radar events and trigger workflows. ### What is the latency of Radar APIs? Radar APIs have a p50 latency of 50ms and a p90 of 150ms. The `/route/matrix` API increases in latency as additional `origin` or `destination` points are added, or as the distance between points increases. ### How often are usage statistics recalculated? Usage statistics are recalculated nightly and reflect the total Monthly Tracked Users (MTUs) and API requests made in the month. Usage statistics can be found on the [Home](https://dashboard.radar.com) page of the Radar dashboard. ## Privacy ### What data does the Radar SDK collect? The Radar SDK collects location data (latitude, longitude), device IDs, IP addresses, and device info by default. We also collect any other user IDs (e.g., user IDs) or metadata that you choose to send us. Radar does not collect personally identifiable information like name or email by default. For more information, see our [privacy policy](https://radar.com/privacy), our [commitment to privacy](https://radar.com/blog/our-commitment-to-privacy), and our [location data privacy checklist](https://radar.com/blog/location-data-privacy-checklist). ### What are privacy best practices for Radar? * Do not send any PII, like names, email addresses, or publicly available IDs, to the Radar SDK or API. * Minimize the data you collect with Radar, turning on only the context types relevant to your use case (store visits for shopping apps, airport visits for travel apps, and so on). * Clearly explain to end users what data will be collected and how it will be used in your apps, in permissions prompts, and in your privacy policy. For more information, see our [location data privacy checklist](https://radar.com/blog/location-data-privacy-checklist). ### What are location permission prompt best practices? The best location permission prompts are: * Transparent: The prompt explains what data will be collected from the end user and how it will be used, with a link to your privacy policy. * Valuable: The prompt explains why the user should grant location permissions, like enabling a location-based feature or unlocking an offer. * Timely: The prompt is shown when the user is engaged, like in an onboarding, when accessing a location-based feature, or after a transaction. Background permission prompts are shown after and incremental to foreground permission prompts. Opt-in rates vary from app to app, but apps that follow best practices can expect 70-80% of users to grant location permissions, with 40-50% of users granting background ("always") location permissions on iOS. For more information, see our [location data privacy checklist](https://radar.com/blog/location-data-privacy-checklist). ### What is Radar's data retention policy? By default, users and events are retained for 1 year, trips are retained for 90 days, and location updates are retained for 7 days. Radar supports custom data retention settings. Admins can adjust these settings in the Radar dashboard under the Privacy section. Data retention settings are customizable per project. ### Is Radar CCPA-compliant and GDPR-compliant? Yes, Radar is CCPA-compliant and GDPR-compliant. For more information, see our [commitment to privacy](https://radar.com/blog/our-commitment-to-privacy). For data deletion requests, you can delete a user manually from the user detail page in the dashboard or [delete a user programmatically](/api#delete-a-user) using the API. Deletions are immediate. For data access requests, you can export a user and all of their events and locations manually from the user detail page in the dashboard. If you need assistance, you can also forward requests to your customer success manager. ## Security ### How do Radar account roles work? * **Read** accounts can: * Read user, geofence, event, and location data * **Write** accounts can also: * Create, update, and delete user, geofence, and event data * Create update, and delete custom reports * Create custom exclusion zones * Create block rules * **Admin** accounts can also: * Invite new accounts * Update project settings, API keys, integrations, and data retention settings * Create custom inclusion zones * Create, delete, and disable bypass rules * Delete and disable block rules * **Owner** accounts can also: * Edit account roles and project access Use the appropriate role (owner, admin, write, or read) for each co-worker's account. See [Radar security best practices](#what-are-security-best-practices-for-radar). By default, an organization can have a maximum of 100 accounts. Contact your customer success manager if you need more. ### How do data access controls work? > [!NOTE] > > Data access controls are available on the [Enterprise plan](https://radar.com/pricing). In addition to the account roles above, owners can also control: * **Project access**: Access to specific projects in an organization * **Environment access**: Access to test or live data across projects in an organization * **Data access**: Access to specific data and pages across projects in an organization * *User locations*: Access to data on the user details page (map and location information) and access to the user locations page * *Trip locations*: Access to data on the trip details page (map and location information) and access to the [trip tracking dashboard](/geofencing/trips#in-the-radar-trip-tracking-dashboard) * *Geofence tags*: Access to geofences with specific tags. An empty list gives access to all geofences. To access a Geofence, both the *tag* and *externalId* access controls must be satisfied. * *Geofence externalIds*: Access to geofences with specific externalIds. An empty list gives access to all geofences. To access a Geofence, both the *tag* and *externalId* access controls must be satisfied. ### Does Radar have a bug bounty or responsible disclosure program? If you discover a potential vulnerability or security concern, please email [security@radar.com](mailto:security@radar.com). We encourage responsible disclosure and review all reports promptly. ### What are security best practices for Radar? #### Account management * Use a strong password (at least 10 characters, at least 1 lowercase letter, at least 1 uppercase letter, at least 1 number, and at least 1 symbol). * Use a password manager like 1Password or LastPass to generate and store passwords, and use a different password for each website. * Use app- or SMS-based multi-factor authentication (MFA). Enable MFA on the Account page. * Do not share your account with co-workers. * Use the appropriate role (owner, admin, write, or read) for each co-worker's account. * When a co-worker is terminated, delete their account. * Use single sign-on (SSO) if supported by your organization. * Use a password protected lock screen on employee workstations set to a short timeout, e.g., 5 minutes. #### Authentication * Use Test keys for development and Live keys for production. * Use [Publishable keys](/sdk#authentication), which are restricted in scope in client-side code. Never use [Secret keys](/api#authentication), which can read or write any data. #### Website restrictions You can restrict which websites can use your publishable API keys. Add domains on the [Settings](https://dashboard.radar.com/settings#website-restrictions) page under *Website restrictions*. Multiple domains and wildcards (\*) are supported. For example: `example.com`, `sub.example.com`, `*.example.com`, `example.com:8000`, `localhost:8080`. #### Mobile restrictions You can also restrict which mobile apps can use your publishable API keys. Add iOS bundle IDs and Android package names on the [Settings](https://dashboard.radar.com/settings#mobile-restrictions) page under *Mobile restrictions*. Multiple bundle IDs and package names are supported. Wildcards (\*) are not supported. For example: `com.example.app1`, `com.example.app2`. #### Data management * Encrypt data stored outside of Radar (e.g., data sent to integrations or sent to webhooks and stored in a data warehouse). * Do not send any PII, like names, email addresses, or publicly available IDs, to the Radar SDK or API. See also [Radar privacy best practices](#what-are-privacy-best-practices-for-radar). ### Does Radar support audit logs? Yes, Radar supports audit logs for enterprise customers. Audit logs include all requests made from the dashboard with the account, project, environment, IP address, and timestamp of each request. The 100 most recent audit logs can be viewed from the dashboard, and the most recent 100,000 audit logs can be exported to CSV. Contact your customer success manager if you need older audit logs. ### How do I set up single sign-on (SSO) in Radar? Radar supports single sign-on (SSO) via SAML, LDAP, Open ID, and other identity providers. SSO is an enterprise-only feature. Contact your customer success manager to enable this feature. #### SAML To set up your SAML identity provider, reach out to your customer success manager who will provide the assertion consumer service URL and application callback URL. They will need the following information in return: * SAML protocol URL * Sign-in URL * Sign-out URL (optional) * X509 Signing Certificate (.pem file) * User ID attribute (defaults to [http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier](http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier) then [http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn](http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn) then [http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name](http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name)) ### Is Radar SOC 2 type II-certified? Yes, Radar is SOC 2 type II-certified. For more information, please ask your account executive for a copy of our attestation report. ### Is the Radar SDK secure? Yes. The Radar SDK calls the Radar API over HTTPS using TLS version 1.2 or higher, so all data is encrypted in transit. API calls are authenticated using your [Publishable keys](/sdk#authentication), which are restricted in scope. ## Location permissions ### How do I get statistics for location permissions? Statistics for location permissions are available for customers who have installed SDK 3.1 or later. ### What do the states in the location permissions graph represent? On iOS, the SDK checks `authorizationStatus` on `CLLocationManager` to determine authorization status: * **`Granted Background`**: `authorizationStatus` is `.authorizedAlways`, meaning that the user has granted background location permissions. * **`Granted Foreground`**: `authorizationStatus` is `.authorizedWhenInUse`, meaning that the user has granted foreground location permissions. * **`Denied`**: `authorizationStatus` is `.denied` or `.restricted`, meaning that the user has denied location permissions. * **`Not Determined`**: `authorizationStatus` is `.notDetermined`, meaning that the user has not yet been prompted for location permissions. On Android, the SDK checks the `ACCESS_FINE_LOCATION` and `ACCESS_BACKGROUND_LOCATION` permissions to determine authorization status: * **`Granted Background`**: The `ACCESS_BACKGROUND_LOCATION` permission is granted, meaning that the user has granted background location permissions. * **`Granted Foreground`**: The `ACCESS_FINE_LOCATION` permission is granted, meaning that the user has granted foreground location permissions. * **`Denied`**: The `ACCESS_FINE_LOCATION` permission is denied and `shouldShowRequestPermissionRationale()` returns `false`, meaning that the user has denied location permissions and checked "Never ask again." * **`Not Determined`**: None of the above criteria are true, meaning that the user has not yet been prompted for location permissions. ### What is a tracked user? A tracked user is a unique user that sends one or more location events to Radar in a given time period. ### What is a unique user? When does Radar create a new user record? The Radar SDK collects IDs for each user and device, including: * `installId`: a GUID automatically generated on fresh install * `deviceId`: IDFV on iOS, Android ID on Android, or a GUID on web * `userId`: set by calling `Radar.setUserId()`, also called *External ID* in the dashboard Each user record is also assigned a unique `_id`, also called *Radar ID* in the dashboard. For usage tracking and security reasons, Radar maintains a separate user record for each unique combination of these IDs. Although calling `Radar.setUserId()` for the first time will assign a `userId` to an existing user record (e.g., on login or when a device is first identified), changing the `userId` for an already identified user (e.g., to set a different `userId` or to clear the `userId` on logout) will create a new user record. A unique user record created or updated in a given time period is counted as a tracked user in that time period. ### What is an active user? An active user is a unique user that has an [app session](#what-qualifies-as-an-app-session) in a given time period. ### What qualifies as an app session? An app session is a period of user activity in your app. A new app session is started whenever the app is opened, assuming at least 5 minutes have elapsed since the last app session started. ### Why are counts of active users different from counts of tracked users? Depending on your Radar SDK implementation, a user may have an [app session](#what-qualifies-as-an-app-session) without sending a location event to Radar. Conversely, a user may send a location event to Radar in the background (assuming they have granted background location permissions) without opening the app. # Beacons Source: https://docs.radar.com/geofencing/beacons Detect nearby Bluetooth beacons with Radar for indoor, curbside, and drive-thru use cases that need accuracy down to a few meters. > [!NOTE] > > Beacons is available on the [Enterprise plan](https://radar.com/pricing). With Beacons, you can detect nearby Bluetooth beacons. Use Beacons for indoor or drive-thru use cases. Beacons are like hardware-enabled micro-geofences, accurate down to a few meters. For example, you might create a store-level [geofence](/geofencing/geofences) and monitor beacons installed at the entrance, in the drive-thru, on registers, on tables, in aisles, or in parking spaces at each store. ![Beacon illustration](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/illustrations/beacons-illustration.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=47db1f4a18bebff238b7d59e984f9683) Beacons provides the following user context: ```json theme={null} { "beacons": [ { "type": "ibeacon", "uuid": "b9407f30-f5f8-466e-aff9-25556b57fe6d", "major": "100", "minor": "1", "description": "Store 123 - Register 1", "tag": "store-register", "externalId": "123-1", "enabled": true }, { "type": "eddystone", "uid": "f7826da6bc5b71e0893e", "instance": "4456384b726a", "description": "Store 123 - Aisle A", "tag": "store-aisle", "externalId": "123-A", "enabled": true } ] } ``` Beacons also provides the following events: * `user.entered_beacon` * `user.exited_beacon` You can receive events client-side via the [SDK](/sdk) or server-side via [event integrations](/integrations/integrations), including webhooks. ## Quickstart First, [sign up](https://radar.com/signup) for Radar and get an API key. Then, [create beacons](#create-beacons). From there, [integrate the SDK](/sdk) and call `Radar.trackOnce()` with `beacons = true` or `Radar.startTracking()` with `trackingOptions.beacons = true`, depending on your use case. Radar will generate an entry event on the first location update within range of a beacon. ## How it works Beacon detection works on iOS and Android in the foreground and in the background. After you import beacons, Radar will sync nearby beacons to the SDK on every location update. On iOS and Android, Radar can range any beacons compatible with [iBeacon](https://developer.apple.com/ibeacon/). On Android, the SDK can also range any beacons compatible with [Eddystone-UID](https://github.com/google/eddystone). Just like the Radar generates `user.entered_geofence` events after you import [geofences](/geofencing/geofences), Radar will generate `user.entered_beacon` events after you import beacons. To range beacons, the user must grant location permissions. On Android, the user must also grant the [required Bluetooth permissions](https://developer.android.com/about/versions/12/features/bluetooth-permissions#declare-new-permissions). If the user grants foreground location permissions, you can range nearby beacons in the foreground by calling `Radar.trackOnce(desiredAccuracy, beacons, completionHandler:)` with `beacons = true`. If the user grants background location permissions, you can monitor beacons in the background by calling `Radar.startTracking()` with `trackingOptions.beacons = true`. See the [SDK reference](/sdk) for more information. Beacon entry and exit events are sent to the SDK, to [webhooks](/integrations/webhooks), and to [integrations](/integrations/integrations) just like geofence entry and exit events. ### Ranging by UUID only By default, Radar will sync nearby beacons to the SDK on every location update using the `coordinates` specified for each beacon. The SDK will then range nearby beacons based on `uuid`, `major`, and `minor` for iBeacon or `uid` and `instance` for Eddystone. Alternatively, the SDK can range beacons based on `uuid` or `uid` only, regardless of the `coordinates` specified for each beacon. To enable this, set *iBeacon UUIDs* and/or `Eddystone UIDs` on the [Settings page](https://dashboard.radar.com/settings), under *Beacons*. On iOS, you must also enable the *Location updates* [background mode](/sdk/ios#background-modes). ## Create beacons You can create beacons via the dashboard, CSV import, or through the API. You can create beacons in the Test environment for development and testing, and in the Live environment for production. Like [geofences](/geofencing/geofences), you also specify the metadata for beacons when you create them, including *tag* (a group for the beacon, e.g., `store-register`), external ID (an external ID for the beacon that maps to your internal database, e.g., `123-1`), *description* (a display name for the beacon, e.g., `Store 123 - Register 1`). You also specify the identifiers used to range the beacon, including `uuid`, `major`, and `minor` for iBeacon or `uid` and `instance` for Eddystone, as well as an approximate latitude and longitude used to sync nearby beacons (within 1 kilometer) to the SDK. **Beacons should be uniquely referenced by tag and external ID, assigned by you when a beacon is created. To disable or rotate identifiers for a beacon, re-import the beacon with the same tag and external ID.** ### Dashboard To create a beacon via the dashboard, go to the [Beacons page](https://dashboard.radar.com/geofencing/beacons) and click the *New* button. Optionally search for an address or place, then enter a type, tag, external ID, UUID, major, minor, and optional metadata. Click *Create* to create the beacon. ### CSV import To import beacons via CSV import, go to the [Beacons page](https://dashboard.radar.com/geofencing/beacons) and click the *Import* button. Then, select a CSV to upload. > [!NOTE] > > Headers are required as the first row of the CSV. The CSV may have the following columns: * **`description`** (string, required): A display name for the beacon. * **`tag`** (string, optional): A group for the beacon. * **`externalId`** (string, optional): An external ID for the beacon that maps to your internal database. * **`type`** (string, required): The type of beacon, one of `ibeacon` (supported on iOS and Android) or `eddystone` (supported on Android only). * **`uuid`** (string, required for `ibeacon`): For iBeacons, the UUID of the beacon. * **`major`** (string, required for `ibeacon`): For iBeacons, the major ID of the beacon. * **`minor`** (string, required for `ibeacon`): For iBeacons, the minor ID of the beacon. * **`uid`** (string, required for `eddystone`): For Eddystone beacons, the UID of the beacon. * **`instance`** (string, required for `eddystone`): For Eddystone beacons, the instance ID of the beacon. * **`coordinates`** (array, required): The approximate location of the beacon, used to sync nearby beacons (within 1 kilometer) to the SDK. A JSON string in the format `[longitude,latitude]`. **Note that longitude comes before latitude, a GeoJSON convention.** * **`enabled`** (boolean, required): If true, the beacon will generate events. If false, the beacon will not generate events. * **`metadata`** (dictionary, optional): A set of custom key-value pairs for the beacon. A JSON string representing a dictionary with up to 16 keys and values of type string, boolean, or number. **If a beacon with the specified tag and external ID already exists, it will be updated. If not, it will be created.** For example, to import beacons installed on registers and in parking spaces at a store, you could use the following CSV: ```csv theme={null} description,tag,externalId,type,uuid,major,minor,uid,instance,coordinates,enabled,metadata "Store #123 - Register #1",store-register,123-1,ibeacon,"b9407f30-f5f8-466e-aff9-25556b57fe6d",100,1,,,"[-73.975384,40.783747]",true,{} "Store #123 - Register #2",store-register,123-2,ibeacon,"c9407f30-f5f8-466e-aff9-25556B57fe6d",100,2,,,"[-73.975384,40.783747]",true,{} "Store #123 - Parking Space #1",store-parking,123-1,ibeacon,"d9407f30-f5f8-466e-aff9-25556b57fe6d",101,1,,,"[-73.975363,40.783826]",true,{} "Store #123 - Parking Space #2",store-parking,123-2,ibeacon,"e9407f30-f5f8-466e-aff9-25556b57fe6d",101,2,,,"[-73.975363,40.783826]",true,"{""type"":""parking""}" "Store #123 - Aisle A",store-aisle,123-A,eddystone,,,,"f7826da6bc5b71e0893e","4456384b726a","[-73.974317,40.785541]",true,{} "Store #123 - Aisle B",store-aisle,123-B,eddystone,,,,"f7826da6bc5b71e0893e","4456384b726b","[-73.974317,40.785541]",true,{} ``` **Again, note that longitude comes before latitude, a GeoJSON convention.** You can find a history of past imports on the [Beacons import history page](https://dashboard.radar.com/geofencing/beacons/imports). ### API You can also create beacons programmatically via the [API](/api). You can create a beacon via **POST** `/api/v1/beacons`, or upsert a beacon based on tag and external ID via **PUT** `/api/v1/beacons/:tag/:externalId`. For example, to upsert a beacon within a store via the [API](/api): ```sh theme={null} curl "https://api.radar.io/v1/beacons/drive-thru/store123-beacon-1" \ -H "Authorization: prj_live_sk_..." \ -X PUT \ -d "description=Store 123 - Register 1" \ -d "tag=store-register" \ -d "tag=123-1" \ -d "type=ibeacon" \ -d "uuid=b9407f30-f5f8-466e-aff9-25556b57fe6d" \ -d "major=100" \ -d "minor=1" \ -d "coordinates=[-73.975384,40.783747]" \ -d "enabled=true" ``` **Again, note that longitude comes before latitude, a GeoJSON convention.** # Campaigns Source: https://docs.radar.com/geofencing/campaigns Create location-based push notifications with Radar campaigns, including targeting, frequency capping, and campaign analytics. > [!NOTE] > > Campaign analytics and frequency capping require [iOS SDK v3.19.6](https://github.com/radarlabs/radar-sdk-ios/releases/tag/3.19.6) or above. Client-side geofence notifications are available on [iOS SDK v3.7.6](https://github.com/radarlabs/radar-sdk-ios/releases/tag/3.7.6) and above. Use campaigns to create location-based notifications effortlessly. Campaigns let you customize your notification content and targeting behavior with ease. ## Quickstart First, [sign up](https://radar.com/signup) for Radar and get an API key. To use campaigns with [Geofences](/geofencing/geofences), start by [creating geofences](/geofencing/geofences#create-geofences) through the dashboard, a CSV import, or the API. To use campaigns with [Places](/geofencing/places), enable Places through the [settings page](https://radar.com/dashboard/settings#places-settings) and `nearby places` is activated. Reach out to your account manager to enable `nearby places` for your project. Then setup nearby places for the project via the [settings page](https://radar.com/dashboard/settings). To use campaigns with events, ensure that the desired trigger events are enabled through the [settings page](https://dashboard.radar.com/settings). To use campaigns with [Beacons](/geofencing/beacons), enable beacons from the [settings page](https://dashboard.radar.com/settings#beacons-settings) then create beacons from the [beacons page](https://dashboard.radar.com/geofencing/beacons) Once set up, [create your campaigns](https://dashboard.radar.com/geofencing/campaigns) using the dashboard. ## Create campaigns To create a campaign via the dashboard, navigate to the [campaigns page](https://dashboard.radar.com/geofencing/campaigns) and click **Create**. Provide the campaign details, targeting options, and notification details. Notifications will only be delivered if the campaign is set to **Enabled**. ## Campaign types ### Client side geofence (iOS only) #### Geofences and Places Use Radar's client side geofence notifications to display a notification on iOS devices when a user enters a geofence. These notifications work with foreground or **"when in use"** permissions, dramatically improving their reachable audience. Radar's client side geofence notifications make use of location notification triggers on iOS. No location data is collected in the background. Calls to `Radar.trackOnce()` and `Radar.startTracking()`, which can be configured through remote configuration in the dashboard, will return to the client nearby geofences with notifications, which will then be registered on the device. Default behavior involves syncing down a number of the closest geofences within 5 kilometers. To sync down geofences from further away, ask your Customer Success Manager to enable unlimited-distance syncing. Radar only controls the registration of notifications on the device. Once that happens, surfacing notifications is subject to the [system limits and heuristics](https://developer.apple.com/documentation/usernotifications/unlocationnotificationtrigger#overview) that iOS enforces. If the device is already inside the geofence when its client-side geofence notification is being synced, it will fire upon subsequent entry, not immediately. #### Message customization The title, body, and button text can all be customized for each user, geofence, and place that triggers the notification or in-app message. For example, a notification title of `"Hello! {{ user.userId }}"` will be sent as "Hello! Alice" and "Hello! Bob" for user Alice or Bob. `user` will be available for all campaigns, `geofence` will be available for geofence targeting campaigns and `place` will be available for place targeting campaigns. ```json theme={null} { user: { userId: string; description: string; metadata: { Your custom metadata set from Radar.setMetadata() } }, geofence: { description: string; tag: string; externalId: string; }, place: { name: string; address: string; street: string; categories: string[]; chain: { domain: string; name: string; slug: string; }, country: string; state: string; city: string; zip: string; } } ``` Some variables may not be available for some users, Radar provides a custom fallback helper, use `{{ default user.userId "Show this as fallback" }}` to configure a simple fallback. For more complex fallback and indexing nested fields or arrays, refer to our templating engine [Handlebars docs](https://handlebarsjs.com/). The Radar dashboard provides an UI to help with simple variable substitutions for campaign personalization. ![Campaign personalization](https://mintcdn.com/radarlabs/1fz7cVF-D0fBTFf0/images/geofencing/assets/images/dashboard_campaign_personalization.png?fit=max\&auto=format\&n=1fz7cVF-D0fBTFf0\&q=85\&s=667b107cb54972ffc8f987b7a70932a4) #### Beacon based notifications Use Radar's client side beacon notifications to display a notification on iOS devices when a user enters a beacon region. These notifications work with foreground or **"when in use"** permissions. Beacon based locations are much more accurate indoors as compared to GPS based locations, allowing for notification deliveries with high indoor accuracy. ### Event based notifications Event based notifications are the more traditional type of location-based notifications that rely on background `Always allow` location permission. These types of notifications often provide less reach, but allow for more insight into conversions and analytics. These notifications can be triggered by events such as: * **Entered geofence** * **Exited geofence** * **Entered place** * **Exited place** * **Entered beacon** * **Dwelled in geofence** ### In app messaging In app messages give you a direct, flexible way to engage users right where they’re already active, without requiring push permissions or external channels. They’re a powerful developer tool for driving adoption, onboarding, and feature discovery with fully customizable timing and presentation. Radar's in app messages allow you to deliver timely in app messages when we detect that the user is in a targeted geofence. No additional code is required to setup in app messages. #### Life cycle hooks Optionally, developers can utilize life cycle hooks to have their own code run at important points at an in app message's lifecycle. For example, the app may decide to keep or discard the in app message based on the app's internal state with the `onNewInAppMessage` hook, or an app's internal state may be modified by the `onInAppMessageButtonClicked` hook. ##### iOS ```swift Swift theme={null} class MyRadarInAppMessageDelegate : RadarInAppMessageDelegate { // Called when the CTA button is clicked by the user. Default behavior open configured deeplink, override to implement custom behavior override func onInAppMessageButtonClicked(_ message: RadarInAppMessage) { ... } // Called when the dismiss button is clicked by the user. Override to implement custom behavior override func onInAppMessageDismissed(_ message: RadarInAppMessage) { ... } // Called just before the SDK displays the in app message. The return values decides if the in app message is displayed or discarded override func onNewInAppMessage(_ message: RadarInAppMessage) { ... // do anything on message, change displayed message, store for deferred display, etc. // show the message when ready Radar.showInAppMessage(message) } // Called to create the in-app message view. Default behavior creates a view defined by Radar, optional override to create a custom view. (note: if a custom view is used, the dashboard preview will not be accurate) override func createInAppMessageView(_ message: RadarInAppMessage, onDismiss: @escaping () -> Void, onInAppMessageClicked: @escaping () -> Void, completionHandler: @escaping (UIViewController) -> Void) { ... let viewController = ... create a view and wrap it in a view controller completionHandler(viewController) } } ``` ```objc Objective-C theme={null} // .h file #import #import #import "RadarSDK/RadarInAppMessageDelegate.h" // The member methods can be optionally defined to use custom behavior, or left out to use default behaviour @interface MyObjC_IAMDelegate : RadarInAppMessageDelegate // Called when the CTA button is clicked by the user. Default behavior open configured deeplink, define this function to override default and implement custom behavior - (void)onInAppMessageButtonClicked:(RadarInAppMessage * _Nonnull)message; // Called when the dismiss button is clicked by the user. Override to implement custom behavior - (void)onInAppMessageDismissed:(RadarInAppMessage *)message; // Called just before the SDK displays the in app message. The return values decides if the in app message is displayed or discarded - (void)onNewInAppMessage:(RadarInAppMessage *)message; // Called to create the in-app message view. Default behavior creates a view defined by Radar, override to create a custom view. (note: if a custom view is used, the dashboard preview will not be accurate) - (void)getIAMViewController:(RadarInAppMessage * _Nonnull)message completionHandler:(void (^)(UIViewController *))completionHandler; @end // .m file @implementation MyObjC_IAMDelegate - (void)onInAppMessageButtonClicked:(RadarInAppMessage *)message { } - (void)onInAppMessageDismissed:(RadarInAppMessage *)message { } - (void)onNewInAppMessage:(RadarInAppMessage *)message { ... // do anything on message, change displayed message, store for deferred display, etc. // show the message when ready [Radar showInAppMessage:message]; } - (void)getIAMViewController:(RadarInAppMessage * _Nonnull)message completionHandler:(void (^__strong)(UIViewController *__strong))completionHandler { } @end ``` ##### Android ```kotlin theme={null} class MyInAppMessageReceiver : RadarInAppMessageReceiver { // Called when the CTA button is clicked by the user and causes the in app message to be dismissed. override fun onInAppMessageButtonClicked(payload: RadarInAppMessage) { ... } // Called when the dismiss button is clicked by the user and causes the in app message to be dismissed. override fun onInAppMessageDismissed(payload: RadarInAppMessage) { ... } // Called just before the SDK displays the in app message. The return values decides if the in app message is displayed or discarded override fun onNewInAppMessage(payload: RadarInAppMessage) { ... // do anything on message, change displayed message, store for deferred display, etc. // show the message when ready Radar.showInAppMessage(message) } } ``` #### Custom styling The Radar dashboard offers many ways to customize the look and feel of your in app messages. At the same time, we also allow developers to replace the in app message view with their very own custom in app message implementation. ##### Android Implement your own custom implementation of `RadarInAppMessageReceiver` and override the method `createInAppMessageView`. Then, either pass the `RadarInAppMessageReceiver` as a parameter in `Radar.initialize()` or to `Radar.setInAppMessageReceiver()` ```kotlin theme={null} class MyInAppMessageReceiver : RadarInAppMessageReceiver { override fun createInAppMessageView( context: Context, inAppMessage: RadarInAppMessage, onDismissListener: (() -> Unit)? = null, onInAppMessageButtonClicked: (() -> Unit)? = null, onViewReady: (View) -> Unit ) { val inAppMessageView = myInAppMessageView.initialize( inAppMessage, onDismissListener, onInAppMessageButtonClicked, ) onViewReady(inAppMessageView) } } ``` ##### iOS Implement your own custom implementation of an class conforming to `RadarInAppMessageProtocol` and override the method `createInAppMessageView`. Then, either pass the class conforming to `RadarInAppMessageProtocol` to `Radar.setInAppMessageDelegate()` ```swift theme={null} class MyInAppMessageDelegate : RadarInAppMessageDelegate { func createInAppMessageView(_ message: RadarInAppMessage, onDismiss: @escaping () -> Void, onInAppMessageClicked: @escaping () -> Void, completionHandler: @escaping (UIViewController) -> Void) { let inAppMessageViewController = myInAppMessageViewController.initialize( inAppMessage, onDismiss, onInAppMessageClicked, ) completionHandler(inAppMessageViewController) } } ``` #### Analytics Analytics for in app messaging are available out of the box for both Android and iOS without additional setup. #### Deep linking The CTA button on the in app message can be used to perform deep linking. Simply define the `CTA link` field during campaign creation Deep linking is available for both Android and iOS without any Radar specific setup. However, developers should register the scheme and handle deep linking as described in this [section](#deep-linking-ios-only) ## Campaign targeting Campaigns allow you to target users based on different triggers. Note not all triggers are available for client side geofence notifications. *In order for a notification to be delivered, all targeting options must be true.* ### Geofences and Places targeting **Geofence tags -** allow you target groups of geofences based on their shared tags **Geofence external IDs -** allow you to target individual geofences by their unique ID **Place categories -** allow you to target categories like shopping malls (shopping-mall) or restaurants (restaurant) **Place chains -** allow you to target specific chains like Starbucks or Target. **Device types -** allow you to target users based on their device type (iOS, Android, or both). ### User targeting options Toggle the show advanced button to reveal the user targeting options. User tags can be used to target specific groups of users. Refer to the [iOS](/sdk/ios#user-tags) or [Android](/sdk/android#user-tags) SDK reference for assigning tags to users. When user tag targeting is configured on a campaign, the campaign will only apply to users who have at least one of the tags targeted. Alternatively, you can use the User ID (the [external ID](/sdk/ios#identify-user)) based targeting to target individual users. ### Location authorization targeting Target users based on their device's location-authorization status. For example, you might target a campaign to only target users with foreground-location permission. ### Beacon region targeting Target beacons based on their tag or their beacon ID. Radar converts those targeting options and converts them into an iBeacon region under the hood to trigger notifications as users enter iBeacon regions. ## Scheduling Control when a campaign is delivered. All scheduling options are evaluated in a user's local timezone. For instance, a window set to "until 5 PM" applies at 5 PM local time to every user. Scheduling options are evaluated on the device each time a track response is received, either from a `Radar.trackOnce()` call or while `Radar.startTracking()` is enabled. On each response, the SDK re-evaluates every nearby campaign against its schedule and only registers a notification if the campaign is currently within its window. A campaign that has moved outside its window is not registered and is removed if it was registered on a previous response. > [!NOTE] > > A silent push can wake an app running in the background, but iOS will not deliver it to an app the user has force-quit. In that case the notification is re-evaluated and removed on the next track response instead. ### Start and end times Optionally set a **start** and/or **end** time for a campaign. The campaign only runs within this window. Leave both blank to run whenever the campaign is enabled. The following fields are all optional and work independently: * **Start only** — launches the campaign at that time and keeps it running indefinitely. * **End only** — starts the campaign immediately and automatically stops at the specified time. * **Both** — runs only within the fixed window. * **Neither** — scheduling is off; the campaign runs whenever it's enabled. ### Client-side notifications after the end time Client-side geofence notifications are registered on the device during a campaign's scheduled window. They stay registered until the device's next successful track response, when the SDK checks the schedule again. Until then, a notification can still be delivered even if the campaign has ended. The next successful track response after the end time removes it. To shorten this gap, set up [silent push](/sdk/silent-push). When a campaign's window closes, Radar sends a silent push that wakes the SDK to remove notifications that are out of schedule, without waiting for a new track response. Silent push is best effort and doesn't remove the gap entirely. See [Client-side geofence notifications uses silent push](#client-side-geofence-notifications-uses-silent-push) for details. ### Active days Within a scheduled campaign, optionally restrict delivery to specific **days of the week** — for example, only Tuesdays and Thursdays. Active days are layered on top of the start and end times: a notification is delivered only when the current time is inside the window **and** falls on a selected day, evaluated in the user's local timezone. Leave the selection empty (the default) to run every day. Active days require a start and/or end time to be set. > [!NOTE] > > Active days for client-side geofence campaigns require [iOS SDK v3.37.0](https://github.com/radarlabs/radar-sdk-ios/releases/tag/3.37.0) or above. ### Operating hours For **client-side geofence** campaigns that target geofences, you can **restrict notifications to a geofence's [operating hours](/geofencing/geofences#operating-hours)** so a notification isn't delivered while the location is closed. Enable this with the **Restrict notifications to operating hours** toggle on the campaign. When enabled, a geofence's client-side notification is only delivered when the user's local time is within the geofence's [operating hours](/geofencing/geofences#operating-hours). A short buffer before closing time keeps a notification from firing right as the location closes. Geofences without operating hours configured are unaffected. > [!NOTE] > > Restricting notifications to operating hours requires [iOS SDK v3.36.0](https://github.com/radarlabs/radar-sdk-ios/releases/tag/3.36.0) or above. ### Client-side geofence notifications uses silent push Client-side geofence notifications are scheduled with the operating system in advance, so once registered they stay on the device until the SDK next re-evaluates them. If your campaign only requires Foreground ("When In Use") permissions, the SDK may not receive another track response before the schedule window closes, so a notification could remain scheduled, and fire, after its window has ended. To close this gap, set up [silent push](/sdk/silent-push). When a campaign's scheduling window closes, Radar sends a silent push that wakes the SDK and triggers an on-device re-evaluation of all scheduled notifications, de-registering any that now fall outside their window without requiring a new location update from the user. This helps keep client-side notifications in sync with their schedule, including for users who have granted only foreground location permissions. > [!WARNING] > > Silent push delivery is best effort and isn't guaranteed. Apple and Google can delay or drop silent pushes, for example when the device is offline, in low power or battery-saver mode, or when the OS throttles background delivery. iOS also won't deliver a silent push to an app the user has force-quit. When a silent push doesn't arrive, a notification can still fire after the campaign's window has ended, until the next successful track response removes it. ## Frequency Capping *Requires SDK version v3.19.6* With frequency capping, you can limit the number of notifications a user receives from a campaign. This is useful to prevent excessive notifications for users. To set up frequency capping, navigate to the [campaign settings](https://radar.com/dashboard/settings#campaigns-settings) within the settings page. From there, define the maximum number of notifications allowed in the specified time window. The frequency cap is the maximum number of notifications allowed per user in the specified time window. This includes notifications from **all campaigns**. The time window is the length of time over which the frequency cap applies. This is a rolling time window, so if the frequency cap is 2 and the time window is 48 hours, a notification could be delivered at hour 1, hour 24, and then a third at hour 49. Additionally, at the campaign level, you can configure each campaign to ignore the global frequency capping or to set a campaign specific frequency cap (works in conjugation with the global cap). ## Analytics ### Notification conversions With Radar [Conversions](/api#log-a-conversion), you can log an event whenever a user interacts with a campaign notification. You can also retrieve the source of an *opened\_app* conversion for iOS apps. Within the *metadata* object of the [logged conversion](/sdk/ios#conversions), we will return a *conversion\_source* with either * **`notification`** (app was opened using an external 3rd party notification) * **`radar_notification`** (app was opened using the configured on-prem notification) You can view these campaign conversion analytics by pressing the analytics button on the campaign's page. Alternatively, you can navigate to Geofencing -> Analytics -> Events -> Filters (top right) -> select Type as *opened\_app* -> Apply Filters. From there, select *campaign\_name* from the *grouped\_by* dropdown. See screenshot below: ![OnPremiseNotifications](https://mintcdn.com/radarlabs/f_3pYOJsnyPEyNca/images/assets/images/conversion_source_analytics-4a52cd8a87055b91f37bebaecc7f5f16.png?fit=max\&auto=format\&n=f_3pYOJsnyPEyNca\&q=85\&s=14bddc3f751b7c4dd8264e316be71097) Both notification conversion logging and app open conversions require additional setup. See [Analytics setup](#analytics-setup) for instructions. ### Notification delivery Radar automatically tracks when notifications are delivered to users' devices. Delivery tracking is available for both client-side geofence notifications and event-based notifications. Note that for client-side notifications, iOS SDK versions earlier than [v3.29.0](https://github.com/radarlabs/radar-sdk-ios/releases/tag/3.29.0) have less accurate delivery tracking. For event-based notifications, delivery is counted when it is triggered, as the notifications is delivered to the user immediately when the client receives it. For client-side notifications, the notification is delivered asynchronously by iOS, and we determine the delivery based whether or not the notification is present in the list of pending notifications. This count is not 100% accurate in some edge cases when a user toggles their notification permissions. ### In app message analytics Radar automatically tracks analytics for in app messages, logging when messages are delivered, clicked, or dismissed. No additional setup is required. ## Additional setup for notification based campaign Client side geofence, Event based notifications, Beacon based notifications are considered notification based campaigns. Some additional setup are required for advanced features like analytics and deep linking. ### Custom data You can add custom metadata to the campaign, which will be accessible when the notification is triggered. On notification clicked, the metadata can be accessed from notification delegate on iOS. ```swift Swift theme={null} class MyApp: UNUserNotificationCenterDelegate { ... func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async { let metadata = response.notification.request.content.userInfo["campaignMetadata"] } } ``` ### Analytics setup *Requires SDK version v3.19.6* To enable conversion logging for campaigns, make sure `radarInitializationOptions.autoSetupNotificationConversion` = `true`. Refer to the [iOS SDK Conversions reference](/sdk/ios#conversions) or [React Native Conversion references](/sdk/react-native#conversions) for setup instructions. #### Android setup No additional setup is required for analytics for Android. ### Automated iOS setup Radar can associate `opened_app` events with a campaign notification that was clicked on to open the app. To set this up automatically, set the relevant flag on the initialization options. ```swift Swift theme={null} import UIKit import RadarSDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let radarInitializeOptions = RadarInitializeOptions() radarInitializeOptions.autoLogNotificationConversions = true Radar.initialize(publishableKey: "prj_test_pk_...", options: radarInitializeOptions) return true } } ``` ```c Objective-C theme={null} #import "AppDelegate.h" @import RadarSDK; @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { RadarInitializeOptions *radarInitializeOptions = [[RadarInitializeOptions alloc] init]; radarInitializeOptions.autoLogNotificationConversions = YES; [Radar initializeWithPublishableKey:@"prj_test_pk_..." options:radarInitializeOptions]; return YES; } @end ``` #### Manual iOS setup Alternatively, perform the manual setup: ```swift Swift theme={null} func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async { Radar.logConversion(response: response) } ``` ```c Objective-C theme={null} - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { [Radar logConversionWithNotificationResponse:response]; completionHandler(); } ``` ### Deep linking (iOS only) Radar's campaign notifications can be used for deep linking. This means that you can use Radar's deep linking functionality to open a specific view via on premise notification taps. Set up deep linking from the Radar's Dashboards by adding the **`radar:notificationURL`** to the `URL Schemes` of the desired navigation view of your app. Radar campaigns use local notifications for deep linking. Due to iOS security restrictions, Universal Links opened from local notifications may redirect to Safari instead of your app. For reliable deep linking, use custom URL schemes (e.g., yourapp\://) in your notification payloads. #### Android setup Refer to the [official android documentation](https://developer.android.com/training/app-links/deep-linking) to configure deep links for the android app. No additional Radar specific setup is required. #### iOS setup ##### Automatic Radar's iOS SDK can automatically set up deep linking for you. To enable this feature, set the `autoHandleNotificationDeepLinks` option to `true` in the Radar `initialize` call. ```swift Swift theme={null} import UIKit import RadarSDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let radarInitializeOptions = RadarInitializeOptions() radarInitializeOptions.autoHandleNotificationDeepLinks = true Radar.initialize(publishableKey: "prj_test_pk_...", options: radarInitializeOptions) return true } } ``` ```c Objective-C theme={null} #import "AppDelegate.h" @import RadarSDK; @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { RadarInitializeOptions *radarInitializeOptions = [[RadarInitializeOptions alloc] init]; radarInitializeOptions.autoHandleNotificationDeepLinks = YES; [Radar initializeWithPublishableKey:@"prj_test_pk_..." options:radarInitializeOptions]; return YES; } @end ``` It is recommended to use the automatic setup in conjugation with the `RadarURLDelegate` to handle the URL open. This implementation provides the most light way approach to get started with deep linking. ##### Manual If you want to set up deep linking manually, you can do so by adding the following line to your `UNUserNotificationCenterDelegate` implementation. ```swift Swift theme={null} func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async { Radar.openURLFromNotification(response.notification) } ``` ```c Objective-C theme={null} - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { [Radar openURLFromNotification:response.notification]; completionHandler(); } ``` #### React Native setup ###### Using the Expo plugin (recommended) If you are using Expo, the `react-native-radar` plugin can set up automatic deep link handling and conversion logging for you at prebuild time. Add the relevant options to your plugin configuration in `app.json`: ```json theme={null} { "expo": { ... "plugins": [ [ "react-native-radar", { // boolean to enable iOS automatic deep link handling for Radar notifications, defaults to false "iosAutoHandleNotificationDeepLinks": true, // boolean to enable iOS automatic logging of notification conversions, defaults to false "iosAutoLogNotificationConversions": true } ] ] } } ``` Then run `npx expo prebuild --clean` to regenerate the native iOS project. The plugin will inject the required `Radar.nativeSetup(...)` call into your `AppDelegate.mm` so that deep linking and conversion logging are configured before the JavaScript bundle loads. ###### Manual setup (bare React Native) If you are not using Expo, set the `autoHandleNotificationDeepLinks` option to true in `radarInitializeOptions` and call `[Radar nativeSetup:]` from your `AppDelegate.mm`: ```objc theme={null} - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.moduleName = @"main"; self.initialProps = @{}; BOOL res = [super application:application didFinishLaunchingWithOptions:launchOptions]; RadarInitializeOptions *radarInitializeOptions = [[RadarInitializeOptions alloc] init]; radarInitializeOptions.autoHandleNotificationDeepLinks = YES; [Radar nativeSetup:radarInitializeOptions]; return res; } ``` Alternatively perform the manual setup if you are setting the `AppDelegate` as the `UNUserNotificationCenterDelegate`. ```objc theme={null} - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { [Radar openURLFromNotification:response.notification]; completionHandler(); } ``` ## Support Have questions or difficulties with campaigns? Contact us at [radar.com/support](https://radar.com/support). # Fraud Source: https://docs.radar.com/geofencing/fraud Detect GPS spoofing, proxies and VPNs, and device tampering with Radar Fraud, and block or allow users by country or state for compliance. > [!NOTE] > > Fraud is available on the [Enterprise plan](https://radar.com/pricing). With Fraud, you can detect GPS spoofing, proxy and VPN usage, device tampering, and much more. Along with [Regions](/geofencing/regions), you can also detect a user's country and state and mark specific regions as allowed or blocked to comply with regulations. ![Fraud illustration](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/illustrations/fraud-illustration.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=d3c8573a21815d1d83964c22b4c6e547) Together, Fraud and Regions provide the following user context: ```json theme={null} { "fraud": { "verified": true, "passed": false, "bypassed": false, "blocked": false, "mocked": true, "jumped": false, "compromised": false, "inaccurate": false, "proxy": false, "sharing": false, "lastMockedAt": "2023-07-27T17:18:28.536Z", "lastJumpedAt": "2023-07-27T17:18:28.536Z", "lastCompromisedAt": null, "lastInaccurateAt": null, "lastProxyAt": null, "lastSharingAt": null }, "country": { "code": "US", "name": "United States", "flag": "🇺🇸", "passed": true, "allowed": true }, "state": { "code": "NJ", "name": "New Jersey", "passed": true, "allowed": true, "distanceToBorder": 1092, "inBufferZone": false, "inExclusionZone": false } } ``` ## Quickstart First, [sign up](https://radar.com/signup) for Radar and get an API key. Then, enable Fraud on the [Settings page](https://dashboard.radar.com/settings#fraud-settings). From there, [integrate the SDK](/sdk/sdk), complete the steps below, and call `Radar.trackVerified()` or `Radar.startTrackingVerified()`. Radar will perform fraud and jurisdiction checks as described below. ## How it works You can call `Radar.trackOnce()` to accurately detect a user's current [geofences](/geofencing/geofences), current [place](/geofencing/places), or current [country and state](/regions/countries). However, users can spoof a device's location. For example, a gaming app user may spoof their location to access sports betting features only available in specific states. Or, a retail app user may spoof their location to access offers only available inside a store geofence. To ensure you can trust a user's location, you can call `Radar.trackVerified()` instead. Radar will collect a variety of fraud signals and perform fraud and jurisdiction checks, calculating flags and a signed geolocation token that you can use for fraud detection and geo-compliance in your app. ## Fraud flags If fraud detection is enabled, Radar exposes the following flags in `user.fraud`: * **`mocked`**: Indicates whether a user's location is being mocked, such as in a simulator or using a location spoofing app (e.g., [Fake GPS location](https://play.google.com/store/apps/details?id=com.lexa.fakegps\&hl=en_US\&gl=US)). * **`jumped`**: Indicates whether the user moved too far too fast (e.g., "jumped" across the country in only a few seconds). * **`compromised`**: Indicates whether the user's device or app has been compromised (e.g., rooted, jailbroken). On Android, uses the [Play Integrity API](https://developer.android.com/google/play/integrity). * **`inaccurate`**: Indicates whether the user's location accuracy is too low to pass verification. * **`sharing`**: Indicates whether the user is using screen sharing or remote desktop software (e.g., using [TeamViewer](https://www.teamviewer.com/en-us/)). * **`proxy`**: Indicates whether the user's IP address is a known proxy or VPN. * **`verified`**: Indicates whether the request was made with `Radar.trackVerified()`. While you can work with individual flags, Radar also exposes a single `user.fraud.passed` flag that indicates whether all fraud checks passed. Additionally, the `lastMockedAt`, `lastJumpedAt`, `lastCompromisedAt`, `lastInaccurateAt`, `lastProxyAt`, and `lastSharingAt` timestamps indicate the last time that the user failed each fraud check. Finally, more detailed [failure reasons](#failure-reasons) are also exposed. ## Bypassing checks for testing If desired, you can bypass fraud checks for individual users using the *Mark as Bypassed* button on the user detail page. If a user is marked as bypassed, `user.fraud.bypassed = true` and `user.fraud.passed = true`, regardless of whether the user passes fraud checks. ## Blocking users and devices You can manually block a user or device using the *Blocked* button on its detail page. If a user is blocked, `user.fraud.blocked = true` and `user.fraud.passed = false`, regardless of whether the user passes fraud checks. You can also [block users and devices](/api#block-users-and-devices) or [unblock them](/api#unblock-users-and-devices) using the API. > [!NOTE] > > These API endpoints must be enabled for your project. Contact your customer success manager for access. ## Allowed states and countries With [Regions](/geofencing/regions), you can mark specific countries or states as allowed or blocked to comply with regulations. For example, a sportsbook or daily fantasy sports app may only be allowed to operate in specific US states. Radar exposes your settings in `user.country.allowed` and `user.state.allowed`. Additionally, you can enable buffer zones and exclusion zones for different states. If buffer zones and exclusion zones are enabled, `user.state.inBufferZone` and `user.state.inExclusionZone` indicates whether the user is within a buffer zone or exclusion zone. While you can work with individual flags, Radar also exposes `user.state.passed` and `user.country.passed` flags that indicate whether all jurisdiction checks passed. Finally, more detailed [failure reasons](#failure-reasons) are also exposed. > [!NOTE] > > Contact your customer success manager for access to buffer zones and exclusion zones. ## Platform-specific configuration ### SDK compatibility Starting with [Android SDK](/sdk/android) version `3.39.0` and [iOS SDK](/sdk/ios) version `3.44.0`, you must use a compatible Fraud SDK plugin version. Use the table below to select compatible core SDK and plugin versions. | Platform | Core SDK | Fraud plugin | | - | - | - | | iOS | `3.44.x` | `1.6.x` | | Android | `3.39.x` -> `4.2.x` | `1.3.x` | If using React Native, see [React Native](#react-native) for how to install the plugins. ### Android #### Install plugin If using [Android SDK](/sdk/android) version `3.25.0` or higher, you must install an additional plugin. Use the [SDK compatibility table](#sdk-compatibility) to select compatible core SDK and plugin versions. Add the plugin to the `dependencies` section of your app's `build.gradle` file: ```gradle theme={null} dependencies { implementation 'io.radar:sdk:4.2.+' implementation 'io.radar:sdk-fraud:1.3.1' } ``` If you do not install the plugin, `Radar.trackVerified()` will return `ERROR_PLUGIN`. #### Initialize SDK To support the `sharing` flag on Android, pass `fraud = true` to `RadarInitializeOptions` in `Radar.initialize()`: ```java theme={null} val options = RadarInitializeOptions( fraud = true ) Radar.initialize( context = this, publishableKey = "prj_test_pk_...", options = options ) ``` Starting in Android SDK `4.2.0`, `Radar.trackVerified()` retries against a backup host by default when the primary host doesn't return a response from Radar. To opt out, pass `trackVerifiedAutoFailover = false` to `RadarInitializeOptions`. In earlier versions, pass `trackVerifiedAutoFailover = true` to turn on failover. #### Play Integrity API To support the `compromised` flag on Android, enable the [Play Integrity API](https://developer.android.com/google/play/integrity) on the [Settings page](https://dashboard.radar.com/settings#fraud-settings). If the user's device or app does not meet [basic integrity checks](https://developer.android.com/google/play/integrity/verdict#device-integrity-field), `user.fraud.compromised = true`. You must add the Play Integrity API dependency before calling `Radar.trackVerified()`. Add the dependency to the `dependencies` section of your app's `build.gradle` file: ```java theme={null} dependencies { implementation 'com.google.android.play:integrity:1.6.0' } ``` If `Radar.trackVerified()` returns `ERROR_FORBIDDEN`, check the logs. The Play Services version on the device may be out of date. #### SSL pinning To enable SSL pinning and prevent man-in-the-middle attacks, add a `res/xml/network_security_config.xml` file: ```xml theme={null} localhost api-verified.radar.io 15ktYXSSU2llpy7YyCgeqUKDBkjcimK/weUcec960sI= 15ktYXSSU2llpy7YyCgeqUKDBkjcimK/weUcec960sI= api-verified.radar.com ++MBgDH5WGvL9Bcn5Be30cRcL0f5O+NyoXuWtQdX1aI= f0KW/FtqTjs108NpYj42SrGvOB2PpxIVM8nWxjPqJGE= NqvDJlas/GRcYbcWE8S/IceH9cq77kg0jVhZeAPXq8k= 9+ze1cZgR9KO1kZrVDxA4HQ6voHRCSVNz4RdTCx4U8U= KwccWaCgrnaw6tsrrSO61FgLacNgG2MMLq8GE6+oP5I= ``` Then, reference this file in your manifest: ```xml theme={null} ``` Learn more about [Network Security Configuration on Android](https://developer.android.com/training/articles/security-config). ### iOS #### Install plugin If using [iOS SDK](/sdk/ios) version `3.26.0` or higher, you must install an additional plugin. The plugin requires iOS 15 or higher. Use the [SDK compatibility table](#sdk-compatibility) to select compatible core SDK and plugin versions. In Xcode, go to *File > Swift Packages > Add Package Dependency*. Enter `https://github.com/radarlabs/radar-sdk-ios-fraud-spm.git` for the *Package Repository URL*. ```text theme={null} .package(url: "https://github.com/radarlabs/radar-sdk-ios-spm.git", "3.45.0"..<"3.46.0") .package(url: "https://github.com/radarlabs/radar-sdk-ios-fraud-spm.git", "1.6.0"..<"1.7.0") ``` If you do not install the plugin, `Radar.trackVerified()` will return `ERROR_PLUGIN`. #### Initialize SDK To enable automatic failover of `trackVerified()` requests to a secondary host if the primary host is unreachable, set `trackVerifiedAutoFailover = true` on `RadarInitializeOptions`: ```swift Swift theme={null} let radarInitializeOptions = RadarInitializeOptions() radarInitializeOptions.trackVerifiedAutoFailover = true Radar.initialize(publishableKey: "prj_test_pk_...", options: radarInitializeOptions) ``` ```c Objective-C theme={null} RadarInitializeOptions *radarInitializeOptions = [[RadarInitializeOptions alloc] init]; radarInitializeOptions.trackVerifiedAutoFailover = YES; [Radar initializeWithPublishableKey:@"prj_test_pk_..." options:radarInitializeOptions]; ``` #### App Attest To support the `compromised` flag on iOS, enable [App Attest](https://developer.apple.com/documentation/devicecheck/preparing-to-use-the-app-attest-service) and configure a list of valid [App IDs](https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/AppID.html) (e.g., `A1B2C3D4E5.com.yourapp.app1,A1B2C3D4E5.com.yourapp.app2`) on the [Settings page](https://dashboard.radar.com/settings#fraud-settings). If App Attest indicates that the user's device or app has been compromised, `user.fraud.compromised = true`. App Attest requires iOS 14 and above. If `Radar.trackVerified()` returns `ERROR_FORBIDDEN`, check the logs. The iOS version on the device may not support App Attest. #### SSL pinning To enable SSL pinning and prevent man-in-the-middle attacks, add the following to your `Info.plist` file: ```html theme={null} NSAppTransportSecurity NSAllowsArbitraryLoads NSPinnedDomains api-verified.radar.io NSIncludesSubdomains NSPinnedLeafIdentities SPKI-SHA256-BASE64 15ktYXSSU2llpy7YyCgeqUKDBkjcimK/weUcec960sI= SPKI-SHA256-BASE64 15ktYXSSU2llpy7YyCgeqUKDBkjcimK/weUcec960sI= api-verified.radar.com NSIncludesSubdomains NSPinnedCAIdentities SPKI-SHA256-BASE64 ++MBgDH5WGvL9Bcn5Be30cRcL0f5O+NyoXuWtQdX1aI= SPKI-SHA256-BASE64 f0KW/FtqTjs108NpYj42SrGvOB2PpxIVM8nWxjPqJGE= SPKI-SHA256-BASE64 NqvDJlas/GRcYbcWE8S/IceH9cq77kg0jVhZeAPXq8k= SPKI-SHA256-BASE64 9+ze1cZgR9KO1kZrVDxA4HQ6voHRCSVNz4RdTCx4U8U= SPKI-SHA256-BASE64 KwccWaCgrnaw6tsrrSO61FgLacNgG2MMLq8GE6+oP5I= ``` Learn more about [SSL pinning on iOS](https://developer.apple.com/news/?id=g9ejcf8y). ### React Native #### Install plugin If using [React Native SDK](/sdk/react-native) version `4.0.0` or higher, you must opt in to the fraud plugin on each platform. `react-native-radar` bundles a compatible iOS plugin. On Android, use the plugin version from the [SDK compatibility table](#sdk-compatibility). If using Expo, set `iosFraud` and `androidFraud` in the `react-native-radar` plugin options in `app.json`, then run `npx expo prebuild --clean`: ```json theme={null} { "expo": { "plugins": [ [ "react-native-radar", { "iosFraud": true, "androidFraud": true } ] ] } } ``` The Expo plugin adds `io.radar:sdk-fraud` and the [Play Integrity API](#play-integrity-api) dependency to `android/app/build.gradle` only if they are not already present. If you are upgrading and your `build.gradle` has an older `io.radar:sdk-fraud` version, update it to a [compatible version](#sdk-compatibility) or run `npx expo prebuild --clean`. If not using Expo, add the iOS plugin to the app target in your `ios/Podfile`, then run `pod install`: ```ruby theme={null} pod 'RadarSDKFraud', :path => '../node_modules/react-native-radar' ``` Then, add the Android plugin and the [Play Integrity API](#play-integrity-api) dependency to the `dependencies` section of `android/app/build.gradle`: ```gradle theme={null} dependencies { implementation 'io.radar:sdk-fraud:1.3.1' implementation 'com.google.android.play:integrity:1.6.0' } ``` If you do not install the plugin, `Radar.trackVerified()` will return `ERROR_PLUGIN`. #### Initialize SDK Pass `true` as the second argument to `Radar.initialize()` to enable fraud detection. This is required to support the `sharing` flag on Android. If using React Native SDK version `4.38.0` or higher, you can enable automatic failover of `trackVerified()` requests to a secondary host if the primary host is unreachable by passing `trackVerifiedAutoFailover: true` in the options: ```javascript theme={null} Radar.initialize('prj_test_pk_...', true, { trackVerifiedAutoFailover: true, }); ``` If using Expo, `iosFraud` and `androidFraud` also configure SSL pinning for `api-verified.radar.io`. If not using Expo, configure SSL pinning as described in the [Android](#android) and [iOS](#ios) sections above, including `api-verified.radar.com` if automatic failover is enabled. ### Web and desktop #### Install plugin If using [web SDK](/sdk/web) version `5.0.0` or higher, you must install an additional plugin. In an HTML page, add the SDK script and the plugin script: ```html theme={null} ``` In a web app, install the SDK package and the plugin package from npm: ```bash theme={null} npm install @radarlabs/plugin-fraud radar-sdk-js ``` #### Companion apps and no-download solution The web SDK supports a companion app solution and a pure-JavaScript no-download solution. The companion app solution uses the Radar Verify apps to support remote desktop detection with the `sharing` flag, more advanced `mocked` and `proxy` detection, and more stable device IDs. Download the [Radar Verify Mac app](https://app.radar-verify.com/mac/latest) or the [Radar Verify Windows app](https://app.radar-verify.com/windows/latest). By default, `Radar.trackVerified()` expects the Radar Verify app to be running and returns `ERROR_VERIFY_APP` if it is not. To skip the Radar Verify app and use the no-download solution, pass `{ skipVerifyApp: true }` to `Radar.trackVerified()`, `Radar.startTrackingVerified()`, and `Radar.getVerifiedLocationToken()`. > [!NOTE] > > Contact your customer success manager to learn how you can customize the Radar Verify app installer or branding. #### Native desktop SDKs A native Mac SDK (supporting macOS 12.4+), a native Windows SDK (supporting Windows 10+ and .NET 8+), and an Electron plugin are available. > [!NOTE] > > Contact your customer success manager for access to desktop SDKs. ## Verifying user locations Once the above configuration is complete, you can perform location checks and verify a user's location with just a few lines of code. Choose your implementation pattern depending on your use cases: * Less regulated gaming implementations, non-US gaming implementations, and non-gaming implementations should generally choose [Manual location checks](#manual-location-checks) and, on web, the no-download solution. * US sportsbook and iGaming implementations should generally choose [Automatic location checks with caching](#automatic-location-checks-with-caching) and, on web, the companion app solution. ### Manual location checks You can call `Radar.trackVerified()` to manually perform a location check. `Radar.trackVerified()` returns a `RadarVerifiedLocationToken` with: * `passed`: A boolean indicating whether the user passed all fraud and jurisdiction checks (`user.fraud.passed && user.country.passed && user.state.passed`). * `token`: A tamper-proof JSON Web Token (JWT) that you can send to your server to validate the signature, signed with the *JSON Web Token (JWT) Secret Key* found under *Fraud* on the [Settings page](https://dashboard.radar.com/settings#fraud-settings). * `failureReasons`: If `passed == false`, an array of more detailed [failure reasons](#failure-reasons). * `expiresAt`: The datetime when the token expires, by default in 20 minutes, but earlier when close to the border based on compliance requirements. * `expiresIn`: The number of seconds until the token expires. * `user`: The user, with detailed information in `user.fraud`, `user.country`, and `user.state`. * `events`: The events generated, if any. You can optionally pass a `reason` to `Radar.trackVerified()` to specify the reason for performing the location check (e.g., `"login"`, `"signup"`, `"withdrawal"`). Location check reasons are exposed in filters, reports, and rules. ```swift Swift (iOS) theme={null} Radar.trackVerified { (status, token) in if token?.passed == true { // allow access, send token to server } else { // deny access, show error message } } ``` ```kotlin Kotlin theme={null} Radar.trackVerified { status, token -> if (token?.passed == true) { // allow access, send token to server } else { // deny access, show error message } } ``` ```javascript Web theme={null} const skipVerifyApp = false; // use true for no-download solution Radar.trackVerified({ skipVerifyApp }).then((result) => { const { passed, token, expiresIn, user } = result; if (passed) { // allow access, send token to server } else { // deny access, show error message } }).catch((err) => { // deny access, show error message }); ``` ```javascript React Native theme={null} Radar.trackVerified().then((result) => { const { token } = result; if (token?.passed) { // allow access, send token to server } else { // deny access, show error message } }).catch((err) => { // deny access, show error message }); ``` ```javascript Capacitor theme={null} Radar.trackVerified().then((result) => { const { token } = result; if (token?.passed) { // allow access, send token to server } else { // deny access, show error message } }).catch((err) => { // deny access, show error message }); ``` ```javascript Flutter theme={null} var res = await Radar.trackVerified(); ``` ```swift Swift (Mac) theme={null} import RadarVerifySDK // request location permissions and warm up location services RadarVerify.setup() // perform a location check let result = await RadarVerify.trackVerified( publishableKey: publishableKey, userId: userId, expectedCountryCode: expectedCountryCode, expectedStateCode: expectedStateCode, product: product, reason: reason, transactionId: transactionId, metadata: metadata ) if result.token?.passed == true { // allow access, send token to server } else { // deny access, show error message } ``` ```csharp C# (Windows) theme={null} using RadarVerify; // request location permissions and warm up location services await Radar.Setup(); // perform a location check var (status, token) = await Radar.TrackVerified( publishableKey: publishableKey, userId: userId, expectedCountryCode: expectedCountryCode, expectedStateCode: expectedStateCode, product: product, reason: reason, transactionId: transactionId, metadata: metadata ); if (token?.Passed == true) { // allow access, send token to server } else { // deny access, show error message } ``` You can send the JWT to your server and validate the signature. For example, in JavaScript: ```javascript theme={null} import { jwtVerify } from 'jose'; try { const { payload } = await jwtVerify(token, SECRET_KEY); const { user } = payload; // token is valid, check payload to allow or deny access } catch (err) { // token is invalid, deny access, show error message } ``` #### Ranging beacons On iOS and Android, you can pass `beacons: true` to `Radar.trackVerified()` to range nearby [beacons](/geofencing/beacons) and include them in the location check. By default, each call waits up to 5 seconds to range beacons. The wait ends early only if every nearby beacon is found. If you need beacon ranging often, call `Radar.startRangingBeacons()` before the location check. The SDK then ranges nearby beacons continuously while the app is in the foreground and searches for nearby beacons again every 60 seconds. `Radar.trackVerified(beacons: true)` uses the beacons seen in the last 5 seconds instead of starting a new ranging window. Call `Radar.startRangingBeacons()` after initializing the SDK and after the user grants location permissions (and, on Android, Bluetooth permissions). To limit battery use, call it when the user enters the flow that calls `Radar.trackVerified(beacons: true)`, and call `Radar.stopRangingBeacons()` when they leave it. Ranging pauses automatically when the app goes to the background and resumes when it returns to the foreground. ```swift Swift theme={null} // when the user enters the flow Radar.startRangingBeacons() // perform a location check with nearby beacons Radar.trackVerified(beacons: true) { (status, token) in if token?.passed == true { // allow access, send token to server } else { // deny access, show error message } } // when the user leaves the flow Radar.stopRangingBeacons() ``` ```kotlin Kotlin theme={null} // when the user enters the flow Radar.startRangingBeacons() // perform a location check with nearby beacons Radar.trackVerified(beacons = true) { status, token -> if (token?.passed == true) { // allow access, send token to server } else { // deny access, show error message } } // when the user leaves the flow Radar.stopRangingBeacons() ``` > [!NOTE] > > `Radar.startRangingBeacons()` and `Radar.stopRangingBeacons()` require iOS SDK `3.43.0`+ or Android SDK `3.38.0`+. Android requires Android 8.0 (API level 26) or later. ### Automatic location checks with caching You can call `Radar.startTrackingVerified()` to automatically perform location checks on connection changes, on the specified `interval`, or more frequently if `token.expiresIn < interval` (based on current state, distance to border, and so on). Instead of calling `Radar.trackVerified()`, which always fetches a fresh location token, you can call `Radar.getVerifiedLocationToken()`, which returns a cached location token immediately if the last location token is still valid, or fetches a fresh location token if not. If you set a delegate on iOS with `Radar.setVerifiedDelegate()` or a receiver on Android with `Radar.setVerifiedReceiver()`, fresh location tokens are also delivered to `RadarVerifiedDelegate.didUpdateToken()` and `RadarVerifiedReceiver.onTokenUpdated()`, respectively. For example, to automatically verify the user's location at least every 20 minutes (1200 seconds), without ranging beacons: ```swift Swift theme={null} Radar.setVerifiedDelegate(delegate) Radar.startTrackingVerified(interval: 1200, beacons: false) // get a cached token if available, or fetch a fresh token if not Radar.getVerifiedLocationToken { (status, token) in if token?.passed == true { // allow access, send token to server } else { // deny access, show error message } } // delivers fresh tokens to RadarVerifiedDelegate func didUpdateToken(_ token: RadarVerifiedLocationToken) { // send token to server } ``` ```kotlin Kotlin theme={null} Radar.setVerifiedReceiver(receiver) Radar.startTrackingVerified(interval = 1200, beacons = false) // get a cached token if available, or fetch a fresh token if not Radar.getVerifiedLocationToken { status, token -> if (token?.passed == true) { // allow access, send token to server } else { // deny access, show error message } } // delivers fresh tokens to RadarVerifiedReceiver override fun onTokenUpdated(context: Context, token: RadarVerifiedLocationToken) { // send token to server } ``` ```javascript Web theme={null} const skipVerifyApp = false; // use true for no-download solution Radar.startTrackingVerified({ skipVerifyApp, interval: 1200 }); // get a cached token if available, or fetch a fresh token if not Radar.getVerifiedLocationToken({ skipVerifyApp }).then((result) => { const { passed, token, expiresIn, user } = result; if (passed) { // allow access, send token to server } else { // deny access, show error message } }).catch((err) => { // deny access, show error message }); Radar.onTokenUpdated((result) => { const { passed, token, expiresIn, user } = result; // send token to server }); ``` ```javascript React Native theme={null} Radar.startTrackingVerified({ interval: 1200, beacons: false, }); // get a cached token if available, or fetch a fresh token if not Radar.getVerifiedLocationToken().then((result) => { const { token } = result; if (token?.passed) { // allow access, send token to server } else { // deny access, show error message } }).catch((err) => { // deny access, show error message }); // delivers fresh tokens to listener Radar.onTokenUpdated((result) => { const { token } = result; // send token to server }); ``` ```javascript Capacitor theme={null} Radar.startTrackingVerified({ interval: 1200, beacons: false, }); // get a cached token if available, or fetch a fresh token if not Radar.getVerifiedLocationToken().then((result) => { const { token } = result; if (token?.passed) { // allow access, send token to server } else { // deny access, show error message } }).catch((err) => { // deny access, show error message }); // delivers fresh tokens to listener Radar.addListener('token', (result) => { const { token } = result; // send token to server }); ``` ```javascript Flutter theme={null} Radar.startTrackingVerified(1200, false) // get a cached token if available, or fetch a fresh token if not var res = await Radar.getVerifiedLocationToken(); // delivers fresh tokens to listener Radar.onToken(onToken); ``` ### Setting product type You can configure multiple product types within a project, each with its own [allowed states and countries](#allowed-states-and-countries) and other settings. Call `Radar.setProduct(product)` to pass the product type before performing a location check. > [!NOTE] > > Contact your customer success manager for help configuring product types and allowed jurisdictions. ### Setting expected jurisdiction In addition to setting [allowed states and countries](#allowed-states-and-countries), you can optionally set an expected jurisdiction and fail location checks outside of that jurisdiction regardless of whether that jurisdiction is allowed in settings. Call `Radar.setExpectedJurisdiction(expectedCountryCode, expectedStateCode)` to set the expected jurisdiction before performing a location check. ### Setting expected address > [!NOTE] > > Contact your customer success manager to enable address verification on your project. You can optionally set an expected address, such as the user's billing or home address, and check whether the user is at that address. Call `Radar.setExpectedAddress(address)` to set the expected address before performing a location check. Radar sends the address with each subsequent location check until you call `Radar.setExpectedAddress(nil)` (`null` on Android). Setting an expected address is supported on [iOS SDK](/sdk/ios) version `3.42.0` or higher and [Android SDK](/sdk/android) version `3.38.0` or higher. ```swift Swift theme={null} Radar.setExpectedAddress("841 Broadway, New York, NY 10003") Radar.trackVerified { (status, token) in if let expectedAddress = token?.user?.expectedAddress { // check expectedAddress.atAddress, check expectedAddress.confidence } } ``` ```kotlin Kotlin theme={null} Radar.setExpectedAddress("841 Broadway, New York, NY 10003") Radar.trackVerified { status, token -> val expectedAddress = token?.user?.setExpectedAddress if (expectedAddress != null) { // check expectedAddress.atAddress, check expectedAddress.confidence } } ``` Radar geocodes the address and compares it to the user's location. The result is returned in `user.expectedAddress`: * `expectedAddress`: The expected address, as passed to `Radar.setExpectedAddress()`. * `formattedAddress`: The formatted address, as geocoded by Radar. May be `nil` if the address could not be geocoded. * `latitude`: The latitude of the geocoded address. May be `nil` if the address could not be geocoded. * `longitude`: The longitude of the geocoded address. May be `nil` if the address could not be geocoded. * `atAddress`: A boolean indicating whether the user is within the distance threshold of the geocoded address. The threshold is 60 meters by default. * `distance`: The distance in meters between the user's location and the geocoded address. May be `nil` if the address could not be geocoded. * `confidence`: The confidence of `atAddress`, one of `high`, `medium`, `low`, or `unknown`. Confidence accounts for the accuracy of the user's location and the uncertainty of the geocoded address. `high` means the result holds even at the edge of that uncertainty, `low` means the uncertainty is more than twice the distance threshold, and `unknown` means the address could not be geocoded or the location accuracy was not available. If the user is not at the expected address, the location check includes an `address_not_expected` warning. Unlike [failure reasons](#failure-reasons), this warning does not cause the location check to fail, so `passed` is unaffected. Use `user.expectedAddress.atAddress` and `user.expectedAddress.confidence` to decide how to handle the result in your app. > [!NOTE] > > Contact your customer success manager to change the distance threshold. ### Auth tokens > [!NOTE] > > Contact your customer success manager to access temporary auth tokens and/or disable publishable API keys on your project. As an alternative to publishable API keys, you can create temporary auth tokens. Auth tokens are JSON Web Tokens (JWTs) created by you on your server, signed with a private key, and sent by you to your client to be used instead of publishable API keys. They have a `ttl` and optional `constraints` (e.g., `product`, `expectedCountryCode`, `expectedStateCode`) as claims. Auth tokens are supported on [iOS SDK](/sdk/ios) version `3.28.0` or higher, [Android SDK](/sdk/android) version `3.27.0` or higher, and web SDK version `5.1.0` or higher. First, create an EC P-256 key pair. Save your private key. Your private key should never leave your server. Copy your public key. For example: ```bash theme={null} openssl ecparam -genkey -name prime256v1 -noout -out private-key.pem openssl ec -in private-key.pem -pubout -out public-key.pem cat public-key.pem | pbcopy ``` Under *Auth tokens* on the [Settings page](https://dashboard.radar.com/settings), add a new public key. Paste the full contents of your public key PEM file, including the `BEGIN` and `END` lines. To create an auth token, sign a JWT using ES256 on your server. The payload should include `now` for `iat`, `now + ttl` for `exp`, the public key *Key ID* from the dashboard for `kid`, and any optional `constraints` as claims. For example: ```javascript theme={null} import { SignJWT } from 'jose'; const payload = { constraints: { // optional expectedCountryCode, expectedStateCode, product, }, }; const authToken = await new SignJWT(payload) .setProtectedHeader({ alg: 'ES256', typ: 'JWT', kid: PUBLIC_KEY_ID, }) .setIssuedAt(now) .setExpirationTime(now + ttl) .sign(PRIVATE_KEY); ``` Send the auth token to your client and use it to initialize the SDK instead of your publishable API key. ```swift Swift theme={null} Radar.initialize(authToken: authToken) ``` ```kotlin Kotlin theme={null} Radar.initialize(RadarInitializeOptions(authToken = authToken, fraud = true)) ``` ```javascript Web theme={null} Radar.initialize({ authToken }); ``` ```javascript React Native theme={null} Radar.initializeWithAuthToken(authToken, true); ``` If the auth token is invalid or the signature is invalid, `Radar.trackVerified()` will return `ERROR_UNAUTHORIZED`. If any of the claims don't match, `Radar.trackVerified()` will return `ERROR_FORBIDDEN`. ### Failure reasons > [!NOTE] > > Some more sensitive or proprietary failure reasons are not documented here. Contact your customer success manager for more information. If `passed == false`, responses include an array of more detailed [failure reasons](#failure-reasons). * **`country_not_allowed`**: The user's location is in a country that is not allowed based on [jurisdiction settings](#allowed-states-and-countries). * **`country_not_expected`**: The user's location is in a country that is not expected based on `Radar.setExpectedJurisdiction()`. * **`country_in_buffer_zone`**: The user's location is too close to [the border of a country](#allowed-states-and-countries), either based on a jurisdiction-specific threshold or based on the location accuracy reported by the device (i.e., a "radius of uncertainty" that overlaps a country border). * **`country_in_exclusion_zone`**: The user's location is in a [country-specific exclusion zone](#allowed-states-and-countries), if enabled. * **`state_not_allowed`**: The user's location is in a state or province that is not allowed according to [jurisdiction settings](#allowed-states-and-countries) * **`state_not_expected`**: The user's location is in a state or province that is not expected according to `Radar.setExpectedJurisdiction()`. * **`state_in_buffer_zone`**: The user's location is too close to [the border of a state or province](#allowed-states-and-countries), either based on a jurisdiction-specific threshold or based on the location accuracy reported by the device (i.e., a "radius of uncertainty" that overlaps a state or province border). * **`state_in_exclusion_zone`**: The user's location is in a [state- or province-specific exclusion zone](#allowed-states-and-countries), if enabled. * **`fraud_blocked_user_id`**: The `userId` of the user is blocked (all platforms). * **`fraud_blocked_device_id`**: The `deviceId` of the user is blocked (all platforms). * **`fraud_blocked_ip`**: The IP of the user is blocked (all platforms). * **`fraud_blocked_mac_address`**: The MAC address of the user is blocked (macOS and Windows only). * **`fraud_blocked_risk_score_auto_block`**: The user or device was automatically blocked based on a [high risk score](#fraud-flags) (all platforms). * **`fraud_compromised_jailbroken`**: The user's iOS device is jailbroken (iOS only). * **`fraud_compromised_app_attest`**: The user's iOS device failed [App Attest](#app-attest) checks (iOS only). * **`fraud_compromised_play_integrity_api`**: The user's Android device failed [Play Integrity API](#play-integrity-api) basic integrity checks (Android only). * **`fraud_mocked_from_mock_provider`**: The user's location is mocked or spoofed according to iOS, Android, macOS, or Windows location services (all platforms). * **`fraud_mocked_known_spoofing_app`**: The user's device is running a known location spoofing app (macOS and Windows only). * **`fraud_mocked_inconsistent_ip_country`**: The user's location is in a country inconsistent with the IP geolocation country (all platforms). * **`fraud_jumped_single_device`**: The user's location moved too far too fast (e.g., "jumped" across the country in a few seconds), possibly indicating impossible travel (all platforms). * **`fraud_jumped_multiple_devices`**: The device's location is inconsistent with another device's location with the same `userId`, possibly indicating account sharing (all platforms). * **`fraud_inaccurate_exceeded_accuracy_threshold`**: The user's location accuracy reported by the device is too low and exceeds a specified threshold (all platforms). * **`fraud_sharing_known_screen_sharing_app`**: The user's device is running a known screen sharing or remote desktop app (macOS and Windows only). * **`fraud_sharing_multiple_displays`**: The user's Android device has multiple displays, indicating possible screen sharing (Android only). * **`fraud_sharing_virtual_input_device`**: The user's Android device has a virtual input device, indicating possible screen sharing (Android only). * **`fraud_proxy_known_proxy_ip`**: The user's IP address is a known proxy or VPN (all platforms). * **`fraud_proxy_network_configuration`**: The user's network configuration indicates the use of a proxy or VPN (macOS and Windows only). ### Troubleshooting To troubleshoot a failed geolocation check, go to the [Locations page](https://dashboard.radar.com/geofencing/locations). Use the *Filters* button to filter down to specific user IDs, IP addresses, or jurisdictions, and use the *date filters* to filter down to specific dates or times. Click on a specific geolocation check to see all the details, including a map view, [failure reasons](#failure-reasons), detailed user, device, IP, and jurisdiction information, and more. > [!NOTE] > > If you need help, please contact your customer success manager. ## Revealing device and network risk > [!NOTE] > > Contact your customer success manager for access. If using `@radarlabs/plugin-fraud` version `1.4.0` or higher, iOS SDK version `3.38.0` or higher, Android SDK version `3.35.0` or higher, or React Native SDK version `4.36.0` or higher, you can call `Radar.revealRisk()` to reveal device and network risk signals before verifying a user's location. `Radar.revealRisk()` returns a `RadarRevealRiskToken` with: * `risk`: Risk information, including a risk `level` (none, low, medium, high, configurable with [Risk scores](#risk-scores)) and `reasons` (includes `proxy`, `compromised`, and `sharing` reasons from [Failure reasons](#failure-reasons)). * `network`: Network information, including IP address, IP geolocation, privacy information, and ASN information. * `device`: Device and browser information. * `token`: A tamper-proof JSON Web Token (JWT) that you can send to your server to validate the signature, signed with the *JSON Web Token (JWT) Secret Key* found under *Fraud* on the [Settings page](https://dashboard.radar.com/settings#fraud-settings). * `expiresAt`: The datetime when the token expires. * `expiresIn`: The number of seconds until the token expires. ```swift Swift (iOS) theme={null} Radar.revealRisk { (status, token) in if status == .success { if token?.risk?.level == 'high' { // high risk, step up to location verification } else { // low risk } } else { // handle error } } ``` ```kotlin Kotlin theme={null} Radar.revealRisk { status, token -> if (status == SUCCESS) { if (token?.risk?.level == HIGH) { // high risk, step up to location verification } else { // low risk } } else { // handle error } } ``` ```javascript Web theme={null} Radar.fraud.revealRisk().then((result) => { const { risk } = result; if (risk.level === 'high') { // high risk, step up to location verification } else { // low risk } }).catch((err) => { // handle error }); ``` ```javascript React Native theme={null} Radar.revealRisk().then((result) => { const { token } = result; if (token?.risk.level === 'high') { // high risk, step up to location verification } else { // low risk } }).catch((err) => { // handle error }); ``` ## Risk scores You can use risk scores to identify high-risk users and devices. By default, risk score weights are based on a "strikes" system: * No strikes = none * 1 strike = low * 2 strikes = medium * 3 strikes = high Users and devices receive strikes for the following risk signals within a lookback period, by default the last 7 days: * `mocked`, `jumped`, `compromised`, `sharing`, and `proxy` flags: 1 strike * More than 5 user IDs per device ID: 1 strike * More than 5 device IDs per user ID: 1 strike When the risk score changes for a user or device, it also changes for all associated users and devices (i.e., all users associated with that device ID, or all device IDs associated with that user). Risk score weights and the lookback period are configurable. You can also automatically block high-risk users. > [!NOTE] > > Contact your customer success manager or fraud operations manager for access to risk scores, or to automatically block high-risk users. ## Error handling On errors or failed fraud checks, you may want to display a message to the end user. For example: * On **`ERROR_PERMISSIONS`**: Unable to determine your location. Please make sure you've granted location permissions and try again. * On **`ERROR_LOCATION`**: Unable to determine your location. Please make sure location services and wi-fi are enabled and try again. * On **`ERROR_NETWORK`**: Unable to determine your location. Please make sure you're connected to the Internet and try again. * On **`country.allowed == false`** or **`state.allowed == false`**: Unable to verify your location. Please make sure you're in an allowed area and try again. * On **`fraud.proxy == true`**: Unable to verify your location. Please disconnect from any VPNs or proxy servers you may be using and try again. * On other error cases, or as a fallback: Unable to verify your location. Please contact support. # Geofences Source: https://docs.radar.com/geofencing/geofences Create and monitor custom geofences in Radar, including polygon, isochrone, and temporary geofences, with stop detection and geofence sync. Geofences represent custom regions or places monitored in your project. Depending on your use case, a geofence might represent a retail store, a neighborhood, and so on. Radar geofencing is more powerful than native iOS or Android geofencing, with cross-platform support for unlimited geofences, polygon geofences, [isochrone](https://en.wikipedia.org/wiki/Isochrone_map) (time-based) geofences, temporary geofences, and stop detection. ![Geofences illustration](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/illustrations/geofence-illustration.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=e5674b3a12f94d7a6912b75ea21a8f65) Geofences provides the following user context: ```json theme={null} { "geofences": [ { "tag": "store", "externalId": "123", "description": "Store #123", "metadata": { "parking": false } } ] } ``` Geofences also provides the following events: * `user.entered_geofence` * `user.exited_geofence` * `user.dwelled_in_geofence` You can receive events client-side via the [SDK](/sdk/sdk) or server-side via [event integrations](/integrations/integrations), including webhooks. You can [create geofences](#create-geofences) via the dashboard, CSV import, the API, nightly sync, or integrations. Alternatively, if you don't have your own custom place data, Radar can detect when a user visits a place even if you haven't set up a geofence for that place. Learn more about [Places](/geofencing/places). ## Quickstart First, [sign up](https://radar.com/signup) for Radar and get an API key. Then, [create geofences](#create-geofences). From there, [integrate the SDK](/sdk/sdk) and call `Radar.trackOnce()` or `Radar.startTracking()`, depending on your use case. Radar will generate an entry event on the first location update inside of a geofence. ## How it works Geofencing works in the foreground and in the background. All 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, [isochrone](https://en.wikipedia.org/wiki/Isochrone_map) (time-based) geofences, temporary geofences, and stop detection. Radar generates a geofence entry event if a user enters a geofence (if [stop detection](#stop-detection) is off) or stops in a geofence (if [stop detection](#stop-detection) is on) with sufficient confidence, then a geofence exit event when the user leaves the geofence with sufficient confidence. A device must exit a geofence before a subsequent entry into that same geofence. ## Create geofences You can create geofences via the dashboard, CSV import, the API, nightly sync, or integrations. You can create geofences in the *Test* environment for development and testing, and in the *Live* environment for production. You specify the metadata for geofences when you create them, including the *tag* (a group for the geofence, e.g., `store`), *external ID* (an external ID for the geofence that maps to your internal database, e.g., `123`), and *description* (a display name for the geofence, e.g., `Store #123`). **Geofences should be uniquely referenced by tag and external ID, assigned by you when a geofence is created. To disable or update metadata for a geofence, re-import the geofence with the same tag and external ID.** ### Dashboard To create a geofence via the dashboard, go to the [Geofences page](https://dashboard.radar.com/geofencing/geofences/new) and click the *Create* button. Optionally search for an address or place, then enter a description, tag, external ID, and optional metadata. Choose *circle* to create a circle geofence, *polygon* to create a polygon geofence, or *isochrone* to create an [isochrone](https://en.wikipedia.org/wiki/Isochrone_map) (time-based) geofence. Click *Create* to create the geofence. ### CSV import To create geofences via CSV import, go to the [Geofences page](https://dashboard.radar.com/geofencing/geofences) and click the *Import* button. Then, select a CSV to upload. Headers are required as the first row of the CSV. The CSV may have the following columns: * **`description`** (string, required): A description for the geofence. * **`type`** (string, required): The type of geofence geometry. `polygon`, `circle`, and `isochrone` are supported. * **`tag`** (string, required): A group for the geofence. * **`externalId`** (string, required): An external ID for the geofence that maps to your internal database. * **`coordinates`** (array, required if `address` and `placeId` are not included): An array or JSON string representing a center for type `circle` or a destination for type `isochrone` in the format `[longitude,latitude]`. A two-dimensional array or JSON string representing a closed ring of between 4 and 2,000 coordinates in the format `[[longitude0, latitude0],[longitude1,latitude1],[longitude2,latitude2],...,[longitude0,latitude0]]` for type `polygon`. **Note that longitude comes before latitude, a GeoJSON convention.** * **`address`** (string, required if `coordinates` and `placeId` are not included): An address to search for, and if found, will represent the center for type `circle` or `isochrone`. If `address` and `coordinates` are both provided, they must be nearby, and `coordinates` will take precedent. Ignored for type `polygon`. * **`radius`** (number, required for type `circle` and `isochrone`): The radius in meters for type `circle`, a number between `10` and `10000`. The travel duration in minutes for type `isochrone`. Ignored for type `polygon`. * **`mode`** (required for type `isochrone`): the [travel mode](/api#routing) for type `isochrone`. * **`enabled`** (boolean, optional): If `true`, the geofence will generate events. If `false`, the geofence will not generate events. Defaults to `true`. * **`metadata`** (dictionary, optional): An optional set of custom key-value pairs for the geofence. A dictionary or JSON string with up to 16 keys and values of type string, boolean, or number. **`Cannot be used with metadata.{key} columns.`** * **`metadata.{key}`** (string, optional): Instead of converting `metadata` to stringified JSON, use columns of this format to add a key-value pairs to `metadata`. For example, the column header `metadata.pickup-mode` with a value of `"drive-thru"` will resolve to `{ pickup-mode: "drive-thru" }`. Avoid using spaces and commas for keys. **`Cannot be used with the metadata column.`** * **`operatingHours`** (dictionary, optional): An optional set of key-value pairs restricting the [operating hours of the geofence](#operating-hours). Each key is a day of the week (e.g., `Sunday`) or the three letter abbreviation of the day (e.g., `Sun`), case insensitive. Each value is a list of pairs, where a pair indicates one opening and closing time for that day. For example, a restaurant only open for lunch and dinner on Sundays would be `{ Sunday: [["11:00", "14:00"], ["19:00", "22:00"]] }`. Accepted time formats include `h:mm aa` (e.g., `12:45 AM`) and `HH:mm` (e.g., `00:45`). If neither `operatingHours` nor `operatingHours.{day}` is provided, the geofence will always be open. **`Cannot be used with operatingHours.{day} columns.`** * **`operatingHours.{day}`** (string, optional): Instead of converting `operatingHours` to stringified JSON, use columns of this format to add a key-value pairs to `operatingHours`. For example, the column header `operatingHours.sunday` (or `operatingHours.sun`) with a value of `"[["11:00", "14:00"], ["19:00", "22:00"]]"` will resolve to `{ Sunday: [["11:00", "14:00"], ["19:00", "22:00"]] }`. If neither `operatingHours` nor `operatingHours.{day}` is provided, the geofence will always be open. **`Cannot be used with the operatingHours column.`** * **`stopDetection`** (boolean, optional): The [stop detection](#stop-detection) setting for the geofence. Overrides the project-level stop detection setting. * **`disableAfter`** (datetime, optional): Use to create temporary geofences. If set, the geofence will be disabled after the specified datetime. `disableAfter` operates independently of `operatingHours`. A date or valid ISO date string. * **`deleteAfter`** (datetime, optional): Use to create temporary geofences. If set, the geofence will be deleted after the specified datetime. A date or valid ISO date string. * **`userId`** (string, optional): An optional user restriction for the geofence. If set, the geofence will only generate events for the specified user. If not set, the geofence will generate events for all users. **Deprecated.** * **`userIds`** (string, optional): An optional user restriction for the geofence. A string of comma-separated user IDs. If set, the geofence will only generate events for the specified users. If not set, the geofence will generate events for all users. * **`ip`** (string, optional): An optional IP address restriction for the geofence. A string of comma-separated IP address ranges, each of which could be a single IP (`8.8.8.8`), wildcard notation (`8.8.8.*`), or CIDR notation (`8.8.8.8/24`). If set, the geofence will only generate events for requests from the specified IP address. If not set, the geofence will generate events for all requests. * **`dwellThreshold`** (number, optional): An optional field to trigger dwell events. If set and `user.dwelled_in_geofence` is enabled in settings, an event is triggered when a user dwells in the geofence longer than the threshold (in minutes). For example, a value of `10` would result in a dwell event on the next track call after a user has occupied a geofence for 10 minutes. * **`placeId`** (string, required if `coordinates` and `address` are not included): For [place matching](/geofencing/places#place-matching), an optional `_id` of the Radar [place](/geofencing/places) to match to the geofence. If a place was matched, the geometry of the place will override the geometry of the geofence. **If a geofence with the specified tag and external ID already exists, it will be updated. If not, it will be created.** For example, to import a circle geofence representing a store and a polygon geofence representing a neighborhood, you could use the following CSV: ```csv theme={null} description,tag,externalId,type,radius,mode,coordinates,address,enabled,metadata,stopDetection,disableAfter,deleteAfter,userIds,operatingHours "Store #123",store,123,circle,50,,"[-73.975363,40.783826]",,true,"{""parking"":false}",,,,, "SoHo",neighborhood,soho,polygon,,,"[[-73.996973,40.725660],[-73.998282,40.726294],[-74.001072,40.727660],[-74.002853,40.728603],[-74.003282,40.727936],[-74.003840,40.726310],[-74.004226,40.725351],[-74.004998,40.723530],[-74.005191,40.722993],[-74.005556,40.722115],[-74.004462,40.721334],[-74.001908,40.719496],[-73.999827,40.718016],[-73.997467,40.720863],[-73.997016,40.722212],[-73.996501,40.723497],[-73.995750,40.724278],[-73.995128,40.725107],[-73.996973,40.725660]]",,true,,,,,, "15 minutes driving to Disney World","car-15",disney,isochrone,15,car,"[-81.563874,28.385233]",,true,"{""type"":""resort""}",,,,, "Madison Square Garden from address",stadium,msg,circle,200,,,"4 Pennsylvania Plaza, New York, NY 10001",true,,,,,, "Disable in 2028 and delete in 2029",new-years,2027,circle,50,,"[-73.9877313,40.7579787]",,true,,,"2028-01-01T00:01:00-05:00","Jan 1, 2029",, "Delivery #123 for user #456 and driver #321",delivery,123,circle,50,,"[-73.9934387,40.7505045]",,true,,,,,"456,321", "Restaurant #789 open for Sunday breakfast and dinner",restaurant,789,circle,50,,"[-73.9934387,40.7505045]",,true,,,,,,"{""Sun"":[[""09:00"",""14:00""], [""17:00"",""22:00""]]}" ``` **Again, note that longitude comes before latitude, a GeoJSON convention.** You can find a history of past imports on the [Geofences import history page](https://dashboard.radar.com/geofencing/geofences/imports). ### API You can also create geofences programmatically via the [API](/api#upsert-a-geofence). You can create a geofence via POST `/api/v1/geofences`, or upsert a geofence based on tag and external ID via PUT `/api/v1/geofences/:tag/:externalId`. For example, to upsert a geofence representing a store via the [API](/api#upsert-a-geofence): ```sh theme={null} curl https://api.radar.io/v1/geofences/store/123 \ -H "Authorization: prj_live_sk_..." \ -X PUT \ -d "description=Store #123" \ -d "type=circle" \ -d "coordinates=[-73.975363,40.783826]" \ -d "radius=100" ``` **Again, note that longitude comes before latitude, a GeoJSON convention.** ### Geofence sync Finally, you can sync geofences nightly from a CSV. On the Radar [Integrations page](https://dashboard.radar.com/integrations) under *Geofence Sync*, set *Enabled* to *Yes*. Enter a *Notification Email* to receive success and failure confirmation emails. Then, choose a *Protocol*: * Choose *HTTP* for geofence CSVs at public HTTP or HTTPS URLs. Enter the URLs of the geofence CSVs. * Or, choose *AWS S3* for geofence CSVs in a private S3 bucket. Enter an S3 bucket region, S3 bucket name, and the S3 object keys of the geofence CSVs. Finally, enter the AWS access key ID and secret access key of an IAM user with `GetObject` permissions for the specified S3 bucket and objects. Note that you can set separate CSVs for the *Test* and *Live* environments. The geofence sync CSV format is the same as the [geofence import CSV format](#csv-import). When you click *Save and Sync*, Radar will attempt a one-time sync and send an email on success or failure. Radar will then attempt syncs nightly. ## Confidence and accuracy All geofence events have confidence levels. Confidence levels range from `1` (low) to `3` (high). Confidence is a function of the accuracy of the location reported by the device and the geometry of the geofence. Confidence will be high when the user, taking into account the accuracy of the location reported by the device, is completely inside the geofence. Confidence will be medium when the user is mostly inside the geofence. Confidence will be low when the user is only partially inside the geofence. ![](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/f2vbu16fzuly/cszDUh5NBGi6lBpslnH67/cc29547e9e38cee37d325814a6f4f589/confidence.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=3a5cc23311a6df2a43dcdc71e5bb32da) The smaller the geofence and the less accurate the location reported by the device, the lower the confidence level. As a result, you may decide to ignore some events based on confidence levels. ## Stop detection When *Geofence stop detection* is on, Radar can understand the difference between a user walking or driving through a geofence and stopping in a geofence, and will only generate a geofence entry event when a user stops in a geofence (i.e., when `stopped` is `true` based on [tracking options](/sdk/tracking) or when `foreground` is `true`). You can enable this setting at a project level on the [Settings page](https://dashboard.radar.com/settings#geofences-settings), or at a geofence level when you [create geofences](#create-geofences). ## Buffer entries and exits Use *Buffer entries* to more aggressively enter geofences and reduce the likelihood of missed entry events. When *Buffer Entries* is off, Radar will only generate an entry event if the location reported by the device is inside the geofence boundary. However, when *Buffer Entries* is on, Radar will generate an entry event if the device is within X meters of the geofence, where X is the accuracy reported by the device. For example, if the device reports a location accurate to within 50 meters, Radar will generate an entry event if the location is within 50 meters of the geofence boundary. Use *Buffer exits* to more conservatively exit geofences and reduce the jumpiness of exit events. When *Buffer Exits* is off, Radar will generate an exit event if the location reported by the device is outside the geofence boundary. However, when *Buffer Exits* is on, Radar will only generate an exit event if the device is more than X meters outside of the geofence, where X is the accuracy reported by the device. For example, if the device reports a location accurate to within 50 meters, Radar will only generate an entry event if the location is more than 50 meters outside of the geofence boundary. You can enable these settings at a project level on the [Settings page](https://dashboard.radar.com/settings#geofences-settings). ## Operating hours When *Operating Hours* are set on a geofence, Radar will indicate whether a user entered, exited, or dwelled in the geofence during its operating hours. Radar will add a boolean flag `currentlyOperating` to all geofence event payloads. Radar can also restrict geofence events from being generated outside of operating hours. Restrict event generation to only operating hours at the project level on the [Settings page](https://dashboard.radar.com/settings#geofences-settings). Operating hours can be set on individual geofences via [CSV import](#csv-import), the [API](/api#upsert-a-geofence), or in the *Advanced* section of the geofence create and edit pages. ![](https://mintcdn.com/radarlabs/f_3pYOJsnyPEyNca/images/f2vbu16fzuly/2NBWd8m5bdREs2U0YEwlOI/658e8683aab80223b0ab50a055dc4136/operating-hours.png?fit=max\&auto=format\&n=f_3pYOJsnyPEyNca\&q=85\&s=9b2e00ce6cfa57d6142586b8ad663fd7) ## Dwell events If `user.dwelled_in_geofence` is enabled, Radar can trigger dwell events after a device remains inside of a geofence boundary for more than a specific threshold. Radar will generate a dwell event after the first location reported by the device beyond the specified threshold. You can enable this event at the project level on the [Settings page](https://dashboard.radar.com/settings#geofences-settings). # Overview Source: https://docs.radar.com/geofencing/overview Overview of Radar's Geofencing Platform: geofencing, place visit detection, trip tracking, fraud detection, and location analytics. Radar's Geofencing Platform is the industry-leading geofencing and location tracking platform, including geofencing, place visit detection, trip tracking, fraud detection, and analytics. Together with our [Maps Platform](/maps/overview), Radar provides full-stack location infrastructure for any product or service. We power location-based experiences for [enterprises and startups](https://radar.com/customers) across hundreds of millions of devices worldwide. ## Features > [card] [Geofences](/geofencing/geofences) > > Industry-leading accuracy with unlimited geofences, polygon geofences, and more > [card] [Trips](/geofencing/trips) > > Trip tracking, live ETAs, arrival detection, and routing for pickups and deliveries > [card] [Places](/geofencing/places) > > Points-of-interest (POI) dataset to detect visits to millions of places > [card] [Regions](/geofencing/regions) > > Admin boundary dataset for country, state, and postal code detection > [card] [User insights](/geofencing/user-insights) > > Infer home, work, travel, and commute context from location history > [card] [Beacons](/geofencing/beacons) > > Hardware-enabled micro-geofences accurately detect locations down to a meter or less > [card] [Fraud](/geofencing/fraud) > > Detect GPS spoofing, proxy and VPN usage, and device tampering > [card] [Integrations](/integrations/integrations) > > Send Radar events and user context to other systems server-to-server # Places Source: https://docs.radar.com/geofencing/places Detect when users visit places, chains, or categories using Radar's points-of-interest database, without setting up geofences. > [!NOTE] > > Places is available on the [Enterprise plan](https://radar.com/pricing). With Places, you can use our points-of-interest (POI) database to detect when a user visits a place, chain, or category, even if you haven't set up geofences for those places. Our database includes millions of places around the world from open and commercial datasets, with coverage for major chains (like McDonald's or Walmart) and categories (like airports or stadiums), often with accurate polygon geometry and additional metadata like address or operating hours. ![Places illustration](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/illustrations/places-illustration.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=01c4e50ed6df05c727fe4485619c9c95) Places provides the following user context: ```json theme={null} { "place": { "name": "Starbucks", "chain": { "name": "Starbucks", "slug": "starbucks", "externalId": "123", "metadata": { "customFlag": true } }, "categories": ["food-beverage", "coffee-shop"], "location": { "type": "Point", "coordinates": [-73.977797, 40.783826] } } } ``` Places also provides the following events: * `user.entered_place` * `user.exited_place` You can receive events client-side via the [SDK](/sdk) or server-side via [event integrations](/integrations/integrations), including webhooks. You can enable Places on the [Settings page](https://dashboard.radar.com/settings). Alternatively, if you have your own custom place data, you can create geofences instead. Learn more about [Geofences](/geofencing/geofences). ## Quickstart First, [sign up](https://radar.com/signup) for Radar and get an API key. Then, enable Places events and enable chains or categories on the [Settings page](https://dashboard.radar.com/settings). From there, [integrate the SDK](/sdk) and call `Radar.trackOnce()` or `Radar.startTracking()`, depending on your use case. Radar will generate an entry event on the first stopped location update at a place matching your enabled chains or categories. ## How it works Radar generates a place entry event if a user stops at a place (i.e., when `stopped` is `true` based on [tracking options](/sdk/tracking) or when `foreground` is `true`) matching [filters](#place-filters) with sufficient confidence, then a place exit event when the user leaves the place with sufficient confidence. All place events have [confidence levels](#confidence), and places may have one or more [categories](#categories) and a [chain](#chains). ## Confidence All place events have confidence levels. Confidence levels range from `1` (low) to `3` (high). Confidence is a function of the accuracy of the location reported by the device, the footprint of the place, the density of the area, the popularity of the place, and other signals. You may decide to ignore events based on confidence levels. ## Categories Places may have one or more categories. Radar supports hundreds of categories, organized in a hierarchy. View the [full list of categories](/places/categories). You can listen for place events with specific categories. For example, to do something if a user is at an airport, on [iOS](/sdk#ios): ```java theme={null} Radar.trackOnce { (status, location, events, user) in if let place = user?.place, place.hasCategory("airport") { // do something } } ``` ## Chains Places may have a chain. Radar supports thousands of U.S. and international chains. View the [full list of chains](/places/chains). You can listen for place events with specific chains. For example, to do something when a user stops at a Starbucks, on [Android](/sdk#android): ```java theme={null} public void onEventsReceived(Context context, RadarEvent[] events, RadarUser user) { for (RadarEvent event : events) { if (event.type == RadarEventType.USER_ENTERED_PLACE && event.confidence == RadarEventConfidence.HIGH && event.place.isChain("starbucks")) { // do something } } } ``` ### Mappings To map Radar chain slugs to custom IDs, set *Chain mappings* under *Places* on the [Settings page](https://dashboard.radar.com/settings). You can set a JSON string representing a dictionary with keys and values of type string. For example, to map `burger-king` to `123` and `mcdonalds` to `456`: ```json theme={null} { "burger-king": "123", "mcdonalds": "456" } ``` Custom chain IDs will be exposed as `place.chain.externalId` in user context and events. These custom IDs can also be used in place of chain slugs when performing searches with the [search places API](/api#search-places). ### Metadata To map Radar chain slugs to custom metadata, set *Chain metadata* under *Places* on the [Settings page](https://dashboard.radar.com/settings). You can set a JSON string with values of type dictionary, each with between 1 and 16 keys and values of type string, boolean, or number. For example, to map `metadata.category` and `metadata.offers` for `burger-king` and `mcdonalds`: ```json theme={null} { "burger-king": { "category": "Restaurant", "offers": true }, "mcdonalds": { "category": "Restaurant", "offers": false } } ``` Custom chain metadata will be exposed as `place.chain.metadata` in user context and events. ## Place filters We recommend filtering events to specific categories or chains under *Places* on the [Settings page](https://dashboard.radar.com/settings). For example, to monitor only fast food restaurants, you might add `fast-food-restaurant` to category filters, or add `burger-king`, `mcdonalds`, and others to chain filters. View the [full list of categories](#categories) and the [full list of chains](#chains). ## State blocklist To suppress tracking specific place categories in certain states, set *Category state blocklist mapping* under *Places* on the [Settings page](https://dashboard.radar.com/settings). For example, blocking the `fast-food-restaurant` category in New York would bypass visits to `fast-food-restaurant` places in New York. [Regions](/geofencing/regions) must be enabled to expose this setting. ## Verify events You can accept or reject places events after user check-ins or other forms of verification. Event verifications will be used to improve the accuracy and confidence level of future events. For example, to accept an event on iOS: ```java theme={null} Radar.acceptEventId(event._id, verifiedPlaceId: event.alternatePlaces[0]._id) ``` ## Place matching > [!NOTE] > > Place matching is available on the [Enterprise plan](https://radar.com/pricing). Place matching is the easiest way to make sure your geofence coordinates and geometries are accurate and stay up-to-date over time. Place matching will ensure that entry and exit events are reliable, trip approaching and arrived signals are precise, and messaging for nearby locations is relevant. Navigate to the [Geofences page](https://dashboard.radar.com/geofencing/geofences) and select *Import*. If [Places](/geofencing/places) are enabled for your project, toggle *Enable place matching* on. ### How it works 1. **Import your geofences against Radar's places data.** Select [chains](#chains) to match your geofences against while importing your geofences into Radar. 2. **View the results of place matching.** After the import has completed, look at the results on the [Import history page](https://dashboard.radar.com/geofencing/geofences/imports). Click *View import* to see a summary and logs that indicate the outcome for each row. If the place match was successful, the import log will contain a link to the Radar place and the distance that the geofence center was corrected. 3. **Filter and export the results for further analysis.** Apply *Filters* to isolate rows that were not place matched, geofences that have large center correction values, or errors. Click *Export rows* to download a CSV of the results. ![Place Matching Gi](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/place-matching.gif?s=3dad550f55e8f5245a036263e5ab4017) ### Geofence types * `circle`: When a `circle` geofence is matched, it will take on the geometry of the Radar place. * `polygon`: When a `polygon` geofence is matched, it will be linked to the Radar place, but not adopt the place center or geometry. * `isochrone`: When an `isochrone` geofence is matched, it will only take on the center of the Radar place, regenerating the [isochrone](https://en.wikipedia.org/wiki/Isochrone_map) geometry from the new center. ### Advanced options * **Search radius.** Place matching will look for the nearest location within 10 kilometers by default. This value can be reduced to enforce a tighter search distance. * **Geofence tag(s).** Filter the rows to place match. For example, only perform place matching on rows where `tag = store` but not `tag = nearby`. * **Use Radar's place geometry.** By default, `circle` geofences will adopt both the center and geometry of the Radar place. Toggle this off for `circle` geofences to take on the center but not the geometry. # Regions Source: https://docs.radar.com/geofencing/regions Detect a user's country, state, DMA, or postal code using Radar's admin boundary database, and generate region entry and exit events. > [!NOTE] > > Regions is available on the [Enterprise plan](https://radar.com/pricing). With Regions, you can use our admin boundary database to detect a user's country, state, DMA (media market), or postal code. ![Regions illustration](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/illustrations/regions-illustration.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=d791139591e3cdfccb35dad5847d3146) Regions provides the following user context: ```json theme={null} { "country": { "code": "US", "name": "United States", "flag": "🇺🇸" }, "state": { "code": "MD", "name": "Maryland" }, "dma": { "code": "26", "name": "Baltimore" }, "postalCode": { "code": "21014" } } ``` Regions also provides the following events: * `user.entered_region_country` * `user.exited_region_country` * `user.entered_region_state` * `user.exited_region_state` * `user.entered_region_dma` * `user.exited_region_dma` * `user.entered_region_postal_code` * `user.exited_region_postal_code` ## Quickstart First, [sign up](https://radar.com/signup) for Radar and get an API key. Then, enable Regions events on the [Settings page](https://dashboard.radar.com/settings). From there, [integrate the SDK](/sdk) and call `Radar.trackOnce()` or `Radar.startTracking()`, depending on your use case. Radar will generate an entry event on the first location update in a region matching your enabled event types. ## Countries Regions supports country detection globally. Each country has a `name` and a unique 2-letter [ISO 3166](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes) `code`. View the [full list of countries](/regions/countries). ### Country allowlist or blocklist Regions can also be used to allowlist or blocklist location updates in specific countries for privacy or compliance reasons. Contact your customer success manager to enable this feature. ## States Regions supports state detection in the US and Canada only. Each state has a `name` and a 2-letter `code` unique to the residing `country`. View the [full list of states](/regions/states). ## DMAs Regions supports DMA (designated market area) detection in the US only. Each DMA has a `name` and a unique `code`. View the [full list of DMAs](/regions/dmas). Or, learn more about [DMAs](https://en.wikipedia.org/wiki/Media_market). ## Postal codes Regions supports postal (ZIP) code detection in the US only. Each postal code has a unique 5-letter `code`. ## Coarse home and traveling detection > [!NOTE] > > Contact your customer success manager for access to coarse home and traveling detection. Regions can automatically detect a user's home regions based on location updates in the last 30 days, and detect when a user is traveling outside of their home regions. Coarse home detection provides the following user context: ```json theme={null} { "homeRegions": { "country": { "code": "US", "name": "United States", "flag": "🇺🇸" }, "state": { "code": "MD", "name": "Maryland" }, "dma": { "code": "26", "name": "Baltimore" }, "postalCode": { "code": "21014" } } } ``` It also provides the following `traveling` state on events: ```json theme={null} { "traveling": { "country": true, "dma": true, "state": true, "postalCode": true, } } ``` # Testing Source: https://docs.radar.com/geofencing/testing Troubleshoot Radar location tracking and event generation, including devices missing from the dashboard and events that don't fire. Use this guide to troubleshoot issues with location tracking and event generation. ## Device is not showing up in the dashboard A device will show up in the Radar dashboard once a successful [track API](/api#track) call has been sent to the server. The Radar [SDK](/sdk/sdk) collects location updates and then sends them to the server via the track API. ### Common issues * Location permissions have not been granted. * The Radar SDK has not been properly initialized. * Radar tracking methods have not been implemented correctly. ### Troubleshooting steps 1. Verify location permissions have been granted. 2. Verify that initializing the SDK uses the correct publishable key and happens during application launch. This initialization should happen in the `onCreate()` method of the `Application` class on [Android](/sdk/android#initialize-sdk) and the `didFinishLaunchingWithOptions()` method of the `AppDelegate` on [iOS](/sdk/ios#initialize-sdk). 3. Call `Radar.trackOnce()` on application launch and log the status in the callback. Refer to the [iOS](/sdk/ios#foreground-tracking) and [Android](/sdk/android#foreground-tracking) implementations to understand the status values returned. 4. Call `Radar.setLogLevel()` with a value of `debug` and monitor for errors in the logs. Refer to the debug logging sections of [iOS](/sdk/ios#debug-logging) and [Android](/sdk/android#debug-logging) for more detail. **A successful Radar API request log looks like the following:** ```bash theme={null} 2022-11-08 11:33:01.784759-0500 RadarImplementation[6947:250060] 📍 Radar API response | method = POST; url = https://api.radar.io/v1/track; statusCode = 200; ``` Once a successful API call is made, there will be a corresponding user on the [Users page](https://dashboard.radar.com/geofencing/users) in the dashboard. **Verify that Radar is registering users on the Users page:** ![Users Page](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/geofencing/assets/images/dashboard_users_page-5bcc7ad96306f57e6ecdc60cd0cbeb7f.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=3d44123ada58bc1a8ba24605e6d4fdd4) ## Events are not firing when the app is backgrounded As the Radar SDK collects location updates and sends them to the server, it will generate events based on location context (e.g., the device moves into or out of a geofence or starts a trip). Generated events will appear on the [Events page](https://dashboard.radar.com/geofencing/events) in the dashboard if location updates are triggering events as expected. If the device's last location is in a geofence or a place, that information will be displayed on the details page for that user. ### Common issues * Background location permissions have not been granted. * Radar events are not enabled on the [Settings page](https://dashboard.radar.com/settings) in the dashboard. * Radar tracking methods have not been implemented correctly. * The test device has issues collecting location updates (e.g., location sensors are not working in the simulator). * Flawed testing based on the [tracking options](/sdk/tracking) applied (e.g., geofence stop detection is on, but the device is not dwelling long enough to detect a stop). ### Troubleshooting steps 1. Verify that initializing the SDK uses the correct publishable key and happens during application launch. This initialization should happen in the `onCreate()` method of the `Application` class on [Android](/sdk/android#initialize-sdk) and the `didFinishLaunchingWithOptions()` method of the `AppDelegate` on [iOS](/sdk/ios#initialize-sdk). On iOS, verify that the *Location updates* [background mode](/sdk/ios#background-modes) has been enabled if using the responsive or continuous presets. 2. Confirm that events are enabled for the context type you are testing on the [Settings page](https://dashboard.radar.com/settings). 3. Confirm that you are calling `Radar.startTracking()`. 4. Determine the behavior needed to trigger location updates based on the [tracking options](/sdk/tracking) in use and verify that they appear in the Radar dashboard. For example, if the device is stopped in responsive mode, move over 200 meters to trigger a location update. Location updates can be verified on the [Users page](https://dashboard.radar.com/geofencing/users) in the dashboard or on the [User Activity](/geofencing/testing#user-activity) page. 5. If location updates are still not appearing, call `Radar.setLogLevel()` with a value of `debug` and monitor for errors in the logs. Refer to the debug logging sections of [iOS](/sdk/ios#debug-logging) and [Android](/sdk/android#debug-logging) for more detail. **Verify that events are firing on the Events page:** ![Recent Events](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/geofencing/assets/images/dashboard_events_feed-e4207fa1e2b2540e78dadf74d3d57e92.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=58fe4e417830d6f4045d94cc332bb442) **Verify a device's current geofences on the User details page:** ![User Details](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/geofencing/assets/images/dashboard_user_geofences-4a932ba5b7fafd95227332923c64dcae.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=fbf548190b1c4007f16d30a5b4ff3077) **Note: a device needs to exit a geofence before generating a subsequent entry event, so ensure that the device has been detected outside of the geofence prior to testing another entry.** ## Event listeners are not delivering ### Common issues * Radar event listeners are not implemented correctly. * Radar events are not generating from location updates. ### Troubleshooting steps 1. Verify the `RadarDelegate` on [iOS](/sdk/ios#listening-for-events-with-a-delegate) and `RadarReceiver` on [Android](/sdk/android#listening-for-events-with-a-receiver) are implemented correctly. For cross-platform frameworks such as [React Native](/sdk/react-native#background-tracking) and [Capacitor](/sdk/capacitor#background-tracking), ensure that the listeners are set up outside of the view lifecycle. Verify that you are using the correct native SDK version via the [Users page](https://dashboard.radar.com/geofencing/users) in the dashboard. 2. Verify that expected events are firing when testing the listeners. 3. Understand the behavior of each of the listeners. The client location listener (`onClientLocationUpdated` on Android, `didUpdateClientLocation` on iOS) is triggered whenever the Radar SDK receives an update from the device. The location updated listener (`onLocationUpdated` on Android, `didUpdateLocation` on iOS) delivers location updates processed by Radar servers and will return refreshed user context. The Radar events listener (`didReceiveEvents` on Android and iOS) will only fire if events are triggered from location updates. 4. Implement the error listener methods (`onError` on Android, `didFail` on iOS) to determine if errors are firing. Review the error messages returned to diagnose the root cause. ## Troubleshooting other behavior ### Multiple Radar users have the same user ID or device ID Learn more about when Radar creates new user records [here](/faqs#what-is-a-unique-user-when-does-radar-create-a-new-user-record). ### Rate limit errors are occurring when tracking location Radar has device specific rate limits per second, hour and day for the [track API endpoint](/api#track), which sends location updates to Radar. To mitigate rate limits, adjust [tracking options](/sdk/tracking) to collect locations less frequently. If you hit the per hour or day limits while testing, reinstalling the application with the Radar SDK will reset the rate limits. ## Simulator The [simulator](https://dashboard.radar.com/geofencing/simulate) is the easiest way to generate location updates to test and visualize entry and exit events at will. Gone are the days of needing to drive around or download spoofing apps to try out location-enabled features. The simulator acts as a playground to experiment with our API without any code! ### How it works 1. **Click around the map to generate locations and events.** The activity feed is populated in real-time to mirror how our APIs would surface locations and events in your app. The data generated flows through to your enabled [integrations](https://dashboard.radar.com/integrations) in the corresponding environment. The locations and events generated abide by your project's [settings](https://dashboard.radar.com/settings) and will persist across the dashboard. To avoid any production side effects, use the test environment with the default user provided (`simulated-user-id`). 2. **Simulate a target user.** To simulate a given [user](/api#users), click into that specific user on the [users](https://dashboard.radar.com/geofencing/users) page and hit the "Simulate" button. You can also set custom user metadata, app-specific information that downstream systems can act upon, such as whether a user has been activated or membership in a target cohort. 3. **Simulate a trip.** There are 3 fields necessary to simulate a [trip](/geofencing/trips): `externalId`, `destinationGeofenceTag`, and `destinationGeofenceExternalId`. You can enter them manually or select a geofence on the map and click "Set as trip destination" to autofill these values. Then, click "Start Trip" to officially kick off and activate the trip! As you click around, you'll notice events such as `user.approaching_trip_destination` and `user.arrived_at_trip_destination`. ![Simulator How It Works Gi](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/simulator-how-it-works.gif?s=8be22d46a33775d3f3bf27c373d44a79) ## User Activity The User Activity page is the most straightforward way to debug a user's recent locations and events. Navigate to the [Users page](https://dashboard.radar.com/geofencing/users) and select *View* within the desired user row. Then, click *View Activity*. Filter the user's recent activity down to the minute to investigate why events did or did not fire, and understand [confidence levels](/geofencing/geofences#confidence-and-accuracy) for events in real-world scenarios. ### How it works 1. **See a unified view of locations, events, and geofences.** The User Activity map displays a user's recent locations and events alongside geofences to pin down exactly when entries and exits occurred. 2. **Focus on an individual location or event.** Hover over a row in the Activity Feed to center the map view around those coordinates and to display the accuracy bubble for that location or event. An Event's [confidence level](/geofencing/geofences#confidence-and-accuracy) is a function of the accuracy of the location and the geometry of the geofence. The smaller the geofence and the less accurate the location, the lower the confidence. 3. **Filter to a specific time period.** Move the bounds of the slider to isolate a range of time for investigation. The slider supports granularity down to the minute. ![User Activity How It Works Gi](https://mintcdn.com/radarlabs/PCH5QhbuqByAtU8d/images/user-activity-how-it-works.gif?s=254863df9ce08319814818beccdec0a1) ### Location sources * **`FOREGROUND_LOCATION`**: location update triggered by `Radar.trackOnce` * **`BACKGROUND_LOCATION`**: location updated triggered by `Radar.startTracking` * **`GEOFENCE_ENTER`**: location update triggered by a client-side geofence entry, either nearby geofences synced from the server or a "bubble" geofence around the device's current location * **`GEOFENCE_EXIT`**: location updated triggered by client-side geofence exit, either nearby geofences synced from the server or a "bubble" geofence around the device's current location * **`BEACON_ENTER`**: location update triggered by a client-side beacon entry * **`BEACON_EXIT`**: location update triggered by a client-side beacon exit * **`VISIT_ARRIVAL`** (iOS only): location update triggered by an arrival from the [iOS visit monitoring service](https://developer.apple.com/documentation/corelocation/clvisit) * **`VISIT_DEPARTURE`** (iOS only): location update triggered by a departure from the [iOS visit monitoring service](https://developer.apple.com/documentation/corelocation/clvisit) * **`MANUAL_LOCATION`**: location update triggered by `Radar.trackOnce` passing in a location not collected by the Radar SDK * **`MOCK_LOCATION`**: location update triggered by `Radar.mockTracking` # Trips Source: https://docs.radar.com/geofencing/trips Track pickup and delivery trips with Radar and calculate live ETAs from an origin to a destination, including multi-leg trips. With Trips, you can track trips and calculate live ETAs from an origin to a destination. Use Trips for use cases like pickup or delivery tracking. ![Trips illustration](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/illustrations/trips-illustration.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=f5c19cae48ee4ddc07282da4a89968d1) Trips provides the following user context: ```json theme={null} { "trip": { "_id": "5f3e50491c2b7d005c81f5d9", "live": true, "status": "started", "externalId": "299", "metadata": { "Customer Name": "Jacob Pena", "Car Model": "Green Honda Civic" }, "mode": "car", "destinationGeofenceTag": "store", "destinationGeofenceExternalId": "123", "destinationLocation": { "coordinates": [ -105.06119826017914, 39.7793665 ], "type": "Point" }, "eta": { "duration": 5.5, // minutes "distance": 1331 // meters }, "createdAt": "2020-08-20T10:27:55.830Z", "updatedAt": "2020-08-20T10:30:55.837Z", "endedAt": "2020-08-20T10:30:55.837Z" } } ``` For [multi-leg trips](#multi-leg-trips), the trip object includes `currentLegId` and `legs` fields. The top-level `destinationGeofenceTag`, `destinationGeofenceExternalId`, and `destinationLocation` fields are not present, as destinations are defined on each leg instead: ```json theme={null} { "trip": { "_id": "5f3e50491c2b7d005c81f5d9", "live": true, "status": "started", "externalId": "multi-stop-route-123", "metadata": { "Customer Name": "Jacob Pena", "Car Model": "Green Honda Civic" }, "mode": "car", "currentLegId": "6f4e60591d3c8e006d9206ea", "legs": [ { "_id": "6f4e60591d3c8e006d9206ea", "status": "started", "destinationGeofenceTag": "stop", "destinationGeofenceExternalId": "stop-1", "stopDuration": 5, "metadata": { "stopName": "Customer A", "orderId": "order-101" }, "eta": { "duration": 8.2, "distance": 3200 } }, { "_id": "705f71602e4d9f117ea307fb", "status": "pending", "destinationGeofenceTag": "stop", "destinationGeofenceExternalId": "stop-2", "stopDuration": 5, "metadata": { "stopName": "Customer B", "orderId": "order-102" }, "eta": { "duration": 15.7, "distance": 6100 } }, { "_id": "806082713f5ea0228fb4a80c", "status": "pending", "destinationGeofenceTag": "store", "destinationGeofenceExternalId": "store-1", "metadata": { "type": "return-to-base" }, "eta": { "duration": 22.3, "distance": 8900 } } ], "eta": { "duration": 22.3, "distance": 8900 }, "createdAt": "2020-08-20T10:27:55.830Z", "updatedAt": "2020-08-20T10:30:55.837Z" } } ``` Trips also provides the following events: * `user.started_trip` * `user.updated_trip` * `user.approaching_trip_destination` * `user.arrived_at_trip_destination` * `user.stopped_trip` ## Quickstart First, [sign up](https://radar.com/signup) for Radar and get an API key. Then, [create a destination geofence](/geofencing/geofences#create-geofences). From there, [integrate the SDK](/sdk) and call `Radar.startTrip()`. Radar will generate trip events with ETAs to the destination geofence. ## Starting trips When it's time to start a trip (e.g., when a user taps "I'm on my way" for a pickup, or when a delivery starts), start a trip with trip options (including an external ID for the trip, a destination geofence, a travel mode, and any custom metadata) and tracking options to be used during the trip (usually `RadarTrackingOptions.CONTINUOUS`). As the trip progresses, the status will update from `started` to `approaching` (based on the *Approaching threshold* on the [Settings page](https://dashboard.radar.com/settings)), then `arrived` (on destination geofence entry). ```swift Swift theme={null} let metadata = [ "Customer Name": "Jacob Pena", "Car Model": "Green Honda Civic" ] let tripOptions = RadarTripOptions(externalId: "299", destinationGeofenceTag: "store", destinationGeofenceExternalId: "123") tripOptions.mode = .car tripOptions.metadata = metadata Radar.startTrip(options: tripOptions, trackingOptions: .presetContinuous) { (status: RadarStatus, trip: RadarTrip?, events: [RadarEvent]?) in if status == .success { // do something } else { // handle error } } ``` ```c Objective-C theme={null} RadarTripOptions *tripOptions = [RadarTripOptions new]; tripOptions.externalId = @"299"; tripOptions.destinationGeofenceTag = @"store"; tripOptions.destinationGeofenceExternalId = @"123"; tripOptions.metadata = @{@"Customer Name": @"Jacob Pena",@"Car Model":@"Green Honda Civic"}; [Radar startTripWithOptions:tripOptions trackingOptions:RadarTrackingOptions.presetContinuous completionHandler:^(RadarStatus status, RadarTrip * _Nullable trip, NSArray * _Nullable events) { if (status == RadarStatusSuccess) { // do something } else { // handle error } }]; ``` ```kotlin Kotlin theme={null} val externalId = "299" val destinationGeofenceExternalId = "123" val destinationGeofenceTag = "store" val metadata = JSONObject() metadata.put("Customer Name","Jacob Pena") metadata.put("Car Model","Green Honda Civic") val mode = Radar.RadarRouteMode.CAR val tripOptions = RadarTripOptions(tripExternalId, tripMetadata, destinationGeofenceTag, destinationGeofenceExternalId, mode) Radar.startTrip(tripOptions, RadarTrackingOptions.CONTINUOUS) { status, trip, events -> if (status == Radar.RadarStatus.SUCCESS) { // do something } else { // handle error } } ``` ```java Java theme={null} JSONObject tripOptionsJson = new JSONObject(); try { tripOptionsJson.put("externalId","299"); tripOptionsJson.put("destinationGeofenceTag","store"); tripOptionsJson.put("destinationGeofenceExternalId","123"); JSONObject tripOptionsMetadata = new JSONObject("{\"Customer Name\":\"Jacob Pena\", \"Car Model\": \"Green Honda Civic\"}"); tripOptionsJson.put("metadata",tripOptionsMetadata) } catch (JSONException e) { e.printStackTrace(); } RadarTripOptions tripOptions = RadarTripOptions.fromJson(tripOptionsJson); Radar.startTrip(tripOptions, RadarTrackingOptions.CONTINUOUS, new Radar.RadarTripCallback() { @Override public void onComplete(@NonNull Radar.RadarStatus status, @Nullable RadarTrip trip, @Nullable RadarEvent[] events) { if (status == Radar.RadarStatus.SUCCESS) { // do something } else { // handle error } } } ); ``` ## Updating trips As the trip progresses, you can update the trip metadata (e.g., when a parking space is assigned for a pickup) or the trip status (e.g., to manually advance the status to `approaching` or `arrived`). This can be done either using the SDK or the [API](/api#update-a-trip). ```swift Swift theme={null} let tripOptions = Radar.getTripOptions() tripOptions.metadata = [ "parkingSpot": "1", ] Radar.updateTrip(options: tripOptions, status: RadarTripStatus.ARRIVED) { status, trip, events -> if (status == Radar.RadarStatus.SUCCESS) { // do something } else { // handle error } } ``` ```c Objective-C theme={null} RadarTripOptions *tripOptions = [Radar getTripOptions]; NSDictionary *tripOptionsMetadata = tripOptions.metadata; NSMutableDictionary *mTripOptionsMetadata = [tripOptionsMetadata mutableCopy]; [mTripOptionsMetadata setObject:[NSNumber numberWithInt:1] forKey:@"Parking Spot"]; [tripOptions setMetadata:mTripOptionsMetadata]; [Radar updateTripWithOptions:tripOptions status:RadarTripStatusArrived completionHandler:^(RadarStatus status, RadarTrip * _Nullable trip, NSArray * _Nullable events) { if (status == RadarStatusSuccess) { // do something } else { // handle error } }]; ``` ```kotlin Kotlin theme={null} var tripOptions = Radar.getTripOptions() var metadata = tripOptions?.metadata metadata?.put("Parking Spot","1") tripOptions?.metadata = metadata Radar.updateTrip(tripOptions, RadarTrip.RadarTripStatus.ARRIVED) { status, trip, events -> if (status == Radar.RadarStatus.SUCCESS) { // do something } else { // handle error } } ``` ```java Java theme={null} RadarTripOptions tripOptions = Radar.getTripOptions(); JSONObject tripOptionsMetadata = tripOptions.getMetadata(); tripOptionsMetadata.put("Parking Spot","1"); tripOptions.setMetadata(tripOptionsMetadata); Radar.updateTrip(tripOptions, RadarTrip.RadarTripStatus.ARRIVED, (status, trip, events) -> { if (status == Radar.RadarStatus.SUCCESS) { // do something } else { // handle error } }); ``` ## Stopping trips Finally, when the trip is complete (e.g., when an order is picked up or a delivery is dropped off), stop the trip. This can be done either using the SDK or the [API](/api#update-a-trip). You can set trips to expire after a set period if not manually stopped using the *Expiration threshold* on the [Settings page](https://dashboard.radar.com/settings). If tracking was started before the trip was started, the previous tracking options will be restored. Otherwise, tracking will be stopped. ```swift Swift theme={null} // trip complete Radar.completeTrip() // trip cancelled Radar.cancelTrip() ``` ```c Objective-C theme={null} // complete trip [Radar completeTrip]; // cancel trip [Radar cancelTrip]; ``` ```kotlin Kotlin theme={null} // trip complete Radar.completeTrip { status, trip, events -> // do something with status, trip, events } // trip cancelled Radar.cancelTrip { status, trip, events -> // do something with status, trip, events } ``` ```java Java theme={null} // Complete trip Radar.completeTrip(new Radar.RadarTripCallback() { @Override public void onComplete(Radar.RadarStatus radarStatus, RadarTrip radarTrip, RadarEvent[] radarEvents) { // do something } }); // Cancel trip Radar.cancelTrip(new Radar.RadarTripCallback() { @Override public void onComplete(Radar.RadarStatus radarStatus, RadarTrip radarTrip, RadarEvent[] radarEvents) { // do something } }); ``` ## Trip events Radar calculates ETAs and generates events when trips are updated: * `user.started_trip` * `user.updated_trip` * `user.approaching_trip_destination` (configurable ETA threshold) * `user.arrived_at_trip_destination` (destination geofence entered) * `user.stopped_trip` ETAs are calculated based on travel mode using the same routing engine that powers our [distance API](/maps/routing). You can receive events client-side via the [SDK](/sdk) or server-side via [event integrations](/integrations/integrations), including webhooks. ```json theme={null} { "events": [ { "_id": "56db1f4613012711002229f6", "type": "user.updated_trip", "createdAt": "2020-08-20T10:30:55.837Z", "live": true, "trip": { "_id": "5f3e50491c2b7d005c81f5d9", "live": true, "externalId": "299", "metadata": { "Customer Name": "Jacob Pena", "Car Model": "Green Honda Civic" }, "mode": "car", "destinationGeofenceTag": "store", "destinationGeofenceExternalId": "123", "destinationLocation": { "coordinates": [ -105.061198, 39.779366 ], "type": "Point" }, "eta": { "duration": 5.5, "distance": 1331 }, "createdAt": "2020-08-20T10:27:55.830Z", "updatedAt": "2020-08-20T10:30:55.837Z", "status": "started" }, }, ], "user": { "_id": "56db1f4613012711002229f4", "live": true, "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", ... } } ``` ## Multi-leg trips > [!NOTE] > > Multi-leg trips require additional configuration. Contact your customer success manager or reach out to us at [radar.com/support](https://radar.com/support) to enable this feature. Multi-leg trips allow you to define a sequence of destination stops within a single trip. Use multi-leg trips for use cases like multi-stop delivery routes, ride-sharing with multiple pickups and dropoffs, or field service visits. ### Creating a multi-leg trip To create a multi-leg trip, define `RadarTripLeg` objects for each stop and attach them to your `RadarTripOptions`. Set a `stopDuration` (in minutes) for intermediate stops to improve ETA accuracy for subsequent legs and the overall trip. Omit `stopDuration` for the final destination. Each leg's destination can be defined in one of three ways: * **Geofence** — by tag and external ID, or by geofence ID * **Address** — by a street address string * **Coordinates** — by latitude and longitude When using address or coordinate destinations, you can set an `arrivalRadius` (in meters) on the leg to define the arrival zone. The examples below use geofence-based destinations. The first leg is automatically set to `started` when the trip begins. ```swift Swift theme={null} let leg1 = RadarTripLeg(destinationGeofenceTag: "stop", destinationGeofenceExternalId: "stop-1") leg1.stopDuration = 5 leg1.metadata = ["stopName": "Customer A", "orderId": "order-101"] let leg2 = RadarTripLeg(destinationGeofenceTag: "stop", destinationGeofenceExternalId: "stop-2") leg2.stopDuration = 5 leg2.metadata = ["stopName": "Customer B", "orderId": "order-102"] let leg3 = RadarTripLeg(destinationGeofenceTag: "stop", destinationGeofenceExternalId: "stop-3") leg3.stopDuration = 5 leg3.metadata = ["stopName": "Customer C", "orderId": "order-103"] let leg4 = RadarTripLeg(destinationGeofenceTag: "store", destinationGeofenceExternalId: "store-1") leg4.metadata = ["type": "return-to-base"] let tripOptions = RadarTripOptions(externalId: "multi-stop-route-123") tripOptions.mode = .car tripOptions.legs = [leg1, leg2, leg3, leg4] Radar.startTrip(options: tripOptions) { status, trip, events in if status == .success { print("Trip started with \(trip?.legs?.count ?? 0) legs") } } ``` ```kotlin Kotlin theme={null} val leg1 = RadarTripLeg.forGeofence("stop", "stop-1") leg1.stopDuration = 5 leg1.metadata = JSONObject(mapOf("stopName" to "Customer A", "orderId" to "order-101")) val leg2 = RadarTripLeg.forGeofence("stop", "stop-2") leg2.stopDuration = 5 leg2.metadata = JSONObject(mapOf("stopName" to "Customer B", "orderId" to "order-102")) val leg3 = RadarTripLeg.forGeofence("stop", "stop-3") leg3.stopDuration = 5 leg3.metadata = JSONObject(mapOf("stopName" to "Customer C", "orderId" to "order-103")) val leg4 = RadarTripLeg.forGeofence("store", "store-1") leg4.metadata = JSONObject(mapOf("type" to "return-to-base")) val tripOptions = RadarTripOptions("multi-stop-route-123") tripOptions.mode = Radar.RadarRouteMode.CAR tripOptions.legs = arrayOf(leg1, leg2, leg3, leg4) Radar.startTrip(tripOptions) { status, trip, events -> if (status == Radar.RadarStatus.SUCCESS) { println("Trip started with ${trip?.legs?.size ?: 0} legs") } } ``` ### Completing a trip leg When a stop is completed, update the current trip leg status to `completed`. The SDK provides several methods depending on how much control you need: * `updateCurrentTripLeg(status:)` — completes the current leg automatically; the SDK resolves the trip and leg IDs for you. * `updateTripLeg(legId:status:)` — targets a specific leg by ID; the SDK resolves the trip ID automatically. * `updateTripLeg(tripId:legId:status:)` — provides full manual control over both trip and leg IDs. All of these methods automatically advance the next leg to `started`. ```swift Swift theme={null} Radar.updateCurrentTripLeg(status: .completed) { status, trip, leg, events in if status == .success { if let nextLegId = trip?.currentLegId { print("Next leg: \(nextLegId)") } else { print("All legs complete") } } } // Target a specific leg by ID Radar.updateTripLeg(legId: someLegId, status: .completed) { status, trip, leg, events in // SDK resolves the trip ID automatically } // Full manual control Radar.updateTripLeg( tripId: tripId, legId: legId, status: .completed ) { status, trip, leg, events in // ... } ``` ```kotlin Kotlin theme={null} Radar.updateCurrentTripLeg(RadarTripLeg.RadarTripLegStatus.COMPLETED) { status, trip, leg, events -> if (status == Radar.RadarStatus.SUCCESS) { val nextLegId = trip?.currentLegId if (nextLegId != null) { println("Next leg: $nextLegId") } else { println("All legs complete") } } } // Target a specific leg by ID Radar.updateTripLeg("someLegId", RadarTripLeg.RadarTripLegStatus.COMPLETED) { status, trip, leg, events -> // SDK resolves the trip ID automatically } // Full manual control Radar.updateTripLeg(tripId, legId, RadarTripLeg.RadarTripLegStatus.COMPLETED) { status, trip, leg, events -> // ... } ``` When the final leg is completed, the trip is automatically finished. The SDK clears the stored trip and restores any previous tracking options. ```swift Swift theme={null} Radar.updateCurrentTripLeg(status: .completed) { status, trip, leg, events in if trip?.status == .completed { print("Final leg completed — trip is now finished") } } ``` ```kotlin Kotlin theme={null} Radar.updateCurrentTripLeg(RadarTripLeg.RadarTripLegStatus.COMPLETED) { status, trip, leg, events -> if (trip?.status == RadarTrip.RadarTripStatus.COMPLETED) { println("Final leg completed — trip is now finished") } } ``` You can also explicitly complete or cancel a multi-leg trip at any time using `Radar.completeTrip()` or `Radar.cancelTrip()` as described in [Stopping trips](#stopping-trips). ### Reordering trip legs If the stop order needs to change mid-trip, call `reorderTripLegs()` with the leg IDs in the desired order. ETAs for each leg will update on the next track call. Call `Radar.trackOnce()` immediately after reordering to refresh ETAs right away. If a previously completed leg is placed after the current leg in the new order, its status will change back to `started` once it becomes the current leg. ```swift Swift theme={null} let legIds = ["legId1", "legId2", "legId3"] Radar.reorderTripLegs(legIds: legIds) { status, trip, events in if status == .success { Radar.trackOnce() } } // Reorder legs of a specific trip (not necessarily the active one) Radar.reorderTripLegs( tripId: tripId, legIds: ["legId1", "legId2", "legId3"] ) { status, trip, events in if status == .success { Radar.trackOnce() } } ``` ```kotlin Kotlin theme={null} val legIds = arrayOf("legId1", "legId2", "legId3") Radar.reorderTripLegs(legIds) { status, trip, events -> if (status == Radar.RadarStatus.SUCCESS) { Radar.trackOnce() } } // Reorder legs of a specific trip (not necessarily the active one) Radar.reorderTripLegs(tripId, arrayOf("legId1", "legId2", "legId3")) { status, trip, events -> if (status == Radar.RadarStatus.SUCCESS) { Radar.trackOnce() } } ``` ### Accessing trip state The SDK stores the active trip locally, so you can access the trip and its legs at any time. ```swift Swift theme={null} if let trip = Radar.getTrip() { print("Trip ID: \(trip._id)") print("Status: \(Radar.stringForTripStatus(trip.status))") print("Current leg: \(trip.currentLegId ?? "none")") for leg in trip.legs ?? [] { let isCurrent = leg._id == trip.currentLegId ? " ← current" : "" print("Leg \(leg._id ?? "?"): \(RadarTripLeg.string(for: leg.status))\(isCurrent)") print(" Destination: \(leg.destinationGeofenceExternalId ?? "unknown")") } } ``` ```kotlin Kotlin theme={null} val trip = Radar.getTrip() if (trip != null) { println("Trip ID: ${trip._id}") println("Status: ${Radar.stringForTripStatus(trip.status)}") println("Current leg: ${trip.currentLegId ?: "none"}") for (leg in trip.legs ?: emptyArray()) { val isCurrent = if (leg._id == trip.currentLegId) " ← current" else "" println("Leg ${leg._id ?: "?"}: ${RadarTripLeg.stringForStatus(leg.status)}$isCurrent") println(" Destination: ${leg.destinationGeofenceExternalId ?: "unknown"}") } } ``` ## Anomaly detection ### Wrong destination arrival detection The wrong destination arrival detection feature identifies when a user on a trip may have entered a different destination than the one intended. Specifically, it triggers an event when the user enters a geofence that shares the same `tag` as the destination geofence, but possesses a different `externalId`. To enable this feature, navigate to the [Settings page](https://dashboard.radar.com/settings#trips-settings) and enable the `user.arrived_at_wrong_trip_destination` event under *Trips* section. ### Delay detection Delay detection identifies trips at risk of being delayed or incomplete. To enable this feature, configure a *Delay threshold* on the [Settings page](https://dashboard.radar.com/settings#trips-settings) under *Trips*. If `scheduledArrivalAt` is set for a trip, delay information is captured in the trip's `delay` field. The `scheduledArrivalTimeDelay` is the predicted arrival delay from the `scheduledArrivalAt` time in minutes. The `delayed` flag is `true` when `scheduledArrivalTimeDelay` exceeds the delay threshold. ## Display live trips and ETAs ### In the Radar trip tracking dashboard > [!NOTE] > > The trip tracking dashboard is available on the [Enterprise plan](https://radar.com/pricing). The Radar trip tracking dashboard displays active trips for a specific destination geofence, including ID, custom metadata, and ETA. Ask your customer success manager for a distribution of the app specific to your organization. ![](https://images.ctfassets.net/f2vbu16fzuly/38fY5fD4H47UGa4KZXHLib/989305812e9b35a741141b1fd9c3befa/tablet-view.gif) ### In your own UI Poll the [list trips API](/api#list-trips) to retrieve active trips for a specific destination geofence, including ID, custom metadata, and ETA. For example, you might poll the list trips API from an internal dashboard. Or, listen for [trip events](#trip-events) sent to a webhook. From there, forward trip information, including ID, custom metadata, and ETA, to other systems. For example, you might set up a webhook that sends ETA to an order management or kitchen display system. ## Analytics Radar offers analytics on trip data and location opt-in rates from [users](/api#users) in your project. [Analytics](https://dashboard.radar.com/geofencing/trips/analytics) on trip data can be found on the Analytics page and grouped under the Trips tab. Analytics on location permission opt-in rates is grouped under the Permissions tab. Read more about Permissions [here](/faqs#location-permissions). ### How to filter your data The Filters button at the top of the page offers ways to look at more granular views of your trip data. The filters will apply to the statistics cards and graphs as well as the data in the By Destination table. **Date range:** A date range can be selected from the drop-down date picker. Make sure that the date in the left-hand box falls before the date in the right-hand box. When accessing the Analytics page, the default date range encompasses all trip data in your project, meaning that you'll see a default range from the date of your earliest trip to yesterday. All trip analytics are updated nightly and trip analytics from today will not be shown in the Analytics page until tomorrow. **Destination Geofence tag:** Each geofence has a geofence tag. You can find the tag to a specific geofence in the "Tag" column on the Geofences page in the sidebar, or you can navigate to the trips page in the sidebar and click on the external ID listed under "Destination", which will show the details of the destination geofence. This field can be used alone or in tandem with the Destination Geofence External ID field. **Destination Geofence external ID**: Each geofence has an external ID. You can find the external ID for a specific geofence in the "External ID" column on the Geofences page in the sidebar, or you can navigate to the Trips page and click on the external ID listed under "Destination". This field can be used alone or in tandem with the Destination Geofence Tag field. **Travel mode:** Select a specific mode of travel to filter all trip data in the Analytics view to only a specific mode. If there is no mode selected, all trip data, regardless of travel mode, will be shown. Trip analytics apply to the environment in which you view the metrics. For example, when viewing the metrics in the test environment, the metrics only include trip data from the test environment. ### Trips overview * **`Median wait time`**: the median duration between the moment when a user arrives at a destination (`user.arrived_at_trip_destination`) and the moment when the trip is marked complete (`completed`). This statistic omits trips which are missing an arrival timestamp. * **`Number of trips`**: the total count of all live trips for a specific project which have a status of `completed`. * **`Median trip time`**: the median duration between the moment when the user starts a trip (`user.started_trip`) and the moment when they arrive at the destination (`user.arrived_at_trip_destination`). This statistic omits trips which are missing an arrival timestamp. * **`Repeat customers`**: the total number of your users who have completed more than one trip. The graphs for each card show the change over time in each statistic. The time windows of each graph are automatically determined by the dates set in the Filters button. To see data grouped by hour, set the date range to encompass 2 days or fewer. To see data grouped by day, set the date range to encompass 21 days or fewer. To see data grouped by weeks, set the date range to encompass 60 days or fewer. To see data grouped by month, the date range must encompass more than 60 days of data. | Number of days | Time grouping | | - | - | | 2 | Hour | | 21 | Day | | 60 | Week | | 60+ | Month | ### By destination table The By Destination table groups your trip data by individual destination geofence and allows you to identify your **slowest and fastest stores** by wait time as well as your **most popular stores** by the number of trips made to the store. By default, the By Destination table is sorted alphabetically based on the Destination column. To toggle the sort order of the column, click the column header. The table has 6 sortable headers: * **`Destination`**: the description of the individual destination geofence. * **`Tag`**: the geofence tag associated with the unique geofence destination listed in the destination column. Clicking on a tag filters the entire Analytics page for only geofences that contain that tag. * **`Geofence ID`**: the geofence ID of the unique geofence destination listed in the destination column. * **`Wait Time`**: the median wait time of all qualifying trips to that destination, given the filters applied. * **`Trips Completed`**: the number of completed trips to that destination, given the filters applied. * **`Trip Time`**: the median trip time of all qualifying trips to that destination, given the filters applied. **By destination table filter box:** The text box in the By Destination table on the Analytics page also allows you to filter only the data in the table. You can filter by Destination, Tag, or Geofence ID. (The filters set in text box only apply to data in the By Destination table and do not apply to the overall trip metrics at the top of the page.) **Additional options in the table:** On the right side of each row, there is an icon with three dots that allows viewers to select additional options. Clicking on this icon offers two actions: * **`Filter by destination`**: This will filter the entire analytics page to only include this single destination. * **`View destination`**: This will bring you to the destination geofence's detail page. ### Calculations Wait time and trip time are only calculated for trips that have a status of `completed` and have timestamp entries for `started_at`, `arrived_at`, and `completed_at`. Reminder that all trip analytics are updated nightly and trip analytics from today will not be shown in the Analytics page until tomorrow. ### Data retention settings and frequency of updates Data retention settings (a setting on the *project* level) apply to the data in Analytics as well. The default data retention settings for trip data is 90 days. Median wait time, trip count, and median trip duration metrics are all updated nightly, so all calculations do not include the current day's data. If your project does not have any past trips, you will not see any data in the analytics section of your dashboard. Take your first trip to see the statistics populate! ## Keep-alive With silent push notifications enabled, Radar will attempt to initiate track requests on users that have lost tracking updates. To enable trip keep-alive via silent push, configure the platform specific push notification settings in dashboard [Settings page](https://dashboard.radar.com/settings#push-notification-settings). Then set up silent push in your app by following the [silent push guide](/sdk/silent-push) for your platform. If the trip is active but has not received any updates within 3 minutes, Radar will send a silent push notification to the device which will attempt to restart tracking. Radar will continue to send silent push notifications every 3 minutes if the trip has not been updated. For iOS devices with location extension push enabled, Radar will attempt to send a background location push after 5 minutes of no updates. Location extension will be able provide a location update in some cases where a regular silent push does not have permission to do so. However, location extension push notifications cannot restart tracking for the app. ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # User insights Source: https://docs.radar.com/geofencing/user-insights Use Radar user insights to tell whether a user is at home, at work, traveling, or commuting, based on their location history. User insights turn a user's location history into current context, like whether the user is at home, at work, traveling, or commuting. Radar infers likely home and work locations from recurring stopped-location patterns. As new location updates arrive, Radar compares the user's current location with those inferred locations and returns insights about the user's location. > [!NOTE] > > Contact your Radar customer success manager to enable user insights for your project. ![Map illustrating commuting insights](https://mintcdn.com/radarlabs/LAk9lCl29oAfklhf/images/geofencing/commuting.png?fit=max\&auto=format\&n=LAk9lCl29oAfklhf\&q=85\&s=845fa4336eccd78eed4c8f7aab14eb72) ## How it works Radar processes recent stopped locations each day. It uses signals such as repeat visits and the local time of each visit to identify and rank likely home and work locations. When Radar has sufficient confidence for an inferred location, new location updates begin producing the following insight states: * **At home**: The user is within their inferred home bubble. * **At work**: The user is within their inferred work bubble. * **Traveling**: The user is far from their inferred home area. * **Commuting**: The user is along an inferred route between home and work. Home and work are mutually exclusive. When the user matches both inferred areas, Radar selects the closer location. > [!NOTE] > > Locations derived from user insights are probabilistic and can change as Radar receives more location history. ## User context When user insights are enabled and Radar has inferred at least one usable home or work location, [track responses](/api#track) include a `locationInsights` object on the user: ```json theme={null} { "user": { "locationInsights": { "atHome": true, "atWork": false, "traveling": false, "commuting": false } } } ``` The `locationInsights` object is omitted when Radar does not have enough historical evidence to infer a usable home or work location. The `commuting` field can be omitted when commute status is unavailable. Inferred home and work coordinates are not included in SDK responses. ## Events Radar generates events when a user's location update changes the insight state: * `user.entered_home` * `user.exited_home` * `user.entered_work` * `user.exited_work` * `user.started_traveling` * `user.stopped_traveling` * `user.started_commuting` * `user.stopped_commuting` For more information on how to receive events, see [event integrations](/integrations/integrations) and [webhooks](/integrations/webhooks). > [!WARNING] > > User insights are calculated separately for the Test and Live environments. Use the Test environment while developing, then use the Live environment in production. ## Test user insights Because user insights depend on historical patterns, they cannot be created from a single location update. After Radar has processed enough location history for a test user: 1. Open the [Simulator](https://dashboard.radar.com/geofencing/simulate) in the Radar dashboard. 2. Select the user and enable the *Insights* map layer to inspect the inferred home, work, and commute corridors. 3. Simulate location updates in and out of those areas. 4. Inspect `user.locationInsights` in the tracking response and verify state changes on the [Events page](https://dashboard.radar.com/geofencing/events). # Documentation Source: https://docs.radar.com/index Radar documentation for location SDKs, APIs, geofencing, trip tracking, fraud detection, and maps. [Radar](https://radar.com) is full-stack location infrastructure for every product and service. Our [SDKs](https://docs.radar.com/sdk) and [APIs](https://docs.radar.com/api) make it easy to add location-based experiences to your app or website, from pickup and delivery tracking to location-based messaging to store locators and more. Our [Geofencing Platform](https://docs.radar.com/geofencing/overview) is the industry-leading geofencing and location tracking platform, including geofencing, place visit detection, trip tracking, fraud detection, and analytics. Our [Maps Platform](https://docs.radar.com/maps/overview) is a cost-effective solution for geocoding APIs, search APIs, routing APIs, and base maps. We power location-based experiences for [enterprises and startups](https://radar.com/customers) across hundreds of millions of devices worldwide. Start exploring our building blocks and developer tools below. ## Geofencing Platform > [card] [Geofences](/geofencing/geofences) > > Industry-leading accuracy with unlimited geofences, polygon geofences, and more > [card] [Trips](/geofencing/trips) > > Trip tracking, live ETAs, arrival detection, and routing for pickups and deliveries > [card] [Places](/geofencing/places) > > Points-of-interest (POI) dataset to detect visits to millions of places > [card] [Regions](/geofencing/regions) > > Admin boundary dataset for country, state, and postal code detection > [card] [Beacons](/geofencing/beacons) > > Hardware-enabled micro-geofences accurately detect locations down to a meter or less > [card] [Fraud](/geofencing/fraud) > > Detect GPS spoofing, proxy and VPN usage, and device tampering > [card] [Integrations](/integrations/integrations) > > Send Radar events and user context to other systems server-to-server ## Maps Platform > [card] [Geocoding APIs](/maps/geocoding) > > Forward, reverse, and IP geocoding APIs > [card] [Search APIs](/maps/search) > > Autocomplete, address validation, and place search APIs > [card] [Routing APIs](/maps/routing) > > Distance, matrix, and route matching APIs > [card] [Maps](/maps/maps) > > A cost-effective alternative to Google Maps and Mapbox ## For developers > [card] [SDK reference](/sdk/sdk) > > Add location to your apps and websites with just a few lines of code > [card] [API reference](/api) > > APIs for server-side implementations > [card] [Tutorials](/tutorials) > > APIs for server-side implementations > [card] [Waypoint](/waypoint) > > Use our waypoint apps to rest Radar before integrating the SDK # Airship Source: https://docs.radar.com/integrations/airship Send Radar location events and tags to Airship to trigger location-based messages and build location-based user segments. > [!NOTE] > > The Airship integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events and tags to [Airship](https://www.airship.com/). Use the Airship integration to send location-triggered and location-targeted messages to increase engagement and conversion, measure the ROI of location-based messaging, and build location-based user segments. ## **Configuration** On the Airship *Tokens* page in *Settings*, create a token with the *All Access* role and copy the app key and access token. Under *Partner Integrations*, enable Radar to enable auto-population of custom event names and properties in the Airship Automation Composer. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations#airship) under *Airship*, set *Enabled* to *Yes* and paste your app key and access token. Note that you can set separate API keys for the *Test* and *Live* environments. Whenever events are generated, Radar will send custom events and tags to Airship. Note that for tags to populate, you must manually create [tag groups](https://docs.airship.com/guides/messaging/user-guide/audience/segmentation/tags/) in Airship first. If you are using Airship SDK `13.x` or earlier with Radar iOS SDK `3.0.4` or earlier or Radar Android SDK `3.0.6` or earlier, the Radar SDK will automatically collect Airship channel ID and Airship session ID. However, if you are using Airship SDK `14.0` or later with Radar iOS SDK `3.0.5` or later or Radar Android SDK `3.0.7` or later, you must set Radar `metadata.airshipChannelId` and `metadata.airshipSessionId` manually to collect Airship channel ID and Airship session ID. ```swift Swift theme={null} Radar.setMetadata([ "airshipChannelId": Airship.channel.identifier, "airshipSessionId": Airship.analytics.sessionID ]) ``` ```kotlin Kotlin theme={null} val channelId = UAirship.shared().channel.id val sessionId = UAirship.shared().analytics.sessionId Radar.setMetadata(JSONObject().put("airshipChannelId",channelId).put("airshipSessionId",sessionId)) ``` It is recommended to set the Radar user metadata once the Airship channel ID becomes available. This can be performed by implementing a channel event listener specific to the [Airship SDK](https://www.airship.com/docs/developer/sdk-integration) in use. ## **Verify integration data delivery** To test that the integration is configured correctly and can deliver data, use the [Simulator](https://dashboard.radar.com/geofencing/simulate) to generate events. Click *View* on an event row and scroll down to the *Logs* section on the details page to verify delivery. Perform a similar process via a test app build with Radar location tracking enabled by spoofing location or moving into the relevant boundary. All integration delivery can be monitored via the integration's event logs by clicking *View event logs* on the [Integrations page](https://dashboard.radar.com/integrations#airship). ## **Example use cases** ### **Send a personalized push notification when a user arrives at a store** 1. Create [Geofences](/geofencing/geofences#create-geofences) in Radar with the geofence tag set to `store`. The geofence tag will be used to trigger messages for the subset of geofence entries where this tag is present. 2. Set up an Airship campaign triggered from the Radar geofence entry event, the `radar_geofence_entered` custom event in Airship, and add property filtering where `radar_geofence_tag` is `store`. These same events can be used as part of an Airship campaign and the event properties can be used in message personalization with [handlebars](https://handlebarsjs.com/). ### **Message all users nearby a store** 1. Create [Geofences](/geofencing/geofences#create-geofences) in Radar to represent nearby store boundaries with geofence tag set to `nearby-store`. The geofence tag will be used to target messages for the subset of geofences where this tag is present. 2. Set up an Airship campaign targeted with the `radar_geofence_tags` tag group that Radar sends. This will be an array of all geofences the user is currently in, so set the tag to match the value of `nearby-store` for the `radar_geofence_tag` group. Additional attribute filtering can be performed for more complex targeting, including regional targeting. ### **In-app messaging** To trigger in-app messaging from detected user state on app open, custom events need to deliver through Airship's SDK rather than via Radar's server to server integration with Airship. To support this, implement custom logic in the SDK leveraging Radar's location update listener, on [iOS](/sdk/ios#listening-for-events-with-a-delegate) or [Android](/sdk/android#listening-for-events-with-a-receiver), to send foreground detections to Airship. The example code below assumes you are calling `Radar.trackOnce()` on application launch. See the [iOS](/sdk/ios#foreground-tracking) and [Android](/sdk/android#foreground-tracking) tracking references if needed. ```swift Swift theme={null} import RadarSDK import AirshipKit @main class AppDelegate: UIResponder, UIApplicationDelegate, RadarDelegate { func didUpdateLocation(_ location: CLLocation, user: RadarUser) { if (user.foreground && user.source == RadarLocationSource.foregroundLocation) { if let place = user.place { let event = CustomEvent(name: "radar_fg_place_detected"); event.interactionType = "location" event.properties = [ "radar_place_name": place.name, "radar_place_categories": place.categories.joined(separator: ","), "radar_place_chain_slug": place.chain?.slug ?? "" ] event.track() } if let geofences = user.geofences { let event = CustomEvent(name: "radar_fg_geofences_detected"); event.interactionType = "location" event.properties = [ "radar_geofence_descriptions": geofences.compactMap({ $0.description }), "radar_geofence_tags": geofences.compactMap({ $0.tag }), "radar_geofence_external_ids": geofences.compactMap({ $0.externalId }) ] event.track() } } } } ``` ```kotlin Kotlin theme={null} class MyRadarReceiver: RadarReceiver() { override fun onLocationUpdated(context: Context, location: Location, user: RadarUser) { if (user.foreground && user.source == RadarLocationSource.FOREGROUND_LOCATION) { var userGeofences = user.geofences var userPlace = user.place if (userGeofences != null && userGeofences.isNotEmpty()) { CustomEvent.newBuilder("radar_fg_geofences_entered") .addProperty("geofence_descriptions", userGeofences.map { it.description }.joinToString()) .addProperty("geofence_tags", userGeofences.map { it.tag }.joinToString()) .addProperty("geofence_external_ids", userGeofences.map { it.externalId }.joinToString()) .build() .track() } if (userPlace != null) { val chain: String = userPlace.chain?.slug ?: "" CustomEvent.newBuilder("radar_fg_place_entered") .addProperty("place_name", userPlace.name) .addProperty("place_chain", chain) .addProperty("categories", userPlace.categories.joinToString()) .build() .track() } } } } ``` ## **User mapping** | **Radar User Field** | **Airship Tag Group Name** | **Type** | **Example Tag** | **Context Type** | | :- | :- | :- | :- | :- | | `locationAuthorization` | `radar_location_authorization` | string | `"GRANTED_FOREGROUND"` | | | `locationAccuracyAuthorization` | `radar_location_accuracy_authorization` | string | `"FULL"` | | | `updatedAt` | `radar_updated_at` | timestamp | `"2018-06-22T15:23:39.000Z"` | | | `segments[*].externalId` | `radar_segment_external_ids` | array\[string] | `["starbucks-visitors"]` | | | `topChains[*].slug` | `radar_top_chain_slugs` | array\[string] | `["starbucks"]` | | | `topChains[*].externalId` | `radar_top_chain_external_ids` | array\[string] | `["123"]` | | | `geofences[*]._id` | `radar_geofence_ids` | array\[string] | `["5b2c0906f5874b001aecfd8e"]` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `radar_geofence_descriptions` | array\[string] | `["Store #123"]` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `radar_geofence_tags` | array\[string] | `["store"]` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `radar_geofence_external_ids` | array\[string] | `["123"]` | [Geofences](/geofencing/geofences) | | `place._id` | `radar_place_id` | string | `"59302bcf8f27e8a156bd4f91"` | [Places](/geofencing/places) | | `place.name` | `radar_place_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.categories` | `radar_place_categories` | string | `"coffee-shop"` | [Places](/geofencing/places) | | `place.chain.slug` | `radar_place_chain_slug` | string | `"starbucks"` | [Places](/geofencing/places) | | `place.chain.name` | `radar_place_chain_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `country.code` | `radar_region_country_code` | string | `"US"` | [Regions](/geofencing/regions) | | `country.name` | `radar_region_country_name` | string | `"United States"` | [Regions](/geofencing/regions) | | `state.code` | `radar_region_state_code` | string | `"MD"` | [Regions](/geofencing/regions) | | `state.name` | `radar_region_state_name` | string | `"Maryland"` | [Regions](/geofencing/regions) | | `dma.code` | `radar_region_dma_code` | string | `"26"` | [Regions](/geofencing/regions) | | `dma.name` | `radar_region_dma_name` | string | `"Baltimore"` | [Regions](/geofencing/regions) | | `postalCode.code` | `radar_region_postal_code` | string | `"21014"` | [Regions](/geofencing/regions) | | `trip.externalId` | `radar_trip_external_id` | string | `"299"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceTag` | `radar_trip_destination_geofence_tag` | string | `"store"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `radar_trip_destination_geofence_external_id` | string | `"123"` | [Trip Tracking](/geofencing/trips) | | `beacons[*]._id` | `radar_beacon_ids` | array\[string] | `["5b2c0906f5874b001aecfd8f"]` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `radar_beacon_descriptions` | array\[string] | `["Store #123 - Drive-Thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `radar_beacon_tags` | array\[string] | `["drive-thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `radar_beacon_external_ids` | array\[string] | `["123"]` | [Beacons](/geofencing/beacons) | ## **Event mapping** | **Radar Event** | **Context Type** | **Airship Event** | | :- | :- | :- | | `user.entered_geofence` | [Geofences](/geofencing/geofences) | `radar_geofence_entered` | | `user.exited_geofence` | [Geofences](/geofencing/geofences) | `radar_geofence_exited` | | `user.dwelled_in_geofence` | [Geofences](/geofencing/geofences) | `radar_dwelled_in_geofence` | | `user.entered_place` | [Places](/geofencing/places) | `radar_place_entered` | | `user.exited_place` | [Places](/geofencing/places) | `radar_place_exited` | | `user.entered_region_country` | [Regions](/geofencing/regions) | `radar_country_entered` | | `user.exited_region_country` | [Regions](/geofencing/regions) | `radar_country_exited` | | `user.entered_region_state` | [Regions](/geofencing/regions) | `radar_state_entered` | | `user.exited_region_state` | [Regions](/geofencing/regions) | `radar_state_exited` | | `user.entered_region_dma` | [Regions](/geofencing/regions) | `radar_dma_entered` | | `user.exited_region_dma` | [Regions](/geofencing/regions) | `radar_dma_exited` | | `user.started_trip` | [Trip Tracking](/geofencing/trips) | `radar_started_trip` | | `user.updated_trip` | [Trip Tracking](/geofencing/trips) | `radar_updated_trip` | | `user.approaching_trip_destination` | [Trip Tracking](/geofencing/trips) | `radar_approaching_trip_destination` | | `user.arrived_at_trip_destination` | [Trip Tracking](/geofencing/trips) | `radar_arrived_at_trip_destination` | | `user.stopped_trip` | [Trip Tracking](/geofencing/trips) | `radar_stopped_trip` | | `user.entered_beacon` | [Beacons](/geofencing/beacons) | `radar_beacon_entered` | | `user.exited_beacon` | [Beacons](/geofencing/beacons) | `radar_beacon_exited` | ### **radar\_geofence\_entered** | **Radar Event Field** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `geofence._id` | `radar_geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `radar_geofence_description` | string | `"Store #123"` | | `geofence.tag` | `radar_geofence_tag` | string | `"store"` | | `geofence.externalId` | `radar_geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `radar_geofence_metadata_{key}` | type | `{value}` | | `confidence` | `radar_confidence` | string | `"high"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_geofence\_exited** | **Radar Event Field** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `geofence._id` | `radar_geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `radar_geofence_description` | string | `"Store #123"` | | `geofence.tag` | `radar_geofence_tag` | string | `"store"` | | `geofence.externalId` | `radar_geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `radar_geofence_metadata_{key}` | type | `{value}` | | `confidence` | `radar_confidence` | string | `"high"` | | `duration` | `radar_duration` | number (minutes) | `42.1` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_dwelled\_in\_geofence** | **Radar Event Field** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `geofence._id` | `radar_geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `radar_geofence_description` | string | `"Store #123"` | | `geofence.tag` | `radar_geofence_tag` | string | `"store"` | | `geofence.externalId` | `radar_geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `radar_geofence_metadata_{key}` | type | `{value}` | | `confidence` | `radar_confidence` | string | `"high"` | | `duration` | `radar_duration` | number (minutes) | `5` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_place\_entered** | **Radar Event Field** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `place._id` | `radar_place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `radar_place_name` | string | `"Starbucks"` | | `place.chain.slug` | `radar_place_chain_slug` | string | `"starbucks"` | | `place.chain.name` | `radar_place_chain_name` | string | `"Starbucks"` | | `place.chain.metadata[{key}]` | `radar_place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `radar_place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `radar_confidence` | string | `"high"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_place\_exited** | **Radar Event Field** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `place._id` | `radar_place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `radar_place_name` | string | `"Starbucks"` | | `place.chain.slug` | `radar_place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `radar_place_chain_name` | string | `"Starbucks"` | | `place.chain.metadata[{key}]` | `radar_place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `radar_place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `radar_confidence` | string | `"high"` | | `duration` | `radar_duration` | number (minutes) | `42.1` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_country\_entered** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `region.code` | `radar_region_code` | string | `"US"` | | `region.name` | `radar_region_name` | string | `"United States"` | | `confidence` | `radar_confidence` | string | `"high"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_country\_exited** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `region.code` | `radar_region_code` | string | `"US"` | | `region.name` | `radar_region_name` | string | `"United States"` | | `confidence` | `radar_confidence` | string | `"high"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_state\_entered** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `region.code` | `radar_region_code` | string | `"MD"` | | `region.name` | `radar_region_name` | string | `"Maryland"` | | `confidence` | `radar_confidence` | string | `"high"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_state\_exited** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `region.code` | `radar_region_code` | string | `"MD"` | | `region.name` | `radar_region_name` | string | `"Maryland"` | | `confidence` | `radar_confidence` | string | `"high"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_dma\_entered** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `region.code` | `radar_region_code` | string | `"26"` | | `region.name` | `radar_region_name` | string | `"Baltimore"` | | `confidence` | `radar_confidence` | string | `"high"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_dma\_exited** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `region.code` | `radar_region_code` | string | `"26"` | | `region.name` | `radar_region_name` | string | `"Baltimore"` | | `confidence` | `radar_confidence` | string | `"high"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_started\_trip** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `trip.externalId` | `radar_trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `radar_trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `radar_trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `radar_trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_updated\_trip** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `trip.externalId` | `radar_trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `radar_trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `radar_trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `radar_trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_approaching\_trip\_destination** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `trip.externalId` | `radar_trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `radar_trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `radar_trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `radar_trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_arrived\_at\_trip\_destination** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `trip.externalId` | `radar_trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `radar_trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `radar_trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `radar_trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_stopped\_trip** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `trip.externalId` | `radar_trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `radar_trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `radar_trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `radar_trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_beacon\_entered** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `beacon._id` | `radar_beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `radar_beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `radar_beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `radar_beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `radar_trip_metadata_{key}` | type | `{value}` | | `confidence` | `radar_confidence` | string | `"high"` | | `foreground` | `radar_foreground` | boolean | `true` | ### **radar\_beacon\_exited** | **Radar Event Attribute** | **Airship Event Property** | **Type** | **Example Value** | | :- | :- | :- | :- | | `beacon._id` | `radar_beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `radar_beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `radar_beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `radar_beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `radar_trip_metadata_{key}` | type | `{value}` | | `confidence` | `radar_confidence` | string | `"high"` | | `duration` | `radar_duration` | number (minutes) | `1.42` | | `foreground` | `radar_foreground` | boolean | `true` | # Amplitude Source: https://docs.radar.com/integrations/amplitude Send Radar location events and user properties to Amplitude to add location context to analytics and build user segments. > [!NOTE] > > The Amplitude integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events and user properties to [Amplitude](https://amplitude.com). Use the Amplitude integration to enrich behavioral events with location context, measure the ROI of location-based features, and build location-based user segments. ## Configuration On the Amplitude *Manage Project* page, copy your API key. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *Amplitude*, set *Enabled* to *Yes* and paste your API key. Note that you can set separate API keys for the *Test* and *Live* environments. Whenever events are generated, Radar will send events and user properties to Amplitude. ## User mapping Note that Radar uses the special string `"(null)"` to represent `null` user property values. | Radar User Field | Amplitude User Property | Type | Example Value | Context Type | | - | - | - | - | - | | `userId` | `userId` | string | `"1"` | | | `deviceId` | `deviceId` | string | `"10974a2ee035770b9"` | | | `location.coordinates[0]` | `location_lng` | number | `-76.350663` | | | `location.coordinates[1]` | `location_lat` | number | `39.525665` | | | `locationAuthorization` | `[Radar] Location Authorization` | string | `GRANTED_FOREGROUND` | | | `locationAccuracyAuthorization` | `[Radar] Location Accuracy Authorization` | string | `FULL` | | | `updatedAt` | `time` | timestamp | `"2018-06-22T15:23:39.000Z"` | | | `_id` | `[Radar] ID` | string | `"5b2c0906f5874b001aecfd8d"` | | | `segments[*].externalId` | `[Radar] Segment External IDs` | array\[string] | `["starbucks-visitors"]` | | | `topChains[*].slug` | `[Radar] Top Chain Slugs` | array\[string] | `["starbucks", "walmart"]` | | | `topChains[*].externalId` | `[Radar] Top Chain External IDs` | array\[string] | `["123", "456"]` | | | `geofences[*]._id` | `[Radar] Geofence IDs` | array\[string] | `["5b2c0906f5874b001aecfd8e"]` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `[Radar] Geofence Descriptions` | array\[string] | `["Store #123"]` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `[Radar] Geofence Tags` | array\[string] | `["store"]` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `[Radar] Geofence External IDs` | array\[string] | `["123"]` | [Geofences](/geofencing/geofences) | | `place._id` | `[Radar] Place ID` | string | `"59302bcf8f27e8a156bd4f91"` | [Places](/geofencing/places) | | `place.name` | `[Radar] Place Name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.categories` | `[Radar] Place Categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | [Places](/geofencing/places) | | `place.chain.slug` | `[Radar] Place Chain Slug` | string | `"starbucks"` | [Places](/geofencing/places) | | `place.chain.name` | `[Radar] Place Chain Name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `country.code` | `[Radar] Region Country Code` | string | `"US"` | [Regions](/geofencing/regions) | | `country.name` | `[Radar] Region Country Name` | string | `"United States"` | [Regions](/geofencing/regions) | | `country._id` | `[Radar] Region Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | [Regions](/geofencing/regions) | | `state.code` | `[Radar] Region State Code` | string | `"MD"` | [Regions](/geofencing/regions) | | `state.name` | `[Radar] Region State Name` | string | `"Maryland"` | [Regions](/geofencing/regions) | | `state._id` | `[Radar] Region State ID` | string | `"5b2c0906f5874b001aecfd8f"` | [Regions](/geofencing/regions) | | `dma.code` | `[Radar] Region DMA Code` | string | `"26"` | [Regions](/geofencing/regions) | | `dma.name` | `[Radar] Region DMA Name` | string | `"Baltimore"` | [Regions](/geofencing/regions) | | `dma._id` | `[Radar] Region DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | [Regions](/geofencing/regions) | | `city.code` | `[Radar] Region City Code` | string | `"_"` | [Regions](/geofencing/regions) | | `city.name` | `[Radar] Region City Name` | string | `"Tokyo"` | [Regions](/geofencing/regions) | | `city._id` | `[Radar] City ID` | string | `"5b2c0906f5874b001aecfd8f"` | [Regions](/geofencing/regions) | | `postalCode.code` | `[Radar] Region Postal Code` | string | `"21014"` | [Regions](/geofencing/regions) | | `postalCode._id` | `[Radar] Region Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | [Regions](/geofencing/regions) | | `trip.externalId` | `[Radar] Trip External ID` | string | `"299"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceTag` | `[Radar] Trip Destination Geofence Tag` | string | `"store"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `[Radar] Trip Destination Geofence External ID` | string | `"123"` | [Trip Tracking](/geofencing/trips) | | `beacons[*]._id` | `[Radar] Beacon IDs` | array\[string] | `["5b2c0906f5874b001aecfd8f"]` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `[Radar] Beacon Descriptions` | array\[string] | `["Store #123 - Drive-Thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `[Radar] Beacon Tags` | array\[string] | `["drive-thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `[Radar] Beacon External IDs` | array\[string] | `["123"]` | [Beacons](/geofencing/beacons) | ## Event mapping | Radar Event | Context Type | Amplitude Event | | - | - | - | | `user.entered_geofence` | [Geofences](/geofencing/geofences) | `[Radar] Geofence Entered` | | `user.exited_geofence` | [Geofences](/geofencing/geofences) | `[Radar] Geofence Exited` | | `user.dwelled_in_geofence` | [Geofences](/geofencing/geofences) | `[Radar] Dwelled in Geofence` | | `user.entered_place` | [Places](/geofencing/places) | `[Radar] Place Entered` | | `user.exited_place` | [Places](/geofencing/places) | `[Radar] Place Exited` | | `user.entered_region_country` | [Regions](/geofencing/regions) | `[Radar] Country Entered` | | `user.exited_region_country` | [Regions](/geofencing/regions) | `[Radar] Country Exited` | | `user.entered_region_state` | [Regions](/geofencing/regions) | `[Radar] State Entered` | | `user.exited_region_state` | [Regions](/geofencing/regions) | `[Radar] State Exited` | | `user.entered_region_dma` | [Regions](/geofencing/regions) | `[Radar] DMA Entered` | | `user.exited_region_dma` | [Regions](/geofencing/regions) | `[Radar] DMA Exited` | | `user.started_trip` | [Trip Tracking](/geofencing/trips) | `[Radar] Started Trip` | | `user.updated_trip` | [Trip Tracking](/geofencing/trips) | `[Radar] Updated Trip` | | `user.approaching_trip_destination` | [Trip Tracking](/geofencing/trips) | `[Radar] Approaching Trip Destination` | | `user.arrived_at_trip_destination` | [Trip Tracking](/geofencing/trips) | `[Radar] Arrived at Trip Destination` | | `user.stopped_trip` | [Trip Tracking](/geofencing/trips) | `[Radar] Stopped Trip` | | `user.entered_beacon` | [Beacons](/geofencing/beacons) | `[Radar] Beacon Entered` | | `user.exited_beacon` | [Beacons](/geofencing/beacons) | `[Radar] Beacon Exited` | ### \[Radar] Geofence Entered | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `Geofence ID` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `Geofence Description` | string | `"Store #123"` | | `geofence.tag` | `Geofence Tag` | string | `"store"` | | `geofence.externalId` | `Geofence External ID` | string | `"123"` | | `geofence.metadata[{key}]` | `Geofence Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Geofence Exited | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `Geofence ID` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `Geofence Description` | string | `"Store #123"` | | `geofence.tag` | `Geofence Tag` | string | `"store"` | | `geofence.externalId` | `Geofence External ID` | string | `"123"` | | `geofence.metadata[{key}]` | `Geofence Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | | `duration` | `Duration` | number (minutes) | `42.1` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Dwelled in Geofence | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `Geofence ID` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `Geofence Description` | string | `"Store #123"` | | `geofence.tag` | `Geofence Tag` | string | `"store"` | | `geofence.externalId` | `Geofence External ID` | string | `"123"` | | `geofence.metadata[{key}]` | `Geofence Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | | `duration` | `Duration` | number (minutes) | `5` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Place Entered | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `Place ID` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `Place Name` | string | `"Starbucks"` | | `place.chain.slug` | `Place Chain Slug` | string | `"starbucks"` | | `place.chain.name` | `Place Chain Name` | string | `"Starbucks"` | | `place.categories` | `Place Categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | | `confidence` | `Confidence` | string | `"high"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Place Exited | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `Place ID` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `Place Name` | string | `"Starbucks"` | | `place.chain.slug` | `Place Chain Slug` | string | `"starbucks"` | | `place.chain.name` | `Place Chain Name` | string | `"Starbucks"` | | `place.categories` | `Place Categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | | `confidence` | `Confidence` | string | `"high"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | | `duration` | `Duration` | number (minutes) | `42.1` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Country Entered | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"US"` | | `region.name` | `Region Name` | string | `"United States"` | | `confidence` | `Confidence` | string | `"high"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Country Exited | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"US"` | | `region.name` | `Region Name` | string | `"United States"` | | `confidence` | `Confidence` | string | `"high"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] State Entered | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"MD"` | | `region.name` | `Region Name` | string | `"Maryland"` | | `confidence` | `Confidence` | string | `"high"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] State Exited | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"MD"` | | `region.name` | `Region Name` | string | `"Maryland"` | | `confidence` | `Confidence` | string | `"high"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] DMA Entered | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"26"` | | `region.name` | `Region Name` | string | `"Baltimore"` | | `confidence` | `Confidence` | string | `"high"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] DMA Exited | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"26"` | | `region.name` | `Region Name` | string | `"Baltimore"` | | `confidence` | `Confidence` | string | `"high"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Started Trip | Radar Event Attribute | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Updated Trip | Radar Event Attribute | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Approaching Trip Destination | Radar Event Attribute | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Arrived at Trip Destination | Radar Event Attribute | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Stopped Trip | Radar Event Attribute | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `accuracy` | `Accuracy` | number (meters) | `5` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Beacon Entered | Radar Event Attribute | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `Beacon ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `Beacon Description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `Beacon Tag` | string | `"drive-thru"` | | `beacon.externalId` | `Beacon External ID` | string | `"123"` | | `beacon.metadata[{key}]` | `Beacon Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | ### \[Radar] Beacon Exited | Radar Event Attribute | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `Beacon ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `Beacon Description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `Beacon Tag` | string | `"drive-thru"` | | `beacon.externalId` | `Beacon External ID` | string | `"123"` | | `beacon.metadata[{key}]` | `Beacon Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | number (minutes) | `1.42` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Amplitude Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `Country Code` | string | `"US"` | | `country.name` | `Country Name` | string | `"United States"` | | `country._id` | `Country ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `state.code` | `State Code` | string | `"MD"` | | `state.name` | `State Name` | string | `"Maryland"` | | `state._id` | `State ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `dma.code` | `DMA Code` | string | `"26"` | | `dma.name` | `DMA Name` | string | `"Baltimore"` | | `dma._id` | `DMA ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `city.code` | `City Code` | string | `"_"` | | `city.name` | `City Name` | string | `"Tokyo"` | | `city._id` | `City ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `postalCode.code` | `Postal Code` | string | `"21014"` | | `postalCode._id` | `Postal Code ID` | string | `"5b2c0906f5874b001aecfd8f"` | # Attentive Source: https://docs.radar.com/integrations/attentive Send Radar location events and user attributes to Attentive to trigger location-based messages. > [!NOTE] > > The Attentive integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events and user attributes to [Attentive](https://www.attentivemobile.com/). Use the Attentive integration to send location-triggered and location-targeted messages to increase engagement and conversion. ## Configuration After logging in to the Attentive console, go to *Marketplace* and click *Create app*. Fill out the form to create your app, making sure to include the `Write` permission for *Custom Events*. Other permissions such as *Subscribers*, *Custom Attributes*, and *Identity* might be needed to assign users to subscription channels and modify their identifiers. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *Attentive*, set *Enabled* to *Yes* and paste your API key. Note that you can set separate API keys for the *Test* and *Live* environments. Whenever events are generated, Radar will send custom events and user mappings to Attentive. Once Attentive is receiving Radar custom events, set up a *Segment* or *Journey* to create triggers from those events to send messages. By default, Radar `userId` maps to Attentive `clientUserId`. However, you can specify custom mappings by setting Radar `metadata.attentiveUserId`. For example, on iOS: ```swift theme={null} // track users with a custom userId mapping (not required if using default mapping) Radar.setMetadata(["attentiveUserId": userId]) ``` ## Event mapping ### user.entered\_geofence | Radar Event Field | Attentive Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Attentive Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### user.exited\_geofence | Radar Event Field | Attentive Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Attentive Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### user.dwelled\_in\_geofence | Radar Event Field | Attentive Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `5` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Attentive Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### user.entered\_place | Radar Event Field | Attentive Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.chain.externalId` | `place_chain_external_id` | string | `"123"` | | `place.chain.metadata[{key}]` | `place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Attentive Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### user.exited\_place | Radar Event Field | Attentive Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.chain.externalId` | `place_chain_external_id` | string | `"123"` | | `place.chain.metadata[{key}]` | `place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Attentive Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### user.entered\_country | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_country | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_state | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_state | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_dma | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_dma | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.started\_trip | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.updated\_trip | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.approaching\_trip\_destination | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.arrived\_at\_trip\_destination | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.stopped\_trip | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_beacon | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_beacon | Radar Event Attribute | Attentive Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `beacon_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `radar_duration` | number (minutes) | `1.42` | | `foreground` | `foreground` | boolean | `true` | # AWS Pinpoint Source: https://docs.radar.com/integrations/aws-pinpoint Send Radar location events and user attributes to AWS Pinpoint to trigger location-based messages. > [!NOTE] > > The AWS Pinpoint integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events and user attributes to [AWS Pinpoint](https://aws.amazon.com/pinpoint/). Use the Pinpoint integration to send location-triggered and location-targeted messages to increase engagement and conversion. ## Configuration In the Pinpoint console page, under *All projects*, find your Project name and the corresponding Project ID. You will also need to get your access key and secret access key, which you can find under the AWS Identity and Access Management (IAM) console under Access Keys. Note that you will need to provide AWS keys that have IAM permissions for Pinpoint operations. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *AWS Pinpoint*, set *Enabled* to *Yes* and paste your AWS access key, your AWS secret key, and your Pinpoint Project ID. You can set separate access keys and project IDs for each of your Radar *Test* and *Live* environments. Finally, select your AWS region. Whenever events are generated, Radar will send custom events and user attributes to Pinpoint. Events and user attributes from iOS devices will be sent using your iOS app identifiers, and events and user attributes from Android devices will be sent using your Android app identifiers. To map a Radar user to a Pinpoint endpoint ID, you must specify a custom mapping by setting Radar `metadata.awsPinpointEndpointId`. For example, on iOS: ```swift theme={null} // track users with custom userId mapping (not required if using default mapping) Radar.setMetadata(["awsPinpointEndpointId": endpointid]) ``` ## User mapping Note that Radar uses the string `[]` to represent `null` user attribute values. | Radar User Field | Pinpoint User Attribute | Type | Example Value | Context Type | | - | - | - | - | - | | `userId` | `UserId` | string | `"1"` | | | `_id` | `RadarId` | array\[string] | `["5b2c0906f5874b001aecfd8d"]` | | | `location.coordinates[1]` | `RadarLocationLatitude` | array\[string] | `[39.525665]` | | | `location.coordinates[0]` | `RadarLocationLongitude` | array\[string] | `[-76.350663]` | | | `locationAuthorization` | `RadarLocationAuthorization` | array\[string] | `["GRANTED_FOREGROUND"]` | | | `locationAccuracyAuthorization` | `RadarLocationAccuracyAuthorization` | array\[string] | `["FULL"]` | | | `updatedAt` | `RadarUpdatedAt` | array\[string] | `["2018-06-22T15:23:39.000Z"]` | | | `segments[*].externalId` | `RadarSegmentExternalIds` | array\[string] | `["starbucks-visitors"]` | | | `topChains[*].slug` | `RadarTopChainSlugs` | array\[string] | `["starbucks", "walmart"]` | | | `topChains[*].externalId` | `RadarTopChainExternalIds` | array\[string] | `["123", "456"]` | | | `geofences[*]._id` | `RadarGeofenceIds` | array\[string] | `["5b2c0906f5874b001aecfd8e"]` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `RadarGeofenceDescriptions` | array\[string] | `["Store #123"]` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `RadarGeofenceTags` | array\[string] | `["store"]` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `RadarGeofenceExternalIds` | array\[string] | `["123"]` | [Geofences](/geofencing/geofences) | | `place._id` | `RadarPlaceId` | array\[string] | `["59302bcf8f27e8a156bd4f91"]` | [Places](/geofencing/places) | | `place.name` | `RadarPlaceName` | array\[string] | `["Starbucks"]` | [Places](/geofencing/places) | | `place.categories` | `RadarPlaceCategories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | [Places](/geofencing/places) | | `place.chain.slug` | `RadarPlaceChainId` | array\[string] | `["starbucks"]` | [Places](/geofencing/places) | | `place.chain.name` | `RadarPlaceChainName` | array\[string] | `["Starbucks"]` | [Places](/geofencing/places) | | `country.code` | `RadarRegionCountryCode` | array\[string] | `["US"]` | [Regions](/geofencing/regions) | | `country.name` | `RadarRegionCountryName` | array\[string] | `["United States"]` | [Regions](/geofencing/regions) | | `state.code` | `RadarRegionStateCode` | array\[string] | `["MD"]` | [Regions](/geofencing/regions) | | `state.name` | `RadarRegionStateName` | array\[string] | `["Maryland"]` | [Regions](/geofencing/regions) | | `dma.code` | `RadarRegionDmaCode` | array\[string] | `["26"]` | [Regions](/geofencing/regions) | | `dma.name` | `RadarRegionDmaName` | array\[string] | `["Baltimore"]` | [Regions](/geofencing/regions) | | `postalCode.code` | `RadarRegionPostalCode` | array\[string] | `["21014"]` | [Regions](/geofencing/regions) | | `trip.externalId` | `RadarTripExternalId` | array\[string] | `["299"]` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceTag` | `RadarTripDestinationGeofenceTag` | array\[string] | `["store"]` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `RadarTripDestinationGeofenceExternalId` | array\[string] | `["123"]` | [Trip Tracking](/geofencing/trips) | | `beacons[*]._id` | `RadarBeaconIds` | array\[string] | `["5b2c0906f5874b001aecfd8f"]` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `RadarBeaconDescriptions` | array\[string] | `["Store #123 - Drive-Thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `RadarBeaconTags` | array\[string] | `["drive-thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `RadarBeaconExternalIds` | array\[string] | `["123"]` | [Beacons](/geofencing/beacons) | ## Event mapping ### user.entered\_geofence | Radar Event Field | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `geofence._id` | `GeofenceId` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `GeofenceDescription` | string | `"Store #123"` | | `geofence.tag` | `GeofenceTag` | string | `"store"` | | `geofence.externalId` | `GeofenceExternalId` | string | `"123"` | | `geofence.metadata[{key}]` | `GeofenceMetadata{key}` | string | `"value"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `country.code` | `CountryCode` | string | `"US"` | | `country.name` | `CountryName` | string | `"United States"` | | `state.code` | `StateCode` | string | `"MD"` | | `state.name` | `StateName` | string | `"Maryland"` | | `dma.code` | `DmaCode` | string | `"26"` | | `dma.name` | `DmaName` | string | `"Baltimore"` | | `postalCode.code` | `PostalCode` | string | `"21014"` | ### user.exited\_geofence | Radar Event Field | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `geofence._id` | `GeofenceId` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `GeofenceDescription` | string | `"Store #123"` | | `geofence.tag` | `GeofenceTag` | string | `"store"` | | `geofence.externalId` | `GeofenceExternalId` | string | `"123"` | | `geofence.metadata[{key}]` | `GeofenceMetadata{key}` | string | `"value"` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | string | `"42.1"` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `country.code` | `CountryCode` | string | `"US"` | | `country.name` | `CountryName` | string | `"United States"` | | `state.code` | `StateCode` | string | `"MD"` | | `state.name` | `StateName` | string | `"Maryland"` | | `dma.code` | `DmaCode` | string | `"26"` | | `dma.name` | `DmaName` | string | `"Baltimore"` | | `postalCode.code` | `PostalCode` | string | `"21014"` | ### user.dwelled\_in\_geofence | Radar Event Field | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `geofence._id` | `GeofenceId` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `GeofenceDescription` | string | `"Store #123"` | | `geofence.tag` | `GeofenceTag` | string | `"store"` | | `geofence.externalId` | `GeofenceExternalId` | string | `"123"` | | `geofence.metadata[{key}]` | `GeofenceMetadata{key}` | string | `"value"` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | string | `"5"` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `country.code` | `CountryCode` | string | `"US"` | | `country.name` | `CountryName` | string | `"United States"` | | `state.code` | `StateCode` | string | `"MD"` | | `state.name` | `StateName` | string | `"Maryland"` | | `dma.code` | `DmaCode` | string | `"26"` | | `dma.name` | `DmaName` | string | `"Baltimore"` | | `postalCode.code` | `PostalCode` | string | `"21014"` | ### user.entered\_place | Radar Event Field | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `place._id` | `PlaceId` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `PlaceName` | string | `"Starbucks"` | | `place.chain.slug` | `PlaceChainId` | string | `"starbucks"` | | `place.chain.name` | `PlaceChainName` | string | `"Starbucks"` | | `place.chain.externalId` | `PlaceChainExternalId` | string | `"123"` | | `place.chain.metadata[{key}]` | `PlaceChainMetadata{key}` | string | `"value"` | | `place.categories` | `PlaceCategories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `country.code` | `CountryCode` | string | `"US"` | | `country.name` | `CountryName` | string | `"United States"` | | `state.code` | `StateCode` | string | `"MD"` | | `state.name` | `StateName` | string | `"Maryland"` | | `dma.code` | `DmaCode` | string | `"26"` | | `dma.name` | `DmaName` | string | `"Baltimore"` | | `postalCode.code` | `PostalCode` | string | `"21014"` | ### user.exited\_place | Radar Event Field | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `place._id` | `PlaceId` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `PlaceName` | string | `"Starbucks"` | | `place.chain.slug` | `PlaceChainId` | string | `"starbucks"` | | `place.chain.name` | `PlaceChainName` | string | `"Starbucks"` | | `place.chain.externalId` | `PlaceChainExternalId` | string | `"123"` | | `place.chain.metadata[{key}]` | `PlaceChainMetadata{key}` | string | `"string"` | | `place.categories` | `PlaceCategories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | string | `"42.1"` | | `foreground` | `Foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `country.code` | `CountryCode` | string | `"US"` | | `country.name` | `CountryName` | string | `"United States"` | | `state.code` | `StateCode` | string | `"MD"` | | `state.name` | `StateName` | string | `"Maryland"` | | `dma.code` | `DmaCode` | string | `"26"` | | `dma.name` | `DmaName` | string | `"Baltimore"` | | `postalCode.code` | `PostalCode` | string | `"21014"` | ### user.entered\_region\_country | Radar Event Attribute | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `region.code` | `RegionCode` | string | `"US"` | | `region.name` | `RegionName` | string | `"United States"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### user.exited\_region\_country | Radar Event Attribute | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `region.code` | `RegionCode` | string | `"US"` | | `region.name` | `RegionName` | string | `"United States"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### user.entered\_region\_state | Radar Event Attribute | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `region.code` | `RegionCode` | string | `"MD"` | | `region.name` | `RegionName` | string | `"Maryland"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### user.exited\_region\_state | Radar Event Attribute | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `region.code` | `RegionCode` | string | `"MD"` | | `region.name` | `RegionName` | string | `"Maryland"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### user.entered\_region\_dma | Radar Event Attribute | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `region.code` | `RegionCode` | string | `"26"` | | `region.name` | `RegionName` | string | `"Baltimore"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### user.exited\_region\_dma | Radar Event Attribute | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `region.code` | `RegionCode` | string | `"26"` | | `region.name` | `RegionName` | string | `"Baltimore"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### user.started\_trip | Radar Event Attribute | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `TripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `TripMetadata{key}` | string | `"value"` | | `trip.destinationGeofenceTag` | `TripDestinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `TripDestinationGeofenceExternalId` | string | `"123"` | | `foreground` | `Foreground` | boolean | `true` | ### user.approaching\_trip\_destination | Radar Event Attribute | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `TripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `TripMetadata{key}` | string | `"value"` | | `trip.destinationGeofenceTag` | `TripDestinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `TripDestinationGeofenceExternalId` | string | `"123"` | | `foreground` | `Foreground` | boolean | `true` | ### user.arrived\_at\_trip\_destination | Radar Event Attribute | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `TripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `TripMetadata{key}` | string | `"value"` | | `trip.destinationGeofenceTag` | `TripDestinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `TripDestinationGeofenceExternalId` | string | `"123"` | | `foreground` | `Foreground` | boolean | `true` | ### user.stopped\_trip | Radar Event Attribute | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `TripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `TripMetadata{key}` | string | `"value"` | | `trip.destinationGeofenceTag` | `TripDestinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `TripDestinationGeofenceExternalId` | string | `"123"` | | `foreground` | `Foreground` | boolean | `true` | ### user.entered\_beacon | Radar Event Attribute | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `beacon._id` | `BeaconId` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `BeaconDescription` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `BeaconTag` | string | `"drive-thru"` | | `beacon.externalId` | `BeaconExternalId` | string | `"123"` | | `beacon.metadata[{key}]` | `BeaconMetadata{key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### user.exited\_beacon | Radar Event Attribute | Pinpoint Event Attribute | Type | Example Value | | - | - | - | - | | `beacon._id` | `BeaconId` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `BeaconDescription` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `BeaconTag` | string | `"drive-thru"` | | `beacon.externalId` | `BeaconExternalId` | string | `"123"` | | `beacon.metadata[{key}]` | `BeaconMetadata{key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | number (minutes) | `1.42` | | `foreground` | `Foreground` | boolean | `true` | # AWS S3 Source: https://docs.radar.com/integrations/aws-s3 Stream Radar events and location data to an AWS S3 bucket for analysis in your own data systems. > [!NOTE] > > The AWS S3 integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can stream both events and locations to [AWS S3](https://aws.amazon.com/s3/). Use the AWS S3 integration to make Radar data available in a simple object storage format within your own systems, making your locations and events data more easily accessible by your engineers and data scientists. By having all of your event and location data in S3, you can integrate your location data with other analysis tools like AWS Athena or Snowflake. Files are delivered via an [AWS Kinesis Data Firehose](https://aws.amazon.com/kinesis/data-firehose/) as snappy-compressed parquet files. Each `/dt=YYYY-MM-DD/` folder will have multiple files in it. This format should be consumable out-of-the-box with Apache Spark, AWS Athena, or other data engineering tools. This can enable you to build custom dashboard visualizations of data like foot traffic, trip duration, or dwell time in a location. ## Configuration Contact your customer success manager to enable this feature. The AWS S3 integration uses an [AWS Kinesis Data Firehose](https://aws.amazon.com/kinesis/data-firehose/) to stream new Radar locations and events. The AWS Kinesis Data Firehose flushes data to your S3 bucket after 10 minutes or 128 MB of data, whichever happens first. Additionally, [AWS KMS](https://aws.amazon.com/kms/) can be used [to encrypt Kinesis data streams server-side](https://docs.aws.amazon.com/streams/latest/dev/server-side-encryption.html). ![Aws S3 Diagram Pn](https://mintcdn.com/radarlabs/f_3pYOJsnyPEyNca/images/aws-s3-diagram.png?fit=max\&auto=format\&n=f_3pYOJsnyPEyNca\&q=85\&s=2e9c453588741f59b6b34531186fd3c0) ### Create a bucket Create an S3 bucket for Radar to deliver data to, for example, `s3://com.example.bucket/`. Data will be delivered to `s3://com.example.bucket/radar/events/project=$PROJECT/dt=YYYY-MM-DD/X.parquet.snappy`. Provide the name of the bucket to your customer success manager. ### Create an AWS Cross-Account IAM policy Create an IAM Policy that allows Radar to deliver data to this bucket. To do this, implement step 2 in the [Cross-Account Delivery to an Amazon S3 Destination IAM Policy documentation](https://docs.aws.amazon.com/firehose/latest/dev/controlling-access.html#cross-account-delivery-s3). Radar will implement steps 1 and 3. Contact your Customer Support Manager to obtain the values for the `accountA-id` and `iam-role-name` values to use in the IAM Policy. ### Location Schema | Name | Type | Description | | - | - | - | | `locationid` | `string` | Unique ID of the location | | `userid` | `string` | Radar ID of user | | `userexternalid` | `string` | External ID of user | | `usermetadata` | `string` | Metadata of the user | | `organization` | `string` | Radar ID of the org | | `locationaccuracy` | `double` | The accuracy reported by the device in meters | | `updatedat` | `string` | Location update time | | `devicetype` | `string` | The type of device | | `live` | `boolean` | Live/test mode | | `foreground` | `boolean` | Did the user send up the location in foreground or background | | `stopped` | `boolean` | Did the user stop | | `sdkversion` | `string` | The Radar SDK version | | `floorlevel` | `double` | The floor level as reported by the device | | `altitude` | `double` | The altitude level as reported by the device | | `verticalaccuracy` | `double` | The altitude accuracy as reported by the device | | `latitude` | `double` | The latitude of the location | | `longitude` | `double` | The longitude of the location | | `timezoneoffset` | `int` | The timezone offset of the user | | `source` | `string` | The sdk source they generated the location | | `events` | `array` | A list of events associated with this location | | `sessionid` | `string` | The session id created by the SDK | | `appstandbybucket` | `int` | The App Standby Bucket as reported by the OS | | `locationauthorization` | `string` | What type of location authorization was granted? (e.g. foreground or background) | | `locationaccuracyauthorization` | `string` | How precise is the location granted? (e.g. precise location vs coarse location) | | `devicemake` | `string` | The make of the device | | `devicemodel` | `string` | The device model | | `deviceos` | `string` | The OS of the device | | `metadata` | `string` | Metadata such as tracking options used by the device | | `project` | `string` | Partition key. The Radar Project ID publishing locations | | `dt` | `string` | Partition key. The day of location delivery, formatted as YYYY-MM-DD | ### Event Schema | Name | Type | Description | | - | - | - | | `_id` | `string` | Radar ID of the event | | `createdat` | `timestamp` | Event creation time of the event from the Radar SDK | | `actualcreatedat` | `timestamp` | Event creation time on the server | | `organization` | `string` | The Radar organization ID | | `live` | `boolean` | Live/test mode | | `locationaccuracy` | `double` | The accuracy reported by the device in meters | | `confidence` | `int` | Event confidence | | `place` | `string` | The Radar ID of a place | | `placecategories` | `string` | The categories of the place | | `placechainname` | `string` | The chain name of the place | | `placechainslug` | `string` | The chain slug of the place | | `placegroup` | `string` | The group of the place | | `placename` | `string` | The name of the place | | `alternateplaces` | `array` | Alternate candidate places where the user entered | | `placecandidates` | `array` | Alternate candidate places where the user entered with extra metadata | | `duration` | `double` | The length of the geofence entry | | `longitude` | `double` | The longitude of the event | | `latitude` | `double` | The latitude of the event | | `user` | `string` | The Radar ID of the user | | `geofence` | `string` | The Radar ID of the geofence | | `geofencedescription` | `string` | The description of the geofence | | `geofencetag` | `string` | The tag of the geofence | | `geofenceexternalid` | `string` | The customer-provided ID of the geofence | | `region` | `string` | The Radar ID of the region | | `countryregionname` | `string` | The name of the country | | `countryregioncode` | `string` | The ISO code of the country | | `countryregion` | `string` | The Radar ID of the country | | `dmaregion` | `string` | The Radar ID of the DMA | | `dmaregionname` | `string` | The name of the DMA | | `dmaregioncode` | `string` | The ISO code of the DMA | | `stateregion` | `string` | The Radar ID of the state | | `stateregionname` | `string` | The name of the state | | `stateregioncode` | `string` | The ISO code of the state | | `postalcoderegion` | `string` | The Radar ID of the postal code | | `postalcoderegioncode` | `string` | The postal cod | | `replayed` | `boolean` | Did the SDK send this up in an event of a retry from a failed request | | `type` | `string` | The event type | | `timezoneoffset` | `int` | The timezone offset of the user | | `trip` | `string` | The Radar ID of the trip | | `beacon` | `string` | The Radar ID of the beacon | | `foreground` | `boolean` | Did the user send up the event in foreground or background | | `locationaccuracyauthorization` | `string` | How precise is the location granted? (e.g. precise location vs coarse location) | | `locationauthorization` | `string` | What type of location authorization was granted? (e.g. foreground or background) | | `devicetype` | `string` | The type of device | | `devicemake` | `string` | The make of the device | | `devicemodel` | `string` | The device model | | `deviceos` | `string` | The OS of the device | | `sdkversion` | `string` | The Radar SDK version | | `stopped` | `boolean` | Did the user stop | | `beacontag` | `string` | The tag of the beacon | | `beaconexternalid` | `string` | The customer-specified ID of the beacon | | `beacontype` | `string` | The type of beacon | | `beaconmajor` | `string` | The major version of the beacon | | \`beaconminor | `string` | The minor version of the beacon | | `beaconuuid` | `string` | The UUID of the beacon | | `tripexternalid` | `string` | The user-specified ID of the trip | | `tripdestinationgeofencetag` | `string` | The geofence tag of the trip destination | | `tripdestinationgeofenceexternalid` | `string` | The customer-specified geofence ID of the trip destination | | `userexternalid` | `string` | The user externalId specified by the customer | | `usermetadata` | `string` | User metadata as stringified JSON | | `traveling` | `string` | Whether a user is traveling or not | | `project` | `string` | Partition key. The Radar Project ID publishing events | | `dt` | `string` | Partition key. The day of event delivery, formatted as YYYY-MM-DD | # Branch Source: https://docs.radar.com/integrations/branch Send Radar location events to Branch to attribute offline actions to online campaigns. > [!NOTE] > > The Branch integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events to [Branch](https://branch.io). Use the Branch integration to attribute offline actions to online campaigns and measure the ROI of location-based features. ## Configuration On the Branch *Account Settings* page under *Profile*, copy your Branch key. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *Branch*, set *Enabled* to *Yes* and paste your key. Note that you can set separate keys for the *Test* and *Live* environments. Whenever events are generated, Radar will send custom events to Branch. ## User mapping Radar `deviceId` maps to `idfv` for iOS devices and `android_id` for Android devices in Branch. For web devices, set Radar `metadata.branchFingerprintId` to the Branch Browser Fingerprint Id. ```javascript theme={null} branch.getBrowserFingerprintId(function(err, data) { Radar.setMetadata({ 'branchFingerprintId': data }); }); ``` ## Event mapping | Radar Event | Context Type | Branch Event | | - | - | - | | `user.entered_geofence` | [Geofences](/geofencing/geofences) | `entered_geofence` | | `user.exited_geofence` | [Geofences](/geofencing/geofences) | `exited_geofence` | | `user.dwelled_in_geofence` | [Geofences](/geofencing/geofences) | `dwelled_in_geofence` | | `user.entered_place` | [Places](/geofencing/places) | `entered_place` | | `user.exited_place` | [Places](/geofencing/places) | `exited_place` | | `user.entered_region_country` | [Regions](/geofencing/regions) | `entered_country` | | `user.exited_region_country` | [Regions](/geofencing/regions) | `exited_country` | | `user.entered_region_state` | [Regions](/geofencing/regions) | `entered_state` | | `user.exited_region_state` | [Regions](/geofencing/regions) | `exited_state` | | `user.entered_region_dma` | [Regions](/geofencing/regions) | `entered_dma` | | `user.exited_region_dma` | [Regions](/geofencing/regions) | `exited_dma` | | `user.started_trip` | [Trip Tracking](/geofencing/trips) | `started_trip` | | `user.updated_trip` | [Trip Tracking](/geofencing/trips) | `updated_trip` | | `user.approaching_trip_destination` | [Trip Tracking](/geofencing/trips) | `approaching_trip_destination` | | `user.arrived_at_trip_destination` | [Trip Tracking](/geofencing/trips) | `arrived_at_trip_destination` | | `user.stopped_trip` | [Trip Tracking](/geofencing/trips) | `stopped_trip` | | `user.entered_beacon` | [Beacons](/geofencing/beacons) | `entered_beacon` | | `user.exited_beacon` | [Beacons](/geofencing/beacons) | `exited_beacon` | ### entered\_geofence | Radar Event Field | Branch Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Branch Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### exited\_geofence | Radar Event Field | Branch Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Branch Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### dwelled\_in\_geofence | Radar Event Field | Branch Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `5` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Branch Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### entered\_place | Radar Event Field | Branch Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.chain.externalId` | `place_chain_external_id` | string | `"123"` | | `place.chain.metadata[{key}]` | `place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Branch Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### exited\_place | Radar Event Field | Branch Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.chain.externalId` | `place_chain_external_id` | string | `"123"` | | `place.chain.metadata[{key}]` | `place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Branch Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"`(/regions) | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### entered\_country | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### exited\_country | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### entered\_state | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### exited\_state | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### entered\_dma | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### exited\_dma | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### started\_trip | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### updated\_trip | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### approaching\_trip\_destination | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### arrived\_at\_trip\_destination | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### stopped\_trip | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### entered\_beacon | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `beacon_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### exited\_beacon | Radar Event Attribute | Branch Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `beacon_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `1.42` | | `foreground` | `foreground` | boolean | `true` | # Brandify Source: https://docs.radar.com/integrations/brandify Sync store locations from Brandify into Radar as geofences. > [!NOTE] > > The Brandify integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can sync locations from [Brandify](http://www.brandify.com) as geofences in Radar, powered by [geofence sync](/geofencing/geofences#geofence-sync). ## Configuration Ask your Brandify account manager to enable a published CSV of your locations as Radar geofences. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *Geofence Sync*, set *Enabled* to *Yes*. Enter the published CSV URL. Note that you can set separate URLs for the *Test* and *Live* environments. The geofence sync CSV format is the same as the [geofence import CSV format](/geofencing/geofences#geofence-sync). When you click *Save and Sync*, Radar will attempt a one-time sync and send an email on success or failure. Radar will then attempt syncs nightly. # Braze Source: https://docs.radar.com/integrations/braze Send Radar location events and user attributes to Braze to trigger location-based messages and campaigns. > [!NOTE] > > The Braze integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events and user attributes to [Braze](https://www.braze.com). Use the Braze integration to send location-triggered and location-targeted messages to increase engagement and conversion. ## Configuration On the Braze *API Keys* page under *Rest API Keys*, create and copy a new workspace API key with `users.track` permissions. Under *Identification*, copy your iOS and Android app identifiers. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations#braze) under *Braze*, set *Enabled* to *Yes* and paste your API key and app identifiers. Note that you can set separate API keys and app identifiers for the *Test* and *Live* environments. Finally, if your account is not on `https://rest.iad-01.braze.com`, select the appropriate *API Endpoint*. Whenever events are generated, Radar will send custom events and user attributes to Braze. Events and user attributes from iOS devices will be sent using your iOS app identifiers, and events and user attributes from Android devices will be sent using your Android app identifiers. By default, Radar `userId` maps to Braze `external_id` for logged in users. However, you can track logged out users or specify custom mappings by setting Radar `metadata.brazeAlias` or `metadata.brazeExternalId`. If you set `metadata.brazeAlias`, you must also add a matching alias in Braze with label `radarAlias`. ```swift Swift theme={null} // track logged out users with alias (deviceId recommended, not required if not tracking logged out users) Radar.setMetadata(["brazeAlias": deviceId])AppDelegate.braze?.user.addAlias(deviceId, withLabel: "radarAlias") // track logged in users with custom external_id mapping (not required if using default mapping) Radar.setMetadata(["brazeExternalId": userId])AppDelegate.braze?.changeUser(userId: userId) ``` ```kotlin Kotlin theme={null} // track logged out users with alias (deviceId recommended, not required if not tracking logged out users) Radar.setMetadata(JSONObject().put("brazeAlias", deviceId))Braze.getInstance(context).currentUser?.addAlias(deviceId, "radarAlias") // track logged in users with custom external_id mapping (not required if using default mapping) Radar.setMetadata(JSONObject().put("brazeExternalId", userId))Braze.getInstance(context).changeUser(userId) ``` ## Verify integration data delivery To test that the integration is configured correctly and can deliver data, use the [Simulator](https://dashboard.radar.com/geofencing/simulate) to generate events. Click *View* on an event row and scroll down to the *Logs* section on the details page to verify delivery. Perform a similar process via a test app build with Radar location tracking enabled by spoofing location or moving into the relevant boundary. ![Verify Integration Braze Gi](https://mintcdn.com/radarlabs/PCH5QhbuqByAtU8d/images/verify_integration_braze.gif?s=fd9ac48a2f369fd87328b25fa7a5b8e4) All integration delivery can be monitored via the integration's event logs by clicking *View event logs* on the [Integrations page](https://dashboard.radar.com/integrations#braze). ## Example use cases ### Send a personalized push notification when a user arrives at a store 1. Create [Geofences](/geofencing/geofences) in Radar with the geofence tag set to `store`. The geofence tag will be used to trigger messages for the subset of geofence entries where this tag is present. 2. Set up a Braze campaign triggered from the Radar geofence entry event, the `entered_geofence` custom event in Braze, and add property filtering where `geofence_tag` is `store`. These same events can be used as part of a Braze [Canvas](https://www.braze.com/docs/user_guide/engagement_tools/canvas) and the event properties can be used in message personalization with [Liquid](https://www.braze.com/docs/user_guide/personalization_and_dynamic_content/liquid). ![Braze Radar Entered Geofence Pn](https://mintcdn.com/radarlabs/f_3pYOJsnyPEyNca/images/braze_radar_entered_geofence.png?fit=max\&auto=format\&n=f_3pYOJsnyPEyNca\&q=85\&s=a97a1e6ebbc5aa566855e67e59390fdf) ### Message all users nearby a store 1. Create [Geofences](/geofencing/geofences) in Radar to represent nearby store boundaries with geofence tag set to `nearby-store`. The geofence tag will be used to target messages for the subset of geofences where this tag is present. 2. Set up a Braze campaign targeted with the `radar_geofence_tags` user attribute that Radar sends. This will be an array of all geofences the user is currently in, so set the attribute to include the value of `nearby-store`. Additional attribute filtering can be performed for more complex targeting, including how recently the location was updated via the `radar_updated_at` user attribute. ![Braze Radar Targeted Messaging Pn](https://mintcdn.com/radarlabs/f_3pYOJsnyPEyNca/images/braze_radar_targeted_messaging.png?fit=max\&auto=format\&n=f_3pYOJsnyPEyNca\&q=85\&s=bedefd489a7b9e97ab78cc9e9469616d) ### In-app messaging To trigger in-app messaging from the user state detected on app open, custom events need to deliver through Braze's SDK rather than via Radar's server to server integration with Braze. To support this, implement custom logic in the SDK leveraging Radar's location update listener, on [iOS](/sdk/ios#install-sdk) or [Android](/sdk/android), to send foreground detections to Braze. The example code below assumes you are calling Radar.trackOnce() on application launch. See the [iOS](/sdk/ios) and [Android](/sdk/android) tracking references if needed. ```swift Swift theme={null} import RadarSDK import Appboy_iOS_SDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, RadarDelegate { func didUpdateLocation(_ location: CLLocation, user: RadarUser) { if user.foreground && user.source == RadarLocationSource.foregroundLocation { if let geofences = user.geofences { var customEventProperties = [String: [String]]() customEventProperties["radar_geofence_descriptions"] = geofences.compactMap({ $0.__description }) customEventProperties["radar_geofence_tags"] = geofences.compactMap({ $0.tag }) customEventProperties["radar_geofence_external_ids"] = geofences.compactMap({ $0.externalId }) Appboy.sharedInstance()?.logCustomEvent("radar_fg_geofences_entered", withProperties: customEventProperties) } if let place = user.place { var customEventProperties = [String: Any]() customEventProperties["radar_place_name"] = place.name customEventProperties["radar_place_categories"] = place.categories customEventProperties["radar_place_chain_slug"] = place.chain?.slug ?? "" Appboy.sharedInstance()?.logCustomEvent("radar_fg_place_entered", withProperties: customEventProperties) } } return } } ``` ```kotlin Kotlin theme={null} class MyRadarReceiver: RadarReceiver() { override fun onLocationUpdated(context: Context, location: Location, user: RadarUser) { val userGeofences = user.geofences val userPlace = user.place if (userGeofences != null && userGeofences.isNotEmpty()) { val eventPropertiesJson = JSONObject() eventPropertiesJson.put("geofenceTags", userGeofences.map { it.tag }) eventPropertiesJson.put("geofenceDescriptions", userGeofences.map { it.description }) eventPropertiesJson.put("geofenceExternalIds", userGeofences.map { it.externalId }) val eventProperties = BrazeProperties(eventPropertiesJson) Braze.getInstance(context).logCustomEvent("radar_fg_geofences_entered", eventProperties) } if (userPlace != null) { val eventPropertiesJson = JSONObject() eventPropertiesJson.put("placeChainSlug", userPlace.chain?.slug ?: "") eventPropertiesJson.put("placeName", userPlace.name) eventPropertiesJson.put("placeCategories", userPlace.categories.toList()) val eventProperties = BrazeProperties(eventPropertiesJson) Braze.getInstance(context).logCustomEvent("radar_fg_place_entered", eventProperties) } } } ``` ### Connected content [Radar APIs](/api) can be used in Braze connected content. See Braze's [documentation](https://www.braze.com/docs/partners/message_personalization/location/radar/#connected-content) for a connected content example. Use the [API explorer](https://dashboard.radar.com/maps/api-explorer) in the dashboard to test relevant APIs. ## User mapping Note that Radar uses the special string `"(null)"` to represent `null` user attribute values. | Radar User Field | Braze User Attribute | Type | Example Value | Context Type | | - | - | - | - | - | | `metadata.brazeExternalId` or `userId` | `external_id` | string | `"1"` | | | `metadata.brazeAlias` | `radarAlias` | string | `"10974a2ee035770b9"` | | | `location` | `current_location` | location | `(39.525665, -76.350663)` | | | `_id` | `radar_id` | string | `"5b2c0906f5874b001aecfd8d"` | | | `updatedAt` | `radar_updated_at` | timestamp | `"2018-06-22T15:23:39.000Z"` | | | `locationAuthorization` | `radar_location_authorization` | string | `"GRANTED_FOREGROUND"` | | | `locationAccuracyAuthorization` | `radar_location_accuracy_authorization` | string | `"FULL"` | | | `segments[*].externalId` | `radar_segment_external_ids` | array\[string] | `["starbucks-visitors"]` | | | `topChains[*].slug` | `radar_top_chain_slugs` | array\[string] | `["starbucks", "walmart"]` | | | `topChains[*].externalId` | `radar_top_chain_external_ids` | array\[string] | `["123", "456"]` | | | `geofences[*]._id` | `radar_geofence_ids` | array\[string] | `["5b2c0906f5874b001aecfd8e"]` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `radar_geofence_descriptions` | array\[string] | `["Store #123"]` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `radar_geofence_tags` | array\[string] | `["store"]` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `radar_geofence_external_ids` | array\[string] | `["123"]` | [Geofences](/geofencing/geofences) | | `place._id` | `radar_place_id` | string | `"59302bcf8f27e8a156bd4f91"` | [Places](/geofencing/places) | | `place.name` | `radar_place_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.categories` | `radar_place_categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | [Places](/geofencing/places) | | `place.chain.slug` | `radar_place_chain_id` | string | `"starbucks"` | [Places](/geofencing/places) | | `place.chain.name` | `radar_place_chain_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `country.code` | `radar_region_country_code` | string | `"US"` | [Regions](/geofencing/regions) | | `country.name` | `radar_region_country_name` | string | `"United States"` | [Regions](/geofencing/regions) | | `state.code` | `radar_region_state_code` | string | `"MD"` | [Regions](/geofencing/regions) | | `state.name` | `radar_region_state_name` | string | `"Maryland"` | [Regions](/geofencing/regions) | | `dma.code` | `radar_region_dma_code` | string | `"26"` | [Regions](/geofencing/regions) | | `dma.name` | `radar_region_dma_name` | string | `"Baltimore"` | [Regions](/geofencing/regions) | | `postalCode.code` | `radar_region_postal_code` | string | `"21014"` | [Regions](/geofencing/regions) | | `trip.externalId` | `radar_trip_external_id` | string | `"299"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceTag` | `radar_trip_destination_geofence_tag` | string | `"store"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `radar_trip_destination_geofence_external_id` | string | `"123"` | [Trip Tracking](/geofencing/trips) | | `beacons[*]._id` | `radar_beacon_ids` | array\[string] | `["5b2c0906f5874b001aecfd8f]"` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `radar_beacon_descriptions` | array\[string] | `["Store #123 - Drive-Thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `radar_beacon_tags` | array\[string] | `["drive-thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `radar_beacon_external_ids` | array\[string] | `["123"]` | [Beacons](/geofencing/beacons) | ## Event mapping | Radar Event | Context Type | Braze Event | | - | - | - | | `user.entered_geofence` | [Geofences](/geofencing/geofences) | `entered_geofence` | | `user.exited_geofence` | [Geofences](/geofencing/geofences) | `exited_geofence` | | `user.dwelled_in_geofence` | [Geofences](/geofencing/geofences) | `dwelled_in_geofence` | | `user.entered_place` | [Places](/geofencing/places) | `entered_place` | | `user.exited_place` | [Places](/geofencing/places) | `exited_place` | | `user.entered_region_country` | [Regions](/geofencing/regions) | `entered_country` | | `user.exited_region_country` | [Regions](/geofencing/regions) | `exited_country` | | `user.entered_region_state` | [Regions](/geofencing/regions) | `entered_state` | | `user.exited_region_state` | [Regions](/geofencing/regions) | `exited_state` | | `user.entered_region_dma` | [Regions](/geofencing/regions) | `entered_dma` | | `user.exited_region_dma` | [Regions](/geofencing/regions) | `exited_dma` | | `user.started_trip` | [Trip Tracking](/geofencing/trips) | `started_trip` | | `user.updated_trip` | [Trip Tracking](/geofencing/trips) | `updated_trip` | | `user.approaching_trip_destination` | [Trip Tracking](/geofencing/trips) | `approaching_trip_destination` | | `user.arrived_at_trip_destination` | [Trip Tracking](/geofencing/trips) | `arrived_at_trip_destination` | | `user.stopped_trip` | [Trip Tracking](/geofencing/trips) | `stopped_trip` | | `user.entered_beacon` | [Beacons](/geofencing/beacons) | `entered_beacon` | | `user.exited_beacon` | [Beacons](/geofencing/beacons) | `exited_beacon` | ### entered\_geofence | Radar Event Field | Braze Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Braze Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### exited\_geofence | Radar Event Field | Braze Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Braze Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### dwelled\_in\_geofence | Radar Event Field | Braze Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `5` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Braze Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### entered\_place | Radar Event Field | Braze Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.chain.externalId` | `place_chain_external_id` | string | `"123"` | | `place.chain.metadata[{key}]` | `place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Braze Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### exited\_place | Radar Event Field | Braze Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.chain.externalId` | `place_chain_external_id` | string | `"123"` | | `place.chain.metadata[{key}]` | `place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Braze Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### entered\_country | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### exited\_country | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### entered\_state | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### exited\_state | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### entered\_dma | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### exited\_dma | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### started\_trip | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### updated\_trip | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### approaching\_trip\_destination | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### arrived\_at\_trip\_destination | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### stopped\_trip | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### entered\_beacon | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `radar_beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `radar_beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `radar_beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `radar_beacon_metadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### exited\_beacon | Radar Event Attribute | Braze Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `radar_beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `radar_beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `radar_beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `radar_beacon_metadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `radar_duration` | number (minutes) | `1.42` | | `foreground` | `foreground` | boolean | `true` | # Census Source: https://docs.radar.com/integrations/census Sync locations from your data warehouse into Radar as geofences using Census. > [!NOTE] > > The Census integration is available on the [**Enterprise plan**](https://radar.com/pricing). With [Census](http://www.getcensus.com), Radar can sync locations stored in a data warehouse as geofences in Radar, powered by the [geofence upsert API](/api#upsert-a-geofence). Census supports syncing data from all major data warehouses, including Amazon Athena and Redshift, Snowflake, Azure Synapse, and Google BigQuery. ## Configuration First, in [Census](http://www.getcensus.com), add Radar as a service. Copy and paste your secret key from the Radar [dashboard](https://dashboard.radar.com). When naming the service, include a reference for the environment, `test` or `live`, that corresponds to the API key being used. ![Create geofence services](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/integrations/census/create-geofence-services.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=4ba4290e059a538a1a7e8a4bcb4bca38) Second, create a data model and connect your data warehouse as a source. ![Create Data Model Pn](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/integrations/census/create-data-model.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=028155de87f6dcf6490f7683aac8c8d7) Third, create a sync and map properties from the data model to [Radar geofence attributes](/geofencing/geofences#create-geofences) like `description`, `tag`, `externalId`, `type`, and `radius`. ![Map properties from the data model](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/integrations/census/map-properties.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=2270ac31a5b7725ec4d35307ed718d0f) Finally, schedule your sync. ![Schedule a sync](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/integrations/census/schedule-sync.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=79b883ec824682788fab17b45ff6990b) For more information, visit the [Census docs](https://www.getcensus.com/integrations/radar). # Cordial Source: https://docs.radar.com/integrations/cordial Send Radar location events and user attributes to Cordial to trigger location-based messages. > [!NOTE] > > The Cordial integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events and user attributes to [Cordial](https://cordial.com). Use the Cordial integration to send location-triggered and location-targeted messages to increase engagement and conversion. ## Configuration On the Cordial *API Keys* page, create and copy a new API key with *Contact Activities* permissions. Additionally, ask the Cordial team to create a secondary key for contacts (e.g., `emailHash`) that you can pass to Radar. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations#cordial) under *Cordial*, set *Enabled* to *Yes* and paste your API key. Note that you can set separate API keys and app identifiers for the *Test* and *Live* environments. Then, paste your async API endpoint, like `https://integrations-ingest-svc.usw2.cordial.com`. Finally, enter the secondary key. Whenever events are generated, Radar will send custom events and user attributes to Cordial. Set `metadata[cordial:{secondaryKey}]` to map Radar users to the secondary key on Cordial contacts. For example, if your secondary key is `emailHash`: ```swift Swift theme={null} Radar.setMetadata(["cordial:emailHash": emailHash]) ``` ```kotlin Kotlin theme={null} Radar.setMetadata(JSONObject().put("cordial:emailHash", emailHash)) ``` ## User mapping | Radar User Field | Cordial Contact Attribute | Type | Example Value | Context Type | | - | - | - | - | - | | `metadata[cordial:{secondaryKey}]` | `{secondaryKey}` | string | `"2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"` | | | `_id` | `radar_id` | string | `"5b2c0906f5874b001aecfd8d"` | | | `location` | `current_location` | location | `(39.525665, -76.350663)` | | | `locationAuthorization` | `radar_location_authorization` | string | `"GRANTED_FOREGROUND"` | | | `locationAccuracyAuthorization` | `radar_location_accuracy_authorization` | string | `"FULL"` | | | `updatedAt` | `radar_updated_at` | timestamp | `"2018-06-22T15:23:39.000Z"` | | | `segments[*].externalId` | `radar_segment_external_ids` | array\[string] | `["starbucks-visitors"]` | | | `topChains[*].slug` | `radar_top_chain_slugs` | array\[string] | `["starbucks", "walmart"]` | | | `topChains[*].externalId` | `radar_top_chain_external_ids` | array\[string] | `["123", "456"]` | | | `geofences[*]._id` | `radar_geofence_ids` | array\[string] | `["5b2c0906f5874b001aecfd8e"]` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `radar_geofence_descriptions` | array\[string] | `["Store #123"]` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `radar_geofence_tags` | array\[string] | `["store"]` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `radar_geofence_external_ids` | array\[string] | `["123"]` | [Geofences](/geofencing/geofences) | | `place._id` | `radar_place_id` | string | `"59302bcf8f27e8a156bd4f91"` | [Places](/geofencing/places) | | `place.name` | `radar_place_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.categories` | `radar_place_categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | [Places](/geofencing/places) | | `place.chain.slug` | `radar_place_chain_id` | string | `"starbucks"` | [Places](/geofencing/places) | | `place.chain.name` | `radar_place_chain_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `country.code` | `radar_region_country_code` | string | `"US"` | [Regions](/geofencing/regions) | | `country.name` | `radar_region_country_name` | string | `"United States"` | [Regions](/geofencing/regions) | | `state.code` | `radar_region_state_code` | string | `"MD"` | [Regions](/geofencing/regions) | | `state.name` | `radar_region_state_name` | string | `"Maryland"` | [Regions](/geofencing/regions) | | `dma.code` | `radar_region_dma_code` | string | `"26"` | [Regions](/geofencing/regions) | | `dma.name` | `radar_region_dma_name` | string | `"Baltimore"` | [Regions](/geofencing/regions) | | `postalCode.code` | `radar_region_postal_code` | string | `"21014"` | [Regions](/geofencing/regions) | | `trip.externalId` | `radar_trip_external_id` | string | `"299"` | [Trips](/geofencing/trips) | | `trip.destinationGeofenceTag` | `radar_trip_destination_geofence_tag` | string | `"store"` | [Trips](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `radar_trip_destination_geofence_external_id` | string | `"123"` | [Trips](/geofencing/trips) | | `beacons[*]._id` | `radar_beacon_ids` | array\[string] | `["5b2c0906f5874b001aecfd8f]"` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `radar_beacon_descriptions` | array\[string] | `["Store #123 - Drive-Thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `radar_beacon_tags` | array\[string] | `["drive-thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `radar_beacon_external_ids` | array\[string] | `["123"]` | [Beacons](/geofencing/beacons) | ## Event mapping | Radar Event | Context Type | Cordial Event | | - | - | - | | `user.entered_geofence` | [Geofences](/geofencing/geofences) | `entered_geofence` | | `user.exited_geofence` | [Geofences](/geofencing/geofences) | `exited_geofence` | | `user.dwelled_in_geofence` | [Geofences](/geofencing/geofences) | `dwelled_in_geofence` | | `user.entered_place` | [Places](/geofencing/places) | `entered_place` | | `user.exited_place` | [Places](/geofencing/places) | `exited_place` | | `user.entered_region_country` | [Regions](/geofencing/regions) | `entered_country` | | `user.exited_region_country` | [Regions](/geofencing/regions) | `exited_country` | | `user.entered_region_state` | [Regions](/geofencing/regions) | `entered_state` | | `user.exited_region_state` | [Regions](/geofencing/regions) | `exited_state` | | `user.entered_region_dma` | [Regions](/geofencing/regions) | `entered_dma` | | `user.exited_region_dma` | [Regions](/geofencing/regions) | `exited_dma` | | `user.started_trip` | [Trips](/geofencing/trips) | `started_trip` | | `user.updated_trip` | [Trips](/geofencing/trips) | `updated_trip` | | `user.approaching_trip_destination` | [Trips](/geofencing/trips) | `approaching_trip_destination` | | `user.arrived_at_trip_destination` | [Trips](/geofencing/trips) | `arrived_at_trip_destination` | | `user.stopped_trip` | [Trips](/geofencing/trips) | `stopped_trip` | | `user.entered_beacon` | [Beacons](/geofencing/beacons) | `entered_beacon` | | `user.exited_beacon` | [Beacons](/geofencing/beacons) | `exited_beacon` | ### entered\_geofence | Radar Event Field | Cordial Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Cordial Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### exited\_geofence | Radar Event Field | Cordial Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Cordial Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### dwelled\_in\_geofence | Radar Event Field | Cordial Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `5` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Cordial Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### entered\_place | Radar Event Field | Cordial Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.chain.externalId` | `place_chain_external_id` | string | `"123"` | | `place.chain.metadata[{key}]` | `place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Cordial Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### exited\_place | Radar Event Field | Cordial Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.chain.externalId` | `place_chain_external_id` | string | `"123"` | | `place.chain.metadata[{key}]` | `place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Cordial Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### entered\_country | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### exited\_country | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### entered\_state | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### exited\_state | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### entered\_dma | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### exited\_dma | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### started\_trip | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### updated\_trip | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### approaching\_trip\_destination | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### arrived\_at\_trip\_destination | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### stopped\_trip | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### entered\_beacon | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `radar_beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `radar_beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `radar_beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `radar_beacon_metadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### exited\_beacon | Radar Event Attribute | Cordial Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `radar_beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `radar_beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `radar_beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `radar_beacon_metadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `radar_duration` | number (minutes) | `1.42` | | `foreground` | `foreground` | boolean | `true` | # Integrations Source: https://docs.radar.com/integrations/integrations Overview of Radar's server-side integrations for sending events to other systems, syncing geofences, and sharing trip ETAs. Radar supports a number of server-side integrations. *Event integrations* like webhooks, mParticle, and Braze allow you to send events from Radar to other systems. *Geofence integrations* like geofence sync and Yext allow you to sync geofences from other systems to Radar. Finally, *trip integrations* allow you to [start and stop trips](/geofencing/trips) and send live ETAs to other platforms. ## **Event integrations** > [card] [Webhooks](/integrations/webhooks) > [card] [Braze](/integrations/braze) > [card] [Airship](/integrations/airship) > [card] [OneSignal](/integrations/onesignal) > [card] [mParticle](/integrations/mparticle) > [card] [Segment](/integrations/segment) > [card] [Branch](/integrations/branch) > [card] [Lytics](/integrations/lytics) > [card] [Iterable](/integrations/iterable) > [card] [Leanplum](/integrations/leanplum) > [card] [Salesforce](/integrations/salesforce) > [card] [Amplitude](/integrations/amplitude) > [card] [Mixpanel](/integrations/mixpanel) > [card] [Amazon Pinpoint](/integrations/aws-pinpoint) > [card] [Attentive](/integrations/attentive) > [card] [Cordial](/integrations/cordial) > [card] [MoEngage](/integrations/moengage) ### **Filters** Click *Show Advanced* on the [Integrations page](https://dashboard.radar.com/integrations) under an integration to show advanced filters. To filter event types sent to an integration, select or unselect event types under *Event Type Allowlist*. To filter keys from the request body sent to an integration, add keys, comma-separated, to *Request Key Blocklist*. For example, to skip sending `radar_geofence_ids` to the Segment `identify` call and to skip sending `geofence_id` to the Segment `track` call, add `radar_geofence_ids,geofence_id` to *Request Key Blocklist*. To filter events sent to an integration based upon a [Geofence](/geofencing/geofences) tag, add tags, comma-separated to *Geofence Tag Blocklist*. For example, to skip sending all events to the Amplitude integration for geofences tagged `gas-station` and `cafe`, add `gas-station,cafe` to *Geofence Tag Blocklist*. ## **Geofence integrations** *Geofence integrations* allow you to sync geofences from other systems to Radar. > [card] [Yext](/integrations/yext) > [card] [Brandify](/integrations/brandify) > [card] [Census](/integrations/census) ## **Trip integrations** > [card] [Olo](/integrations/olo) # Iterable Source: https://docs.radar.com/integrations/iterable Send Radar location events and user data to Iterable to trigger location-based messages. > [!NOTE] > > The Iterable integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send custom events and user data to [Iterable](https://iterable.com). Use the Iterable integration to send location-triggered and location-targeted messages to increase engagement and conversion. ## Configuration On the Iterable *API Keys* page, create and copy a Mobile API key. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *Iterable*, set *Enabled* to *Yes* and paste your key. Note that you can set separate keys for the *Test* and *Live* environments. Whenever events are generated, Radar will send custom events and user data to Iterable. User IDs must be aligned between Iterable and Radar for the integration to function properly. This is easiest if the user ID in matches the Iterable user ID. For example: ```swift Swift theme={null} IterableAPI.userId = userId Radar.setUserId(userId) let dataField = ["userId": userId] IterableAPI.updateUser(dataField, mergeNestedObjects: false) ``` ```kotlin Kotlin theme={null} IterableApi.getInstance().setUserId(userId) Radar.setUserId(userId) val dataFields = JSONObject() dataFields.put("userId",userId) IterableApi.getInstance().updateUser(dataFields) ``` If your Iterable user ID differs from your Radar user ID, you can instead specify the Iterable user ID in your user's metadata. When set, this value will be used as the `userId` in the Iterable integration instead of the Radar user ID. ```swift Swift theme={null} Radar.setMetadata(["iterable:user_id": iterableUserId]) ``` ```kotlin Kotlin theme={null} val metadata = JSONObject() metadata.put("iterable:user_id", iterableUserId) Radar.setMetadata(metadata) ``` ## Example use cases Learn how to create powerful location-based messaging campaigns using Radar and Iterable. ### Send a personalized push notification when user is near a store You'll need access to both Radar and Iterable to build this messaging campaign. In this campaign, we'll set up a simple push notification based on a Radar geofence entry event. #### Configure geofences in Radar 1. First, ensure your [Geofences](/geofencing/geofences) are configured in Radar. For a "nearby" use case, we typically suggest something like a 500 meter radius. You may also want to take advantage of *isochrone* (time-based) geofences, which would allow you to define, for example, a geofence with boundaries set to all points within a 10 minute walk from your target location. 2. Note the **tag** for the nearby geofences you've set up in step one. You can find your geofence tags in Radar by viewing your [geofences](https://dashboard.radar.com/geofencing/geofences). #### Create a new Journey in Iterable 3. In Iterable, navigate to [Journeys](https://app.iterable.com/workflows) and click **+ New journey**. For more on Journeys in Iterable, please refer to [Iterable's documentation](https://support.iterable.com/hc/en-us/articles/4405798856212-Introduction-to-Journeys-). 4. New Journeys in Iterable have a "start" node by default. Double click this node and change the **Received Api Trigger** dropdown value to **Triggered Custom Event**. Under *Event name*, start typing *Radar* and you should see a list of available events begin to auto-populate. Select *radarGeofenceEntered*. 5. Change the **Use Filter** option to *Yes*. 6. Where it says **Select a property**, start typing *RadarGeofence* and look for the *radarGeofenceEntered.geofenceTag* property. Set this property to *contain* (use Iterable's **Contains** operator) the tag you set up in step one and verified in step two. 7. Click **Update Node**. 8. Add a new node via Iterable's drag and drop functionality. For this example, drag in the **Send Push** node, then connect the *Start* node with the *Send Push* node. #### Set up a push notification template in Iterable 9. Now, we'll need to create an [Iterable Template](https://support.iterable.com/hc/en-us/articles/205480315-Introduction-to-Templates-) to create a personalized push to be used for this campaign. Navigate to Content -> Templates, and click **+ New template** -> **Push** -> **Create template** (giving it a name as needed). 10. We're going to customize the title of the Template using data from Radar so your message can say "You're near `{{Store name}}` ", with `{{Store name}}` representing the name of the nearby store whose geofence the user has entered. In the **Title** text box, enter `**{{radarGeofenceEntered.geofenceDescription}}**`. This syntax is called *Handlebar* notation. You can read more about it in Iterable's [documentation](https://support.iterable.com/hc/en-us/articles/205480365-Using-Merge-Parameters-and-Handlebars-Logic-for-Personalization). 11. Add in a Push message, then click **Save Template**. 12. Back in the *Journey*, double click on the **Send mobile push** node and change the template to the one you just created. #### Test your campaign To test this campaign, you can either trigger the Journey on a test app by moving physically into the geofence, *or* you can take advantage of the [Radar simulator](/geofencing/testing#simulator). The simulator allows you to simulate a specific user as if they were moving throughout the world. Navigate to the **Users** page in Radar and select a user who exists in Iterable and is linked via Radar user id. Then, click the *Simulate* button at the top of the page. Click around on the map and enter a geofence which will trigger the campaign you built in the steps above. If hooked up correctly, you should receive the relevant notification on your device. ### Filter users in an Iterable Journey whose last known location is X minutes away from a store You'll need access to both Radar and Iterable to build this messaging campaign. In this example, we'll set up a push campaign that is sent to users who have opened an email associated with a specific Iterable campaign **and** are within 10 minutes drive of a store. We can add isochrone (time-based) geofences (via import, the UI, or the API) in Radar to support this use case. #### Configure geofences in Radar 1. First, let's configure [Geofences](/geofencing/geofences) in Radar. Read more about creating geofences [here](/geofencing/geofences#create-geofences). Set up isochrone geofences with a 10 minute drive time. 2. Note the **tag** for the 10 minute drive geofences you've set up in step one. You can find your geofence tags in Radar by viewing your [geofences](https://dashboard.radar.com/geofencing/geofences). #### Create a new Journey in Iterable 3. In Iterable, navigate to [Journeys](https://app.iterable.com/workflows) and click **+ New journey**. For more on Journeys in Iterable, please refer to [Iterable's documentation](https://support.iterable.com/hc/en-us/articles/4405798856212-Introduction-to-Journeys-). 4. Iterable will start your Journey with a "start" node by default. Double click this node and change the **Received Api Trigger** dropdown value to **Opened An Email**. Select the campaign and filter as desired. Click **Update Node**. 5. Now, we'll add a new node that filters this initial trigger down based on Radar data. Under *Filters* on the left sidebar of Iterable's Journey builder, drag **Fields Match** in below the Start node. 6. Double click on this new **Filter users** node. Where it says *Choose a property*, select *Contact Property*. Type in *radarGeofenceTags*, and set it to *contain* (use Iterable's **Contains** operator) the tag you set up in step one and verified in step two. Click **Update Node**. 7. Connect the *Start* node with the *Filter users* node. #### Set up a push notification template in Iterable 8. Now, we'll need to create an [Iterable Template](https://support.iterable.com/hc/en-us/articles/205480315-Introduction-to-Templates-) to create a personalized push to be used for this campaign. Navigate to Content -> Templates, and click **+ New template** -> **Push** -> **Create template** (giving it a name as needed). 9. Add in a Push message, then click **Save Template**. 10. Back in the *Journey*, drag a *Send Push* action into the Journey builder. Double click on the **Send mobile push** node and change the template to the one you just created. Finally, drag from the *Yes* option under the *Filter users* node to the *Send Push* node to finish the Journey connection. #### Test your campaign To test this campaign, you can either trigger the Journey on a test app by moving physically into the geofence, *or* you can take advantage of the [Radar simulator](/geofencing/testing#simulator). The simulator allows you to simulate a specific user as if they were moving throughout the world. Navigate to the **Users** page in Radar and select a user who exists in Iterable and is linked via Radar user id. Then, click the *Simulate* button at the top of the page. Click around on the map and enter a geofence which will trigger the campaign you built in the steps above. If hooked up correctly, you should receive the relevant notification on your device. ## User mapping Note that Radar uses the special string `"(null)"` to represent `null` user data field values. | Radar User Field | Iterable User Data Field | Type | Example Value | Context Type | | - | - | - | - | - | | `userId` or `metadata['iterable:user_id']` | `userId` | string | `"1"` | | | `location.coordinates[0]` | `radar_geo_location.lon` | number | `-76.350663` | | | `location.coordinates[1]` | `radar_geo_location.lat` | number | `39.525665` | | | `locationAuthorization` | `radarLocationAuthorization` | string | `"GRANTED_FOREGROUND"` | | | `locationAccuracyAuthorization` | `radarLocationAccuracyAuthorization` | string | `"FULL"` | | | `_id` | `radarId` | string | `"5b2c0906f5874b001aecfd8d"` | | | `updatedAt` | `radarUpdatedAt` | timestamp | `"2018-06-22T15:23:39.000Z"` | | | `segments[*].externalId` | `radarSegmentExternalIds` | array\[string] | `["starbucks-visitors"]` | | | `topChains[*].slug` | `radarTopChainSlugs` | array\[string] | `["starbucks", "walmart"]` | | | `topChains[*].externalId` | `radarTopChainExternalIds` | array\[string] | `["123", "456"]` | | | `geofences[*]._id` | `radarGeofenceIds` | array\[string] | `["5b2c0906f5874b001aecfd8e"]` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `radarGeofenceDescriptions` | array\[string] | `["Store #123"]` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `radarGeofenceTags` | array\[string] | `["store"]` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `radarGeofenceExternalIds` | array\[string] | `["123"]` | [Geofences](/geofencing/geofences) | | `place._id` | `radarPlaceId` | string | `"59302bcf8f27e8a156bd4f91"` | [Places](/geofencing/places) | | `place.name` | `radarPlaceName` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.categories` | `radarPlaceCategories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | [Places](/geofencing/places) | | `place.chain.slug` | `radarPlaceChainSlug` | string | `"starbucks"` | [Places](/geofencing/places) | | `place.chain.name` | `radarPlaceChainName` | string | `"Starbucks"` | [Places](/geofencing/places) | | `country.code` | `radarRegionCountryCode` | string | `"US"` | [Regions](/geofencing/regions) | | `country.name` | `radarRegionCountryName` | string | `"United States"` | [Regions](/geofencing/regions) | | `state.code` | `radarRegionStateCode` | string | `"MD"` | [Regions](/geofencing/regions) | | `state.name` | `radarRegionStateName` | string | `"Maryland"` | [Regions](/geofencing/regions) | | `dma.code` | `radarRegionDMACode` | string | `"26"` | [Regions](/geofencing/regions) | | `dma.name` | `radarRegionDMAName` | string | `"Baltimore"` | [Regions](/geofencing/regions) | | `postalCode.code` | `radarRegionPostalCode` | string | `"21014"` | [Regions](/geofencing/regions) | | `trip.externalId` | `radarTripExternalId` | string | `"299"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceTag` | `radarTripDestinationGeofenceTag` | string | `"store"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `radarTripDestinationGeofenceExternalId` | string | `"123"` | [Trip Tracking](/geofencing/trips) | | `beacons[*]._id` | `radarBeaconIds` | array\[string] | `["5b2c0906f5874b001aecfd8f"]` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `radarBeaconDescriptions` | array\[string] | `["Store #123 - Drive-Thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `radarBeaconTags` | array\[string] | `["drive-thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `radarBeaconExternalIds` | array\[string] | `["123"]` | [Beacons](/geofencing/beacons) | ## Event mapping | Radar Event | Context Type | Iterable Event | | - | - | - | | `user.entered_geofence` | [Geofences](/geofencing/geofences) | `radarGeofenceEntered` | | `user.exited_geofence` | [Geofences](/geofencing/geofences) | `radarGeofenceExited` | | `user.dwelled_in_geofence` | [Geofences](/geofencing/geofences) | `radarDwelledInGeofence` | | `user.entered_place` | [Places](/geofencing/places) | `radarPlaceEntered` | | `user.exited_place` | [Places](/geofencing/places) | `radarPlaceExited` | | `user.entered_region_country` | [Regions](/geofencing/regions) | `radarCountryEntered` | | `user.exited_region_country` | [Regions](/geofencing/regions) | `radarCountryExited` | | `user.entered_region_state` | [Regions](/geofencing/regions) | `radarStateEntered` | | `user.exited_region_state` | [Regions](/geofencing/regions) | `radarStateExited` | | `user.entered_region_dma` | [Regions](/geofencing/regions) | `radarDMAEntered` | | `user.exited_region_dma` | [Regions](/geofencing/regions) | `radarDMAExited` | | `user.started_trip` | [Trip Tracking](/geofencing/trips) | `radarTripStarted` | | `user.updated_trip` | [Trip Tracking](/geofencing/trips) | `radarTripUpdated` | | `user.approaching_trip_destination` | [Trip Tracking](/geofencing/trips) | `radarApproachingTripDestination` | | `user.arrived_at_trip_destination` | [Trip Tracking](/geofencing/trips) | `radarArrivedTripDestination` | | `user.stopped_trip` | [Trip Tracking](/geofencing/trips) | `radarTripStopped` | | `user.entered_beacon` | [Beacons](/geofencing/beacons) | `radarBeaconEntered` | | `user.exited_beacon` | [Beacons](/geofencing/beacons) | `radarBeaconExited` | ### radarGeofenceEntered | Radar Event Field | Iterable Event Data Field | Type | Example | | - | - | - | - | | `geofence._id` | `geofenceId` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofenceDescription` | string | `"Store #123"` | | `geofence.tag` | `geofenceTag` | string | `"store"` | | `geofence.externalId` | `geofenceExternalId` | string | `"123"` | | `geofence.metadata[{key}]` | `geofenceMetadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### radarGeofenceExited | Radar Event Field | Iterable Event Data Field | Type | Example | | - | - | - | - | | `geofence._id` | `geofenceId` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofenceDescription` | string | `"Store #123"` | | `geofence.tag` | `geofenceTag` | string | `"store"` | | `geofence.externalId` | `geofenceExternalId` | string | `"123"` | | `geofence.metadata[{key}]` | `geofenceMetadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | ### radarDwelledInGeofence | Radar Event Field | Iterable Event Data Field | Type | Example | | - | - | - | - | | `geofence._id` | `geofenceId` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofenceDescription` | string | `"Store #123"` | | `geofence.tag` | `geofenceTag` | string | `"store"` | | `geofence.externalId` | `geofenceExternalId` | string | `"123"` | | `geofence.metadata[{key}]` | `geofenceMetadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `5` | | `foreground` | `foreground` | boolean | `true` | ### radarPlaceEntered | Radar Event Field | Iterable Event Data Field | Type | Example | | - | - | - | - | | `place._id` | `placeId` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `placeName` | string | `"Starbucks"` | | `place.chain.slug` | `placeChainSlug` | string | `"starbucks"` | | `place.chain.name` | `placeChainName` | string | `"Starbucks"` | | `place.categories` | `placeCategories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | | `place.chain.externalId` | `placeChainExternalId` | string | `"123"` | | `place.chain.metadata[{key}]` | `placeChainMetadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### radarPlaceExited | Radar Event Field | Iterable Event Data Field | Type | Example | | - | - | - | - | | `place._id` | `placeId` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `placeName` | string | `"Starbucks"` | | `place.chain.slug` | `placeChainSlug` | string | `"starbucks"` | | `place.chain.name` | `placeChainName` | string | `"Starbucks"` | | `place.categories` | `placeCategories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | | `place.chain.externalId` | `placeChainExternalId` | string | `"123"` | | `place.chain.metadata[{key}]` | `placeChainMetadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | ### radarCountryEntered | Radar Event Field | Iterable Event Data Field | Type | Example Value | | - | - | - | - | | `region.code` | `regionCode` | string | `"US"` | | `region.name` | `regionName` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### radarCountryExited | Radar Event Field | Iterable Event Data Field | Type | Example Value | | - | - | - | - | | `region.code` | `regionCode` | string | `"US"` | | `region.name` | `regionName` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### radarStateEntered | Radar Event Field | Iterable Event Data Field | Type | Example Value | | - | - | - | - | | `region.code` | `regionCode` | string | `"MD"` | | `region.name` | `regionName` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### radarStateExited | Radar Event Field | Iterable Event Data Field | Type | Example Value | | - | - | - | - | | `region.code` | `regionCode` | string | `"MD"` | | `region.name` | `regionName` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### radarDMAEntered | Radar Event Field | Iterable Event Data Field | Type | Example Value | | - | - | - | - | | `region.code` | `regionCode` | string | `"26"` | | `region.name` | `regionName` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### radarDMAExited | Radar Event Field | Iterable Event Data Field | Type | Example Value | | - | - | - | - | | `region.code` | `regionCode` | string | `"26"` | | `region.name` | `regionName` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### radarTripStarted | Radar Event Attribute | Iterable Event Data Field | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `tripMetadata{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `destinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `destinationGeofenceExternalId` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### radarApproachingTripDestination | Radar Event Attribute | Iterable Event Data Field | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `tripMetadata{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `destinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `destinationGeofenceExternalId` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### radarArrivedTripDestination | Radar Event Attribute | Iterable Event Data Field | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `tripMetadata{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `destinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `destinationGeofenceExternalId` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### radarTripStopped | Radar Event Attribute | Iterable Event Data Field | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `tripMetadata{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `destinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `destinationGeofenceExternalId` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### radarBeaconEntered | Radar Event Attribute | Iterable Event Data Field | Type | Example Value | | - | - | - | - | | `beacon._id` | `beaconId` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beaconDescription` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beaconTag` | string | `"drive-thru"` | | `beacon.externalId` | `beaconExternalId` | string | `"123"` | | `beacon.metadata[{key}]` | `beaconMetadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### radarBeaconExited | Radar Event Attribute | Iterable Event Data Field | Type | Example Value | | - | - | - | - | | `beacon._id` | `beaconId` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beaconDescription` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beaconTag` | string | `"drive-thru"` | | `beacon.externalId` | `beaconExternalId` | string | `"123"` | | `beacon.metadata[{key}]` | `beaconMetadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `1.42` | | `foreground` | `foreground` | boolean | `true` | # Leanplum Source: https://docs.radar.com/integrations/leanplum Send Radar location events and user attributes to Leanplum to trigger location-based messages. > [!NOTE] > > The Leanplum integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events and user attributes to [Leanplum](https://www.leanplum.com). Use the Leanplum integration to send location-triggered and location-targeted messages to increase engagement and conversion. ## Configuration On the Leanplum *App Settings* page, click *Keys & Settings* and copy the *App ID*, *Production Key*, and *Development Key*. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *Leanplum*, set *Enabled* to *Yes* and paste the app ID and API keys. The Radar *Test* environment automatically maps to the *Development* environment in Leanplum, and the Radar *Live* environment automatically maps to the *Production* environment in Leanplum. Whenever events are generated, Radar will call `track` and `setUserAttributes` to send events and user attributes to Leanplum. ## User mapping Note that Radar uses the special string `"(null)"` to represent `null` user attribute values. | Radar User Field | Leanplum User Attribute | Type | Example Value | Context Type | | - | - | - | - | - | | `userId` | `Distinct ID` | string | `"1"` | | | `location.coordinates[0]` | `Radar Location Longitude` | number | `-76.350663` | | | `location.coordinates[1]` | `Radar Location Latitude` | number | `39.525665` | | | `locationAuthorization` | `Radar Location Authorization` | string | `"GRANTED_FOREGROUND"` | | | `locationAccuracyAuthorization` | `Radar Location Accuracy Authorization` | string | `"FULL"` | | | `_id` | `Radar ID` | string | `"5b2c0906f5874b001aecfd8d"` | | | `segments[*].externalId` | `Radar Segment External IDs` | array\[string] | `["starbucks-visitors"]` | | | `topChains[*].slug` | `Radar Top Chain Slugs` | array\[string] | `["starbucks", "walmart"]` | | | `topChains[*].externalId` | `Radar Top Chain External IDs` | array\[string] | `["123", "456"]` | | | `geofences[*]._id` | `Radar Geofence IDs` | array\[string] | `["5b2c0906f5874b001aecfd8e"]` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `Radar Geofence Descriptions` | array\[string] | `["Store #123"]` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `Radar Geofence Tags` | array\[string] | `["store"]` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `Radar Geofence External IDs` | array\[string] | `["123"]` | [Geofences](/geofencing/geofences) | | `place._id` | `Radar Place ID` | string | `"59302bcf8f27e8a156bd4f91"` | [Places](/geofencing/places) | | `place.name` | `Radar Place Name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.categories` | `Radar Place Categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | [Places](/geofencing/places) | | `place.chain.slug` | `Radar Place Chain Slug` | string | `"starbucks"` | [Places](/geofencing/places) | | `place.chain.name` | `Radar Place Chain Name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.chain.externalId` | `Radar Place Chain External ID` | string | `"123"` | [Places](/geofencing/places) | | `country.code` | `Radar Region Country Code` | string | `"US"` | [Regions](/geofencing/regions) | | `country.name` | `Radar Region Country Name` | string | `"United States"` | [Regions](/geofencing/regions) | | `state.code` | `Radar Region State Code` | string | `"MD"` | [Regions](/geofencing/regions) | | `state.name` | `Radar Region State Name` | string | `"Maryland"` | [Regions](/geofencing/regions) | | `dma.code` | `Radar Region DMA Code` | string | `"26"` | [Regions](/geofencing/regions) | | `dma.name` | `Radar Region DMA Name` | string | `"Baltimore"` | [Regions](/geofencing/regions) | | `postalCode.code` | `Radar Region Postal Code` | string | `"21014"` | [Regions](/geofencing/regions) | | `trip.externalId` | `Radar Trip External ID` | string | `"299"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceTag` | `Radar Trip Destination Geofence Tag` | string | `"store"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `Radar Trip Destination Geofence External ID` | string | `"123"` | [Trip Tracking](/geofencing/trips) | | `beacons[*]._id` | `Radar Beacon IDs` | array\[string] | `["5b2c0906f5874b001aecfd8f"]` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `Radar Beacon Descriptions` | array\[string] | `["Store #123 - Drive-Thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `Radar Beacon Tags` | array\[string] | `["drive-thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `Radar Beacon External IDs` | array\[string] | `["123"]` | [Beacons](/geofencing/beacons) | ## Event mapping | Radar Event | Context Type | Leanplum Event | | - | - | - | | `user.entered_geofence` | [Geofences](/geofencing/geofences) | `Radar Geofence Entered` | | `user.exited_geofence` | [Geofences](/geofencing/geofences) | `Radar Geofence Exited` | | `user.dwelled_in_geofence` | [Geofences](/geofencing/geofences) | `Radar Dwelled in Geofence` | | `user.entered_place` | [Places](/geofencing/places) | `Radar Place Entered` | | `user.exited_place` | [Places](/geofencing/places) | `Radar Place Exited` | | `user.entered_region_country` | [Regions](/geofencing/regions) | `Radar Country Entered` | | `user.exited_region_country` | [Regions](/geofencing/regions) | `Radar Country Exited` | | `user.entered_region_state` | [Regions](/geofencing/regions) | `Radar State Entered` | | `user.exited_region_state` | [Regions](/geofencing/regions) | `Radar State Exited` | | `user.entered_region_dma` | [Regions](/geofencing/regions) | `Radar DMA Entered` | | `user.exited_region_dma` | [Regions](/geofencing/regions) | `Radar DMA Exited` | | `user.started_trip` | [Trip Tracking](/geofencing/trips) | `Radar Started Trip` | | `user.updated_trip` | [Trip Tracking](/geofencing/trips) | `Radar Updated Trip` | | `user.approaching_trip_destination` | [Trip Tracking](/geofencing/trips) | `Radar Approaching Trip Destination` | | `user.arrived_at_trip_destination` | [Trip Tracking](/geofencing/trips) | `Radar Arrived at Trip Destination` | | `user.stopped_trip` | [Trip Tracking](/geofencing/trips) | `Radar Stopped Trip` | | `user.entered_beacon` | [Beacons](/geofencing/beacons) | `Radar Beacon Entered` | | `user.exited_beacon` | [Beacons](/geofencing/beacons) | `Radar Beacon Exited` | ### Radar Geofence Entered | Radar Event Field | Leanplum Event Parameter | Type | Example | | - | - | - | - | | `geofence._id` | `Geofence ID` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `Geofence Description` | string | `"Store #123"` | | `geofence.tag` | `Geofence Tag` | string | `"store"` | | `geofence.externalId` | `Geofence External ID` | string | `"123"` | | `geofence.metadata[{key}]` | `Geofence Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar Geofence Exited | Radar Event Field | Leanplum Event Parameter | Type | Example | | - | - | - | - | | `geofence._id` | `Geofence ID` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `Geofence Description` | string | `"Store #123"` | | `geofence.tag` | `Geofence Tag` | string | `"store"` | | `geofence.externalId` | `Geofence External ID` | string | `"123"` | | `geofence.metadata[{key}]` | `Geofence Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | number (minutes) | `42.1` | | `foreground` | `Foreground` | boolean | `true` | ### Radar Dwelled in Geofence | Radar Event Field | Leanplum Event Parameter | Type | Example | | - | - | - | - | | `geofence._id` | `Geofence ID` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `Geofence Description` | string | `"Store #123"` | | `geofence.tag` | `Geofence Tag` | string | `"store"` | | `geofence.externalId` | `Geofence External ID` | string | `"123"` | | `geofence.metadata[{key}]` | `Geofence Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | number (minutes) | `5` | | `foreground` | `Foreground` | boolean | `true` | ### Radar Place Entered | Radar Event Field | Leanplum Event Parameter | Type | Example | | - | - | - | - | | `place._id` | `Place ID` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `Place Name` | string | `"Starbucks"` | | `place.chain.slug` | `Place Chain ID` | string | `"starbucks"` | | `place.chain.name` | `Place Chain Name` | string | `"Starbucks"` | | `place.categories` | `Place Categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar Place Exited | Radar Event Field | Leanplum Event Parameter | Type | Example | | - | - | - | - | | `place._id` | `Place ID` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `Place Name` | string | `"Starbucks"` | | `place.chain.slug` | `Place Chain ID` | string | `"starbucks"` | | `place.chain.name` | `Place Chain Name` | string | `"Starbucks"` | | `place.categories` | `Place Categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | number (minutes) | `42.1` | | `foreground` | `Foreground` | boolean | `true` | ### Radar Country Entered | Radar Event Field | Leanplum Event Parameter | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"US"` | | `region.name` | `Region Name` | string | `"United States"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar Country Exited | Radar Event Field | Leanplum Event Parameter | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"US"` | | `region.name` | `Region Name` | string | `"United States"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar State Entered | Radar Event Field | Leanplum Event Parameter | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"MD"` | | `region.name` | `Region Name` | string | `"Maryland"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar State Exited | Radar Event Field | Leanplum Event Parameter | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"MD"` | | `region.name` | `Region Name` | string | `"Maryland"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar DMA Entered | Radar Event Field | Leanplum Event Parameter | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"26"` | | `region.name` | `Region Name` | string | `"Baltimore"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar DMA Exited | Radar Event Field | Leanplum Event Parameter | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"26"` | | `region.name` | `Region Name` | string | `"Baltimore"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar Started Trip | Radar Event Attribute | Leanplum Event Parameter | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar Approaching Trip Destination | Radar Event Attribute | Leanplum Event Parameter | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar Arrived at Trip Destination | Radar Event Attribute | Leanplum Event Parameter | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar Stopped Trip | Radar Event Attribute | Leanplum Event Parameter | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar Beacon Entered | Radar Event Attribute | Leanplum Event Parameter | Type | Example Value | | - | - | - | - | | `beacon._id` | `Beacon ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `Beacon Description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `Beacon Tag` | string | `"drive-thru"` | | `beacon.externalId` | `Beacon External ID` | string | `"123"` | | `beacon.metadata[{key}]` | `Beacon Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | boolean | `true` | ### Radar Beacon Exited | Radar Event Attribute | Leanplum Event Parameter | Type | Example Value | | - | - | - | - | | `beacon._id` | `Beacon ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `Beacon Description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `Beacon Tag` | string | `"drive-thru"` | | `beacon.externalId` | `Beacon External ID` | string | `"123"` | | `beacon.metadata[{key}]` | `Beacon Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | number (minutes) | `1.42` | | `foreground` | `Foreground` | boolean | `true` | # Lytics Source: https://docs.radar.com/integrations/lytics Send Radar location events and user state to Lytics to build location-based user segments. > [!NOTE] > > The Lytics integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events and user state to [Lytics](https://www.lytics.com). Use the Lytics integration to build location-based user segments. ## Configuration Before enabling the integration, contact your Lytics account manager. After Lytics is configured, in Lytics, [create an API token](https://learn.lytics.com/understanding/product-docs/account-management/managing-api-tokens#creating-a-new-api-token) with no expiration and the *Data Manager* role. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *Lytics*, set *Enabled* to *Yes*, paste your API token. Note that you can set separate API tokens and stream names for the *Test* and *Live* environments. Whenever events are generated, Radar will send events to the `radar_events` stream and user state to the `radar_users` stream. ## User mapping Note that Radar uses the special string `"(null)"` to represent `null` user data field values. | Radar User Field | Lytics User Data Field | Type | Example Value | Context Type | | - | - | - | - | - | | `userId` | `radarUserId` | string | `"1"` | | | `deviceId` | `radarDeviceId` | string | `"10974a2ee035770b9"` | | | `location.coordinates[0]` | `radarLocationLongitude` | number | `-76.350663` | | | `location.coordinates[1]` | `radarLocationLatitude` | number | `39.525665` | | | `locationAuthorization` | `radarLocationAuthorization` | string | `"GRANTED_FOREGROUND"` | | | `locationAccuracyAuthorization` | `radarLocationAccuracyAuthorization` | string | `"FULL"` | | | `_id` | `radarId` | string | `"5b2c0906f5874b001aecfd8d"` | | | `updatedAt` | `radarUpdatedAt` | timestamp | `"2018-06-22T15:23:39.000Z"` | | | `segments[*].externalId` | `radarSegmentExternalIds` | array\[string] | `["starbucks-visitors"]` | | | `topChains[*].slug` | `radarTopChainSlugs` | array\[string] | `["starbucks", "walmart"]` | | | `topChains[*].externalId` | `radarTopChainExternalIds` | array\[string] | `["123", "456"]` | | | `geofences[*]._id` | `radarGeofenceIds` | array\[string] | `["5b2c0906f5874b001aecfd8e"]` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `radarGeofenceDescriptions` | array\[string] | `["Store #123"]` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `radarGeofenceTags` | array\[string] | `["store"]` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `radarGeofenceExternalIds` | array\[string] | `["123"]` | [Geofences](/geofencing/geofences) | | `place._id` | `radarPlaceId` | string | `"59302bcf8f27e8a156bd4f91"` | [Places](/geofencing/places) | | `place.name` | `radarPlaceName` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.categories` | `radarPlaceCategories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | [Places](/geofencing/places) | | `place.chain.slug` | `radarPlaceChainSlug` | string | `"starbucks"` | [Places](/geofencing/places) | | `place.chain.name` | `radarPlaceChainName` | string | `"Starbucks"` | [Places](/geofencing/places) | | `country.code` | `radarRegionCountryCode` | string | `"US"` | [Regions](/geofencing/regions) | | `country.name` | `radarRegionCountryName` | string | `"United States"` | [Regions](/geofencing/regions) | | `state.code` | `radarRegionStateCode` | string | `"MD"` | [Regions](/geofencing/regions) | | `state.name` | `radarRegionStateName` | string | `"Maryland"` | [Regions](/geofencing/regions) | | `dma.code` | `radarRegionDMACode` | string | `"26"` | [Regions](/geofencing/regions) | | `dma.name` | `radarRegionDMAName` | string | `"Baltimore"` | [Regions](/geofencing/regions) | | `postalCode.code` | `radarRegionPostalCode` | string | `"21014"` | [Regions](/geofencing/regions) | | `trip.externalId` | `radarTripExternalId` | string | `"299"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceTag` | `radarTripDestinationGeofenceTag` | string | `"store"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `radarTripDestinationGeofenceExternalId` | string | `"123"` | [Trip Tracking](/geofencing/trips) | | `beacons[*]._id` | `radarBeaconIds` | array\[string] | `["5b2c0906f5874b001aecfd8f"]` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `radarBeaconDescriptions` | array\[string] | `["Store #123 - Drive-Thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `radarBeaconTags` | array\[string] | `["drive-thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `radarBeaconExternalIds` | array\[string] | `["123"]` | [Beacons](/geofencing/beacons) | ## Event mapping ### user.entered\_geofence | Radar Event Field | Lytics Event Data Field | Type | Example | | - | - | - | - | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `geofence._id` | `geofenceId` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofenceDescription` | string | `"Store #123"` | | `geofence.tag` | `geofenceTag` | string | `"store"` | | `geofence.externalId` | `geofenceExternalId` | string | `"123"` | | `geofence.metadata[{key}]` | `geofenceMetadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_geofence | Radar Event Field | Lytics Event Data Field | Type | Example | | - | - | - | - | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `geofence._id` | `geofenceId` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofenceDescription` | string | `"Store #123"` | | `geofence.tag` | `geofenceTag` | string | `"store"` | | `geofence.externalId` | `geofenceExternalId` | string | `"123"` | | `geofence.metadata[{key}]` | `geofenceMetadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | ### user.dwelled\_in\_geofence | Radar Event Field | Lytics Event Data Field | Type | Example | | - | - | - | - | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `geofence._id` | `geofenceId` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofenceDescription` | string | `"Store #123"` | | `geofence.tag` | `geofenceTag` | string | `"store"` | | `geofence.externalId` | `geofenceExternalId` | string | `"123"` | | `geofence.metadata[{key}]` | `geofenceMetadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `5` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_place | Radar Event Field | Lytics Event Data Field | Type | Example | | - | - | - | - | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `place._id` | `placeId` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `placeName` | string | `"Starbucks"` | | `place.chain.slug` | `placeChainSlug` | string | `"starbucks"` | | `place.chain.name` | `placeChainName` | string | `"Starbucks"` | | `place.categories` | `placeCategories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_place | Radar Event Field | Lytics Event Data Field | Type | Example | | - | - | - | - | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `place._id` | `placeId` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `placeName` | string | `"Starbucks"` | | `place.chain.slug` | `placeChainSlug` | string | `"starbucks"` | | `place.chain.name` | `placeChainName` | string | `"Starbucks"` | | `place.categories` | `placeCategories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_region\_country | Radar Event Field | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `region.code` | `regionCode` | string | `"US"` | | `region.name` | `regionName` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_region\_country | Radar Event Field | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `region.code` | `regionCode` | string | `"US"` | | `region.name` | `regionName` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_region\_state | Radar Event Field | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `region.code` | `regionCode` | string | `"MD"` | | `region.name` | `regionName` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_region\_state | Radar Event Field | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `region.code` | `regionCode` | string | `"MD"` | | `region.name` | `regionName` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_region\_dma | Radar Event Field | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `region.code` | `regionCode` | string | `"26"` | | `region.name` | `regionName` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_region\_dma | Radar Event Field | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `region.code` | `regionCode` | string | `"26"` | | `region.name` | `regionName` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.started\_trip | Radar Event Attribute | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `tripMetadata{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `tripDestinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `tripDestinationGeofenceExternalId` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.updated\_trip | Radar Event Attribute | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `tripMetadata{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `tripDestinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `tripDestinationGeofenceExternalId` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.approaching\_trip\_destination | Radar Event Attribute | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `tripMetadata{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `tripDestinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `tripDestinationGeofenceExternalId` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.arrived\_at\_trip\_destination | Radar Event Attribute | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `tripMetadata{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `tripDestinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `tripDestinationGeofenceExternalId` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.stopped\_trip | Radar Event Attribute | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string | `"299"` | | `trip.metadata[{key}]` | `tripMetadata{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `tripDestinationGeofenceTag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `tripDestinationGeofenceExternalId` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_beacon | Radar Event Attribute | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `beacon._id` | `beaconId` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beaconDescription` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beaconTag` | string | `"drive-thru"` | | `beacon.externalId` | `beaconExternalId` | string | `"123"` | | `beacon.metadata[{key}]` | `beaconMetadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_beacon | Radar Event Attribute | Lytics Event Data Field | Type | Example Value | | - | - | - | - | | `beacon._id` | `beaconId` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beaconDescription` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beaconTag` | string | `"drive-thru"` | | `beacon.externalId` | `beaconExternalId` | string | `"123"` | | `beacon.metadata[{key}]` | `beaconMetadata{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `1.42` | | `foreground` | `foreground` | boolean | `true` | # Mixpanel Source: https://docs.radar.com/integrations/mixpanel Send Radar location events and user properties to Mixpanel to add location context to analytics and build user segments. > [!NOTE] > > The Mixpanel integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events and user properties to [Mixpanel](https://www.mixpanel.com). Use the Mixpanel integration to enrich behavioral events with location context, measure the ROI of location-based features, and build location-based user segments. ## Configuration On the Mixpanel *Project Settings* page, copy the token from the Access Keys section. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *Mixpanel*, set *Enabled* to *Yes* and paste your token. Note that you can set separate tokens for the *Test* and *Live* environments. Whenever events are generated, Radar will send custom events and user properties to Mixpanel. By default, Radar `userId` maps to Mixpanel `distinct ID` for logged in users. However, you can specify a custom mapping by setting Radar `metadata.mixpanelDistinctId`. For example, on iOS: ```swift theme={null} Radar.setMetadata(["mixpanelDistinctId": distinctIdValue]) ``` ## User mapping Note that Radar uses the special string `"(null)"` to represent `null` user property values. | Radar User Field | Mixpanel User Property | Type | Example Value | Context Type | | - | - | - | - | - | | `location.coordinates[1]` | `$latitude` | number | `39.525665` | | | `location.coordinates[0]` | `$longitude` | number | `-76.350663` | | | `metadata.mixpanelDistinctId` or `userId` | `Distinct ID` | string | `"1"` | | | `location.coordinates[0]` | `Radar Location Longitude` | number | `-76.350663` | | | `location.coordinates[1]` | `Radar Location Latitude` | number | `39.525665` | | | `locationAuthorization` | `Radar Location Authorization` | string | `"GRANTED_FOREGROUND"` | | | `locationAccuracyAuthorization` | `Radar Location Accuracy Authorization` | string | `"FULL"` | | | `_id` | `Radar ID` | string | `"5b2c0906f5874b001aecfd8d"` | | | `updatedAt` | `Radar Updated At` | timestamp | `"2018-06-22T15:23:39.000Z"` | | | `segments[*].externalId` | `Radar Segment External IDs` | array\[string] | `["starbucks-visitors"]` | | | `topChains[*].slug` | `Radar Top Chain Slugs` | array\[string] | `["starbucks", "walmart"]` | | | `topChains[*].externalId` | `Radar Top Chain External IDs` | array\[string] | `["123", "456"]` | | | `geofences[*]._id` | `Radar Geofence IDs` | array\[string] | `["5b2c0906f5874b001aecfd8e"]` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `Radar Geofence Descriptions` | array\[string] | `["Store #123"]` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `Radar Geofence Tags` | array\[string] | `["store"]` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `Radar Geofence External IDs` | array\[string] | `["123"]` | [Geofences](/geofencing/geofences) | | `place._id` | `Radar Place ID` | string | `"59302bcf8f27e8a156bd4f91"` | [Places](/geofencing/places) | | `place.name` | `Radar Place Name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.categories` | `Radar Place Categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | [Places](/geofencing/places) | | `place.chain.slug` | `Radar Place Chain Slug` | string | `"starbucks"` | [Places](/geofencing/places) | | `place.chain.name` | `Radar Place Chain Name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `country.code` | `Radar Region Country Code` | string | `"US"` | [Regions](/geofencing/regions) | | `country.name` | `Radar Region Country Name` | string | `"United States"` | [Regions](/geofencing/regions) | | `state.code` | `Radar Region State Code` | string | `"MD"` | [Regions](/geofencing/regions) | | `state.name` | `Radar Region State Name` | string | `"Maryland"` | [Regions](/geofencing/regions) | | `dma.code` | `Radar Region DMA Code` | string | `"26"` | [Regions](/geofencing/regions) | | `dma.name` | `Radar Region DMA Name` | string | `"Baltimore"` | [Regions](/geofencing/regions) | | `postalCode.code` | `Radar Region Postal Code` | string | `"21014"` | [Regions](/geofencing/regions) | | `trip.externalId` | `Radar Trip External ID` | string | `"299"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceTag` | `Radar Trip Destination Geofence Tag` | string | `"store"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `Radar Trip Destination Geofence External ID` | string | `"123"` | [Trip Tracking](/geofencing/trips) | | `beacons[*]._id` | `Radar Beacon IDs` | array\[string] | `["5b2c0906f5874b001aecfd8f"]` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `Radar Beacon Descriptions` | array\[string] | `["Store #123 - Drive-Thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `Radar Beacon Tags` | array\[string] | `["drive-thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `Radar Beacon External IDs` | array\[string] | `["123"]` | [Beacons](/geofencing/beacons) | ## Event mapping | Radar Event | Context Type | Mixpanel Event | | - | - | - | | `user.entered_geofence` | [Geofences](/geofencing/geofences) | `Radar Geofence Entered` | | `user.exited_geofence` | [Geofences](/geofencing/geofences) | `Radar Geofence Exited` | | `user.dwelled_in_geofence` | [Geofences](/geofencing/geofences) | `Radar Dwelled in Geofence` | | `user.entered_place` | [Places](/geofencing/places) | `Radar Place Entered` | | `user.exited_place` | [Places](/geofencing/places) | `Radar Place Exited` | | `user.entered_region_country` | [Regions](/geofencing/regions) | `Radar Country Entered` | | `user.exited_region_country` | [Regions](/geofencing/regions) | `Radar Country Exited` | | `user.entered_region_state` | [Regions](/geofencing/regions) | `Radar State Entered` | | `user.exited_region_state` | [Regions](/geofencing/regions) | `Radar State Exited` | | `user.entered_region_dma` | [Regions](/geofencing/regions) | `Radar DMA Entered` | | `user.exited_region_dma` | [Regions](/geofencing/regions) | `Radar DMA Exited` | | `user.started_trip` | [Trip Tracking](/geofencing/trips) | `Radar Started Trip` | | `user.updated_trip` | [Trip Tracking](/geofencing/trips) | `Radar Updated Trip` | | `user.approaching_trip_destination` | [Trip Tracking](/geofencing/trips) | `Radar Approaching Trip Destination` | | `user.arrived_at_trip_destination` | [Trip Tracking](/geofencing/trips) | `Radar Arrived at Trip Destination` | | `user.stopped_trip` | [Trip Tracking](/geofencing/trips) | `Radar Stopped Trip` | | `user.entered_beacon` | [Beacons](/geofencing/beacons) | `Radar Beacon Entered` | | `user.exited_beacon` | [Beacons](/geofencing/beacons) | `Radar Beacon Exited` | ### Radar Geofence Entered | Radar Event Field | Mixpanel Event Property | Type | Example | | - | - | - | - | | `geofence._id` | `Geofence ID` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `Geofence Description` | string | `"Store #123"` | | `geofence.tag` | `Geofence Tag` | string | `"store"` | | `geofence.externalId` | `Geofence External ID` | string | `"123"` | | `geofence.metadata[{key}]` | `Geofence Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | string | `true` | ### Radar Geofence Exited | Radar Event Field | Mixpanel Event Property | Type | Example | | - | - | - | - | | `geofence._id` | `Geofence ID` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `Geofence Description` | string | `"Store #123"` | | `geofence.tag` | `Geofence Tag` | string | `"store"` | | `geofence.externalId` | `Geofence External ID` | string | `"123"` | | `geofence.metadata[{key}]` | `Geofence Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | number (minutes) | `42.1` | | `foreground` | `Foreground` | string | `true` | ### Radar Dwelled in Geofence | Radar Event Field | Mixpanel Event Property | Type | Example | | - | - | - | - | | `geofence._id` | `Geofence ID` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `Geofence Description` | string | `"Store #123"` | | `geofence.tag` | `Geofence Tag` | string | `"store"` | | `geofence.externalId` | `Geofence External ID` | string | `"123"` | | `geofence.metadata[{key}]` | `Geofence Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | number (minutes) | `5` | | `foreground` | `Foreground` | string | `true` | ### Radar Place Entered | Radar Event Field | Mixpanel Event Property | Type | Example | | - | - | - | - | | `place._id` | `Place ID` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `Place Name` | string | `"Starbucks"` | | `place.chain.slug` | `Place Chain ID` | string | `"starbucks"` | | `place.chain.name` | `Place Chain Name` | string | `"Starbucks"` | | `place.categories` | `Place Categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | string | `true` | ### Radar Place Exited | Radar Event Field | Mixpanel Event Property | Type | Example | | - | - | - | - | | `place._id` | `Place ID` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `Place Name` | string | `"Starbucks"` | | `place.chain.slug` | `Place Chain ID` | string | `"starbucks"` | | `place.chain.name` | `Place Chain Name` | string | `"Starbucks"` | | `place.categories` | `Place Categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | number (minutes) | `42.1` | | `foreground` | `Foreground` | string | `true` | ### Radar Country Entered | Radar Event Field | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"US"` | | `region.name` | `Region Name` | string | `"United States"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | string | `true` | ### Radar Country Exited | Radar Event Field | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"US"` | | `region.name` | `Region Name` | string | `"United States"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | string | `true` | ### Radar State Entered | Radar Event Field | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"MD"` | | `region.name` | `Region Name` | string | `"Maryland"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | string | `true` | ### Radar State Exited | Radar Event Field | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"MD"` | | `region.name` | `Region Name` | string | `"Maryland"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | string | `true` | ### Radar DMA Entered | Radar Event Field | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"26"` | | `region.name` | `Region Name` | string | `"Baltimore"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | string | `true` | ### Radar DMA Exited | Radar Event Field | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `Region Code` | string | `"26"` | | `region.name` | `Region Name` | string | `"Baltimore"` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | string | `true` | ### Radar Started Trip | Radar Event Attribute | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `foreground` | `Foreground` | string | `true` | ### Radar Updated Trip | Radar Event Attribute | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `foreground` | `Foreground` | string | `true` | ### Radar Approaching Trip Destination | Radar Event Attribute | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `foreground` | `Foreground` | string | `true` | ### Radar Arrived at Trip Destination | Radar Event Attribute | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `foreground` | `Foreground` | string | `true` | ### Radar Stopped Trip | Radar Event Attribute | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `Trip External ID` | string | `"299"` | | `trip.metadata[{key}]` | `Trip Metadata {key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `Trip Destination Geofence Tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `Trip Destination Geofence External ID` | string | `"123"` | | `foreground` | `Foreground` | string | `true` | ### Radar Beacon Entered | Radar Event Attribute | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `Beacon ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `Beacon Description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `Beacon Tag` | string | `"drive-thru"` | | `beacon.externalId` | `Beacon External ID` | string | `"123"` | | `beacon.metadata[{key}]` | `Beacon Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `foreground` | `Foreground` | string | `true` | ### Radar Beacon Exited | Radar Event Attribute | Mixpanel Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `Beacon ID` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `Beacon Description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `Beacon Tag` | string | `"drive-thru"` | | `beacon.externalId` | `Beacon External ID` | string | `"123"` | | `beacon.metadata[{key}]` | `Beacon Metadata {key}` | type | `{value}` | | `confidence` | `Confidence` | string | `"high"` | | `duration` | `Duration` | number (minutes) | `1.42` | | `foreground` | `Foreground` | string | `true` | # MoEngage Source: https://docs.radar.com/integrations/moengage Send Radar location events and user attributes to MoEngage to trigger location-based messages. > [!NOTE] > > The MoEngage integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events and user attributes to [MoEngage](https://www.moengage.com/). Use the MoEngage integration to send location-triggered and location-targeted messages to increase engagement and conversion. ## Configuration On the MoEngage *APIs* page, copy both your Workspace ID and Data API Key. Then, on the Radar [Integrations page](https://radar.com/dashboard/integrations#moengage) under *MoEngage*, set *Enabled* to *Yes* and paste your Workspace ID and Data API key into their respective fields. Finally, if your account is not on `https://api-01.moengage.com`, select the appropriate *API Endpoint*. Whenever events are generated, Radar will send custom events and user attributes to MoEngage. Set `metadata[moengage:customer_id]` to map Radar users to their respective MoEngage User. For example: ```swift Swift theme={null} Radar.setMetadata(["moengage:customer_id": "example@radar.com"]) ``` ```kotlin Java theme={null} Radar.setMetadata(JSONObject().put("moengage:customer_id", "example@radar.com")) ``` ## User mapping | Radar User Field | MoEngage User Attribute | Type | Example Value | Context Type | | - | - | - | - | - | | `metadata[moengage:customer_id]` | `ID` | string | `"example@radar.com"` | | | `_id` | `radar_id` | string | `"5b2c0906f5874b001aecfd8d"` | | | `locationAuthorization` | `radar_location_authorization` | string | `"GRANTED_FOREGROUND"` | | | `locationAccuracyAuthorization` | `radar_location_accuracy_authorization` | string | `"FULL"` | | | `updatedAt` | `radar_updated_at` | timestamp | `"25 Jul 2025, 10:36:17 am"` | | | `segments[*].externalId` | `radar_segment_external_ids` | array\[string] | `["starbucks-visitors"]` | | | `topChains[*].slug` | `radar_top_chain_slugs` | array\[string] | `["starbucks", "walmart"]` | | | `topChains[*].externalId` | `radar_top_chain_external_ids` | array\[string] | `["123", "456"]` | | | `geofences[*]._id` | `radar_geofence_ids` | array\[string] | `["5b2c0906f5874b001aecfd8e"]` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `radar_geofence_descriptions` | array\[string] | `["Store #123"]` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `radar_geofence_tags` | array\[string] | `["store"]` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `radar_geofence_external_ids` | array\[string] | `["123"]` | [Geofences](/geofencing/geofences) | | `place._id` | `radar_place_id` | string | `"59302bcf8f27e8a156bd4f91"` | [Places](/geofencing/places) | | `place.name` | `radar_place_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.categories` | `radar_place_categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | [Places](/geofencing/places) | | `place.chain.slug` | `radar_place_chain_id` | string | `"starbucks"` | [Places](/geofencing/places) | | `place.chain.name` | `radar_place_chain_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `country.code` | `radar_region_country_code` | string | `"US"` | [Regions](/geofencing/regions) | | `country.name` | `radar_region_country_name` | string | `"United States"` | [Regions](/geofencing/regions) | | `state.code` | `radar_region_state_code` | string | `"MD"` | [Regions](/geofencing/regions) | | `state.name` | `radar_region_state_name` | string | `"Maryland"` | [Regions](/geofencing/regions) | | `dma.code` | `radar_region_dma_code` | string | `"26"` | [Regions](/geofencing/regions) | | `dma.name` | `radar_region_dma_name` | string | `"Baltimore"` | [Regions](/geofencing/regions) | | `postalCode.code` | `radar_region_postal_code` | string | `"21014"` | [Regions](/geofencing/regions) | | `trip.externalId` | `radar_trip_external_id` | string | `"299"` | [Trips](/geofencing/trips) | | `trip.destinationGeofenceTag` | `radar_trip_destination_geofence_tag` | string | `"store"` | [Trips](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `radar_trip_destination_geofence_external_id` | string | `"123"` | [Trips](/geofencing/trips) | | `beacons[*]._id` | `radar_beacon_ids` | array\[string] | `["5b2c0906f5874b001aecfd8f]"` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `radar_beacon_descriptions` | array\[string] | `["Store #123 - Drive-Thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `radar_beacon_tags` | array\[string] | `["drive-thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `radar_beacon_external_ids` | array\[string] | `["123"]` | [Beacons](/geofencing/beacons) | ## Event mapping | Radar Event | Context Type | MoEngage Event | | - | - | - | | `user.entered_geofence` | [Geofences](/geofencing/geofences) | `[Radar] Geofence Entered` | | `user.exited_geofence` | [Geofences](/geofencing/geofences) | `[Radar] Geofence Exited` | | `user.dwelled_in_geofence` | [Geofences](/geofencing/geofences) | `[Radar] Dwelled in Geofence` | | `user.entered_place` | [Places](/geofencing/places) | `[Radar] Place Entered` | | `user.exited_place` | [Places](/geofencing/places) | `[Radar] Place Exited` | | `user.entered_region_country` | [Regions](/geofencing/regions) | `[Radar] Country Entered` | | `user.exited_region_country` | [Regions](/geofencing/regions) | `[Radar] Country Exited` | | `user.entered_region_state` | [Regions](/geofencing/regions) | `[Radar] State Entered` | | `user.exited_region_state` | [Regions](/geofencing/regions) | `[Radar] State Exited` | | `user.entered_region_dma` | [Regions](/geofencing/regions) | `[Radar] DMA Entered` | | `user.exited_region_dma` | [Regions](/geofencing/regions) | `[Radar] DMA Exited` | | `user.started_trip` | [Trip Tracking](/geofencing/trips) | `[Radar] Started Trip` | | `user.updated_trip` | [Trip Tracking](/geofencing/trips) | `[Radar] Updated Trip` | | `user.approaching_trip_destination` | [Trip Tracking](/geofencing/trips) | `[Radar] Approaching Trip Destination` | | `user.arrived_at_trip_destination` | [Trip Tracking](/geofencing/trips) | `[Radar] Arrived at Trip Destination` | | `user.stopped_trip` | [Trip Tracking](/geofencing/trips) | `[Radar] Stopped Trip` | | `user.entered_beacon` | [Beacons](/geofencing/beacons) | `[Radar] Beacon Entered` | | `user.exited_beacon` | [Beacons](/geofencing/beacons) | `[Radar] Beacon Exited` | ### \[Radar] Geofence Entered | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### \[Radar] Geofence Exited | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### \[Radar] Dwelled in Geofence | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `5` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### \[Radar] Place Entered | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.chain.externalId` | `place_chain_external_id` | string | `"123"` | | `place.chain.metadata[{key}]` | `place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### \[Radar] Place Exited | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.chain.externalId` | `place_chain_external_id` | string | `"123"` | | `place.chain.metadata[{key}]` | `place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `country.code` | `country_code` | string | `"US"` | | `country.name` | `country_name` | string | `"United States"` | | `state.code` | `state_code` | string | `"MD"` | | `state.name` | `state_name` | string | `"Maryland"` | | `dma.code` | `dma_code` | string | `"26"` | | `dma.name` | `dma_name` | string | `"Baltimore"` | | `postalCode.code` | `postal_code` | string | `"21014"` | ### \[Radar] Country Entered | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### \[Radar] Country Exited | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### \[Radar] State Entered | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### \[Radar] State Exited | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### \[Radar] DMA Entered | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### \[Radar] DMA Exited | Radar Event Field | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### \[Radar] Started Trip | Radar Event Attribute | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### \[Radar] Updated Trip | Radar Event Attribute | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### \[Radar] Approaching Trip Destination | Radar Event Attribute | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### \[Radar] Arrived at Trip Destination | Radar Event Attribute | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### \[Radar] Stopped Trip | Radar Event Attribute | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### \[Radar] Beacon Entered | Radar Event Attribute | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `radar_beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `radar_beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `radar_beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `radar_beacon_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### \[Radar] Beacon Exited | Radar Event Attribute | MoEngage Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `radar_beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `radar_beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `radar_beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `radar_beacon_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | # mParticle Source: https://docs.radar.com/integrations/mparticle Send Radar location events and user attributes to mParticle as an input feed, or install the Radar SDK as an mParticle kit. > [!NOTE] > > The mParticle integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events and user attributes to [mParticle](https://www.mparticle.com) as an input feed. You can use events and user attributes to build audiences in mParticle, and mParticle can send events and user attributes to hundreds of outputs. The mParticle SDK can also install and initialize the [Radar SDK](/sdk/sdk) as a kit. Use the mParticle integration to build location-based audiences and to forward location events and user context to any outputs. ## Configuration ### Feed To configure the feed, in mParticle, add Radar input feeds for iOS and Android and copy your API keys and secrets. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *mParticle Feed*, set *Enabled* to *Yes* and paste your API keys and secrets. Whenever events are generated, Radar will send events and user attributes to mParticle. Events and user attributes from iOS devices will be sent to the iOS input feed, and events and user attributes from Android devices will be sent to the Android input feed. The Radar *Test* environment automatically maps to the *Development* environment in mParticle, and the Radar *Live* environment automatically maps to the *Production* environment in mParticle. By default, Radar sends the IDFV on iOS and Android Id on Android to associate the Radar events with the correct mParticle user. Additionally, the Radar `userId` maps to mParticle `customerid` for logged in users. You can specify a custom mapping for the mParticle customer ID by setting Radar `metadata.mParticleCustomerId`. For example, on iOS: ```swift theme={null} // track logged in users with custom userId mapping (not required if using default mapping) // map by mParticle CustomerIdRadar.setMetadata(["mParticleCustomerId": customerid]) ``` If not leveraging a customer ID in mParticle but there is a need to set the Radar `userId`, collect the mParticle ID and set as Radar `metadata.mParticleId`. ```swift Swift theme={null} // setting the Radar userId, but not leveraging a customer ID in mParticle // map by mParticleId let options = MParticleOptions(key: "mp_key_..", secret: "mp_secret_...") options.onIdentifyComplete = {(result: MPIdentityApiResult?, error: Error?) in if (result?.user != nil) { if let mpId = result?.user.userId { let radarMetadata = ["mParticleId":mpId] Radar.setMetadata(radarMetadata) } } else { // handle failure } } MParticle.sharedInstance().start(with: options) ``` ```kotlin Kotlin theme={null} // setting the Radar userId, but not leveraging a customer ID in mParticle // map by mParticleId MParticle.getInstance()?.Identity()?.addIdentityStateListener { user, _ -> val mParticleId = user.id var radarMetadata = JSONObject() radarMetadata.put("mParticleId",mParticleId) Radar.setMetadata(radarMetadata) } ``` ### Kit To configure the kit, on the Radar [Settings page](https://dashboard.radar.com/settings) under *Keys*, copy your test and live publishable keys. Then, in mParticle, add and enable Radar outputs for iOS and Android, paste your keys, and choose whether to run automatically. Install the kit using CocoaPods or Carthage on iOS and Gradle on Android. See the [iOS kit code and readme](https://github.com/mparticle-integrations/mparticle-apple-integration-radar), [Android kit code and readme](https://github.com/mparticle-integrations/mparticle-android-integration-radar), and [mParticle Kit documentation for Radar](https://docs.mparticle.com/integrations/radar/event/). The kit will initialize the [Radar SDK](/sdk/sdk) and identify the user with the mParticle customer ID. After version `8.0.2` of the iOS kit and `5.15.1` of the Android kit, Radar will also set `metadata.mParticleId` to the [MPID](https://docs.mparticle.com/developers/sdk/web/users/#mparticle-id). In addition, if you chose to run automatically and the user has granted permissions, the kit will automatically track the user's location in the foreground on app open and/or in the background. ## User mapping Note that Radar uses the special string `"(null)"` to represent `null` user attribute values. | Radar User Field | mParticle User Attribute | Type | Example Value | Context Type | | - | - | - | - | - | | `metadata.mParticleId` | `mpid` | string | `"4294967296"` | | | `metadata.mParticleCustomerId` or `userId` | `customerid` | string | `"1"` | | | `deviceId` | `ios_idfv` or `android_uuid` | string | `"10974a2ee035770b9"` | | | `location.coordinates[0]` | `radar_location_longitude` | number | `-76.350663` | | | `location.coordinates[1]` | `radar_location_latitude` | number | `39.525665` | | | `locationAuthorization` | `radar_location_authorization` | string | `"GRANTED_FOREGROUND"` | | | `locationAccuracyAuthorization` | `radar_location_accuracy_authorization` | string | `"FULL"` | | | `_id` | `radar_id` | string | `"5b2c0906f5874b001aecfd8d"` | | | `updatedAt` | `radar_updated_at` | timestamp | `"2018-06-22T15:23:39.000Z"` | | | `segments[*].externalId` | `radar_segment_external_ids` | array\[string] | `["starbucks-visitors"]` | | | `topChains[*].slug` | `radar_top_chain_slugs` | array\[string] | `["starbucks", "walmart"]` | | | `topChains[*].externalId` | `radar_top_chain_external_ids` | array\[string] | `["123", "456"]` | | | `geofences[*]._id` | `radar_geofence_ids` | array\[string] | `["5b2c0906f5874b001aecfd8e"]` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `radar_geofence_descriptions` | array\[string] | `["Store #123"]` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `radar_geofence_tags` | array\[string] | `["store"]` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `radar_geofence_external_ids` | array\[string] | `["123"]` | [Geofences](/geofencing/geofences) | | `place._id` | `radar_place_id` | string | `"59302bcf8f27e8a156bd4f91"` | [Places](/geofencing/places) | | `place.name` | `radar_place_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.categories` | `radar_place_categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | [Places](/geofencing/places) | | `place.chain.slug` | `radar_place_chain_slug` | string | `"starbucks"` | [Places](/geofencing/places) | | `place.chain.name` | `radar_place_chain_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `country.code` | `radar_region_country_code` | string | `"US"` | [Regions](/geofencing/regions) | | `country.name` | `radar_region_country_name` | string | `"United States"` | [Regions](/geofencing/regions) | | `state.code` | `radar_region_state_code` | string | `"MD"` | [Regions](/geofencing/regions) | | `state.name` | `radar_region_state_name` | string | `"Maryland"` | [Regions](/geofencing/regions) | | `dma.code` | `radar_region_dma_code` | string | `"26"` | [Regions](/geofencing/regions) | | `dma.name` | `radar_region_dma_name` | string | `"Baltimore"` | [Regions](/geofencing/regions) | | `postalCode.code` | `radar_region_postal_code` | string | `"21014"` | [Regions](/geofencing/regions) | | `trip.externalId` | `radar_trip_external_id` | string | `"299"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceTag` | `radar_trip_destination_geofence_tag` | string | `"store"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `radar_trip_destination_geofence_external_id` | string | `"123"` | [Trip Tracking](/geofencing/trips) | | `beacons[*]._id` | `radar_beacon_ids` | array\[string] | `["5b2c0906f5874b001aecfd8f]"` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `radar_beacon_descriptions` | array\[string] | `["Store #123 - Drive-Thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `radar_beacon_tags` | array\[string] | `["drive-thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `radar_beacon_external_ids` | array\[string] | `["123"]` | [Beacons](/geofencing/beacons) | ## Event mapping ### user.entered\_geofence | Radar Event Field | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_geofence | Radar Event Field | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | ### user.dwelled\_in\_geofence | Radar Event Field | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `5` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_place | Radar Event Field | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_slug` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.categories` | `place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_place | Radar Event Field | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Target"` | | `place.chain.slug` | `place_chain_slug` | string | `"target"` | | `place.chain.name` | `place_chain_name` | string | `"Target"` | | `place.categories` | `place_categories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_region\_country | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_region\_country | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_region\_state | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_region\_state | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_region\_dma | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_region\_dma | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.started\_trip | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.updated\_trip | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.approaching\_trip\_destination | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.arrived\_at\_trip\_destination | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.stopped\_trip | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_beacon | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `beacon_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_beacon | Radar Event Attribute | mParticle Event Attribute | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `beacon_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `1.42` | | `foreground` | `foreground` | boolean | `true` | # Olo Source: https://docs.radar.com/integrations/olo Track customer pickups for Olo orders with Radar, fire orders based on live location, and send arrival alerts to Olo Expo. > [!NOTE] > > The Olo integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can track customer pickups for orders placed through [Olo](https://www.olo.com). The integration includes optional capabilities to [fire orders](/integrations/olo#order-firing) based on live location updates and send approaching and arrival alerts to [Olo Expo](/integrations/olo#expo-notifications). ## Configuration Configure an Olo webhook to deliver order events to `https://api.radar.io/webhooks/olo` via the *Development Tools* section of the Olo Dashboard (requires two-factor authentication and at least Brand Manager permission). Under the *Order Events* section, enable *Order Placed* and *Order Cancelled*. If leveraging [Olo Expo](/integrations/olo#expo-notifications), enable the *Order Picked Up* event as well. Once the webhook is setup, your Radar account team will setup the configuration on the [Integrations page](https://dashboard.radar.com/integrations). Applicable Olo *Handoff modes*, a destination geofence tag (e.g., `restaurant`), and custom field mappings from the Olo webhook body to Radar trip metadata will be set. Finally, on the Radar [Geofences page](https://dashboard.radar.com/geofencing/geofences), [import geofences](/geofencing/geofences#csv-import) for your restaurants. Use the tag from the Olo integration configuration for the geofence `tag` attribute. ![Olo Webhook Configuration Pn](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/integrations/olo/olo_webhook_configuration.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=6eed089cbf70e540830942641cc4a82d) Radar will automatically create trips when new orders are placed, as well as complete or cancel trips when orders are completed or cancelled in Olo. Call `Radar.startTrip(tripOptions, trackingOptions)` with `tripOptions.externalId` set to the Olo order ID to start the Radar trip and enable tracking. The mapping below will be used between the Olo webhook and a Radar trip: | Olo webhook field | Radar trip attribute | | - | - | | `orderId` | Trip external id | | `storeNumber` | Trip destination | | `timeReady` - `timePlaced` | Trip approaching threshold\* | | `timeReady` | Trip scheduled arrival at\* | \**Requires enabling the associated auto-calculate order firing setting* Assuming locations permissions have been granted and location tracking has been started in your app, Radar will calculate live ETAs to the restaurant and generate `user.updated_trip`, `user.approaching_trip_destination`, and `user.arrived_at_trip_destination` events. Learn more about [Trip Tracking](/geofencing/trips). ## Order firing Radar can fire orders in Olo based on customer location rather than a preset time to ensure food preparation time aligns with customer arrival. Orders in Olo will need to set a `timewanted` for advance orders, or alternatively, set the `externalRef` to any value that starts with `radar_` (i.e. `radar_h87y12rgb`). Additionally, configure Radar with a *Partnership Type* of *Customer Arrival* via the *Partner Management* section of the Olo Dashboard. Select stores in the configuration where order firing will be enabled. Upon completion, reach out to your Radar account team to complete the order firing integration. When starting a trip for an order, include the `oloOrderGuid` and `oloHandoffMode` in trip metadata. The trip's approaching threshold and scheduled arrival at attributes are used to determine the order firing time. When an active trip ETA drops below the approaching threshold, Radar generates a `user.approaching_trip_destination` event and Radar will fire the order. If the trip is started inside the destination geofence, Radar will fire the order immediately. In the event the `scheduledArrivalAt` set on the trip is reached before the approaching threshold is crossed, the order will automatically fire. See below for how to configure these two parameters. ### Scheduled arrival at A `scheduledArrivalAt` datetime is required as a fallback in the event location sharing is disabled or the device is experiencing connectivity issues. You can enable auto-calculation of the `scheduledArrivalAt`, which is initially set to the `timeReady` value from the Olo Order Placed webhook and then continues to update based on each trip ETA calculation. This includes a backup fire delay setting which is a maximum number of minutes to push back the initial scheduled arrival at. This can be configured in [Trips Settings](https://dashboard.radar.com/settings#trips-settings). As an alternative to Radar's automatic calculation, manually set the `scheduledArrivalAt` either via `Radar.startTrip()` in the app, `Radar.updateTrip()` in the app or the [Trips API](/api#trips) server-side. Setting this manually will override use of Radar's auto-calculated `scheduledArrivalAt` setting. ### Approaching threshold In the Radar [Trips Settings](https://dashboard.radar.com/settings#trips-settings), set the *Approaching threshold (minutes)* value as the default number of minutes away from arriving that the order should automatically be fired to Olo. You can enable Radar to auto-calculate the approaching threshold for ASAP orders, which is initially set to the time difference between `timeReady` and `timePlaced` from the Olo Order Placed webhook. As an alternative to Radar's automatic calculation, set the approaching threshold either at the store level via the `tripApproachingThreshold` property in the [geofences API](/api#geofences) or at the order level via `Radar.updateTrip()` in the app or [Trips API](/api#trips) server-side. ### Multiple order support Sometimes, multiple orders are placed to the same store. To ensure that all orders receive real-time ETAs and are processed simultaneously, Radar automatically combines additional orders into an existing trip if they are headed to the same destination and the expected arrival time is within an hour. For scheduled orders, the `scheduledArrivalAt` parameter included with `Radar.startTrip()` is used to verify the timing. If this parameter is not provided, we assume the order is an ASAP order and use the current time instead. ## Expo notifications Radar is a Customer Arrival Olo partner and can automatically provide *Approaching* and *Arrival* status updates to Olo Expo based on Radar trip tracking [events](/geofencing/trips#trip-events). This keeps in-store teams up-to-date with real-time status updates on tracked mobile orders. Additionally, if your team utilizes the *Picked Up* button in Olo Expo, this will automatically complete the Radar trip and capture completion time for trip duration and wait time analytics. Configure Radar as a Customer Arrival Partnership Type via the Partner Management section of the Olo Dashboard if this was not completed to enable order firing. Select stores in the configuration where order firing will be enabled. Upon completion, reach out to your Radar account team to complete the order firing integration. Finally, on the [Integrations page](https://dashboard.radar.com/integrations) under *Olo*, you will need to set *Expo updates enabled* to *Yes*, and save your integration settings. # OneSignal Source: https://docs.radar.com/integrations/onesignal Send Radar location tags to OneSignal and trigger location-based notifications. > [!NOTE] > > The OneSignal integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send tags to and trigger notifications in [OneSignal](https://onesignal.com). You can create notifications triggered by tag changes. Use the OneSignal integration to send location-triggered and location-targeted messages to increase engagement and conversion. ## Configuration On the OneSignal *Settings* page under *Keys & IDs*, copy your REST API key. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *OneSignal*, set *Enabled* to *Yes* and paste your API key. Note that you can set separate API keys for the *Test* and *Live* environments. Whenever events are generated, Radar will call the [edit device API](https://documentation.onesignal.com/reference/edit-device) and set tags in OneSignal. You can create notifications triggered by tag changes. By default, Radar `userId` and `deviceId` do not map to OneSignal. To map users in Radar to devices in OneSignal, you must send the OneSignal player ID to Radar by setting `metadata.oneSignalPlayerId`. For example, on iOS: ```swift Swift theme={null} let playerId = OneSignal.getPermissionSubscriptionState().subscriptionStatus.userId Radar.setMetadata(["oneSignalPlayerId": playerId]) ``` ```kotlin Kotlin theme={null} let playerId = OneSignal.getPermissionSubscriptionState().subscriptionStatus.userId Radar.setMetadata(["oneSignalPlayerId": playerId]) ``` Because OneSignal does not support associating custom events with a user, the most recent event types triggered from a location update are sent as a comma-separated list under the OneSignal tag `radar_events`. For example, if a user has exited a geofence and entered a place, the value for the `radar_events` tag would be `exited_geofence,entered_place`. | Radar Event | Context Type | OneSignal Tag Value | | - | - | - | | `user.entered_geofence` | [Geofences](/geofencing/geofences) | `entered_geofence` | | `user.exited_geofence` | [Geofences](/geofencing/geofences) | `exited_geofence` | | `user.dwelled_in_geofence` | [Geofences](/geofencing/geofences) | `dwelled_in_geofence` | | `user.entered_place` | [Places](/geofencing/places) | `place_entered` | | `user.exited_place` | [Places](/geofencing/places) | `place_exited` | | `user.entered_region_country` | [Regions](/geofencing/regions) | `entered_region_country` | | `user.exited_region_country` | [Regions](/geofencing/regions) | `exited_region_country` | | `user.entered_region_state` | [Regions](/geofencing/regions) | `entered_region_state` | | `user.exited_region_state` | [Regions](/geofencing/regions) | `exited_region_state` | | `user.entered_region_dma` | [Regions](/geofencing/regions) | `entered_region_dma` | | `user.exited_region_dma` | [Regions](/geofencing/regions) | `exited_region_dma` | | `user.started_trip` | [Trips](/geofencing/trips) | `started_trip` | | `user.updated_trip` | [Trips](/geofencing/trips) | `updated_trip` | | `user.approaching_trip_destination` | [Trips](/geofencing/trips) | `approaching_trip_destination` | | `user.arrived_at_trip_destination` | [Trips](/geofencing/trips) | `arrived_at_trip_destination` | | `user.stopped_trip` | [Trips](/geofencing/trips) | `stopped_trip` | | `user.entered_beacon` | [Beacons](/geofencing/beacons) | `entered_beacon` | | `user.exited_beacon` | [Beacons](/geofencing/beacons) | `exited_beacon` | ## User mapping | Radar User Field | OneSignal Tag Name | Type | Example Tag | Context Type | | - | - | - | - | - | | `location.coordinates[1]` | `lat` | number | `39.525665` | | | `location.coordinates[0]` | `long` | number | `-76.350663` | | | `locationAuthorization` | `radar_location_authorization` | string | `"GRANTED_FOREGROUND"` | | | `locationAccuracyAuthorization` | `radar_location_accuracy_authorization` | string | `"FULL"` | | | `segments[*].externalId` | `radar_segment_external_ids` | string (comma-separated) | `"starbucks-visitors"` | | | `topChains[*].slug` | `radar_top_chain_slugs` | string (comma-separated) | `"starbucks"` | | | `topChains[*].externalId` | `radar_top_chain_external_ids` | string (comma-separated) | `"123"` | | | `geofences[*]._id` | `radar_geofence_ids` | string (comma-separated) | `"5b2c0906f5874b001aecfd8e"` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `radar_geofence_descriptions` | string (comma-separated) | `"Store #123"` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `radar_geofence_tags` | string (comma-separated) | `"store"` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `radar_geofence_external_ids` | string (comma-separated) | `"123"` | [Geofences](/geofencing/geofences) | | `place._id` | `radar_place_id` | string | `"59302bcf8f27e8a156bd4f91"` | [Places](/geofencing/places) | | `place.name` | `radar_place_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.categories` | `radar_place_categories` | string | `"coffee-shop"` | [Places](/geofencing/places) | | `place.chain.slug` | `radar_place_chain_slug` | string | `"starbucks"` | [Places](/geofencing/places) | | `place.chain.name` | `radar_place_chain_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `country.code` | `radar_region_country_code` | string | `"US"` | [Regions](/geofencing/regions) | | `country.name` | `radar_region_country_name` | string | `"United States"` | [Regions](/geofencing/regions) | | `state.code` | `radar_region_state_code` | string | `"MD"` | [Regions](/geofencing/regions) | | `state.name` | `radar_region_state_name` | string | `"Maryland"` | [Regions](/geofencing/regions) | | `dma.code` | `radar_region_dma_code` | string | `"26"` | [Regions](/geofencing/regions) | | `dma.name` | `radar_region_dma_name` | string | `"Baltimore"` | [Regions](/geofencing/regions) | | `postalCode.code` | `radar_region_postal_code` | string | `"21014"` | [Regions](/geofencing/regions) | | `trip.externalId` | `radar_trip_external_id` | string | `"123"` | [Trip tracking](/geofencing/trips) | | `trip.destinationGeofenceTag` | `radar_trip_destination_geofence_tag` | string | `"store"` | [Trip tracking](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `radar_trip_destination_geofence_external_id` | string | `"123"` | [Trip tracking](/geofencing/trips) | | `trip.approached` | `radar_trip_approached` | boolean | `true` | [Trip tracking](/geofencing/trips) | | `trip.arrived` | `radar_trip_arrived` | boolean | `false` | [Trip tracking](/geofencing/trips) | | `beacons[*]._id` | `radar_beacon_ids` | string (comma-separated) | `"5b2c0906f5874b001aecfd8f"` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `radar_beacon_descriptions` | string (comma-separated) | `"Store #123 - Drive-Thru"` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `radar_beacon_tags` | string (comma-separated) | `"drive-thru"` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `radar_beacon_external_ids` | string (comma-separated) | `"123"` | [Beacons](/geofencing/beacons) | # Salesforce Marketing Cloud Source: https://docs.radar.com/integrations/salesforce Send Radar location events to Salesforce Marketing Cloud to trigger journeys in Journey Builder. > [!NOTE] > > The Salesforce Marketing Cloud integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events to [Salesforce Marketing Cloud](https://www.salesforce.com/products/marketing-cloud/overview/) to trigger journeys in *Journey Builder*. Use the Salesforce Marketing Cloud integration to send location-triggered messages to increase engagement and conversion. ## Configuration On the Salesforce Marketing Cloud *Setup* menu, under *Installed Packages*, click *New*. Add an installed package with the name *Radar*. On the package details page, add an *API Integration* component with the *Server-to-Server* integration type and all permissions for the *Automation*, *Contacts*, *Cross Cloud Platform*, and *Data* scopes. Copy your *Client ID*, *Client Secret*, *Authentication Base URI*, and *REST Base URI*. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations#salesforce) under *Salesforce Marketing Cloud*, set *Enabled* to *Yes* and paste these values. When you click *Save*, Radar will create an event definition and data extension with the specified event definition key (`radar-event` by default). Whenever events are generated, Radar will send events to your Salesforce Marketing Cloud data extension to trigger journeys. In Salesforce Marketing Cloud's *Contact Builder*, under *Data Designer*, connect the Radar data extension to your data model by linking the Customer Data's *Contact Key* field to the Radar Data Extension's *contactKey* field in a one to many relationship. To map a Radar user to a Salesforce Marketing Cloud contact, you must specify a custom mapping by setting Radar `metadata.salesforceContactKey`. ```swift Swift theme={null} let contactKey = SFMCSdk.mp.contactKey() Radar.setMetadata(["salesforceContactKey": contactKey]) ``` ```kotlin Kotlin theme={null} SFMCSdk.requestSdk { sdk -> sdk.mp { val contactKey = it.moduleIdentity.profileId Radar.setMetadata(JSONObject().put("salesforceContactKey",contactKey)) } } ``` ## Verify integration data delivery To test that the integration is configured correctly and can deliver data, use the [Simulator](https://dashboard.radar.com/geofencing/simulate) to generate events. Click *View* on an event row and scroll down to the *Logs* section on the details page to verify delivery. Perform a similar process via a test app build with Radar location tracking enabled by spoofing location or moving into the relevant boundary. ![Salesforce Verify Integration Gi](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/salesforce-verify-integration.gif?s=bfbc6aa00105e4e7b80c09bc6a838775) Additionally, check the Radar data extension in Salesforce's *Contact Builder* to verify records are delivering. All integration delivery can be monitored via the integration's event logs by clicking *View event logs* on the [Integrations page](https://dashboard.radar.com/integrations#salesforce). ## Example use cases ### Send a personalized push notification when a user arrives at a store 1. Create [Geofences](/geofencing/geofences#create-geofences) in Radar with the geofence tag set to `store`. The geofence tag will be used to trigger messages for the subset of geofence entries where this tag is present. 2. Create a Salesforce Journey triggered by an API Event from the Radar data extension. The Radar data extension will be filtered on `user.entered_geofence` as the `type` attribute and `store` as the `geofenceTag` attribute. ![Salesforce Radar Triggered Message Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/salesforce-radar-triggered-message.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=f7a604d6ce8cafedb62ae24c7cb0c01e) ### Message all users who have been nearby a store 1. Create [Geofences](/geofencing/geofences#create-geofences) in Radar to represent nearby store boundaries with geofence tag set to `nearby-store`. The geofence tag will be used to target messages for the subset of geofences where this tag has been present on an event in the last 7 days. 2. Create a Salesforce Mobile List filtered on the Radar data extension attributes of `type` equal to `user.entered_geofence`, `geofenceTag` equal to `nearby` and `createdAt` set to the last 7 days. 3. Create a Salesforce MobilePush Message with audience targeting set to the Salesforce Mobile List created in the step above. ![Salesforce Message All Users Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/salesforce-message-all-users.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=a937cb15e30dd2b634010c1fda824617) ## Event mapping ### user.entered\_geofence | Radar Event Field | Salesforce Event Attribute | Type | Example | | - | - | - | - | | `type` | `type` | string | `"user.entered_geofence"` | | `user.userId` | `userUserId` | string (max length 100) | `"1"` | | `user.deviceId` | `userDeviceId` | string (max length 100) | `"10974a2ee035770b9"` | | `geofence._id` | `geofenceId` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofenceDescription` | string (max length 100) | `"Store #123"` | | `geofence.tag` | `geofenceTag` | string (max length 100) | `"store"` | | `geofence.externalId` | `geofenceExternalId` | string (max length 100) | `"123"` | | `geofence.metadata` | `geofenceMetadata` | string (max length 4,000) | `'{"parking":false}'` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Salesforce Event Attribute | Type | Example | | - | - | - | - | | `country.code` | `countryCode` | string | `"US"` | | `country.name` | `countryName` | string | `"United States"` | | `state.code` | `stateCode` | string | `"MD"` | | `state.name` | `stateName` | string | `"Maryland"` | | `dma.code` | `dmaCode` | string | `"26"` | | `dma.name` | `dmaName` | string | `"Baltimore"` | | `postalCode.code` | `postalCode` | string | `"21014"` | ### user.exited\_geofence | Radar Event Field | Salesforce Event Attribute | Type | Example | | - | - | - | - | | `type` | `type` | string | `"user.exited_geofence"` | | `user.userId` | `userUserId` | string (max length 100) | `"1"` | | `user.deviceId` | `userDeviceId` | string (max length 100) | `"10974a2ee035770b9"` | | `geofence._id` | `geofenceId` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofenceDescription` | string (max length 100) | `"Store #123"` | | `geofence.tag` | `geofenceTag` | string (max length 100) | `"store"` | | `geofence.externalId` | `geofenceExternalId` | string (max length 100) | `"123"` | | `geofence.metadata` | `geofenceMetadata` | string (max length 4,000) | `'{"parking":false}'` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1``foreground` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Salesforce Event Attribute | Type | Example | | - | - | - | - | | `country.code` | `countryCode` | string | `"US"` | | `country.name` | `countryName` | string | `"United States"` | | `state.code` | `stateCode` | string | `"MD"` | | `state.name` | `stateName` | string | `"Maryland"` | | `dma.code` | `dmaCode` | string | `"26"` | | `dma.name` | `dmaName` | string | `"Baltimore"` | | `postalCode.code` | `postalCode` | string | `"21014"` | ### user.dwelled\_in\_geofence | Radar Event Field | Salesforce Event Attribute | Type | Example | | - | - | - | - | | `type` | `type` | string | `"user.exited_geofence"` | | `user.userId` | `userUserId` | string (max length 100) | `"1"` | | `user.deviceId` | `userDeviceId` | string (max length 100) | `"10974a2ee035770b9"` | | `geofence._id` | `geofenceId` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofenceDescription` | string (max length 100) | `"Store #123"` | | `geofence.tag` | `geofenceTag` | string (max length 100) | `"store"` | | `geofence.externalId` | `geofenceExternalId` | string (max length 100) | `"123"` | | `geofence.metadata` | `geofenceMetadata` | string (max length 4,000) | `'{"parking":false}'` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `5` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Salesforce Event Attribute | Type | Example | | - | - | - | - | | `country.code` | `countryCode` | string | `"US"` | | `country.name` | `countryName` | string | `"United States"` | | `state.code` | `stateCode` | string | `"MD"` | | `state.name` | `stateName` | string | `"Maryland"` | | `dma.code` | `dmaCode` | string | `"26"` | | `dma.name` | `dmaName` | string | `"Baltimore"` | | `postalCode.code` | `postalCode` | string | `"21014"` | ### user.entered\_place | Radar Event Field | Salesforce Event Attribute | Type | Example | | - | - | - | - | | `type` | `type` | string | `"user.entered_place"` | | `user.userId` | `userUserId` | string (max length 100) | `"1"` | | `user.deviceId` | `userDeviceId` | string (max length 100) | `"10974a2ee035770b9"` | | `place._id` | `placeId` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `placeName` | string | `"Starbucks"` | | `place.chain.slug` | `placeChainSlug` | string | `"starbucks"` | | `place.chain.name` | `placeChainName` | string | `"Starbucks"` | | `place.chain.metadata` | `placeChainMetadata` | string (max length 4,000) | `'{"parking":false}'` | | `place.categories` | `placeCategories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Salesforce Event Attribute | Type | Example | | - | - | - | - | | `country.code` | `countryCode` | string | `"US"` | | `country.name` | `countryName` | string | `"United States"` | | `state.code` | `stateCode` | string | `"MD"` | | `state.name` | `stateName` | string | `"Maryland"` | | `dma.code` | `dmaCode` | string | `"26"` | | `dma.name` | `dmaName` | string | `"Baltimore"` | | `postalCode.code` | `postalCode` | string | `"21014"` | ### user.exited\_place | Radar Event Field | Salesforce Event Attribute | Type | Example | | - | - | - | - | | `type` | `type` | string | `"user.exited_place"` | | `user.userId` | `userUserId` | string (max length 100) | `"1"` | | `user.deviceId` | `userDeviceId` | string (max length 100) | `"10974a2ee035770b9"` | | `place._id` | `placeId` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `placeName` | string | `"Starbucks"` | | `place.chain.slug` | `placeChainSlug` | string | `"starbucks"` | | `place.chain.name` | `placeChainName` | string | `"Starbucks"` | | `place.chain.metadata` | `placeChainMetadata` | string (max length 4,000) | `'{"parking":false}'` | | `place.categories` | `placeCategories` | string (comma-separated) | `"food-beverage,cafe,coffee-shop"` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | If [Regions](/geofencing/regions) is enabled, Radar will also send the following attributes: | Radar Event Field | Salesforce Event Attribute | Type | Example | | - | - | - | - | | `country.code` | `countryCode` | string | `"US"` | | `country.name` | `countryName` | string | `"United States"` | | `state.code` | `stateCode` | string | `"MD"` | | `state.name` | `stateName` | string | `"Maryland"` | | `dma.code` | `dmaCode` | string | `"26"` | | `dma.name` | `dmaName` | string | `"Baltimore"` | | `postalCode.code` | `postalCode` | string | `"21014"` | ### user.entered\_region\_country | Radar Event Field | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `type` | `type` | string | `"user.entered_region_country"` | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `region.code` | `regionCode` | string | `"US"` | | `region.name` | `regionName` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_region\_country | Radar Event Field | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `type` | `type` | string | `"user.exited_region_country"` | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `region.code` | `regionCode` | string | `"US"` | | `region.name` | `regionName` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_region\_state | Radar Event Field | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `type` | `type` | string | `"user.entered_region_state"` | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `region.code` | `regionCode` | string | `"MD"` | | `region.name` | `regionName` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_region\_state | Radar Event Field | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `type` | `type` | string | `"user.exited_region_state"` | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `region.code` | `regionCode` | string | `"MD"` | | `region.name` | `regionName` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_region\_dma | Radar Event Field | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `type` | `type` | string | `"user.entered_region_dma"` | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `region.code` | `regionCode` | string | `"26"` | | `region.name` | `regionName` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_region\_dma | Radar Event Field | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `type` | `type` | string | `"user.exited_region_dma"` | | `user.userId` | `userUserId` | string | `"1"` | | `user.deviceId` | `userDeviceId` | string | `"10974a2ee035770b9"` | | `region.code` | `regionCode` | string | `"26"` | | `region.name` | `regionName` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.started\_trip | Radar Event Attribute | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string (max length 100) | `"299"` | | `trip.metadata` | `tripMetadata` | string (max length 4,000) | `'{"Car Model":"Green Honda Civic"}'` | | `trip.destinationGeofenceTag` | `tripDestinationGeofenceTag` | string (max length 100) | `"store"` | | `trip.destinationGeofenceExternalId` | `tripDestinationGeofenceExternalId` | string (max length 100) | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.updated\_trip | Radar Event Attribute | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string (max length 100) | `"299"` | | `trip.metadata` | `tripMetadata` | string (max length 4,000) | `'{"Car Model":"Green Honda Civic"}'` | | `trip.destinationGeofenceTag` | `tripDestinationGeofenceTag` | string (max length 100) | `"store"` | | `trip.destinationGeofenceExternalId` | `tripDestinationGeofenceExternalId` | string (max length 100) | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.approaching\_trip\_destination | Radar Event Attribute | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string (max length 100) | `"299"` | | `trip.metadata` | `tripMetadata` | string (max length 4,000) | `'{"Car Model":"Green Honda Civic"}'` | | `trip.destinationGeofenceTag` | `tripDestinationGeofenceTag` | string (max length 100) | `"store"` | | `trip.destinationGeofenceExternalId` | `tripDestinationGeofenceExternalId` | string (max length 100) | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.arrived\_at\_trip\_destination | Radar Event Attribute | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string (max length 100) | `"299"` | | `trip.metadata` | `tripMetadata` | string (max length 4,000) | `'{"Car Model":"Green Honda Civic"}'` | | `trip.destinationGeofenceTag` | `tripDestinationGeofenceTag` | string (max length 100) | `"store"` | | `trip.destinationGeofenceExternalId` | `tripDestinationGeofenceExternalId` | string (max length 100) | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.stopped\_trip | Radar Event Attribute | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `trip.externalId` | `tripExternalId` | string (max length 100) | `"299"` | | `trip.metadata` | `tripMetadata` | string (max length 4,000) | `'{"Car Model":"Green Honda Civic"}'` | | `trip.destinationGeofenceTag` | `tripDestinationGeofenceTag` | string (max length 100) | `"store"` | | `trip.destinationGeofenceExternalId` | `tripDestinationGeofenceExternalId` | string (max length 100) | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### user.entered\_beacon | Radar Event Attribute | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `beacon._id` | `beaconId` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beaconDescription` | string (max length 100) | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beaconTag` | string (max length 100) | `"drive-thru"` | | `beacon.externalId` | `beaconExternalId` | string (max length 100) | `"123"` | | `beacon.metadata` | `beaconMetadata` | string (max length 4,000) | `'{"type":"parking"}'` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### user.exited\_beacon | Radar Event Attribute | Salesforce Event Attribute | Type | Example Value | | - | - | - | - | | `beacon._id` | `beaconId` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beaconDescription` | string (max length 100) | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beaconTag` | string (max length 100) | `"drive-thru"` | | `beacon.externalId` | `beaconExternalId` | string (max length 100) | `"123"` | | `beacon.metadata` | `beaconMetadata` | string (max length 4,000) | `'{"type":"parking"}'` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `1.42` | | `foreground` | `foreground` | boolean | `true` | # Segment Source: https://docs.radar.com/integrations/segment Send Radar location events and user traits to Segment as a source and forward them to your warehouse and other destinations. > [!NOTE] > > The Segment integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can send events and user traits to [Segment](https://segment.com) as a source. Segment can send those events and user traits to your warehouse and to hundreds of destinations. Use the Segment integration to forward location events and user context to any destinations or to build location-based user segments with Personas. ## Configuration In Segment, add Radar as a source and copy your write key. Then, on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *Segment Source*, set *Enabled* to *Yes* and paste your write key. Note that you can set separate write keys for the *Test* and *Live* environments. Whenever events are generated, Radar will call `track` and `identify` to send events and user traits to Segment. By default, Radar `userId` maps to Segment `userId` for logged in users, and Radar `deviceId` maps to Segment `anonymousId` for logged out users. However, you can specify custom mappings by setting Radar `metadata.segmentUserId` or `metadata.segmentAnonymousId`. For example, on iOS: ```swift theme={null} // track logged out users with custom anonymousId mapping (not required if using default mapping) Radar.setMetadata(["segmentAnonymousId": anonymousId]) // track logged in users with custom userId mapping (not required if using default mapping) Radar.setMetadata(["segmentUserId": userId]) ``` ## User mapping Note that Radar uses the special string `"(null)"` to represent `null` user trait values. | Radar User Field | Segment User Trait | Type | Example Value | Context Type | | - | - | - | - | - | | `metadata.segmentUserId` or `userId` | `userId` | string | `"1"` | | | `metadata.segmentAnonymousId` or `deviceId` | `anonymousId` | string | `"10974a2ee035770b9"` | | | `_id` | `radar_id` | string | `"5b2c0906f5874b001aecfd8d"` | | | `location.coordinates[1]` | `radar_location_latitude` | number | `39.525665` | | | `location.coordinates[0]` | `radar_location_longitude` | number | `-76.350663` | | | `locationAuthorization` | `radar_location_authorization` | string | `"GRANTED_FOREGROUND"` | | | `locationAccuracyAuthorization` | `radar_location_accuracy_authorization` | string | `"FULL"` | | | `updatedAt` | `radar_updated_at` | timestamp | `"2018-06-22T15:23:39.000Z"` | | | `segments[*].externalId` | `radar_segment_external_ids` | array\[string] | `["starbucks-visitors"]` | | | `topChains[*].slug` | `radar_top_chain_slugs` | array\[string] | `["starbucks", "walmart"]` | | | `topChains[*].externalId` | `radar_top_chain_external_ids` | array\[string] | `["123", "456"]` | | | `geofences[*]._id` | `radar_geofence_ids` | array\[string] | `["5b2c0906f5874b001aecfd8e"]` | [Geofences](/geofencing/geofences) | | `geofences[*].description` | `radar_geofence_descriptions` | array\[string] | `["Store #123"]` | [Geofences](/geofencing/geofences) | | `geofences[*].tag` | `radar_geofence_tags` | array\[string] | `["store"]` | [Geofences](/geofencing/geofences) | | `geofences[*].externalId` | `radar_geofence_external_ids` | array\[string] | `["123"]` | [Geofences](/geofencing/geofences) | | `place._id` | `radar_place_id` | string | `"59302bcf8f27e8a156bd4f91"` | [Places](/geofencing/places) | | `place.name` | `radar_place_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `place.categories` | `radar_place_categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | [Places](/geofencing/places) | | `place.chain.slug` | `radar_place_chain_slug` | string | `"starbucks"` | [Places](/geofencing/places) | | `place.chain.name` | `radar_place_chain_name` | string | `"Starbucks"` | [Places](/geofencing/places) | | `country.code` | `radar_region_country_code` | string | `"US"` | [Regions](/geofencing/regions) | | `country.name` | `radar_region_country_name` | string | `"United States"` | [Regions](/geofencing/regions) | | `state.code` | `radar_region_state_code` | string | `"MD"` | [Regions](/geofencing/regions) | | `state.name` | `radar_region_state_name` | string | `"Maryland"` | [Regions](/geofencing/regions) | | `dma.code` | `radar_region_dma_code` | string | `"26"` | [Regions](/geofencing/regions) | | `dma.name` | `radar_region_dma_name` | string | `"Baltimore"` | [Regions](/geofencing/regions) | | `postalCode.code` | `radar_region_postal_code` | string | `"21014"` | [Regions](/geofencing/regions) | | `trip.externalId` | `radar_trip_external_id` | string | `"299"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceTag` | `radar_trip_destination_geofence_tag` | string | `"store"` | [Trip Tracking](/geofencing/trips) | | `trip.destinationGeofenceExternalId` | `radar_trip_destination_geofence_external_id` | string | `"123"` | [Trip Tracking](/geofencing/trips) | | `beacons[*]._id` | `radar_beacon_ids` | array\[string] | `["5b2c0906f5874b001aecfd8f]"` | [Beacons](/geofencing/beacons) | | `beacons[*].description` | `radar_beacon_descriptions` | array\[string] | `["Store #123 - Drive-Thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].tag` | `radar_beacon_tags` | array\[string] | `["drive-thru"]` | [Beacons](/geofencing/beacons) | | `beacons[*].externalId` | `radar_beacon_external_ids` | array\[string] | `["123"]` | [Beacons](/geofencing/beacons) | ## Event mapping | Radar Event | Context Type | Segment Event | | - | - | - | | `user.entered_geofence` | [Geofences](/geofencing/geofences) | `Geofence Entered` | | `user.exited_geofence` | [Geofences](/geofencing/geofences) | `Geofence Exited` | | `user.dwelled_in_geofence` | [Geofences](/geofencing/geofences) | `Dwelled in Geofence` | | `user.entered_place` | [Places](/geofencing/places) | `Place Entered` | | `user.exited_place` | [Places](/geofencing/places) | `Place Exited` | | `user.entered_region_country` | [Regions](/geofencing/regions) | `Country Entered` | | `user.exited_region_country` | [Regions](/geofencing/regions) | `Country Exited` | | `user.entered_region_state` | [Regions](/geofencing/regions) | `State Entered` | | `user.exited_region_state` | [Regions](/geofencing/regions) | `State Exited` | | `user.entered_region_dma` | [Regions](/geofencing/regions) | `DMA Entered` | | `user.exited_region_dma` | [Regions](/geofencing/regions) | `DMA Exited` | | `user.started_trip` | [Trip Tracking](/geofencing/trips) | `Trip Started` | | `user.updated_trip` | [Trip Tracking](/geofencing/trips) | `Trip Updated` | | `user.approaching_trip_destination` | [Trip Tracking](/geofencing/trips) | `Trip Approaching Destination` | | `user.arrived_at_trip_destination` | [Trip Tracking](/geofencing/trips) | `Trip Arrived Destination` | | `user.stopped_trip` | [Trip Tracking](/geofencing/trips) | `Trip Stopped` | | `user.entered_beacon` | [Beacons](/geofencing/beacons) | `Beacon Entered` | | `user.exited_beacon` | [Beacons](/geofencing/beacons) | `Beacon Exited` | ### Geofence Entered | Radar Event Field | Segment Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### Geofence Exited | Radar Event Field | Segment Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | ### Dwelled in Geofence | Radar Event Field | Segment Event Property | Type | Example Value | | - | - | - | - | | `geofence._id` | `geofence_id` | string | `"5b2c0906f5874b001aecfd8e"` | | `geofence.description` | `geofence_description` | string | `"Store #123"` | | `geofence.tag` | `geofence_tag` | string | `"store"` | | `geofence.externalId` | `geofence_external_id` | string | `"123"` | | `geofence.metadata[{key}]` | `geofence_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | ### Place Entered | Radar Event Field | Segment Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.chain.metadata[{key}]` | `place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `place_categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### Place Exited | Radar Event Field | Segment Event Property | Type | Example Value | | - | - | - | - | | `place._id` | `place_id` | string | `"59302bcf8f27e8a156bd4f91"` | | `place.name` | `place_name` | string | `"Starbucks"` | | `place.chain.slug` | `place_chain_id` | string | `"starbucks"` | | `place.chain.name` | `place_chain_name` | string | `"Starbucks"` | | `place.chain.metadata[{key}]` | `place_chain_metadata_{key}` | type | `{value}` | | `place.categories` | `place_categories` | array\[string] | `["food-beverage", "cafe", "coffee-shop"]` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `42.1` | | `foreground` | `foreground` | boolean | `true` | ### Country Entered | Radar Event Field | Segment Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### Country Exited | Radar Event Field | Segment Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"US"` | | `region.name` | `region_name` | string | `"United States"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### State Entered | Radar Event Field | Segment Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### State Exited | Radar Event Field | Segment Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"MD"` | | `region.name` | `region_name` | string | `"Maryland"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### DMA Entered | Radar Event Field | Segment Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### DMA Exited | Radar Event Field | Segment Event Property | Type | Example Value | | - | - | - | - | | `region.code` | `region_code` | string | `"26"` | | `region.name` | `region_name` | string | `"Baltimore"` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### Trip Started | Radar Event Attribute | Segment Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### Trip Updated | Radar Event Attribute | Segment Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### Trip Approaching Destination | Radar Event Attribute | Segment Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### Trip Arrived Destination | Radar Event Attribute | Segment Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### Trip Stopped | Radar Event Attribute | Segment Event Property | Type | Example Value | | - | - | - | - | | `trip.externalId` | `trip_external_id` | string | `"299"` | | `trip.metadata[{key}]` | `trip_metadata_{key}` | type | `{value}` | | `trip.destinationGeofenceTag` | `trip_destination_geofence_tag` | string | `"store"` | | `trip.destinationGeofenceExternalId` | `trip_destination_geofence_external_id` | string | `"123"` | | `foreground` | `foreground` | boolean | `true` | ### Beacon Entered | Radar Event Attribute | Segment Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `beacon_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `foreground` | `foreground` | boolean | `true` | ### Beacon Exited | Radar Event Attribute | Segment Event Property | Type | Example Value | | - | - | - | - | | `beacon._id` | `beacon_id` | string | `"5b2c0906f5874b001aecfd8f"` | | `beacon.description` | `beacon_description` | string | `"Store #123 - Drive-Thru"` | | `beacon.tag` | `beacon_tag` | string | `"drive-thru"` | | `beacon.externalId` | `beacon_external_id` | string | `"123"` | | `beacon.metadata[{key}]` | `beacon_metadata_{key}` | type | `{value}` | | `confidence` | `confidence` | string | `"high"` | | `duration` | `duration` | number (minutes) | `1.42` | | `foreground` | `foreground` | boolean | `true` | # Webhooks Source: https://docs.radar.com/integrations/webhooks Send Radar events and user state to your server, a cloud function, or any HTTP endpoint with webhooks, including payloads and signature verification. You can use webhooks to send events and user state from Radar to your server, a [Google or Firebase Cloud Function](https://firebase.google.com/docs/functions/functions-and-firebase), an [AWS Lambda Function](https://aws.amazon.com/lambda/), or any HTTP endpoint. From there, you can store events and user state in a database, send them to a marketing automation or analytics platform, and more. ## Configuration Create a webhook on the Radar [Integrations page](https://dashboard.radar.com/integrations) under *Webhooks*. For *Environment*, choose *Test* to receive callbacks for events in the *Test* environment, or choose *Live* to receive callbacks for events in the *Live* environment. For *Event Delivery*, choose *Single Event* to receive a single event in each request, or choose *Multiple Events* to receive multiple events in each request when events occur simultaneously. Finally, enter a URL. Whenever events are generated, Radar will send a `POST` request containing event and user data to the specified URL. You can also click the *Test* button to send test event and user data. If you chose *Single Event*, the request body will contain an `event` dictionary and a `user` dictionary. If you chose *Multiple Events*, the request body will contain an `events` array and a `user` dictionary. For multiple events, if there are over 5 events, the events will be chunked out in groups of 5 into separate `POST` requests. To acknowledge receipt of the request, your webhook should return a `2xx` status code (e.g., `200 OK`, `201 Created`, or `202 Accepted`). Each webhook has a random security token. The authenticity of a request made to a webhook URL can be verified using the `X-Radar-Signature` header. The header will contain an `HMAC-SHA1` hash of the `X-Radar-Signing-Id` header using the security token as the key. Note that you can also receive events client-side via the [SDK](/sdk). **Sample request body** ```json theme={null} { "events": [ { "_id": "56db1f4613012711002229f6", "type": "user.entered_geofence", "createdAt": "2018-06-12T13:44:10.535Z", "live": true, "user": { "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", "metadata": { "customId": "abc", "customFlag": false }, "locationAuthorization": "GRANTED_FOREGROUND", "locationAccuracyAuthorization": "FULL" }, "geofence": { "tag": "store", "externalId": "123", "description": "Store #123", "metadata": { "parking": false } }, "location": { "type": "Point", "coordinates": [ -73.977797, 40.783826 ] }, "locationAccuracy": 5, "confidence": 3, "foreground": true, "actualCreatedAt": "2018-06-12T13:44:10.535Z" }, { "_id": "56db1f4613012711002229f7", "type": "user.entered_place", "createdAt": "2018-06-12T13:44:10.535Z", "live": true, "user": { "_id": "56db1f4613012711002229f4", "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", "metadata": { "customId": "abc", "customFlag": false }, "locationAuthorization": "GRANTED_FOREGROUND", "locationAccuracyAuthorization": "FULL" }, "place": { "name": "Starbucks", "chain": { "name": "Starbucks", "slug": "starbucks", "externalId": "123", "metadata": { "customFlag": true } }, "categories": [ "food-beverage", "coffee-shop" ], "location": { "type": "Point", "coordinates": [ -73.977797, 40.783826 ] } }, "location": { "type": "Point", "coordinates": [ -73.977797, 40.783826 ] }, "locationAccuracy": 5, "confidence": 2, "foreground": true, "actualCreatedAt": "2018-06-12T13:44:10.535Z" } ], "user": { "_id": "56db1f4613012711002229f4", "live": true, "userId": "1", "deviceId": "C305F2DB-56DC-404F-B6C1-BC52F0B680D8", "metadata": { "customId": "abc", "customFlag": false }, "updatedAt": "2018-06-12T13:44:10.535Z", "createdAt": "2018-06-10T11:23:58.741Z", "location": { "type": "Point", "coordinates": [ -73.977797, 40.783826 ] }, "locationAccuracy": 5, "locationAuthorization": "GRANTED_FOREGROUND", "locationAccuracyAuthorization": "FULL", "stopped": true, "foreground": false, "deviceType": "iOS", "ip": "173.14.0.1", "geofences": [ { "tag": "store", "externalId": "123", "description": "Store #123", "metadata": { "parking": false } } ], "place": { "name": "Starbucks", "chain": { "name": "Starbucks", "slug": "starbucks" }, "categories": [ "food-beverage", "coffee-shop" ], "location": { "type": "Point", "coordinates": [ -73.977797, 40.783826 ] } }, "country": { "code": "US", "name": "United States", "flag": "🇺🇸" }, "state": { "code": "MD", "name": "Maryland", "passed": false, "allowed": true, "distanceToBorder": 1092.3, "inBufferZone": false, "inExclusionZone": false }, "dma": { "code": "26", "name": "Baltimore" }, "postalCode": { "code": "21014", "name": "21014" }, "segments": [ { "description": "Starbucks Visitors", "externalId": "starbucks-visitors" } ], "topChains": [ { "name": "Starbucks", "slug": "starbucks", "externalId": "123" }, { "name": "Walmart", "slug": "walmart", "externalId": "456" } ], "fraud": { "verified": true, "passed": false, "bypassed": false, "blocked": false, "mocked": true, "jumped": false, "compromised": false, "inaccurate": false, "proxy": false, "sharing": false, "lastMockedAt": "2023-07-27T17:18:28.536Z", "lastJumpedAt": "2023-07-27T17:18:28.536Z", "lastCompromisedAt": null, "lastInaccurateAt": null, "lastProxyAt": null, "lastSharingAt": null } } } ``` # Yext Source: https://docs.radar.com/integrations/yext Sync locations from Yext into Radar as geofences. > [!NOTE] > > The Yext integration is available on the [**Enterprise plan**](https://radar.com/pricing). Radar can sync locations from [Yext](http://www.yext.com) as geofences in Radar. ## Configuration On the Radar [Integrations page](https://dashboard.radar.com/integrations) under *Yext*, set *Enabled* to *Yes* and optionally configure any additional settings. ### Default Settings Radar will use the following default mappings when syncing Yext locations to Radar geofences: | Yext Location Field | Radar Geofence Field | Type | | - | - | - | | `locationName` | `description` | string | | `id` | `externalId` | string | | `closed.isClosed` | `enabled` | boolean | Radar will use the following default values when syncing Yext locations to Radar geofences: | Radar Geofence Field | Default Value | Type | | - | - | - | | `type` | `circle` | string (`circle` or `isochrone`) | | `tag` | `location` | string | | `radius` | `100` (for `circle`) `15` (for `isochrone`) | number (meters for `circle`, minutes for `isochrone`) | ### Additional Settings You can choose to override certain defaults with additional configuration settings for the [geofences](/geofencing/geofences) synced from Yext. The available overrides include: * Default geofence `type` * Default geofence `radius` * An override for the mapping of the `description` field to a different Yext field than `locationName` (e.g. `address`) * An override for the default `tag` value that will be mapped to a Yext field (e.g. `schemaTypes.0`) Additionally, you can map up to 16 Yext fields to Radar geofence metadata. Use *dot notation* to access nested Yext fields. For example, if you have a Yext location with the following property: `"schemaTypes": ["Restaurant"]`, you can store the value `"Restaurant"` by adding `schemaTypes.0` as a *Yext Key*. If you include a Yext field in the metadata mapping and that field is not found, or the value in Yext is undefined or `null`, the value will not be copied over to the geofence. ### Syncing Data Once configured, click *Connect & Sync* and you will be redirected to Yext, where you can authorize Radar. Then, you will be redirected back to the Radar [Integrations page](https://dashboard.radar.com/integrations) with an indication of whether the authorization succeeded or failed. If the authorization succeeded, your Yext locations will immediately begin syncing to Radar [geofences](/geofencing/geofences). Radar will automatically keep geofences in sync when you create or update locations in Yext. Radar will sync geofences both to the *Test* and *Live* environments. **If you update the geometry of a geofence in Radar that has been synced with Yext, your changes will not be overwritten in Radar with subsequent updates from Yext.** Update any of the defaults after the initial sync by changing the integration settings and clicking *Update & Sync*. Once clicked, a full sync of every Yext location will occur. **A change in these default overrides will only be reflected for newly created locations in Yext. Previously synced locations turned geofences will not be updated to the new defaults.** # Autocomplete Source: https://docs.radar.com/maps/autocomplete Add address autocomplete to your website or app with Radar's autocomplete UI component. Use Radar's autocomplete component to add address autocomplete to your websites and apps with just a few lines of code. You can check out the [autocomplete explorer](https://dashboard.radar.com/maps/maps-explorer/autocomplete) in the dashboard, or check out a full-page [maps demo](https://radar.com/demo/maps) and [store locator demo](https://radar.com/demo/locator) with an autocomplete component. ## How it works To use the autocomplete component, simply initialize the Radar SDK with your publishable key and specify the container to render the input into. ## Configuration When creating the autocomplete component, you can provide options to customize the autocomplete behavior, as well as the size and style of the input. Available options include: | Name | Default | Possible values | Description | SDK availability | | - | - | - | - | - | | `container` | `autocomplete` | string \| HTMLElement | The container to render the autocomplete into. You can specify an `id` of an HTML element or a DOM element. If an `` is provided as a container, the style of the input will not be modified. | Web | | `width` | `400` | number \| string | The width of the input, a number (in pixels) or any valid CSS width. | Web | | `maxHeight` | `null` | number \| string | The max height of the results list, a number (in pixels) or any valid CSS height. | Web | | `near` | `null` | string \| Location | The location to search near, in the format `"latitude,longitude"` or `{ latitude, longitude }`. If not specified, the search will automatically be biased based on the client's [IP geolocation](/api#ip-geocode). | Web, React Native | | `debounceMS` | `200` | number | The number of milliseconds to wait after typing is complete to refresh the results list. | Web, React Native | | `minCharacters` | `3` | number | The minimum number of characters that need to be typed before fetching results. | Web, React Native | | `limit` | `8` | number | The maximum number of results to show in the results list. | Web, React Native | | `onSelection` | `null` | function `(address) => {}` | A function called when a result is selected from the results list. | Web, React Native | | `onResults` | `null` | function `(addresses) => {}` | A function called when the results list is refreshed. | Web, React Native | | `onError` | `null` | function `(error) => {}` | A function called if any errors occur. | Web, React Native | | `placeholder` | `Search address` | string | The placeholder string for the input. | Web, React Native | | `responsive` | `true` | boolean | A boolean that indicates whether the input should expand to fill the parent container. If `responsive = true` and a `width` is specified, `width` will be treated as a `max-width`. | Web | | `disabled` | `false` | boolean | A boolean that indicates whether the input should be disabled. | Web, React Native | | `layers` | `null` | array | Optional layer filters. An array including one or more of `place`, `address`, `street`, `neighborhood`, `postalCode`, `locality`, `county`, `state`, `country`, `coarse`, and `fine`. See the [autocomplete API documentation](/api#autocomplete) for more info. | Web, React Native | | `countryCode` | `null` | string | An optional 2-letter [ISO 3166](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes) country code. If set, results will only be fetched from the specified country. | Web, React Native | | `showMarkers` | `true` | boolean | A boolean that indicates whether to show marker icons in the results list. | Web, React Native | | `markerColor` | `#acbdc8` | string | The CSS color of marker icons in the results list. | Web | | `style` | `null` | React Native style object | Styles for the element. See the [code](https://github.com/radarlabs/react-native-radar/blob/master/js/ui/autocomplete.jsx) for more info. | React Native | ## Quickstart First, [sign up](https://radar.com/signup) for Radar and get an API key. Then, get started with the sample code below. ### JavaScript ```html theme={null}
``` ### React ```javascript theme={null} import React, { useEffect, useRef } from 'react'; import Radar from 'radar-sdk-js'; import { createAutocompletePlugin } from '@radarlabs/plugin-autocomplete'; import '@radarlabs/plugin-autocomplete/dist/radar-autocomplete.css'; Radar.registerPlugin(createAutocompletePlugin()); const RadarAutocomplete = () => { const autocompleteRef = useRef(null); useEffect(() => { Radar.initialize('prj_live_pk_...'); autocompleteRef.current = Radar.ui.autocomplete({ container: 'autocomplete', width: '600px', onSelection: (address) => { // Do something with the selected address console.log(address); }, }); return () => { autocompleteRef.current?.remove(); }; }, []); return (
); }; export default RadarAutocomplete; ``` ### React Native ```javascript theme={null} import { View } from 'react-native'; import { useState, useEffect } from 'react'; import Radar, { Autocomplete } from 'react-native-radar'; Radar.initialize('prj_live_pk_...'); export const App = () => ( { // do something with selected address }, } /> ); ``` ## Examples ### Use Autocomplete with Radar Maps in React Below is an example of how you can use [Radar Maps](/maps/maps) with Radar Autocomplete in React. ```javascript theme={null} import React, { useEffect, useRef } from 'react'; import Radar from 'radar-sdk-js'; import { createMapsPlugin } from '@radarlabs/plugin-maps'; import { createAutocompletePlugin } from '@radarlabs/plugin-autocomplete'; import '@radarlabs/plugin-maps/dist/radar-maps.css'; import '@radarlabs/plugin-autocomplete/dist/radar-autocomplete.css'; Radar.registerPlugin(createMapsPlugin()); Radar.registerPlugin(createAutocompletePlugin()); const RadarMap = () => { const mapRef = useRef(null); const markerRef = useRef(null); const autocompleteRef = useRef(null); useEffect(() => { Radar.initialize('prj_live_pk_...'); // Create a map const map = Radar.ui.map({ container: 'map', style: 'radar-default-v1', center: [-73.9911, 40.7342], // NYC zoom: 14, }); mapRef.current = map; // Add a marker to the map const marker = Radar.ui.marker({ popup: { text: 'Radar HQ' } }) .setLngLat([-73.9910078, 40.7342465]) .addTo(map); markerRef.current = marker; // Initialize Radar autocomplete autocompleteRef.current = Radar.ui.autocomplete({ container: 'autocomplete', width: '400px', onSelection: (address) => { const { latitude, longitude } = address; console.log('Selected address:', address); // Update marker position markerRef.current.setLngLat([longitude, latitude]); // Center the map on the selected address mapRef.current.flyTo({ center: [longitude, latitude], zoom: 14 }); }, }); return () => { autocompleteRef.current?.remove(); }; }, []); return (
); }; export default RadarMap; ``` # Geocoding APIs Source: https://docs.radar.com/maps/geocoding Convert addresses to coordinates and coordinates to addresses with Radar's forward geocoding, reverse geocoding, and IP geocoding APIs. Use Radar's geocoding APIs to convert addresses to latitude and longitude coordinates, or vice versa. ![Geocode illustration](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/illustrations/geocode-illustration.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=3fc8c50615bc6a80292ace16ee45c02f) ## Quickstart First, [sign up](https://radar.com/signup) for Radar and get an API key. Then, call one of the geocoding APIs below, either [directly](/api) or [using the SDK](/sdk/sdk). From there, use the APIs to build location features in your app or website, such as store locators, address autocomplete, or delivery tracking. ## Endpoints ### Forward geocoding Use the forward geocoding API to convert addresses to coordinates. This endpoint is best for complete addresses. For partial addresses, call the [autocomplete API](/maps/search#address-autocomplete) instead. Use cases for this endpoint include converting an address to coordinates to drop a pin on a map or search nearby the address. See the forward geocoding API reference [here](/api#forward-geocode). ### Reverse geocoding Use the reverse geocoding API to convert coordinates to an address. Use cases for this endpoint include displaying an address for a pin dropped on a map. See the reverse geocoding API reference [here](/api#reverse-geocode). ### IP geocoding Use the IP geocoding API to convert IP address to city, state, and country. Use cases for this endpoint include localizing content on a website or in an app without requesting location permissions. See the IP geocoding API reference [here](/api#ip-geocode). ## Coverage Radar's geocoding APIs incorporate both open and commercial datasets for maximum coverage at an affordable price relative to alternatives. The following table describes data coverage for geocoding APIs, by country, for consumer use cases (e.g., store locators) and logistics use cases (e.g., ride sharing, delivery). #### Legend | Icon | Description | | - | - | | ⬤ | Great data quality and availability | | ◐ | Good data quality and availability | | ◯ | Approximate data quality and availability | #### Coverage | | Coarse (city-level) forward and reverse geocoding | Fine (address-level) forward and reverse geocoding | IP geocoding | | - | - | - | - | | Afghanistan | ⬤ | ◯ | ⬤ | | Albania | ⬤ | ◯ | ⬤ | | Algeria | ⬤ | ⬤ | ⬤ | | Andorra | ⬤ | ⬤ | ⬤ | | Angola | ⬤ | ◯ | ⬤ | | Anguilla | ⬤ | ◯ | ⬤ | | Antarctica | ⬤ | ◯ | ⬤ | | Antigua and Barbuda | ⬤ | ◯ | ⬤ | | Argentina | ⬤ | ⬤ | ⬤ | | Armenia | ⬤ | ⬤ | ⬤ | | Aruba | ⬤ | ◯ | ⬤ | | Australia | ⬤ | ⬤ | ⬤ | | Austria | ⬤ | ⬤ | ⬤ | | Azerbaijan | ⬤ | ⬤ | ⬤ | | Bahamas | ⬤ | ◯ | ⬤ | | Bahrain | ⬤ | ⬤ | ⬤ | | Bangladesh | ⬤ | ◯ | ⬤ | | Barbados | ⬤ | ◯ | ⬤ | | Belarus | ⬤ | ⬤ | ⬤ | | Belgium | ⬤ | ⬤ | ⬤ | | Belize | ⬤ | ◯ | ⬤ | | Benin | ⬤ | ◯ | ⬤ | | Bermuda | ⬤ | ◯ | ⬤ | | Bhutan | ⬤ | ◯ | ⬤ | | Bolivia | ⬤ | ◯ | ⬤ | | Bonaire Sint Eustatius and Saba | ⬤ | ◯ | ⬤ | | Bosnia-Herzegovina | ⬤ | ⬤ | ⬤ | | Botswana | ⬤ | ◯ | ⬤ | | Bouvet Island | ⬤ | ◯ | ⬤ | | Brazil | ⬤ | ⬤ | ⬤ | | British Virgin Islands | ⬤ | ◯ | ⬤ | | Brunei | ⬤ | ◐ | ⬤ | | Bulgaria | ⬤ | ⬤ | ⬤ | | Burkina Faso | ⬤ | ◯ | ⬤ | | Burundi | ⬤ | ◯ | ⬤ | | Cabo Verde | ⬤ | ◯ | ⬤ | | Cambodia | ⬤ | ◐ | ⬤ | | Cameroon | ⬤ | ◯ | ⬤ | | Canada | ⬤ | ⬤ | ⬤ | | Cayman Islands | ⬤ | ◯ | ⬤ | | Central African Republic | ⬤ | ◯ | ⬤ | | Chad | ⬤ | ◯ | ⬤ | | Chile | ⬤ | ⬤ | ⬤ | | Clipperton Island | ⬤ | ◯ | ⬤ | | Cocos (Keeling) Islands | ⬤ | ◯ | ⬤ | | Colombia | ⬤ | ⬤ | ⬤ | | Comoros | ⬤ | ◯ | ⬤ | | Congo-Brazzaville | ⬤ | ◯ | ⬤ | | Cook Islands | ⬤ | ◯ | ⬤ | | Costa Rica | ⬤ | ◯ | ⬤ | | Cote d'Ivoire | ⬤ | ◯ | ⬤ | | Croatia | ⬤ | ⬤ | ⬤ | | Cuba | ⬤ | ◯ | ⬤ | | Curacao | ⬤ | ◯ | ⬤ | | Cyprus | ⬤ | ⬤ | ⬤ | | Czechia | ⬤ | ⬤ | ⬤ | | Democratic Republic of the Congo | ⬤ | ◯ | ⬤ | | Denmark | ⬤ | ⬤ | ⬤ | | Djibouti | ⬤ | ◯ | ⬤ | | Dominica | ⬤ | ◯ | ⬤ | | Dominican Republic | ⬤ | ◯ | ⬤ | | Ecuador | ⬤ | ⬤ | ⬤ | | Egypt | ⬤ | ◐ | ⬤ | | El Salvador | ⬤ | ◯ | ⬤ | | Equatorial Guinea | ⬤ | ◯ | ⬤ | | Eritrea | ⬤ | ◯ | ⬤ | | Estonia | ⬤ | ⬤ | ⬤ | | Eswatini | ⬤ | ◯ | ⬤ | | Ethiopia | ⬤ | ◯ | ⬤ | | Falkland Islands | ⬤ | ◯ | ⬤ | | Faroe Islands | ⬤ | ⬤ | ⬤ | | Federated States of Micronesia | ⬤ | ◯ | ⬤ | | Fiji | ⬤ | ◯ | ⬤ | | Finland | ⬤ | ⬤ | ⬤ | | France | ⬤ | ⬤ | ⬤ | | French Guiana | ⬤ | ⬤ | ⬤ | | French Polynesia | ⬤ | ◯ | ⬤ | | French Southern and Antarctic Lands | ⬤ | ◯ | ⬤ | | Gabon | ⬤ | ◯ | ⬤ | | Georgia | ⬤ | ⬤ | ⬤ | | Germany | ⬤ | ⬤ | ⬤ | | Ghana | ⬤ | ◯ | ⬤ | | Gibraltar | ⬤ | ◯ | ⬤ | | Greece | ⬤ | ⬤ | ⬤ | | Greenland | ⬤ | ◯ | ⬤ | | Grenada | ⬤ | ◯ | ⬤ | | Guadeloupe | ⬤ | ⬤ | ⬤ | | Guatemala | ⬤ | ◯ | ⬤ | | Guinea | ⬤ | ◯ | ⬤ | | Guinea-Bissau | ⬤ | ◯ | ⬤ | | Guyana | ⬤ | ◯ | ⬤ | | Haiti | ⬤ | ◯ | ⬤ | | Heard Island and McDonald Islands | ⬤ | ◯ | ⬤ | | Holy See | ⬤ | ◯ | ⬤ | | Honduras | ⬤ | ◯ | ⬤ | | Hong Kong | ⬤ | ◐ | ⬤ | | Hungary | ⬤ | ⬤ | ⬤ | | Iceland | ⬤ | ⬤ | ⬤ | | India | ⬤ | ◐ | ⬤ | | Indonesia | ⬤ | ◐ | ⬤ | | Iran | ⬤ | ◯ | ⬤ | | Iraq | ⬤ | ◯ | ⬤ | | Ireland | ⬤ | ⬤ | ⬤ | | Israel | ⬤ | ◐ | ⬤ | | Italy | ⬤ | ⬤ | ⬤ | | Jamaica | ⬤ | ◯ | ⬤ | | Japan | ⬤ | ◐ | ⬤ | | Jordan | ⬤ | ◐ | ⬤ | | Kazakhstan | ⬤ | ◐ | ⬤ | | Kenya | ⬤ | ◯ | ⬤ | | Kiribati | ⬤ | ◯ | ⬤ | | Kosovo | ⬤ | ⬤ | ⬤ | | Kuwait | ⬤ | ◐ | ⬤ | | Kyrgyzstan | ⬤ | ◯ | ⬤ | | Laos | ⬤ | ◐ | ⬤ | | Latvia | ⬤ | ⬤ | ⬤ | | Lebanon | ⬤ | ◐ | ⬤ | | Lesotho | ⬤ | ◯ | ⬤ | | Liberia | ⬤ | ◯ | ⬤ | | Libya | ⬤ | ◯ | ⬤ | | Liechtenstein | ⬤ | ⬤ | ⬤ | | Lithuania | ⬤ | ⬤ | ⬤ | | Luxembourg | ⬤ | ⬤ | ⬤ | | Macao | ⬤ | ◐ | ⬤ | | Madagascar | ⬤ | ◯ | ⬤ | | Malawi | ⬤ | ◯ | ⬤ | | Malaysia | ⬤ | ◐ | ⬤ | | Maldives | ⬤ | ◯ | ⬤ | | Mali | ⬤ | ◯ | ⬤ | | Malta | ⬤ | ⬤ | ⬤ | | Marshall Islands | ⬤ | ◯ | ⬤ | | Martinique | ⬤ | ⬤ | ⬤ | | Mauritania | ⬤ | ◯ | ⬤ | | Mauritius | ⬤ | ◯ | ⬤ | | Mayotte | ⬤ | ⬤ | ⬤ | | Mexico | ⬤ | ⬤ | ⬤ | | Moldova | ⬤ | ⬤ | ⬤ | | Monaco | ⬤ | ◐ | ⬤ | | Mongolia | ⬤ | ◯ | ⬤ | | Montenegro | ⬤ | ⬤ | ⬤ | | Montserrat | ⬤ | ◯ | ⬤ | | Morocco | ⬤ | ◐ | ⬤ | | Mozambique | ⬤ | ◯ | ⬤ | | Myanmar | ⬤ | ◐ | ⬤ | | Namibia | ⬤ | ◯ | ⬤ | | Nauru | ⬤ | ◯ | ⬤ | | Nepal | ⬤ | ◯ | ⬤ | | Netherlands | ⬤ | ⬤ | ⬤ | | New Caledonia | ⬤ | ◯ | ⬤ | | New Zealand | ⬤ | ⬤ | ⬤ | | Nicaragua | ⬤ | ◯ | ⬤ | | Niger | ⬤ | ◯ | ⬤ | | Nigeria | ⬤ | ◯ | ⬤ | | Niue | ⬤ | ◯ | ⬤ | | Norfolk Island | ⬤ | ◯ | ⬤ | | Norway | ⬤ | ⬤ | ⬤ | | Pakistan | ⬤ | ◯ | ⬤ | | Palau | ⬤ | ◯ | ⬤ | | Panama | ⬤ | ◯ | ⬤ | | Papua New Guinea | ⬤ | ◯ | ⬤ | | Paraguay | ⬤ | ⬤ | ⬤ | | Peru | ⬤ | ⬤ | ⬤ | | Philippines | ⬤ | ◐ | ⬤ | | Pitcairn Islands | ⬤ | ◯ | ⬤ | | Poland | ⬤ | ⬤ | ⬤ | | Portugal | ⬤ | ⬤ | ⬤ | | Qatar | ⬤ | ◯ | ⬤ | | Republic of Belarus | ⬤ | ⬤ | ⬤ | | Republic of Korea | ⬤ | ◯ | ⬤ | | Republic of North Macedonia | ⬤ | ⬤ | ⬤ | | Reunion | ⬤ | ⬤ | ⬤ | | Romania | ⬤ | ⬤ | ⬤ | | Russia | ⬤ | ⬤ | ⬤ | | Rwanda | ⬤ | ◯ | ⬤ | | Saint Barthelemy | ⬤ | ◯ | ⬤ | | Saint Helena | ⬤ | ◯ | ⬤ | | Saint Kitts and Nevis | ⬤ | ◯ | ⬤ | | Saint Lucia | ⬤ | ◯ | ⬤ | | Saint Martin | ⬤ | ◯ | ⬤ | | Saint Pierre and Miquelon | ⬤ | ◯ | ⬤ | | Saint Vincent and the Grenadines | ⬤ | ◯ | ⬤ | | Samoa | ⬤ | ◯ | ⬤ | | San Marino | ⬤ | ⬤ | ⬤ | | Sao Tome and Principe | ⬤ | ◯ | ⬤ | | Saudi Arabia | ⬤ | ◐ | ⬤ | | Senegal | ⬤ | ◯ | ⬤ | | Serbia | ⬤ | ⬤ | ⬤ | | Seychelles | ⬤ | ◯ | ⬤ | | Sierra Leone | ⬤ | ◯ | ⬤ | | Singapore | ⬤ | ◐ | ⬤ | | Sint Maarten | ⬤ | ◯ | ⬤ | | Slovakia | ⬤ | ⬤ | ⬤ | | Slovenia | ⬤ | ⬤ | ⬤ | | Solomon Islands | ⬤ | ◯ | ⬤ | | Somalia | ⬤ | ◯ | ⬤ | | South Africa | ⬤ | ⬤ | ⬤ | | South Georgia and the South Sandwich Islands | ⬤ | ◯ | ⬤ | | South Sudan | ⬤ | ◯ | ⬤ | | Spain | ⬤ | ⬤ | ⬤ | | Sri Lanka | ⬤ | ◯ | ⬤ | | State Of Palestine | ⬤ | ◯ | ⬤ | | Sudan | ⬤ | ◯ | ⬤ | | Suriname | ⬤ | ◯ | ⬤ | | Sweden | ⬤ | ⬤ | ⬤ | | Switzerland | ⬤ | ⬤ | ⬤ | | Syria | ⬤ | ◯ | ⬤ | | Taiwan | ⬤ | ◯ | ⬤ | | Tajikistan | ⬤ | ◯ | ⬤ | | Tanzania | ⬤ | ◯ | ⬤ | | Thailand | ⬤ | ◯ | ⬤ | | The Gambia | ⬤ | ◯ | ⬤ | | The Sultanate of Oman | ⬤ | ◯ | ⬤ | | Timor-Leste | ⬤ | ◯ | ⬤ | | Togo | ⬤ | ◯ | ⬤ | | Tokelau | ⬤ | ◯ | ⬤ | | Tonga | ⬤ | ◯ | ⬤ | | Trinidad and Tobago | ⬤ | ◯ | ⬤ | | Tunisia | ⬤ | ⬤ | ⬤ | | Turkey | ⬤ | ⬤ | ⬤ | | Turkmenistan | ⬤ | ◯ | ⬤ | | Turks and Caicos Islands | ⬤ | ◯ | ⬤ | | Tuvalu | ⬤ | ◯ | ⬤ | | Uganda | ⬤ | ◯ | ⬤ | | Ukraine | ⬤ | ⬤ | ⬤ | | United Arab Emirates | ⬤ | ◐ | ⬤ | | United Kingdom | ⬤ | ⬤ | ⬤ | | United States | ⬤ | ⬤ | ⬤ | | Uruguay | ⬤ | ⬤ | ⬤ | | Uzbekistan | ⬤ | ◯ | ⬤ | | Vanuatu | ⬤ | ◯ | ⬤ | | Venezuela | ⬤ | ◯ | ⬤ | | Vietnam | ⬤ | ◯ | ⬤ | | Wallis and Futuna | ⬤ | ◯ | ⬤ | | Yemen | ⬤ | ◯ | ⬤ | | Zambia | ⬤ | ◯ | ⬤ | | Zimbabwe | ⬤ | ◯ | ⬤ | ## Caching You can cache API responses for up to 30 days. For more information, see our terms of use [here](https://radar.com/terms). ## Report an issue The Radar team is constantly working to improve data coverage for our geocoding, search, and routing APIs. Bad response? Unexpected error? Report it [here](https://forms.gle/9ZfHi95wd8xgEERb6), and our team will fix it ASAP. ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # Maps Source: https://docs.radar.com/maps/maps Add interactive Radar Maps to your website or app as a cost-effective alternative to Google Maps Platform and Mapbox. Radar Maps is a cost-effective alternative to Google Maps Platform and Mapbox. For example, here's a Radar Map displaying a marker for Radar HQ: [https://maps-demo.radar.com/map](https://maps-demo.radar.com/map) You can also check out the [maps explorer](https://dashboard.radar.com/maps/maps-explorer/maps) in the dashboard, or check out a full-page [maps demo](https://radar.com/demo/maps) and [store locator demo](https://radar.com/demo/locator). ## How it works To use Radar Maps, simply initialize the Radar SDK with your publishable key and specify the container to render the map into. Radar Maps is an extension of the [MapLibre GL JS](https://maplibre.org) library. See their [docs](https://maplibre.org/maplibre-gl-js/docs/API/) for more customization info. ## Getting Started First, [sign up](https://radar.com/signup) for Radar and get an API key. Then add the Radar SDK to your application. ### With npm or yarn Install the core SDK along with the maps plugin and MapLibre GL JS: ```sh theme={null} npm install radar-sdk-js @radarlabs/plugin-maps maplibre-gl ``` Then import and register the maps plugin in your project: ```javascript theme={null} import Radar from 'radar-sdk-js'; import { createMapsPlugin } from '@radarlabs/plugin-maps'; import '@radarlabs/plugin-maps/dist/radar-maps.css'; Radar.registerPlugin(createMapsPlugin()); // initialize with your test or live publishable key Radar.initialize('prj_test_pk_...', { /* map config options */ }); ``` Note: The maps plugin has a peer dependency on [maplibre-gl](https://github.com/maplibre/maplibre-gl-js). ### With HTML Add the core SDK and maps plugin scripts to your `html` file: ```html theme={null} ``` The maps plugin CDN bundle auto-registers with the core SDK when loaded. Then initialize the Radar SDK: ```html theme={null} ``` ### Create a map Specify the HTML element where you want to render the map, by providing the element's ID, or the element object itself. ```html HTML theme={null}
``` ```javascript React theme={null} import React from 'react'; import Radar from 'radar-sdk-js'; import { createMapsPlugin } from '@radarlabs/plugin-maps'; import '@radarlabs/plugin-maps/dist/radar-maps.css'; Radar.registerPlugin(createMapsPlugin()); class RadarMap extends React.Component { componentDidMount() { Radar.initialize('prj_live_pk_...'); // create a map const map = Radar.ui.map({ container: 'map', style: 'radar-default-v1', center: [-73.9911, 40.7342], // NYC zoom: 14, }); // add a marker to the map Radar.ui.marker({ popup: { text: 'Radar HQ' } }) .setLngLat([-73.9910078, 40.7342465]) .addTo(map); } render() { return (
); } }; export default RadarMap; ``` ## Configuration ### Map You can configure a map with any MapLibre [MapOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapOptions/). The minimum recommended options are the following: | Name | Default | Possible values | Description | | - | - | - | - | | `container` | none (required) | string \| HTMLElement | The container to render the map into. You can specify an `id` of an HTML element or a DOM element. The width and height of this element will determine the size of the map. | | `style` | `radar-default-v1` | `radar-default-v1`, `radar-light-v1`, `radar-dark-v1`, `radar-satellite-v1`, `radar-hybrid-v1` | The style of the map. See the [Styles](/maps/maps#styles) section below for more details. | | `center` | none (IP geolocation) | `[longitude, latitude]` | The center of the map. If not specified, the map will automatically be centered based on the client's [IP geolocation](/api#ip-geocode). | | `zoom` | 11 | number | The zoom level of the map, a number between 0 (fully zoomed out) and 23 (fully zoomed in). | | `language` | none | string (ISO code) | The display language for map. Can be any 2-letter [ISO Code](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes), or `local` to use the device's specified language. Defaults to `en-US` if none is provided. | ```javascript theme={null} const map = Radar.ui.map({ container: 'map', style: 'radar-default-v1', center: [-73.990550, 40.735225], zoom: 10, language: 'en-US', }); ``` #### Functions The Radar map class also includes some additional functions for handling common map interactions | Function | Arguments | Return value | Description | | - | - | - | - | | `on` | [MapLibre event](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapEventType/) | void | Register a callback to fire on a map event. | | `getMarkers` | none | RadarMarker\[] | Returns an array of all markers currently associated with the map. | | `fitToMarkers` | fitBoundsOptions, RadarMarker\[] (optional) | void | Fit the map zoom and bounds to all markers on the map. Optionally takes a list of markers to fit (defaults to all markers). | | `clearMarkers` | none | void | Remove all markers from the map. | | `getFeatures` | none | RadarMapFeature\[] | Returns an array of all features currently associated with the map. | | `fitToFeatures` | fitBoundsOptions | void | Fit the map zoom and bounds to all features on the map. | | `clearFeatures` | none | void | Remove all features from the map. | | `addPolygon` | GeoJSON\ Feature, polygonOptions | RadarMapFeature | Add a new polygon [Feature](/maps/maps#polygon-and-multipolygon) to the map. | | `addLine` | GeoJSON\ Feature, lineOptions | RadarMapFeature | Add a new line [Feature](/maps/maps#line-and-polyline) to the map. | | `addPolyline` | encodedPolyline, polylineOptions | RadarMapFeature | Accepts an encoded polyline and converts it to a line feature. Defaults to six decimals precision. | ```javascript theme={null} map.on('load', (event) => { // map loaded }); map.on('click', (event) => { // handle click on map }); map.fitToMarkers({ padding: 20 }); // fit map view to markers map.fitToFeatures({ padding: 20 }); // fit map view to features ``` ### Styles Radar provides several out-of-the box map styles: | Style | Preview | Description | | - | - | - | | `radar-default-v1` | ![](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/radar-default-theme.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=7cd2b9cc1d1b3e4684f00b68ab220284) | Radar's default map style, showcasing detailed street-level information about roads and nearby places. A general purpose map suitable for most use cases. | | `radar-light-v1` | ![](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/radar-light-theme.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=eec8b8b4bf864b0865c6493d516a92cd) | A light monochrome map style, useful for highlighting your own information or visualizations. | | `radar-dark-v1` | ![](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/radar-dark-theme.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=7c506018d6b07245c4c2f427c72956a0) | A dark monochrome map style, useful for highlighting your own information or visualizations in dark mode. | | `radar-satellite-v1` | ![](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/satellite.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=30d6910cc5e4ee704b7109c16d55de7f) | A map style featuring detailed satellite imagery. Available on Enterprise plans. | | `radar-hybrid-v1` | ![](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/hybrid.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=45d1bb9ca6dec37b12f562cca4cbf8e7) | A map style showcasing both satellite imagery and features such as roads. Available on Enterprise plans. | #### Custom styles You can also [create a custom map style](/tutorials/create-a-custom-map-style) with Radar Maps Studio. Maps Studio is a visual maps editor available in the Radar dashboard, and supports advanced maps customizations, custom fonts, and custom markers. | Style | Preview | Description | | - | - | - | | `CUSTOM_STYLE_ID` | ![](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/custom-map-style.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=519eef95242a6a47c2bb0ca37a063eac) | Custom map style that can be tailored to your brand, or support more advanced map visualizations and features. The custom style ID can be found in the **share** modal when viewing or editing a map style in the Radar dashboard. | ### Marker Markers can be used to denote places on the map. Radar Maps support custom marker images, and easily attaching popup's when a marker is clicked. Radar Marker's support all options in the MapLibre GL [marker options](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MarkerOptions/), as well as the following options for the most common scenarios: | Name | Default | Possible values | Description | | - | - | - | - | | `color` | #000257 | string | Color of the default marker image. | | `marker` | none | string | ID of a marker uploaded as part of a [custom style](/tutorials/create-a-custom-map-style) | | `url` | none | string | URL of image to use for the marker. | | `element` | none | HTMLElement | DOM element to be used as the marker. | | `width` | none | number | Size for marker width in pixels. | | `height` | none | number | Size for marker height in pixels. | | `scale` | 1 | number | Scale used for marker size (if element is not provided). | | `popup` | none | [Popup](#) | Config for the popup associated with the marker to be shown on click. See the [Popup](#) config for more info. | ```javascript theme={null} const marker = Radar.ui.marker({ color: '#000257', width: 40, height: 80, popup: { text: 'My popup.', } }) .setLngLat([-73.990550, 40.735225]) .addTo(map); ``` ### Popup Popups can be used to display text or custom HTML at a point on the map, usually upon some user interaction. Radar Popup's support all options in the MapLibre GL [popup options](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/PopupOptions/), as well as the following options for the most common scenarios: | Name | Default | Possible values | Description | | - | - | - | - | | `text` | none | string | Text to display inside popup. | | `html` | none | string | The HTML string to be displayed inside the popup. | | `element` | none | HTMLElement | The DOM element to be used as the popup content. | ```javascript theme={null} const popup = Radar.ui.popup({ text: 'My popup.', }) .setLngLat([-73.990550, 40.735225]) .addTo(map); ``` ### Features Radar Map Features are custom lines and geometries that can be styled and interacted with on the map. The primary format for a map feature is a [GeoJSON Feature](https://datatracker.ietf.org/doc/html/rfc7946#section-3.2) (Polygon, MultiPolygon, and LineString are supported). Feature ids should be unique, and properties can be used for attaching additional metadata to the features. #### Polygon and MultiPolygon Polygons and MultiPolygons can be added to the map through the `map.addPolygon(feature, options)` function. The following `paint` properties for styling. | Property | Possible values | | - | - | | `fill-color` | string (CSS color) | | `fill-opacity` | number (0 - 1) | | `border-width` | number (px) | | `border-color` | string (CSS color) | | `border-opacity` | number (0 - 1) | ```javascript theme={null} const geojson = { type: 'Feature', id: `feature-id-1`, properties: { name: 'Central Park', }, geometry: { type: 'Polygon', coordinates: [[[-73.95820498349376,40.80026256420331],[-73.9816545434309,40.76824212209061],[-73.97283590550576,40.764244806438285],[-73.94918592197929,40.79677293396304],[-73.95820498349376,40.80026256420331]]] }, }; const feature = map.addPolygon(geojson, { paint: { 'fill-color': 'blue', 'fill-opacity': 0.4, }, }); feature.on('click', ({ feature, event }) => { // handle click on feature }); ``` #### Line and Polyline Lines can be added to the map through the `map.addLine(feature, options)` function for GeoJSON LineStrings, or `map.addPolyline(polyline, options)` for encoded polylines. The following `paint` properties for styling. | Property | Possible values | | - | - | | `line-color` | string (CSS color) | | `line-width` | number (px) | | `line-opacity` | number (0 - 1) | | `line-cap` | 'butt' \| 'round' \| 'square' | | `line-offset` | number (px) | | `line-blur` | number (px) | | `line-dasharray` | number\[] | | `line-gap-width` | number (px) | | `line-gradient` | [expression](https://maplibre.org/maplibre-gl-js/docs/examples/line-gradient/) | | `border-width` | number (px) | | `border-color` | string (CSS color) | | `border-opacity` | number (0 - 1) | ```javascript theme={null} const feature = map.addPolyline('iyeulAveaclCuVfw...', { precision: 6, /* encoded polyline precision */ id: 'line-id-1', properties: { name: 'My line', }, paint: { 'line-color': 'blue', 'line-opacity': 0.4, 'line-width': 6, 'border-width': 2, 'border-color': '#FFFFFF', }, }); ``` ## Examples ### Fit map to markers Use the `map.fitToMarkers()` function to center and zoom the map to encompass all the markers on the map. It accepts [FlyToOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/FlyToOptions/) as an optional argument. In the example below, clicking the map will place a new marker, and refit the map so all markers are visible. Clicking a marker will remove it. [https://maps-demo.radar.com/fit-bounds-map](https://maps-demo.radar.com/fit-bounds-map) ```html HTML theme={null}
``` ```javascript React theme={null} import React from 'react'; import Radar from 'radar-sdk-js'; import { createMapsPlugin } from '@radarlabs/plugin-maps'; import '@radarlabs/plugin-maps/dist/radar-maps.css'; Radar.registerPlugin(createMapsPlugin()); class RadarMap extends React.Component { componentDidMount() { Radar.initialize('prj_live_pk_...'); // create a map const map = Radar.ui.map({ container: 'map', }); // add marker on map click map.on('click', (e) => { const { lng, lat } = e.lngLat; // create marker from click location const marker = Radar.ui.marker() .setLngLat([lng, lat]) .addTo(map); // fit map to markers map.fitToMarkers({ maxZoom: 14, padding: 80 }); // add listener to remove marker on click marker.on('click', (e) => { marker.remove(); map.fitToMarkers({ maxZoom: 14, padding: 80 }); // refit after marker removed }); }); } render() { return (
); } }; export default RadarMap; ``` ### Add a custom icon Add a `Marker` with a custom image to the map by specifying the image URL. [https://maps-demo.radar.com/custom-image-marker-map](https://maps-demo.radar.com/custom-image-marker-map) ```html HTML theme={null}
``` ```javascript React theme={null} import React from 'react'; import Radar from 'radar-sdk-js'; import { createMapsPlugin } from '@radarlabs/plugin-maps'; import '@radarlabs/plugin-maps/dist/radar-maps.css'; Radar.registerPlugin(createMapsPlugin()); class RadarMap extends React.Component { componentDidMount() { Radar.initialize('prj_live_pk_...'); // create map const map = Radar.ui.map({ container: 'map', }); map.on('load', () => { const { lng, lat } = map.getCenter(); // add marker to map at map center Radar.ui.marker({ url: 'https://static.radar.com/images/logo.png', width: '48px', height: '48px', popup: { text: 'Radar HQ', }, }) .setLngLat([lng, lat]) .addTo(map); }); } render() { return (
); } }; export default RadarMap; ``` ### Display a custom popup Display a popup with customized HTML. [https://maps-demo.radar.com/custom-popup-map](https://maps-demo.radar.com/custom-popup-map) ```html HTML theme={null}
``` ```javascript React theme={null} import React from 'react'; import Radar from 'radar-sdk-js'; import { createMapsPlugin } from '@radarlabs/plugin-maps'; import '@radarlabs/plugin-maps/dist/radar-maps.css'; Radar.registerPlugin(createMapsPlugin()); class RadarMap extends React.Component { componentDidMount() { Radar.initialize('prj_live_pk_...'); // create map const map = Radar.ui.map({ container: 'map', center: [-73.990550, 40.735225], zoom: 16, }); map.on('load', () => { // Create a marker with a custom popup using HTML Radar.ui.marker({ popup: { html: `

The Roosevelt Building

`, }, }) .setLngLat([-73.9910078, 40.7342465]) .addTo(map); // Create a marker with a custom popup using a DOM element const element = document.getElementById('custom-popup').cloneNode(true /* deep */); element.style.visibility = 'visible'; element.id = 'custom-popup-1'; Radar.ui.marker({ popup: { element, }, }) .setLngLat([-73.990389, 40.735862]) .addTo(map); }); } render() { return (
); } }; export default RadarMap; ``` ### Display a route Routes can be plotted on a Radar Map as a GeoJSON LineString, or an encoded polyline, both of which are formats provided by Radar's [routing APIs](/maps/routing). Polylines can be added to the map with the `map.addPolyline` function, and accepts an optional precision value (defaults to 6). LineString's use the `map.addLine` function. Lines can be styled according to the MapLibre [Line Layer properties](https://maplibre.org/maplibre-style-spec/layers/#line). [https://maps-demo.radar.com/route-map](https://maps-demo.radar.com/route-map) ```html HTML theme={null}
``` ```javascript React theme={null} import React from 'react'; import Radar from 'radar-sdk-js'; import { createMapsPlugin } from '@radarlabs/plugin-maps'; import '@radarlabs/plugin-maps/dist/radar-maps.css'; Radar.registerPlugin(createMapsPlugin()); class RadarMap extends React.Component { componentDidMount() { Radar.initialize('prj_live_pk_...'); // create map const map = Radar.ui.map({ container: 'map', }); map.on('load', () => { // create new feature from polyline const polyline = 'iyeulAveaclCuVfw@aA|CuAlEgj@teBm@jBs@|BbBjA~XzRdFnDfBlA`A{C`@mA~h@icBfAmD`A{Cff@c|A|A{E|BZfJrAh[lEhC^dBThMdBnTtCd@LzBx@|BjA^RhZnUzBdB`BtAl\\zWvAjAlBzA|UjRfEhD`ClBhRfOlCxBjBxAhBxAxKzItNhL|BhBnB|Af]rXnB~A|AnAn[fWbAv@~ArAzBfBxStPbInGtB`BlBzA~b@l]bAx@d@\\jBxAjMdKTPxGlFnJvH|StPnCxBhFbEr@{EfEeYvCyRf@kD\\{BBUtC}RfAoFbAcFpDsNl@_Cl@aCfLcd@r@sCn@cC`Lsc@p@kCl@aCjE}P`E}Od@iBz@{DrD`A|JxCxWdFxc@fLzIzBzL~C~Bj@dAXlg@rM~Ab@pA^|`@pLp@RtBl@bBf@xEpAjQ`FtBl@xF~AjEjAtIbCxGMzWjIhCv@jBl@ju@pUnCz@pCdAvRnIfUpJlV~KtBbAlB~@l`@|SvBhAXNjCvApLnGxBlAnFtCnGeEbZyQ~G}E`B}AhBsBfByBnFkH|AiBzAeBzAcB|A{AdB}ApBwAhCyAfCkApVwKbh\\qjOjBKhBWdCu@zDgBvAi@xAi@dBc@`BQpAGrAFvAVtAp@lAz@lAvA~@hBj@|BXdCFtBIhCWtBe@`By@|AeArAm@`@e@Rs@PyANoB@yAL}AT_BXyBQ}IW_Um@aQUqAHcBTyBf@_Dt@{Ad@uAj@}CrAuR|IoCnA\\gUBiBmCBoDGaIOkL[yNWeB@gBBcC?ao@iBwBEyBGkYs@}HQoAEeBEua@aAyAEyGQ'; const polylineFeature = map.addPolyline(polyline, { id: 'polyline', precision: 6, properties: { name: 'Polyline Feature', }, paint: { 'line-color': 'red', }, }); // create new feature from GeoJSON LineString const lineString = { type: 'Feature', id: 'line-string', properties: { name: 'LineString Feature', }, geometry: { type: 'LineString', coordinates: [[-73.953506,40.721755],[-73.951791,40.723347],[-73.951716,40.723417],[-73.951643,40.723488],[-73.951603,40.723411],[-73.950675,40.721777],[-73.950651,40.721704],[-73.95074,40.721652],[-73.952666,40.720491],[-73.952775,40.720422],[-73.952855,40.720376],[-73.953253,40.720001],[-73.953414,40.719851],[-73.953469,40.719798],[-73.953515,40.719755],[-73.954007,40.719296],[-73.954061,40.719246],[-73.954116,40.719195],[-73.954598,40.718747],[-73.954655,40.718694],[-73.954708,40.718645],[-73.955193,40.718194],[-73.955251,40.71814],[-73.955301,40.718094],[-73.955461,40.717945],[-73.955788,40.717641],[-73.955844,40.717589],[-73.955895,40.717541],[-73.956384,40.717083],[-73.956439,40.717032],[-73.956489,40.716986],[-73.956978,40.716532],[-73.957031,40.716483],[-73.957081,40.716436],[-73.957573,40.715977],[-73.957626,40.715927],[-73.957679,40.715878],[-73.958176,40.715433],[-73.958241,40.715374],[-73.958285,40.715332],[-73.958466,40.715155],[-73.958728,40.7149],[-73.958802,40.714833],[-73.958882,40.714764],[-73.959293,40.714395],[-73.959493,40.714211],[-73.959743,40.713963],[-73.959808,40.713891],[-73.959863,40.71383],[-73.960131,40.713397],[-73.960163,40.713345],[-73.960192,40.713299],[-73.960282,40.713157],[-73.96052,40.712779],[-73.960561,40.712714],[-73.960597,40.712658],[-73.96099,40.712031],[-73.961029,40.711969],[-73.961062,40.711916],[-73.96138,40.711414],[-73.961414,40.71136],[-73.961452,40.7113],[-73.961758,40.71082],[-73.961792,40.710767],[-73.961821,40.710718],[-73.961824,40.710714],[-73.961765,40.710703],[-73.961111,40.710502],[-73.961079,40.710494],[-73.961061,40.710491],[-73.961039,40.710488],[-73.96102,40.710486],[-73.961,40.710487],[-73.960989,40.710488],[-73.960978,40.710488],[-73.960968,40.710486],[-73.960961,40.71048],[-73.960937,40.710466],[-73.96094,40.710453],[-73.960946,40.710441],[-73.960954,40.710431],[-73.960964,40.710423],[-73.960975,40.710419],[-73.960988,40.710418],[-73.961001,40.71042],[-73.96106,40.710434],[-73.961115,40.71045],[-73.961611,40.710603],[-73.963514,40.711182],[-73.96506,40.711654],[-73.966925,40.712193],[-73.967125,40.712135],[-73.967169,40.712149],[-73.972137,40.713651],[-73.976941,40.715098],[-73.978385,40.715543],[-73.978471,40.7155],[-73.984214,40.71723],[-73.985504,40.717633],[-73.985582,40.717658],[-73.985774,40.717726],[-73.985792,40.717685],[-73.985824,40.717616],[-73.985842,40.717574],[-73.985868,40.717522],[-73.985894,40.717468],[-73.986194,40.716898],[-73.986627,40.716045],[-73.986633,40.716038],[-73.986666,40.716002],[-73.986694,40.715975],[-73.986731,40.715929],[-73.986782,40.715857],[-73.986829,40.715771],[-73.986932,40.71557],[-73.987005,40.715414],[-73.987074,40.715241],[-73.987085,40.715188],[-73.987103,40.715105],[-73.987125,40.715017],[-73.987148,40.714837],[-73.987165,40.714622],[-73.987167,40.714467],[-73.987168,40.714397],[-73.98717,40.714317],[-73.987169,40.714234],[-73.987167,40.714169],[-73.987154,40.714088],[-73.987093,40.713709],[-73.987081,40.713634],[-73.987071,40.713574],[-73.986981,40.712999],[-73.986967,40.712909],[-73.986952,40.712813],[-73.986942,40.71275],[-73.986878,40.712347],[-73.986858,40.712217],[-73.98684,40.712107],[-73.986765,40.71163],[-73.98675,40.711533],[-73.986737,40.71145],[-73.986673,40.711044],[-73.986666,40.710997],[-73.986618,40.710698],[-73.986627,40.710656],[-73.98664,40.710618],[-73.986655,40.710585],[-73.986658,40.710579],[-73.986666,40.710565],[-73.986674,40.710549],[-73.986708,40.710482],[-73.986733,40.710435],[-73.986746,40.710409],[-73.986804,40.710402],[-73.987234,40.710354],[-73.987287,40.710349],[-73.987561,40.710319],[-73.987612,40.710313],[-73.987813,40.710291],[-73.988185,40.710248],[-73.988264,40.710239],[-73.988354,40.710228],[-73.988706,40.710188],[-73.989152,40.710138],[-73.989714,40.710071],[-73.989831,40.710054],[-73.990709,40.709927],[-73.991667,40.709783],[-73.991848,40.709756],[-73.992033,40.70973],[-73.992299,40.709691],[-73.99364,40.70949],[-73.993857,40.709467],[-73.99388,40.709464],[-73.994156,40.709431],[-73.994406,40.709398],[-73.995021,40.709314],[-73.99588,40.709189],[-73.995992,40.709138],[-73.996245,40.709099],[-73.996487,40.709064],[-73.996754,40.709027],[-73.997374,40.708951],[-73.997825,40.708859],[-73.998223,40.708741],[-73.998523,40.70864],[-73.998925,40.708485],[-73.999061,40.708409],[-73.999288,40.708282],[-73.999604,40.708037],[-73.999725,40.707965],[-73.999766,40.707942],[-73.999888,40.707874],[-73.999994,40.707817],[-74.000044,40.707791],[-74.000102,40.707762],[-74.000136,40.707745],[-74.000832,40.707382],[-74.000891,40.707352],[-74.001298,40.70714],[-74.001326,40.707125],[-74.002165,40.706675],[-74.002182,40.706665],[-74.002212,40.706648],[-74.00224,40.706632],[-74.002268,40.706615],[-74.002311,40.706591],[-74.002553,40.706451],[-74.002939,40.706223],[-74.002983,40.706197],[-74.003016,40.706177],[-74.00305,40.706157],[-74.003105,40.706125],[-74.00312,40.706116],[-74.003395,40.705944],[-74.003459,40.705908],[-74.003521,40.705878],[-74.003601,40.705854],[-74.003691,40.705823],[-74.003755,40.705791],[-74.003873,40.705717],[-74.004418,40.705367],[-74.004599,40.70525],[-74.004773,40.705138],[-74.006118,40.704274],[-74.006291,40.704161],[-74.006921,40.703763],[-74.006938,40.703752],[-74.00719,40.703598],[-74.007215,40.703583],[-74.007244,40.703565],[-74.007408,40.703468],[-74.00747,40.703431],[-74.007499,40.703414],[-74.007529,40.703396],[-74.007624,40.70334],[-74.007653,40.703313],[-74.007665,40.703294],[-74.007679,40.70326],[-74.007686,40.703232],[-74.007698,40.703159],[-74.007702,40.70314],[-74.007717,40.703076],[-74.007722,40.703042],[-74.007725,40.703025],[-74.007733,40.702983],[-74.007751,40.702948],[-74.007771,40.70292],[-74.007794,40.702898],[-74.007825,40.702878],[-74.008149,40.702681],[-74.009182,40.70206],[-74.009223,40.702037],[-74.009259,40.702021],[-74.009297,40.702005],[-74.009393,40.70197],[-74.009569,40.701907],[-74.009599,40.701898],[-74.009648,40.701887],[-74.009716,40.701874],[-74.00976,40.701863],[-74.010014,40.701792],[-74.010073,40.701776],[-74.010233,40.701727],[-74.010275,40.701716],[-74.010482,40.701664],[-74.011082,40.701527],[-74.011111,40.701519],[-74.011172,40.7015],[-74.011211,40.70149],[-74.011472,40.701429],[-74.011638,40.70139],[-74.011826,40.701346],[-74.012132,40.701275],[-74.012268,40.701246],[-74.012284,40.701242],[-74.012302,40.701239],[-74.012318,40.701238],[-74.012338,40.701241],[-74.012352,40.70125],[-74.01236,40.70126],[-74.012377,40.7013],[-74.012394,40.701341],[-74.012401,40.701359],[-74.012407,40.701372],[-74.012413,40.701383],[-74.01242,40.701393],[-74.012428,40.701403],[-74.012437,40.701411],[-74.012446,40.701417],[-74.012456,40.701422],[-74.012466,40.701426],[-74.01248,40.70143],[-74.012499,40.701432],[-74.012545,40.701439],[-74.012562,40.701444],[-74.012578,40.70145],[-74.012594,40.701457],[-74.012609,40.701465],[-74.012622,40.701473],[-74.012633,40.701483],[-74.012647,40.701498],[-74.012657,40.701518],[-74.012668,40.701543],[-74.012682,40.701578],[-74.01271,40.701658],[-74.012722,40.701684],[-74.012739,40.701702],[-74.012772,40.701725],[-74.0128,40.701755],[-74.012819,40.70179],[-74.012885,40.702055],[-74.012906,40.702153],[-74.012919,40.702189],[-74.012926,40.702207],[-74.012937,40.702225],[-74.012951,40.702242],[-74.012969,40.702256],[-74.012989,40.702267],[-74.013021,40.702277],[-74.013051,40.70228],[-74.013593,40.702258],[-74.013676,40.70225],[-74.013745,40.702243],[-74.013804,40.702239],[-74.013877,40.702234],[-74.013899,40.702235],[-74.013922,40.702238],[-74.013941,40.702245],[-74.013959,40.702252],[-74.013975,40.702261],[-74.01399,40.702272],[-74.014011,40.70229],[-74.014045,40.702331],[-74.014078,40.702361],[-74.01412,40.70239],[-74.014171,40.702422],[-74.014233,40.702453],[-74.014262,40.702466],[-74.014306,40.702487],[-74.014365,40.702518],[-74.014424,40.702552],[-74.014488,40.702598],[-74.014546,40.702644],[-74.014604,40.702699],[-74.014649,40.702744],[-74.014682,40.702783],[-74.014704,40.702816],[-74.014723,40.70285],[-74.014737,40.702882],[-74.014751,40.702924],[-74.014762,40.70297],[-74.01477,40.703027],[-74.014776,40.703089],[-74.014778,40.703141],[-74.01477,40.703192],[-74.014762,40.703238],[-74.014754,40.703271],[-74.014744,40.703313],[-74.014733,40.703353],[-74.014717,40.703411],[-74.014699,40.703466],[-74.014682,40.703512],[-74.014668,40.703556],[-74.014659,40.70359],[-74.014653,40.703623],[-74.014652,40.703654],[-74.014651,40.703682],[-74.014655,40.703707],[-74.014661,40.703731],[-74.014675,40.703762],[-74.014686,40.70379],[-74.014694,40.703813],[-74.014698,40.703835],[-74.014698,40.703863],[-74.014691,40.703892],[-74.014686,40.703917],[-74.014675,40.703947],[-74.014659,40.703979],[-74.014652,40.704008],[-74.014651,40.704028],[-74.014663,40.704105],[-74.014673,40.704136],[-74.014688,40.704183],[-74.014712,40.704245],[-74.014736,40.704289],[-74.014765,40.704335],[-74.014794,40.70437],[-74.014839,40.704409],[-74.014889,40.704443],[-74.014937,40.70447],[-74.014984,40.704494],[-74.015046,40.704524],[-74.015141,40.704558],[-74.015196,40.704572],[-74.015262,40.704586],[-74.01532,40.704596],[-74.015384,40.704602],[-74.015463,40.704606],[-74.015543,40.704607],[-74.015616,40.70461],[-74.015665,40.704613],[-74.015751,40.704629],[-74.015836,40.70464],[-74.015892,40.704646],[-74.015934,40.704648],[-74.015974,40.704646],[-74.016019,40.704641],[-74.016087,40.704627],[-74.016148,40.704617],[-74.016196,40.704612],[-74.016245,40.70461],[-74.016288,40.704612],[-74.016326,40.704616],[-74.016364,40.704624],[-74.016403,40.70463],[-74.016449,40.704633],[-74.016502,40.704634],[-74.016577,40.704633],[-74.01678,40.704629],[-74.016812,40.70463],[-74.016848,40.704631],[-74.017007,40.704641],[-74.017029,40.704647],[-74.01705,40.704655],[-74.017068,40.704668],[-74.017081,40.704684],[-74.017087,40.704699],[-74.017086,40.704715],[-74.017079,40.704737],[-74.01706,40.704785],[-74.017036,40.704843],[-74.017013,40.7049],[-74.017,40.704954],[-74.016995,40.704975],[-74.016989,40.704993],[-74.016907,40.705196],[-74.016741,40.705627],[-74.016725,40.705667],[-74.016658,40.705837],[-74.016614,40.705947],[-74.016467,40.70633],[-74.016463,40.706345],[-74.016459,40.706359],[-74.016427,40.706488],[-74.01642,40.706517],[-74.016407,40.706569],[-74.016389,40.706632],[-74.016372,40.70668],[-74.01636,40.706716],[-74.016257,40.706988],[-74.016224,40.70706],[-74.016177,40.707146],[-74.016104,40.707272],[-74.016071,40.707341],[-74.015976,40.707593],[-74.015944,40.707674],[-74.015941,40.707682],[-74.015933,40.707704],[-74.015922,40.70773],[-74.01592,40.707734],[-74.015897,40.707797],[-74.015873,40.707859],[-74.015865,40.70788],[-74.015861,40.70789],[-74.01584,40.707947],[-74.015436,40.709038],[-74.015357,40.709272],[-74.015322,40.709406],[-74.015258,40.709668],[-74.015242,40.709731],[-74.015238,40.709752],[-74.015229,40.709787],[-74.015209,40.709839],[-74.015281,40.709849],[-74.015342,40.70986],[-74.015803,40.709961],[-74.015821,40.709965],[-74.016244,40.710061],[-74.016374,40.71009],[-74.016512,40.710121],[-74.016953,40.71022],[-74.017489,40.710341],[-74.017525,40.71035],[-74.017538,40.710355],[-74.017561,40.710364],[-74.017544,40.710384],[-74.017537,40.710406],[-74.017541,40.710429],[-74.017554,40.71045],[-74.017576,40.710466],[-74.017604,40.710475],[-74.017634,40.710476],[-74.017663,40.71047],[-74.017687,40.710457],[-74.017704,40.710439],[-74.017706,40.710434]], }, }; const lineStringFeature = map.addLine(lineString); // create popup when clicking on line [polylineFeature, lineStringFeature].forEach((radarFeature) => { radarFeature.on('click', ({ feature, originalEvent: event }) => { Radar.ui.popup({ text: feature.properties.name, // popup text from feature.properties }) .setLngLat([event.lngLat.lng, event.lngLat.lat]) .addTo(map); }); }); // fit the map bounds to the features map.fitToFeatures({ padding: 40 }); }); } render() { return (
); } }; export default RadarMap; ``` ### Display a polygon Polygons or complex shapes can be drawn on a Radar Map by providing a GeoJSON Polygon or MultiPolygon feature to the `map.addPolygon` function. Polygon features can be styled according to the polygon options highlighted above. [https://maps-demo.radar.com/polygon-map](https://maps-demo.radar.com/polygon-map) ```html HTML theme={null}
``` ```javascript React theme={null} import React from 'react'; import Radar from 'radar-sdk-js'; import { createMapsPlugin } from '@radarlabs/plugin-maps'; import '@radarlabs/plugin-maps/dist/radar-maps.css'; Radar.registerPlugin(createMapsPlugin()); class RadarMap extends React.Component { componentDidMount() { Radar.initialize('prj_live_pk_...'); // create map const map = Radar.ui.map({ container: 'map', }); map.on('load', () => { // create new feature from GeoJSON Feature const geojson = { type: 'Feature', id: 1, properties: { name: 'Central Park', }, geometry: { type: 'Polygon', coordinates: [[[-73.95820498349376,40.80026256420331],[-73.9816545434309,40.76824212209061],[-73.97283590550576,40.764244806438285],[-73.94918592197929,40.79677293396304],[-73.95820498349376,40.80026256420331]]] }, }; const feature = map.addPolygon(geojson) feature.on('click', ({ feature, originalEvent: event }) => { Radar.ui.popup({ text: feature.properties.name, }) .setLngLat([event.lngLat.lng, event.lngLat.lat]) .addTo(map); }); // fit the map bounds to the features map.fitToFeatures({ padding: 40 }); }); } render() { return (
); } }; export default RadarMap; ``` ### Display a globe Display a Radar Map with an interactive globe projection. Only available on MapLibre v5 and above. [https://maps-demo.radar.com/globe-map](https://maps-demo.radar.com/globe-map) ```html HTML theme={null}
``` ```javascript React theme={null} import React, { useEffect, useRef } from 'react'; import Radar from 'radar-sdk-js'; import { createMapsPlugin } from '@radarlabs/plugin-maps'; import '@radarlabs/plugin-maps/dist/radar-maps.css'; Radar.registerPlugin(createMapsPlugin()); const RadarMap = () => { const mapRef = useRef(null); useEffect(() => { if (mapRef.current) return; Radar.initialize('prj_live_pk_...'); // create map mapRef.current = Radar.ui.map({ container: 'map', zoom: 2, minZoom: 0, center: [-73.9910078, 40.7342465], }); mapRef.current.on('style.load', () => { mapRef.current.setProjection({ type: 'globe' }); }); return () => { if (mapRef.current) { mapRef.current.remove(); mapRef.current = null; } }; }, []); return
; }; export default RadarMap; ``` ### Change map language The map display language can be changed by setting the `language` option to the ISO language code (`en`), or the browser's current setting from `navigator.language`. You can also set `language: "local"` to use the device language by default. [https://maps-demo.radar.com/custom-language-map](https://maps-demo.radar.com/custom-language-map) ```html theme={null}
``` ## Compatibility Radar Maps are built using the [Mapbox Vector Tile (MVT)](https://github.com/mapbox/vector-tile-spec) and [TileJSON](https://github.com/mapbox/tilejson-spec) standards, which means they can be used with any SDK that supports these protocols. Below are some alternative libraries that can be used to display Radar Maps. ### MapLibre GL JS The Radar SDK uses the [MapLibre GL JS](https://maplibre.org/maplibre-gl-js/docs/) library, which offers some usability enhancements when creating maps. If you want more low-level control over the map behavior, or are migrating from a Mapbox GL JS implementation, you can use the MapLibre library directly. To use a Radar Map with MapLibre, you can use the following Radar URL as the [style URL](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapOptions/#style). ``` https://api.radar.io/maps/styles/radar-default-v1?publishableKey=prj_live_pk_... ``` ```html theme={null}
``` ### Leaflet Radar Maps can be used as a base map for Leaflet through the [maplibre-gl-leaflet](https://github.com/maplibre/maplibre-gl-leaflet) library. It uses the same style URL format as in the MapLibre example above. ```html theme={null}
``` ### iOS Radar Maps are compatible with [MapLibre Native for iOS](https://maplibre.org/maplibre-native/ios/latest/documentation/maplibre/). For more info, see the [displaying Radar Maps on iOS](/tutorials/displaying-radar-maps-on-ios) tutorial. ### Android Radar Maps are compatible with [MapLibre Native for Android](https://maplibre.org/maplibre-native/android/examples/getting-started/). For more info, see the [displaying Radar Maps on Android](/tutorials/displaying-radar-maps-on-android) tutorial. ### React Native Radar's React Native SDK has built-in support for displaying Radar Maps. See the [displaying Radar Maps with React Native](/tutorials/displaying-radar-maps-with-react-native) tutorial for more info. ### Flutter Radar Maps can be used in a flutter application with [flutter-maplibre-gl](https://github.com/maplibre/flutter-maplibre-gl) or [flutter\_map](https://docs.fleaflet.dev/). See the [displaying Radar Maps with Flutter](/tutorials/displaying-radar-maps-with-flutter) tutorial for more info. ### Google Maps To use Radar Maps with your existing Google Maps implementation, see our [Migration SDK](/maps/migration-sdk) for more details. ## Coverage Radar map data comes from [OpenStreetMap](https://www.openstreetmap.org). The following table describes data coverage for maps, by country, for consumer use cases (e.g., store locators) and logistics use cases (e.g., ride sharing, delivery). #### Legend | Icon | Description | | - | - | | ⬤ | Great data quality and availability | | ◐ | Good data quality and availability | | ◯ | Approximate data quality and availability | #### Coverage | | Maps | | - | - | | 🇺🇸 US (consumer) | ⬤ | | 🇺🇸 US (logistics) | ⬤ | | 🇨🇦 CA (consumer) | ⬤ | | 🇨🇦 CA (logistics) | ⬤ | | 🇬🇧 UK (consumer) | ⬤ | | 🇬🇧 UK (logistics) | ⬤ | | 🌎 Other (consumer) | ⬤ | | 🌎 Other (logistics) | ◐ | ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # Migration SDK Source: https://docs.radar.com/maps/migration-sdk Migrate a Google Maps web implementation to Radar Maps by swapping a script with the Radar Maps Migration SDK. The Radar Maps Migration SDK allows you to easily convert your Google Maps web implementations with Radar Maps by simply swapping the script import tag. ## How it works The Google maps import will look like one of the following: **Direct src import** ```html theme={null} ``` **Dynamic Library import** ```html theme={null} ``` For either of these imports, simply replace these lines with the Radar Migration SDK script. Now without any further changes to the code, calls to the Google Maps API will now be made to Radar's API. ```html theme={null} ``` Additionally you can specify a callback and Radar map style which is defined below. ## Configuration #### Definition `src` `https://js.radar.com/v1/radar-migration-sdk.js` ### Query Parameters | Name | Default | Possible values | Description | | - | - | - | - | | `key` | none (required) | string | Your Radar publishable API key. | | `style` | `radar-default-v1` | `radar-default-v1`, `radar-light-v1`, `radar-dark-v1`, `CUSTOM_STYLE_ID` | The style of the map. One of Radar's out-of-the box styles, or a [custom style](/maps/maps#custom-styles) ID. See [map styles](https://radar.com/maps/maps#styles) for more details. | | `callback` | none | string | The name of a maps callback function to be called once the library is imported | ## Coverage See [Maps coverage](/maps/maps#coverage) for more details. ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # Overview Source: https://docs.radar.com/maps/overview Overview of Radar's Maps Platform: geocoding, search, routing, and base map APIs as a cost-effective alternative to Google Maps and Mapbox. Radar Maps Platform is a cost-effective solution for geocoding APIs, search APIs, routing APIs, and base maps. Together with our [Geofencing Platform](/geofencing/overview), Radar provides full-stack location infrastructure for any product or service. We power location-based experiences for [enterprises and startups](https://radar.com/customers) across hundreds of millions of devices worldwide. ## Features > [card] [Geocoding APIs](/maps/geocoding) > > Forward, reverse, and IP geocoding APIs > [card] [Search APIs](/maps/search) > > Autocomplete, address validation, and place search APIs > [card] [Routing APIs](/maps/routing) > > Distance, matrix, and route matching APIs > [card] [Maps](/maps/maps) > > A cost-effective alternative to Google Maps and Mapbox # Routing APIs Source: https://docs.radar.com/maps/routing Calculate travel distances, distance matrices, directions, and optimized routes with Radar's routing APIs. Use Radar's routing APIs to calculate travel distances between origins and destinations. ![Routing illustration](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/illustrations/route-illustration.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=924768f3e083b71f93c4bac38cc98271) ## Quickstart First, [sign up](https://radar.com/signup) for Radar and get an API key. Then, call one of the routing APIs below, either [directly](/api) or [using the SDK](/sdk). From there, use the APIs to build location features in your app or website, such as store locators, address autocomplete, or delivery tracking. ## Endpoints ### Distance Use the distance API to calculate the travel distance and duration between an origin and a destination. You can specify one or more travel modes, including `foot`, `bike`, and `car`. Use cases for this endpoint include calculating the distance and duration of a trip from point A to point B, calculating the ETA for a pickup or delivery, or calculating the walking and driving distance to a nearby store. See the distance API reference [here](/api#distance). ### Matrix Use the matrix API to calculate travel distances and durations between multiple origins and destinations. Use cases for this endpoint include calculating the walking or driving distance to multiple nearby stores (e.g., in a store locator) or optimizing routes. See the matrix API reference [here](/api#matrix). ### Route matching Use the route matching API to snap points collected along a route to roads that were most likely traveled on. Returns the matched path and road information. Use cases for this endpoint include producing clean paths that can be displayed on a map, used for accurate mileage tracking and other analysis, as well as retrieving road context such as speed limits and road names along a traveled path. See the route matching API reference [here](/api#route-match). ### Directions Use the directions API to calculate the most efficient route between two or more locations to visit in order. Use cases for this endpoint include calculating and displaying paths between locations on a map. See the directions API reference [here](/api#directions). ### Route optimization Use the route optimization API to calculate the optimal ordering and route to visit a list of locations. Use cases for this endpoint include determining the best sequence for several pickups or deliveries, or calculating the optimal route to visit multiple stops. See the route optimization API reference [here](/api#optimize-route). ## Coverage Radar's routing APIs incorporate both open and commercial datasets for maximum coverage at an affordable price relative to alternatives. The following table describes data coverage for routing APIs, by country, for consumer use cases (e.g., store locators) and logistics use cases (e.g., ride sharing, delivery). #### Legend | Icon | Description | | - | - | | ⬤ | Great data quality and availability | | ◐ | Good data quality and availability | | ◯ | Approximate data quality and availability | #### Coverage | | Distance, matrix, match | | - | - | | 🇺🇸 US (consumer) | ⬤ | | 🇺🇸 US (logistics) | ⬤ | | 🇨🇦 CA (consumer) | ⬤ | | 🇨🇦 CA (logistics) | ⬤ | | 🇬🇧 UK (consumer) | ⬤ | | 🇬🇧 UK (logistics) | ⬤ | | 🇪🇺 EU (consumer) | ⬤ | | 🇪🇺 EU (logistics) | ⬤ | | 🌎 Other (consumer) | ◐ | | 🌎 Other (logistics) | ◐ | ## Caching You can cache API responses for up to 30 days. For more information, see our terms of use [here](https://radar.com/terms). ## Report an issue The Radar team is constantly working to improve data coverage for our geocoding, search, and routing APIs. Bad response? Unexpected error? Report it [here](https://forms.gle/9ZfHi95wd8xgEERb6), and our team will fix it ASAP. ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # Search APIs Source: https://docs.radar.com/maps/search Search addresses, places, and geofences with Radar's search APIs, including address autocomplete. Use Radar's search APIs to search data in Radar, including addresses, places, and geofences. ![Search illustration](https://mintcdn.com/radarlabs/ccKDKXrkAAqb0okD/images/illustrations/search-illustration.png?fit=max\&auto=format\&n=ccKDKXrkAAqb0okD\&q=85\&s=2aae8beefa840e442430fb1d2945bade) ## Quickstart First, [sign up](https://radar.com/signup) for Radar and get an API key. Then, call one of the search APIs below, either [directly](/api) or [using the SDK](/sdk/sdk). From there, use the APIs to build location features in your app or website, such as store locators, address autocomplete, or delivery tracking. ## Endpoints ### Address autocomplete Use the address autocomplete API to autocomplete partial addresses. This endpoint is best for partial addresses. For complete addresses, call the [forward geocoding API](/maps/geocoding#forward-geocoding) instead. Use cases for this endpoint include autocompleting partial addresses for checkout forms or store locators. See the autocomplete API reference [here](/api#autocomplete). ### Address validation Use the address validation API to validate complete structured addresses. Use cases for this endpoint include verifying addresses or suggesting mailable addresses for checkout forms or delivery. See the address validation API reference [here](/api#validate-an-address). ### Places search Use the places search API to search for places near a location, filtered by [chain](/geofencing/places#chains) (e.g., `mcdonalds`) or [category](/geofencing/places#categories) (e.g., `airport`). Use cases for this endpoint include nearby search. See the places search API reference [here](/api#search-places). ### Geofences search Use the geofences search API to search for geofences near a location, filtered by tag. Use cases for this endpoint include store locators, assuming you've imported your stores as geofences. See the geofences search API reference [here](/api#search-geofences). ## Coverage Radar's search APIs incorporate both open and commercial datasets for maximum coverage at an affordable price relative to alternatives. The following table describes data coverage for search APIs, by country, for consumer use cases (e.g., store locators) and logistics use cases (e.g., ride sharing, delivery). #### Legend | Icon | Description | | - | - | | ⬤ | Great data quality and availability | | ◐ | Good data quality and availability | | ◯ | Approximate data quality and availability | #### Coverage | | Coarse (city-level) address autocomplete | Fine (address-level) address autocomplete | Place detection and search | | - | - | - | - | | Afghanistan | ⬤ | ◯ | ◐ | | Albania | ⬤ | ◯ | ◐ | | Algeria | ⬤ | ⬤ | ◐ | | Andorra | ⬤ | ⬤ | ◐ | | Angola | ⬤ | ◯ | ◐ | | Anguilla | ⬤ | ◯ | ◐ | | Antarctica | ⬤ | ◯ | ◐ | | Antigua and Barbuda | ⬤ | ◯ | ◐ | | Argentina | ⬤ | ◐ | ◐ | | Armenia | ⬤ | ⬤ | ◐ | | Aruba | ⬤ | ◯ | ◐ | | Australia | ⬤ | ⬤ | ◐ | | Austria | ⬤ | ⬤ | ◐ | | Azerbaijan | ⬤ | ⬤ | ◐ | | Bahamas | ⬤ | ◯ | ◐ | | Bahrain | ⬤ | ⬤ | ◐ | | Bangladesh | ⬤ | ◯ | ◐ | | Barbados | ⬤ | ◯ | ◐ | | Belarus | ⬤ | ⬤ | ◐ | | Belgium | ⬤ | ⬤ | ◐ | | Belize | ⬤ | ◯ | ◐ | | Benin | ⬤ | ◯ | ◐ | | Bermuda | ⬤ | ◯ | ◐ | | Bhutan | ⬤ | ◯ | ◐ | | Bolivia | ⬤ | ◯ | ◐ | | Bonaire Sint Eustatius and Saba | ⬤ | ◯ | ◐ | | Bosnia-Herzegovina | ⬤ | ⬤ | ◐ | | Botswana | ⬤ | ◯ | ◐ | | Bouvet Island | ⬤ | ◯ | ◐ | | Brazil | ⬤ | ⬤ | ◐ | | British Virgin Islands | ⬤ | ◯ | ◐ | | Brunei | ⬤ | ◐ | ◐ | | Bulgaria | ⬤ | ⬤ | ◐ | | Burkina Faso | ⬤ | ◯ | ◐ | | Burundi | ⬤ | ◯ | ◐ | | Cabo Verde | ⬤ | ◯ | ◐ | | Cambodia | ⬤ | ◐ | ◐ | | Cameroon | ⬤ | ◯ | ◐ | | Canada | ⬤ | ⬤ | ◐ | | Cayman Islands | ⬤ | ◯ | ◐ | | Central African Republic | ⬤ | ◯ | ◐ | | Chad | ⬤ | ◯ | ◐ | | Chile | ⬤ | ⬤ | ◐ | | Clipperton Island | ⬤ | ◯ | ◐ | | Cocos (Keeling) Islands | ⬤ | ◯ | ◐ | | Colombia | ⬤ | ⬤ | ◐ | | Comoros | ⬤ | ◯ | ◐ | | Congo-Brazzaville | ⬤ | ◯ | ◐ | | Cook Islands | ⬤ | ◯ | ◐ | | Costa Rica | ⬤ | ◯ | ◐ | | Cote d'Ivoire | ⬤ | ◯ | ◐ | | Croatia | ⬤ | ⬤ | ◐ | | Cuba | ⬤ | ◯ | ◐ | | Curacao | ⬤ | ◯ | ◐ | | Cyprus | ⬤ | ⬤ | ◐ | | Czechia | ⬤ | ⬤ | ◐ | | Democratic Republic of the Congo | ⬤ | ◯ | ◐ | | Denmark | ⬤ | ⬤ | ◐ | | Djibouti | ⬤ | ◯ | ◐ | | Dominica | ⬤ | ◯ | ◐ | | Dominican Republic | ⬤ | ◯ | ◐ | | Ecuador | ⬤ | ◐ | ◐ | | Egypt | ⬤ | ◐ | ◐ | | El Salvador | ⬤ | ◯ | ◐ | | Equatorial Guinea | ⬤ | ◯ | ◐ | | Eritrea | ⬤ | ◯ | ◐ | | Estonia | ⬤ | ⬤ | ◐ | | Eswatini | ⬤ | ◯ | ◐ | | Ethiopia | ⬤ | ◯ | ◐ | | Falkland Islands | ⬤ | ◯ | ◐ | | Faroe Islands | ⬤ | ⬤ | ◐ | | Federated States of Micronesia | ⬤ | ◯ | ◐ | | Fiji | ⬤ | ◯ | ◐ | | Finland | ⬤ | ⬤ | ◐ | | France | ⬤ | ⬤ | ◐ | | French Guiana | ⬤ | ⬤ | ◐ | | French Polynesia | ⬤ | ◯ | ◐ | | French Southern and Antarctic Lands | ⬤ | ◯ | ◐ | | Gabon | ⬤ | ◯ | ◐ | | Georgia | ⬤ | ⬤ | ◐ | | Germany | ⬤ | ⬤ | ◐ | | Ghana | ⬤ | ◯ | ◐ | | Gibraltar | ⬤ | ◯ | ◐ | | Greece | ⬤ | ⬤ | ◐ | | Greenland | ⬤ | ◯ | ◐ | | Grenada | ⬤ | ◯ | ◐ | | Guadeloupe | ⬤ | ⬤ | ◐ | | Guatemala | ⬤ | ◯ | ◐ | | Guinea | ⬤ | ◯ | ◐ | | Guinea-Bissau | ⬤ | ◯ | ◐ | | Guyana | ⬤ | ◯ | ◐ | | Haiti | ⬤ | ◯ | ◐ | | Heard Island and McDonald Islands | ⬤ | ◯ | ◐ | | Holy See | ⬤ | ◯ | ◐ | | Honduras | ⬤ | ◯ | ◐ | | Hong Kong | ⬤ | ◐ | ◐ | | Hungary | ⬤ | ⬤ | ◐ | | Iceland | ⬤ | ⬤ | ◐ | | India | ⬤ | ◐ | ◐ | | Indonesia | ⬤ | ◐ | ◐ | | Iran | ⬤ | ◯ | ◐ | | Iraq | ⬤ | ◯ | ◐ | | Ireland | ⬤ | ⬤ | ◐ | | Israel | ⬤ | ◐ | ◐ | | Italy | ⬤ | ⬤ | ◐ | | Jamaica | ⬤ | ◯ | ◐ | | Japan | ⬤ | ◐ | ◐ | | Jordan | ⬤ | ◐ | ◐ | | Kazakhstan | ⬤ | ◐ | ◐ | | Kenya | ⬤ | ◯ | ◐ | | Kiribati | ⬤ | ◯ | ◐ | | Kosovo | ⬤ | ⬤ | ◐ | | Kuwait | ⬤ | ◐ | ◐ | | Kyrgyzstan | ⬤ | ◯ | ◐ | | Laos | ⬤ | ◐ | ◐ | | Latvia | ⬤ | ⬤ | ◐ | | Lebanon | ⬤ | ◐ | ◐ | | Lesotho | ⬤ | ◯ | ◐ | | Liberia | ⬤ | ◯ | ◐ | | Libya | ⬤ | ◯ | ◐ | | Liechtenstein | ⬤ | ⬤ | ◐ | | Lithuania | ⬤ | ⬤ | ◐ | | Luxembourg | ⬤ | ⬤ | ◐ | | Macao | ⬤ | ◐ | ◐ | | Madagascar | ⬤ | ◯ | ◐ | | Malawi | ⬤ | ◯ | ◐ | | Malaysia | ⬤ | ◐ | ◐ | | Maldives | ⬤ | ◯ | ◐ | | Mali | ⬤ | ◯ | ◐ | | Malta | ⬤ | ⬤ | ◐ | | Marshall Islands | ⬤ | ◯ | ◐ | | Martinique | ⬤ | ⬤ | ◐ | | Mauritania | ⬤ | ◯ | ◐ | | Mauritius | ⬤ | ◯ | ◐ | | Mayotte | ⬤ | ⬤ | ◐ | | Mexico | ⬤ | ⬤ | ◐ | | Moldova | ⬤ | ⬤ | ◐ | | Monaco | ⬤ | ◐ | ◐ | | Mongolia | ⬤ | ◯ | ◐ | | Montenegro | ⬤ | ⬤ | ◐ | | Montserrat | ⬤ | ◯ | ◐ | | Morocco | ⬤ | ◐ | ◐ | | Mozambique | ⬤ | ◯ | ◐ | | Myanmar | ⬤ | ◐ | ◐ | | Namibia | ⬤ | ◯ | ◐ | | Nauru | ⬤ | ◯ | ◐ | | Nepal | ⬤ | ◯ | ◐ | | Netherlands | ⬤ | ⬤ | ◐ | | New Caledonia | ⬤ | ◯ | ◐ | | New Zealand | ⬤ | ⬤ | ◐ | | Nicaragua | ⬤ | ◯ | ◐ | | Niger | ⬤ | ◯ | ◐ | | Nigeria | ⬤ | ◯ | ◐ | | Niue | ⬤ | ◯ | ◐ | | Norfolk Island | ⬤ | ◯ | ◐ | | Norway | ⬤ | ⬤ | ◐ | | Pakistan | ⬤ | ◯ | ◐ | | Palau | ⬤ | ◯ | ◐ | | Panama | ⬤ | ◯ | ◐ | | Papua New Guinea | ⬤ | ◯ | ◐ | | Paraguay | ⬤ | ⬤ | ◐ | | Peru | ⬤ | ◐ | ◐ | | Philippines | ⬤ | ◐ | ◐ | | Pitcairn Islands | ⬤ | ◯ | ◐ | | Poland | ⬤ | ⬤ | ◐ | | Portugal | ⬤ | ⬤ | ◐ | | Qatar | ⬤ | ◯ | ◐ | | Republic of Belarus | ⬤ | ⬤ | ◐ | | Republic of Korea | ⬤ | ◯ | ◐ | | Republic of North Macedonia | ⬤ | ⬤ | ◐ | | Reunion | ⬤ | ⬤ | ◐ | | Romania | ⬤ | ⬤ | ◐ | | Russia | ⬤ | ⬤ | ◐ | | Rwanda | ⬤ | ◯ | ◐ | | Saint Barthelemy | ⬤ | ◯ | ◐ | | Saint Helena | ⬤ | ◯ | ◐ | | Saint Kitts and Nevis | ⬤ | ◯ | ◐ | | Saint Lucia | ⬤ | ◯ | ◐ | | Saint Martin | ⬤ | ◯ | ◐ | | Saint Pierre and Miquelon | ⬤ | ◯ | ◐ | | Saint Vincent and the Grenadines | ⬤ | ◯ | ◐ | | Samoa | ⬤ | ◯ | ◐ | | San Marino | ⬤ | ⬤ | ◐ | | Sao Tome and Principe | ⬤ | ◯ | ◐ | | Saudi Arabia | ⬤ | ◐ | ◐ | | Senegal | ⬤ | ◯ | ◐ | | Serbia | ⬤ | ⬤ | ◐ | | Seychelles | ⬤ | ◯ | ◐ | | Sierra Leone | ⬤ | ◯ | ◐ | | Singapore | ⬤ | ◐ | ◐ | | Sint Maarten | ⬤ | ◯ | ◐ | | Slovakia | ⬤ | ⬤ | ◐ | | Slovenia | ⬤ | ⬤ | ◐ | | Solomon Islands | ⬤ | ◯ | ◐ | | Somalia | ⬤ | ◯ | ◐ | | South Africa | ⬤ | ⬤ | ◐ | | South Georgia and the South Sandwich Islands | ⬤ | ◯ | | | South Sudan | ⬤ | ◯ | ◐ | | Spain | ⬤ | ⬤ | ◐ | | Sri Lanka | ⬤ | ◯ | ◐ | | State Of Palestine | ⬤ | ◯ | ◐ | | Sudan | ⬤ | ◯ | ◐ | | Suriname | ⬤ | ◯ | ◐ | | Sweden | ⬤ | ⬤ | ◐ | | Switzerland | ⬤ | ⬤ | ◐ | | Syria | ⬤ | ◯ | ◐ | | Taiwan | ⬤ | ◯ | ◐ | | Tajikistan | ⬤ | ◯ | ◐ | | Tanzania | ⬤ | ◯ | ◐ | | Thailand | ⬤ | ◯ | ◐ | | The Gambia | ⬤ | ◯ | ◐ | | The Sultanate of Oman | ⬤ | ◯ | ◐ | | Timor-Leste | ⬤ | ◯ | ◐ | | Togo | ⬤ | ◯ | ◐ | | Tokelau | ⬤ | ◯ | ◐ | | Tonga | ⬤ | ◯ | ◐ | | Trinidad and Tobago | ⬤ | ◯ | ◐ | | Tunisia | ⬤ | ⬤ | ◐ | | Turkey | ⬤ | ⬤ | ◐ | | Turkmenistan | ⬤ | ◯ | ◐ | | Turks and Caicos Islands | ⬤ | ◯ | ◐ | | Tuvalu | ⬤ | ◯ | ◐ | | Uganda | ⬤ | ◯ | ◐ | | Ukraine | ⬤ | ⬤ | ◐ | | United Arab Emirates | ⬤ | ◐ | ◐ | | United Kingdom | ⬤ | ⬤ | ◐ | | United States | ⬤ | ⬤ | ⬤ | | Uruguay | ⬤ | ⬤ | ◐ | | Uzbekistan | ⬤ | ◯ | ◐ | | Vanuatu | ⬤ | ◯ | ◐ | | Venezuela | ⬤ | ◯ | ◐ | | Vietnam | ⬤ | ◯ | ◐ | | Wallis and Futuna | ⬤ | ◯ | ◐ | | Yemen | ⬤ | ◯ | ◐ | | Zambia | ⬤ | ◯ | ◐ | | Zimbabwe | ⬤ | ◯ | ◐ | ## Caching You can cache API responses for up to 30 days. For more information, see our terms of use [here](https://radar.com/terms). ## Report an issue The Radar team is constantly working to improve data coverage for our geocoding, search, and routing APIs. Bad response? Unexpected error? Report it [here](https://forms.gle/9ZfHi95wd8xgEERb6), and our team will fix it ASAP. ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # Static Maps Source: https://docs.radar.com/maps/static-maps The Radar Static Maps API generates standalone images of Radar Maps that can be easily embedded anywhere an image can be used. These images can be created without the use of JavaScript or any additional mapping libraries. For example, here's a Radar Static Map displaying a marker for Radar HQ: ```html theme={null} Radar static map over New York City ``` ![Static Map Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/static-map.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=1b71ee148eb196568482981ca7e1b782) ## How it works To generate an image with Radar's Static Maps API, simply make an HTTP request with your desired map size, location, and any markers (map pins) for highlighting important features. Static Map images can be used inline with HTML `` tags by setting the `src` attribute to the Static Maps endpoint. ## Configuration #### Definition `GET` `https://api.radar.io/maps/static` ### Parameters | Name | Default | Possible values | Description | | - | - | - | - | | `width` | none (required) | number | The width of the image in pixels as a number between `100` and `2048`. | | `height` | none (required) | number | The height of the image in pixels as a number between `100` and `2048`. | | `center` | none (required, unless markers are provided) | string | The coordinates specified in `latitude,longitude` format for the center of the map. If `center` is not provided then the map will be centered to visibly fit all markers in view. | | `zoom` | none (required, unless bbox, markers, or path are provided) | number | The `zoom` position of the map which is a number between `1` and `23`. If `zoom` is not provided then the map will fit the view to the markers. | | `scale` | 1 | number | The scale or resolution of the map as a number between `1` and `3`. This is useful for high-density displays and will affect the width and height parameters by returning an image that is the product of the width/height and scale. | | `style` | `radar-default-v1` | `radar-default-v1`, `radar-light-v1`, `radar-dark-v1`, `CUSTOM_STYLE_ID` | The style of the map. One of Radar's out-of-the box styles, or a [custom style](/maps/maps#custom-styles) ID. See [map styles](/maps/maps#styles) for more details. | | `language` | none | string (ISO code) | The display language for map. Can be any 2-letter [ISO Code](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes), or `local` to use the device's specified language. Defaults to `en-US` if none is provided. | | `bbox` | none | string | The bbox or latitude and longitude bounds of the image. Specified as `min_latitude,min_longitude,max_latitude,max_longitude`. The image returned will fit the specified bounding box. | | `markers` | none | string | For rendering markers on the map. See [markers](#markers) for more details. | | `path` | none | string | For rendering paths on the map. See [paths](#paths) for more details. | | `publishableKey` | none (required) | string | Your Radar publishable API key. | ### Markers Adding markers (or map pins) to your static images can be useful for highlighting important features on your map. The Static Maps endpoint accepts a `markers` parameter that can be configured for rendering one, or many markers on the map. Each markers parameter is made up of optional `markerStyle` sections, and one or more `markerLocations`. ``` markers=markerStyle|markerLocation1|markerLocation2|... ``` *markerLocation* are specified in the following format `latitude,longitude` and are pipe separated. *markerStyle* are specified in the following format `optionName:optionValue` and are pipe separated. *markerStyle* have the following options: * `color` (string, optional): The color of the image specified as a hex in the following format `0xFFFFFF` or a [standard color](https://developer.mozilla.org/en-US/docs/Web/CSS/named-color). The default value if color is not specified is `0x000257`. * `size` (string, optional): By specifying `size:small` as an option, you can render a scaled down version of the marker. * `icon` (string, optional): The marker image to use. Can be a URL to valid SVG or PNG file, or the ID of custom uploaded marker. The default marker image will be used if not provided. For instance, to apply a single marker styling to multiple pins: ```html theme={null} https://api.radar.io/maps/static?width=900&height=600&style=radar-light-v1&scale=2&markers=color:0x000257|40.73430,-73.99110|40.706436,-73.997271&publishableKey=prj_live_pk_... ``` ![Static Map Two Pins Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/static-map-two-pins.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=cb7535af573604feee83139aa1677d08) Additionally, if you want more than one marker style in an image, you can provide multiple `markers` parameters in the request. `markers=markerStyle1|markerLocation1|...&markers=markerStyle2|markerLocation2|...` An example request with two different styles is defined below. ``` https://api.radar.io/maps/static?width=900&height=600¢er=37.80176,-122.42376&zoom=13&style=radar-dark-v1&scale=2&markers=color:0xD1F3E0|size:small|37.808387,-122.409673&markers=color:0xBFD1FF|37.822503,-122.478923&publishableKey=prj_live_pk_... ``` ![Static Map Two Pins Different Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/static-map-two-pins-different.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=fb5beeea637c2592f788af4172c9b46a) ### Paths Paths lines can be added to highlight routes or connect items on your map. The `path` parameter can be configured for rendering a connected list of coordinates or an encoded polyline. Each paths parameter is made up of optional `pathStyle` sections, an encoded polyline, or one or more `pathLocations`. ``` path=pathStyle|pathLocation1|pathLocation2|... ``` *pathLocation* are specified in the following format `latitude,longitude` and are pipe separated. Locations must come *after* the style options. The locations can also be provided via encoded polyline by specifying `enc:` as the option (or `enc6:` for a polyline with 6 decimals precision). ``` path=pathStyle|enc:g{rwFnlrbMkArDENGRiCfIEJCJHFpA|@VPHFDOBGdC_IFQDO|BiHHUJBb@FxARLBH@ ``` *pathStyle* are specified in the following format `optionName:optionValue` and are pipe separated. *pathStyle* have the following options: * `stroke` (string, optional): The color of the path specified as a hex in the following format `0xFFFFFF` or a [standard color](https://developer.mozilla.org/en-US/docs/Web/CSS/named-color). The default value if color is not specified is `0x000257`. * `width` (number, optional): The width of the path in pixels. The default is `3`. * `border` (string, optional): The color of the path border as a hex in the following format `0xFFFFFF` or a [standard color](https://developer.mozilla.org/en-US/docs/Web/CSS/named-color). The default value if color is not specified is `white`. * `borderWidth` (number, optional): The width of the border in pixels. The default is `2`. ```html theme={null} https://api.radar.io/maps/static?width=900&height=600&style=radar-light-v1&scale=2&path=stroke:0xFF0000|width:3|border:0xFFFFFF|borderwidth:2|40.715442411463755,-74.01477925566485|40.71536228528052,-74.0135811740668|40.70948610234797,-74.01499068182932|40.70491834742046,-74.01675256653202|40.701953145830515,-74.01583638648677|40.70120514620143,-74.0143916410303|40.701819575084386,-74.01051549468332|40.70409024134315,-74.006357446784|40.706975211514106,-74.00167083347398|40.70871147591237,-73.99786516251531|40.709405968996606,-73.99455281927393|40.70961965771903,-73.99289664765297|40.71023400897673,-73.9875052804617|40.710901775653895,-73.9812682086125|40.711168880450145,-73.97918918466307|40.712798196502035,-73.97735682457207|40.71418709018175,-73.97682825916088|40.71765919762373,-73.97527780062218|40.72105100464597,-73.97464352212923|40.72334772071008,-73.97407971902413|40.72513696783835,-73.97267021126159|40.727032983196096,-73.97185974429856|40.728501692329786,-73.97566548297984|40.72588470062763,-73.97763879384702|40.72460287122638,-73.97837878542222|40.725671064108695,-73.98077494861835&path=|stroke:0x000257|width:3|border:0xFFFFFF|borderwidth:2|40.70376498115374,-73.98661916459334|40.700657698018915,-73.98670300220783|40.70003622399656,-73.9863583364594|40.70003622399656,-73.98677752453152|40.70514908788235,-73.98957211168081|40.71508654363487,-73.99501313325952|40.71646714228771,-73.99607566267477|40.72020611986693,-73.99421623619756|40.71750257248871,-73.98518473616696|40.71128974971751,-73.96465514996301|40.71005286858238,-73.9601393999477|40.710486585375435,-73.95607565049288|40.71330547192764,-73.95433006645362|40.71577909038294,-73.95155990047758|40.71934554124928,-73.95243269249747&publishableKey=prj_live_pk_... ``` ![Static Map Paths Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/static-map-paths.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=f98be213e789f483082af92eb208de97) ## Examples ### Embedding a Radar Static Map using HTML Radar Static Maps can easily be embedded into `` using the element's `src` attribute. For instance, if we wanted an image of a map with the following attributes: * **width**: 900 * **height**: 600 * **center**: 43.64259,-79.387087 * **zoom**: 13 * **style**: `radar-default-v1` * **scale**: 2 * **marker**: * color: `0x000257` * location: 43.64259,-79.387087 We can specify these options as query parameters in the image `src`. ```html theme={null} https://api.radar.io/maps/static?width=900&height=600¢er=43.64259,-79.387087&zoom=13&style=radar-default-v1&scale=2&markers=color:0x000257|43.64259,-79.387087&publishableKey=prj_live_pk_... ``` ![Static Map Embed Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/static-map-embed.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=4a02f6c6fd3d9b5fd59198861fefc1b5) ### Autofitting map bounds to markers or paths When markers or paths are included as part of the Static Image request, you have the option for the `center` and `zoom` to automatically be determined based on the items' locations. By omitting the `center` and `zoom` parameters, the map's position will be calculated to ensure all markers and paths are visible. ```html theme={null} https://api.radar.io/maps/static?width=900&height=600&style=radar-default-v1&scale=2&markers=color:0xFF428E|40.781196,-73.974075|40.782938,-73.959041&markers=color:0xE2052C|size:small|40.779344,-73.962486|40.76144,-73.977597|40.753664,-73.981905&path=stroke:0x000257|width:3|border:white|borderwidth:2|enc:qwwwF|cqbMIG@CBIMKIEeBiAKIKGeBkAIGMIs@e@q@c@IGKGeBgAKGMIcBiAECECKIGEw@g@c@YKGKIcBiAMIKGIGa@Wy@i@AAIGIEgBkAGESMAAi@]u@g@QKSOiAs@[UOKKGeBeASKHW[EEGOSEKIOEQAMOa@W]WQYQMIKKKKIMUg@COGc@GUIYU]W]]g@MSGGGCGAIAGEGKEKIKIIGGEKEOEOEKEIGIGEQKKEMIQKMIKGCYAOIMCIAG?G@G@K@I?GAI?GMQ?GM_@EUCOCQ?MAK?S?U?K@K@I@I@IBI@IBGBKBGBGDKDIDK@EBIHQDOBSBQ?O?Q?MAOAMAMEOIUEMKSIQGMS]EGMKSMc@UKEWGIESKUMOMSSQWMSKUMYM_@KYKUIWKSEKIMKMGIMMMKWOSMQGQI@G@IF_@QO[SSSMMGEEMCOAS@QD[RaAb@yAJWQKSMkBoAGEKGiBmAIEIGgBkAKGIGiBmAIGMGa@YgAs@IGGEgBkAKGKImAw@]UOKUOk@_@[SIEWQCCCCMGFSj@gB&publishableKey=prj_live_pk_... ``` ![Static Map Autofit Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/static-map-autofit.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=20eeca6c17f747998b806f7cd8b734b8) ### Using a custom marker image To use a custom marker image, set the `icon:` option as a URL that resolves to a valid `.png` or `.svg` file. Note: images will be capped at 64 x 64 pixels. ```html theme={null} https://api.radar.io/maps/static?width=900&height=600&style=radar-default-v1&scale=2&markers=icon:https://radar.com/static/image/logo.png|40.73430,-73.99110&publishableKey=prj_live_pk_... ``` ![Static Map Custom Marker Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/static-map-custom-marker.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=45ab4bcba3fe3d2eee6f4db4fb94b90e) ### Rendering a route Radar [Routing API](/api#routing) responses include the shape of the route in either the polyline or LineString format. Both of these formats are supported for rendering a path, which can be used to plot the route in a static image. ```html theme={null} https://api.radar.io/maps/static?width=900&height=600&style=radar-light-v1&scale=2&markers=size:small|icon:https://radar.com/static/image/maps/map-pin-origin@3x.png|40.70425,-73.9865&markers=size:small|icon:https://radar.com/static/image/maps/map-pin-destination@3x.png|40.73412,-73.99128&path=borderwidth:2|border:0xFFFFFF|width:3|stroke:0x000257|enc:g{rwFnlrbMkArDENGRiCfIEJCJHFpA|@VPHFDOBGdC_IFQDO|BiHHUJBb@FxARLBH@l@HbANB?LDJF@@vAfAJHHF|AnAHFHHhA|@RNJJ|@r@LJJFHHh@`@p@h@JJJF~ApAJHFFzAlADDHFJHbAx@^XJHHHrB~ADDBBJFl@f@@@ZVb@%08Av@LJVRBURsAN}@BQ@K?AN_AFWDUPq@BMBKj@wBBMDMh@sBBMBMTy@Pu@BIDQPDd@NnATtBh@`@Ll@NJBD@`Cl@HBFBjBj@D@JBHBTFx@TJDVFTF`@LZAnA`@JBJDlDfALDLD~@`@fAd@hAf@JFHDjBbAJD@@LFj@ZJFVLZQtA}@ZUHGJKHKV]HKFIHIFGJIHGLILGjAg@t|Aks@H?JCJCRIFEHCHCH?FAF@F@HBFDFHDHBJ@L@JALAJCHEFEHE@C@C@I@I?I@G@I@KAc@AeACy@AG?I@KBODIBGBOF}@b@OFBgA?IM?Q?_@Ai@Cs@AI?I@K?yCKK?MAsAC_@AG?IAmBEI?[A&publishableKey=prj_live_pk_... ``` ![Static Map Routing Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/static-map-routing.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=624a413f9606d4a00e97fa292e27842d) ### Images for high resolution device When embedding images on high resolution devices, images may look blurry (low resolution) or be too small if the image is not scaled to match the device's pixel ratio. The `scale` parameter can be used to increase the resolution of an image, while keeping the same map area visible. For example an image with `scale=2` will return an image that is two times the size, but at the same zoom/area. ```html theme={null} https://api.radar.io/maps/static?width=200&height=200¢er=40.71257,-74.00260&zoom=12.5&style=radar-default-v1&scale=2&publishableKey=prj_live_pk_... ``` | 200x200 @ 1x scale | 200x200 @ 2x scale | | - | - | | ![Static Map 1x scale](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/static-map-high-res-1x.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=2e85680691d265d46d6dbdc386d76b75) | ![Static Map 2x scale](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/maps/static-map-high-res-2x.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=bedf941d7062bc089e0a296ce4b71c8b) | ## Coverage See [Maps coverage](/maps/maps#coverage) for more details. ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # Android SDK Source: https://docs.radar.com/sdk/android Install and integrate the Radar Android SDK to add geofencing, location tracking, trip tracking, and geocoding to your Android app. The Radar SDK abstracts away cross-platform differences between location services, allowing you to add geofencing, location tracking, trip tracking, geocoding, and search to your apps with just a few lines of code. Learn how to integrate the Android SDK below. You can also see the [source](https://github.com/radarlabs/radar-sdk-android) and a [detailed SDK reference](https://radarlabs.github.io/radar-sdk-android/) on GitHub. ## Install SDK The best way to add the SDK to your project is via Gradle in Android Studio. > [!NOTE] > > For details on the latest SDK releases, see the [releases page](https://github.com/radarlabs/radar-sdk-android/releases) on GitHub. You can also star ⭐️ and watch 👀 the repo. The SDK is small and typically adds less than 500 KB to your compiled app. ### Gradle (recommended) The SDK is distributed using [Maven Central](https://search.maven.org/artifact/io.radar/sdk). Add the SDK to the `dependencies` section of your app's `build.gradle` file: ```gradle theme={null} dependencies { implementation 'io.radar:sdk:4.2.+' } ``` ### Add manually You can also add the SDK to your project manually. Download [the current release](https://github.com/radarlabs/radar-sdk-android/releases) 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*. ## Dependencies The SDK depends on [Google Play Services Location](https://developer.android.com/training/location) version `21.0.1` and higher, which will be automatically included as a transitive dependency by Gradle. Learn more about managing dependencies in Gradle [here](https://docs.gradle.org/current/userguide/core_dependency_management.html). If you haven't already configured your project for Google Play Services, follow the instructions [here](https://developers.google.com/android/guides/google-services-plugin). As of version `3.8.0`, the SDK uses `play-services-location:21.0.1`. If another dependency that depends on `play-services-location` is causing version conflicts, you can exclude the transitive dependencies and include the `play-services-location` dependency at the project level instead. We strongly recommend using `21.0.1` or higher. As an alternative to Google Play Services, the SDK also optionally supports [Huawei Mobile Services](#huawei). The SDK currently supports API level `23` or above. ## Initialize SDK When your app starts, in application `onCreate()`, initialize the SDK with your publishable API key, found on the [Settings page](https://dashboard.radar.com/settings). Use your `Test Publishable` key for testing and non-production environments. Use your `Live Publishable` key for production environments. > [!WARNING] > > 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. ```java Java theme={null} import io.radar.sdk.Radar; public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Radar.initialize(this, "prj_test_pk_..."); } } ``` ```kotlin Kotlin theme={null} import io.radar.sdk.Radar class MyApplication : Application() { override fun onCreate() { super.onCreate() Radar.initialize(this, "prj_test_pk_...") } } ``` ### Network timeout To override the default network timeout, set `networkTimeout` on `RadarInitializeOptions` as a Kotlin `Duration`. The extended timeout used for longer-running requests is automatically set to 2.5x this value. Values are clamped to `[1, 300]` seconds. ```kotlin Kotlin theme={null} import io.radar.sdk.Radar import io.radar.sdk.RadarInitializeOptions import kotlin.time.Duration.Companion.seconds val options = RadarInitializeOptions(networkTimeout = 30.seconds) Radar.initialize(this, "prj_test_pk_...", options) ``` ## Request permissions Radar respects [standard Android location permissions](https://developer.android.com/training/permissions/requesting.html). For foreground tracking or trip tracking with continuous mode, Radar requires the `ACCESS_FINE_LOCATION` permission for precise location and/or the `ACCESS_COARSE_LOCATION` permission for [approximate location](https://developer.android.com/about/versions/12/approximate-location). These permissions are automatically added by the SDK manifest along with the `INTERNET`, `ACCESS_NETWORK_STATE`, `FOREGROUND_SERVICE`, and `RECEIVE_BOOT_COMPLETED` permissions. For background tracking or geofencing with responsive mode, and if targeting API level `29` or above, Radar also requires the new `ACCESS_BACKGROUND_LOCATION` permission. You must add the `ACCESS_BACKGROUND_LOCATION` permission to your manifest manually. To start a [foreground service](https://developer.android.com/training/location/permissions#foreground) or use the `continuous` tracking preset, you must add the `FOREGROUND_SERVICE_LOCATION` permission. In Android SDK 4.0.0 and later, you must also [declare `RadarForegroundService`](#foreground-services-and-google-play-policy). Add the permissions to your manifest: ```xml theme={null} ``` To request foreground and background permissions: ```java Java theme={null} import android.Manifest; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.pm.PackageManager; import android.os.Build; import androidx.core.app.ActivityCompat; import io.radar.sdk.Radar; public class MainActivity extends AppCompatActivity { private final int FOREGROUND_LOCATION_PERMISSION_CODE = 1; private final int BACKGROUND_LOCATION_PERMISSION_CODE = 2; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Radar.initialize(this, "prj_test_pk_.."); requestLocationPermissions(); } private void requestLocationPermissions() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_PERMISSION_CODE); } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, FOREGROUND_LOCATION_PERMISSION_CODE); } } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == FOREGROUND_LOCATION_PERMISSION_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { askPermissionForBackgroundUsage(); } return; } } private void askPermissionForBackgroundUsage() { if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)) { new AlertDialog.Builder(this) .setTitle("Background location permissions needed") .setMessage("Background location permissions needed, tap \"Allow all the time\" on the next screen") .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_PERMISSION_CODE); } }) .create() .show(); } } } ``` ```kotlin Kotlin theme={null} import android.Manifest import android.app.AlertDialog import android.content.pm.PackageManager import android.os.Build import androidx.core.app.ActivityCompat import io.radar.sdk.Radar class MainActivity : AppCompatActivity() { private val foregroundLocationPermissionsRequestCode = 1 private val backgroundLocationPermissionsRequestCode = 2 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Radar.initialize(this, "prj_test_pk_...") requestLocationPermissions() } private fun requestLocationPermissions() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION), backgroundLocationPermissionsRequestCode) } else { ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION), foregroundLocationPermissionsRequestCode) } } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == foregroundLocationPermissionsRequestCode && grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION)) { AlertDialog.Builder(this) .setTitle("Background location permissions needed") .setMessage("Background location permission needed, tap \"Allow all the time\" on the next screen") .setPositiveButton( "OK" ) { _, _ -> ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION), backgroundLocationPermissionsRequestCode) } .create() .show() } } } } ``` > [!NOTE] > > Build and run the app to make sure permissions prompts are displayed! > [!NOTE] > > Not seeing permissions prompts? First, make sure you've added permissions to your manifest. Second, check your device settings to make sure you haven't already granted location permissions. ## Foreground tracking Once the user has granted foreground permissions, you can track the user's location in the foreground. To track the user's location in the foreground, call: ```java Java theme={null} Radar.trackOnce(new RadarTrackCallback() { @Override public void onComplete(RadarStatus status, Location location, RadarEvent[] events, RadarUser user) { // do something with location, events, user } }); ``` ```kotlin Kotlin theme={null} Radar.trackOnce { status, location, events, user -> // do something with location, events, user } ``` You may provide an optional instance of `RadarTrackCallback` 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`**: success * **`RadarStatus.ERROR_PUBLISHABLE_KEY`**: SDK not initialized * **`RadarStatus.ERROR_PERMISSIONS`**: location permissions not granted * **`RadarStatus.ERROR_LOCATION`**: location services error or timeout (10 seconds) * **`RadarStatus.ERROR_NETWORK`**: network error or timeout (10 seconds) * **`RadarStatus.ERROR_BAD_REQUEST`**: bad request (missing or invalid params) * **`RadarStatus.ERROR_UNAUTHORIZED`**: unauthorized (invalid API key) * **`RadarStatus.ERROR_PAYMENT_REQUIRED`**: payment required (organization disabled or usage exceeded) * **`RadarStatus.ERROR_FORBIDDEN`**: forbidden (insufficient permissions) * **`RadarStatus.ERROR_NOT_FOUND`**: not found * **`RadarStatus.ERROR_RATE_LIMIT`**: too many requests ([rate limit](/api#track) exceeded) * **`RadarStatus.ERROR_SERVER`**: internal server error * **`RadarStatus.ERROR_UNKNOWN`**: unknown error > [!WARNING] > > Build and run the app, then find your user on the [Users page](https://dashboard.radar.com/geofencing/users)! To trigger an event, you'll need to [create a geofence](https://dashboard.radar.com/geofencing/geofences) if you haven't already. Not seeing your user on the Users page? Check `status` in the callback to see what went wrong. ## Background tracking for geofencing Once you have initialized the SDK and the user has authorized background permissions, you can start tracking the user's location in the background. The SDK supports custom tracking options as well as three presets. For geofencing, we recommend using `RadarTrackingOptions.RESPONSIVE`. This preset detects whether the device is stopped or moving. When moving, it tells the SDK to send location updates to the server every 2-3 minutes. When stopped, it tells the SDK to shut down to save battery. Once stopped, the device will need to move more than 100 meters to wake up and start moving again. Assuming the user has authorized background permissions, background tracking will work even if the app has been backgrounded or killed, as Android location services will wake up the app to deliver events and the SDK uses `JobScheduler` to schedule network requests. > [!WARNING] > > Note that location updates may be delayed significantly by [Doze Mode](https://developer.android.com/training/monitoring-device-state/doze-standby), [App Standby](https://developer.android.com/training/monitoring-device-state/doze-standby), and [Background Location Limits](https://developer.android.com/about/versions/oreo/background-location-limits), or if the device has connectivity issues, low battery, or wi-fi disabled.***In practice, location updates may be sent to the server every 5-10 minutes while moving, faster if you power on the screen or if other apps are requesting location, and slower otherwise.*** These restrictions apply to all apps using location services, not just Radar. > [!NOTE] > > Though we recommend using presets for most use cases, you can modify the presets. See the [tracking options reference](/sdk/tracking). To start tracking for geofencing, call: ```java Java theme={null} Radar.startTracking(RadarTrackingOptions.RESPONSIVE); ``` ```kotlin Kotlin theme={null} Radar.startTracking(RadarTrackingOptions.RESPONSIVE) ``` To determine whether tracking has been started, call: ```java Java theme={null} Radar.isTracking(); ``` ```kotlin Kotlin theme={null} Radar.isTracking() ``` To stop tracking (e.g., when the user logs out), call: ```java Java theme={null} Radar.stopTracking(); ``` ```kotlin Kotlin theme={null} Radar.stopTracking() ``` You only need to call these methods once, as these settings will be persisted across app sessions. To test, go for a walk or a drive! Not seeing location updates or events? Remember that, once stopped, the device will need to move more than 100 meters to wake up and start moving again. Also, check your device settings to make sure you've granted background location permissions. Don't forget! You can always find your user on the [Users page](https://dashboard.radar.com/geofencing/users) or events on the [Events page](https://dashboard.radar.com/geofencing/events). To trigger an event, you'll need to [create a geofence](https://dashboard.radar.com/geofencing/geofences) if you haven't already. ### Foreground services and Google Play policy Geofencing does not require a [foreground service](https://developer.android.com/guide/components/foreground-services). The SDK registers nearby geofences with the Android [Geofence API](https://developer.android.com/develop/sensors-and-location/location/geofencing), and Android wakes up the app to deliver geofence transitions. The `RESPONSIVE` and `EFFICIENT` presets never start a foreground service. Google Play's [updated location permissions policy](https://support.google.com/googleplay/android-developer/answer/16926792) no longer accepts geofencing as a use case for foreground services. Only enable a foreground service, with the `CONTINUOUS` preset or `foregroundServiceEnabled`, for use cases that Google Play still allows, such as [trips](#background-tracking-for-trips), navigation, or user-initiated location sharing. You must declare foreground service usage in the Play Console. Starting in Android SDK 4.0.0, the SDK manifest does not declare `RadarForegroundService`. To use the `CONTINUOUS` preset or `foregroundServiceEnabled`, declare the service and the `FOREGROUND_SERVICE_LOCATION` permission in your app manifest: ```xml theme={null} ``` If the service is not declared, the SDK logs an error and tracks without a foreground service. This also applies when [remote tracking options](/sdk/remote-configuration) enable the foreground service. In Android SDK versions before 4.0.0, the SDK manifest declares `RadarForegroundService`. If your app never uses the foreground service, remove it from your merged manifest: ```xml theme={null} ``` ## Background tracking for trips For trips, we recommend using `RadarTrackingOptions.continuous`. This preset tells the SDK to send location updates to the server every 30 seconds, regardless of whether the device is moving. To avoid [Background Location Limits](https://developer.android.com/about/versions/oreo/background-location-limits), the continuous preset starts a [foreground service](https://developer.android.com/guide/components/foreground-services) with a notification while tracking. When the foreground service with a notification is running, only foreground permissions are required for tracking. See the [tracking options reference](/sdk/tracking#android-foreground-service-options) to adjust the foreground service notification copy and behavior. In Android SDK 4.0.0 and later, you must [declare `RadarForegroundService`](#foreground-services-and-google-play-policy) in your app manifest. If you publish on Google Play, declare foreground service usage in the Play Console. Tracking for the duration of a trip is started or updated by including tracking options in the `startTrip` call: ```java Java theme={null} Radar.startTrip(tripOptions, RadarTrackingOptions.CONTINUOUS, new Radar.RadarTripCallback() { @Override public void onComplete(@NonNull Radar.RadarStatus status, @Nullable RadarTrip trip, @Nullable RadarEvent[] events) { if (status == Radar.RadarStatus.SUCCESS) { // do something } else { // handle error } } }); ``` ```kotlin Kotlin theme={null} Radar.startTrip(tripOptions, RadarTrackingOptions.CONTINUOUS) { status, trip, events -> if (status == Radar.RadarStatus.SUCCESS) { // do something } else { // handle error } } ``` If tracking was disabled before the trip started, it will stop after the trip ends. Otherwise, it will revert to the tracking options in use before the trip started: ```java Java theme={null} // Complete trip Radar.completeTrip(new Radar.RadarTripCallback() { @Override public void onComplete(Radar.RadarStatus radarStatus, RadarTrip radarTrip, RadarEvent[] radarEvents) { // do something } }); // Cancel trip Radar.cancelTrip(new Radar.RadarTripCallback() { @Override public void onComplete(Radar.RadarStatus radarStatus, RadarTrip radarTrip, RadarEvent[] radarEvents) { // do something } }); ``` ```kotlin Kotlin theme={null} // Complete trip Radar.completeTrip { status, trip, events -> // do something } // Cancel trip Radar.cancelTrip { status, trip, events -> // do something } ``` Learn more about starting, completing, and canceling trips in the [trip tracking documentation](/geofencing/trips). Don't forget! You can always find your user on the [Users page](https://dashboard.radar.com/geofencing/users) or events on the [Events page](https://dashboard.radar.com/geofencing/events). To trigger an event, you'll need to [create a geofence](https://dashboard.radar.com/geofencing/geofences) or [start a trip](/geofencing/trips) if you haven't already. ## Mock tracking for testing Can't go for a walk or a drive? You can simulate a sequence of location updates. For example, to simulate a sequence of 10 location updates every 3 seconds by car from an origin to a destination, call: ```java Java theme={null} Location origin = new Location("mock"); origin.setLatitude(40.78382); origin.setLongitude(-73.97536); Location destination = new Location("mock"); destination.setLatitude(40.70390); destination.setLongitude(-73.98670); Radar.mockTracking( origin, destination, Radar.RadarRouteMode.CAR, 10, 3, new RadarTrackCallback() { @Override public void onComplete(RadarStatus status, Location location, RadarEvent[] events, RadarUser user) { // do something with location, events, user } }); ``` ```kotlin Kotlin theme={null} val origin = Location("mock") origin.latitude = 40.78382 origin.longitude = -73.97536 val destination = Location("mock") destination.latitude = 40.70390 destination.longitude = -73.98670 Radar.mockTracking( origin, destination, Radar.RadarRouteMode.CAR, 10, 3) { status, location, events, user -> // do something with location, events, user } ``` Don't forget! You can always find your user on the [Users page](https://dashboard.radar.com/geofencing/users) or events on the [Events page](https://dashboard.radar.com/geofencing/events). To trigger an event, you'll need to [create a geofence](https://dashboard.radar.com/geofencing/geofences) if you haven't already. ## Location metadata The SDK can also pass along information like motion activity detection, speed and heading via the location metadata field. Turn on `useMotion` in your `sdkConfiguration` to enable this feature. Include permissions for motion activity detection in your manifest ```xml theme={null} ``` You will need to manually prompt for motion permissions with ```java Java theme={null} ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACTIVITY_RECOGNITION}, ACTIVITY_RECOGNITION_PERMISSION_CODE); ``` ```kotlin Kotlin theme={null} ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACTIVITY_RECOGNITION), ACTIVITY_RECOGNITION_PERMISSION_CODE) ``` ## Listening for events with a receiver To listen for events, location updates, and errors client-side, create a class that extends `RadarReceiver`. Then, pass in an instance of your receiver when initializing the SDK in application `onCreate()`. ```java Java theme={null} import io.radar.sdk.Radar; public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); MyRadarReceiver receiver = new MyRadarReceiver(); Radar.initialize(this, "prj_test_pk_...", receiver, Radar.RadarLocationServicesProvider.GOOGLE); } } ``` ```kotlin Kotlin theme={null} import io.radar.sdk.Radar class MyApplication : Application() { override fun onCreate() { super.onCreate() val receiver = MyRadarReceiver() Radar.initialize(this, "prj_test_pk_...", receiver, Radar.RadarLocationServicesProvider.GOOGLE) } } ``` The receiver should be instantiated only once and set before tracking begins. Your receiver should implement the following: ```java Java theme={null} public class MyRadarReceiver extends RadarReceiver { @Override public void onEventsReceived(Context context, RadarEvent[] events, RadarUser user) { // do something with events, user } @Override public void onLocationUpdated(Context context, Location location, RadarUser user) { // do something with location, user } @Override public void onClientLocationUpdated(Context context, Location location, boolean stopped, RadarLocationSource source) { // do something with location, stopped, source } @Override public void onError(Context context, RadarStatus status) { // do something with status } @Override public void onLog(Context context, String message) { // print message for debug logs } @Override public void onLocationPermissionStatusUpdated(context: Context,status: RadarLocationPermissionStatus) { // do something with location permission status } } ``` ```kotlin Kotlin theme={null} class MyRadarReceiver: RadarReceiver() { override fun onEventsReceived(context: Context, events: Array, user: RadarUser?) { // do something with events, user } override fun onLocationUpdated(context: Context, location: Location, user: RadarUser) { // do something with location, user } override fun onClientLocationUpdated(context: Context, location: Location, stopped: Boolean, source: RadarLocationSource) { // do something with location, stopped, source } override fun onError(context: Context, status: RadarStatus) { // do something with status } override fun onLog(context: Context, message: String) { // print message for debug logs } overide fun onLocationPermissionStatusUpdated(context: Context,status: RadarLocationPermissionStatus) { // do something with location permission status } } ``` To listen for events server-side instead, add a [webhook](/integrations/webhooks) or enable an [integration](/integrations/integrations). ## Manual tracking If you want to manage location services yourself, you can manually update the user's location instead by calling: ```java Java theme={null} Radar.trackOnce( location, new RadarTrackCallback() { @Override public void onComplete(RadarStatus status, Location location, RadarEvent[] events, RadarUser user) { // do something with location, events, user } }); ``` ```kotlin Kotlin theme={null} Radar.trackOnce(location) { status, location, events, user -> // do something with location, events, user } ``` where `location` is a `Location` instance with a valid latitude, longitude, and accuracy. ## Identify user The SDK automatically collects `installId` (a GUID generated on fresh install) and `deviceId` ([Android ID](https://developer.android.com/reference/android/provider/Settings.Secure.html#ANDROID_ID)). You can also assign a custom `userId`, also called *External ID* in the dashboard. To set a custom `userId`, call: ```java Java theme={null} Radar.setUserId(userId); ``` ```kotlin Kotlin theme={null} Radar.setUserId(userId) ``` where `userId` is a stable unique ID for the user. Do not send any PII, like names, email addresses, or publicly available IDs, for `userId`. See [privacy best practices](/faqs#what-are-privacy-best-practices-for-radar) for more information. To set a dictionary of custom metadata for the user, call: ```java Java theme={null} Radar.setMetadata(metadata); ``` ```kotlin Kotlin theme={null} Radar.setMetadata(metadata) ``` where `metadata` is a `JSONObject` with up to 16 keys and values of type string, boolean, or number. Finally, to set an optional description for the user, displayed in the dashboard, call: ```java Java theme={null} Radar.setDescription(description); ``` ```kotlin Kotlin theme={null} Radar.setDescription(description) ``` You only need to call these methods once, as these settings will be persisted across app sessions. Learn more about when Radar creates new user records [here](/faqs#what-is-a-unique-user-when-does-radar-create-a-new-user-record). ## Debug logging By default, only critical errors are logged to the console. To enable debug logging, call: ```java Java theme={null} Radar.setLogLevel(Radar.RadarLogLevel.DEBUG); ``` ```kotlin Kotlin theme={null} Radar.setLogLevel(Radar.RadarLogLevel.DEBUG) ``` The Android SDK automatically logs lifecycle events without the additional setup required on iOS. Contact your customer success manager to enable logging app lifecycle events. ## Other APIs The Android SDK also exposes APIs for beacons, geocoding, search, and distance. ### Beacons To range and monitor [beacons](/geofencing/beacons), you must [request Bluetooth permissions](https://developer.android.com/about/versions/12/features/bluetooth-permissions#declare-new-permissions). If targeting API level `31` or above, both `BLUETOOTH_CONNECT` and `BLUETOOTH_SCAN` are required runtime permissions. The following bluetooth permissions must be added to your manifest: ```xml theme={null} ``` To range beacons in the foreground, call: ```java Java theme={null} Radar.trackOnce(RadarTrackingOptionsDesiredAccuracy.HIGH, true, new RadarTrackCallback() { @Override public void onComplete(RadarStatus status, Location location, RadarEvent[] events, RadarUser user) { // do something with user.beacons } }); ``` ```kotlin Kotlin theme={null} Radar.trackOnce(RadarTrackingOptionsDesiredAccuracy.HIGH, true) { status, location, events, user -> // do something with user.beacons } ``` To monitor beacons in the background, update your tracking options: ```java Java theme={null} RadarTrackingOptions trackingOptions = RadarTrackingOptions.RESPONSIVE; trackingOptions.beacons = true; Radar.startTracking(trackingOptions); ``` ```kotlin Kotlin theme={null} val trackingOptions = RadarTrackingOptions.RESPONSIVE trackingOptions.beacons = true Radar.startTracking(trackingOptions) ``` If you call `Radar.trackVerified(beacons = true)`, you can call `Radar.startRangingBeacons()` to range beacons continuously in the foreground, so location checks don't wait for a new ranging window. Call `Radar.stopRangingBeacons()` when you no longer need beacons. These methods require Android 8.0 (API level 26) or later. Learn more about [ranging beacons with location checks](/geofencing/fraud#ranging-beacons). ```java Java theme={null} Radar.startRangingBeacons(); Radar.stopRangingBeacons(); ``` ```kotlin Kotlin theme={null} Radar.startRangingBeacons() Radar.stopRangingBeacons() ``` Learn more about [beacons](/geofencing/beacons). ### Geocoding With the [forward geocoding API](/api#forward-geocode), geocode an address, converting address to coordinates: ```java Java theme={null} Radar.geocode( "20 jay street brooklyn ny", // query new RadarGeocodeCallback() { @Override public void onComplete(RadarStatus status, RadarAddress[] addresses) { // do something with addresses } }); ``` ```kotlin Kotlin theme={null} Radar.geocode("20 jay street brooklyn ny") { status, addresses -> // do something with addresses } ``` With the [reverse geocoding API](/api#reverse-geocode), reverse geocode a location, converting coordinates to address: ```java Java theme={null} Radar.reverseGeocode( location, new RadarGeocodeCallback() { @Override public void onComplete(RadarStatus status, RadarAddress[] addresses) { // do something with addresses } }); ``` ```kotlin Kotlin theme={null} Radar.reverseGeocode(location) { status, addresses -> // do something with addresses } ``` With the [IP geocoding API](/api#ip-geocode), geocode the device's current IP address, converting IP address to city, state, and country: ```java Java theme={null} Radar.ipGeocode(new RadarIpGeocodeCallback() { @Override public void onComplete(RadarStatus status, RadarAddress address, boolean proxy, Throwable throwable) { // do something with address, proxy } }); ``` ```kotlin Kotlin theme={null} Radar.ipGeocode { status, address, proxy, throwable -> // do something with address, proxy } ``` ### Search With the [autocomplete API](/api#autocomplete), autocomplete partial addresses and place names, sorted by relevance: ```java Java theme={null} Radar.autocomplete( "brooklyn roasting", // query near, null, // layers 10, // limit new RadarGeocodeCallback() { @Override public void onComplete(RadarStatus status, RadarAddress[] addresses) { // do something with addresses } }); ``` ```kotlin Kotlin theme={null} Radar.autocomplete( query = "brooklyn roasting", near = near, limit = 10 ) { status, addresses -> // do something with addresses } ``` With the [geofence search API](/api#search-geofences), search for geofences near a location, sorted by distance: ```java Java theme={null} Radar.searchGeofences( near, 1000, // radius (meters) {"store"}, // tags null, //metadata 10, // limit new RadarSearchGeofencesCallback() { @Override public void onComplete(RadarStatus status, Location location, RadarGeofence[] geofences) { // do something with geofences } }); ``` ```kotlin Kotlin theme={null} Radar.searchGeofences( near, 1000, // radius (meters) arrayOf("store"), // tags null, // metadata 10 // limit ) { status, location, geofences -> // do something with geofences } ``` With the [places search API](/api#search-places), search for places near a location, sorted by distance: ```java Java theme={null} Radar.searchPlaces( near, 1000, // radius (meters) new String[]{"starbucks"}, // chains null, // chainMetadata null, // categories null, // groups null, // countryCodes 10, // limit new RadarSearchPlacesCallback() { @Override public void onComplete(RadarStatus status, Location location, RadarPlace[] places) { // do something with places } }); ``` ```kotlin Kotlin theme={null} Radar.searchPlaces( near = near, radius = 1000, // meters chains = arrayOf("starbucks"), chainMetadata = null, categories = null, groups = null, countryCodes = null, limit = 10 ) { status, location, places -> // do something with places } ``` With the [address validation API](/api#validate-an-address) (currently in beta), validate a structured address in the US or Canada: ```java Java theme={null} Radar.validateAddress( address, // query new RadarValidateAddressCallback() { @Override public void onComplete(RadarStatus status, RadarAddress address, ValidationResult result) { // do something with validation result and address } }); ``` ```kotlin Kotlin theme={null} Radar.validateAddress(address) { status, address, result -> // do something with validation result and address } ``` ### Distance With the [distance API](/api#distance), calculate the travel distance and duration from an origin to a destination: ```java Java theme={null} Radar.getDistance( origin, destination, EnumSet.of(RadarRouteMode.FOOT, RadarRouteMode.CAR), RadarRouteUnits.IMPERIAL, new RadarRouteCallback() { @Override public void onComplete(RadarStatus status, RadarRoutes routes) { // do something with routes } }); ``` ```kotlin Kotlin theme={null} Radar.getDistance( origin, destination, EnumSet.of(RadarRouteMode.FOOT, RadarRouteMode.CAR), RadarRouteUnits.IMPERIAL ) { status, routes -> // do something with routes } ``` ### Matrix With the [matrix API](/api#matrix), calculate the travel distance and duration between multiple origins and destinations for up to 25 routes: ```java Java theme={null} Radar.getMatrix( origins, destinations, RadarRouteMode.CAR, RadarRouteUnits.IMPERIAL, new RadarRouteCallback() { @Override public void onComplete(RadarStatus status, RadarRouteMatrix matrix) { // do something with matrix.routeBetween(originIndex, destinationIndex) } }); ``` ```kotlin Kotlin theme={null} Radar.getMatrix( origins, destinations, RadarRouteMode.CAR, RadarRouteUnits.IMPERIAL ) { status, routes -> // do something with matrix.routeBetween(originIndex, destinationIndex) } ``` ### Conversions With the [conversions API](/api#log-a-conversion), log a conversion, such as a purchase or signup, to analyze alongside your app's location activity: ```java Java theme={null} Radar.logConversion( name, metadata, new RadarLogConversionCallback() { @Override public void onComplete(RadarStatus status, RadarEvent event) { // do something with the conversion event } }) // Conversion with revenue Radar.logConversion( name, revenue, metadata, new RadarLogConversionCallback() { @Override public void onComplete(RadarStatus status, RadarEvent event) { // do something with the conversion event } }) ``` ```kotlin Kotlin theme={null} Radar.logConversion( name, metadata, ) { status, event -> // do something with the conversion event } // Conversion with revenue Radar.logConversion( name, revenue, metadata, ) { status, event -> // do something with the conversion event } ``` ### User tags With the [user tag API](/geofencing/campaigns#campaign-targeting), you can configure [campaigns](/geofencing/campaigns) to only target users with the corresponding tags: ```java Java theme={null} Radar.addTags(new String[]{"tag1", "tag2"}); Radar.removeTags(new String[]{"tag1", "tag2"}); Radar.setTags(new String[]{"tag1", "tag2"}); Radar.getTags(); ``` ```kotlin Kotlin theme={null} Radar.addTags(arrayOf("tag1", "tag2")) Radar.removeTags(arrayOf("tag1", "tag2")) Radar.setTags(arrayOf("tag1", "tag2")) Radar.getTags() ``` ## Notifications With `setNotificationOptions`, set the icon and the background color of foreground service and event notifications: ```java Java theme={null} // Set both foreground service and event notifications JSONObject notificationOptions = new JSONObject(); try { notificationOptions.put("iconString", "icon_1"); notificationOptions.put("iconColor", "color_1"); } catch (JSONException e) { e.printStackTrace(); } Radar.setNotificationOptions(RadarNotificationsOptions.fromJson(notificationOptions)); // Or, set the foreground service notification and event notifications separately JSONObject notificationOptions = new JSONObject(); try { notificationOptions.put("foregroundServiceIconString", "icon_1"); notificationOptions.put("foregroundServiceIconColor", "color_1"); notificationOptions.put("eventIconString", "icon_2"); notificationOptions.put("eventIconColor", "color_2"); } catch (JSONException e) { e.printStackTrace(); } Radar.setNotificationOptions(RadarNotificationsOptions.fromJson(notificationOptions)); ``` ```kotlin Kotlin theme={null} // Set both foreground service and event notifications Radar.setNotificationOptions(RadarNotificationsOptions( "icon_1", // iconString "color_1", // iconColor )) // Or, set the foreground service notification and event notifications separately Radar.setNotificationOptions(RadarNotificationsOptions( foregroundServiceIconString = "icon_2", foregroundServiceIconColor = "color_2", eventIconString = "icon_3", eventIconColor = "color_3", )) ``` ## Huawei By default, the SDK [depends on](#dependencies) [Google Play Services Location](https://developer.android.com/training/location). However, you can use [Huawei Mobile Services Location Kit](https://developer.huawei.com/consumer/en/hms/huawei-locationkit/) instead. If you haven't already configured your project for Huawei Mobile Services, follow the instructions [here](https://developer.huawei.com/consumer/en/doc/development/HMSCore-Guides/integrate-as-sdk-0000001050168936). Then, add the dependency to your app's `build.gradle` file: ```gradle theme={null} dependencies { implementation 'com.huawei.hms:location:6.4.0.300' } ``` Finally, pass in `RadarLocationServicesProvider.HUAWEI` when you initialize the SDK: ```java Java theme={null} Radar.initialize(this, publishableKey, receiver, RadarLocationServicesProvider.HUAWEI); ``` ```kotlin Kotlin theme={null} Radar.initialize(context, publishableKey, receiver, RadarLocationServicesProvider.HUAWEI) ``` # Capacitor plugin Source: https://docs.radar.com/sdk/capacitor Install and integrate the Radar Capacitor plugin to add location tracking, geofencing, and trip tracking to your Capacitor app. This is the documentation for the Capacitor plugin. Before integrating, read the [native SDK documentation](https://docs.radar.com/sdk) to familiarize yourself with the platform. See the source on GitHub [here](https://github.com/radarlabs/capacitor-radar). Or, see the `capacitor-radar` package on npm [here](https://www.npmjs.com/package/capacitor-radar). ## Install Install the package from npm: ```bash theme={null} npm install --save capacitor-radar ``` Then, update dependencies: ```bash theme={null} npx cap sync ``` If successful, you will see: ``` ✔ Updating Android plugins Found 1 Capacitor plugin for android: capacitor-radar ✔ update android ... ✔ Updating iOS plugins Found 1 Capacitor plugin for ios: capacitor-radar ✔ Updating iOS native dependencies with "pod install" (may take several minutes) ✔ update ios ``` Before writing any JavaScript, you must integrate the Radar SDK with your iOS and Android apps as described in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### iOS You must add location usage descriptions and background modes to your `Info.plist`. For foreground permissions, you must add a value for `NSLocationWhenInUseUsageDescription` *(Privacy - Location When In Use Usage Description)*. For background permissions, you must add a value for `NSLocationAlwaysAndWhenInUseUsageDescription` *(Privacy - Location Always and When In Use Usage Description)*. These strings are displayed in permissions prompts. ![](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/sdk/f2vbu16fzuly/66LUD7W9uTt7f2H5pMmpBp/1e5a2bb2baaf79328e88c3ea47a7f6ff/permissions.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=cd1d20f197db651000cfc17c30a494ce) If you are planning to leverage background tracking, such as responsive or continuous mode, in your project settings, go to *Signing & Capabilities*, add *Background Modes*, and turn on *Background fetch* and *Location updates*. Note that this requires additional justification during App Store review. [Learn more](/sdk/ios#submit-to-app-store). ![Background Modes Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/sdk/background-modes.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=7a20ffae1206dfb6c64d1943a3724c75) Finally, initialize the SDK in `application:didFinishLaunchingWithOptions:` in `AppDelegate.swift`, passing in your Radar publishable API key: ```swift theme={null} import Capacitor import RadarSDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Radar.initialize(publishableKey: publishableKey) return true } } ``` ### Android You must add Google Play Services Location to your project *(use version 21.0.1 or higher)*. ```gradle theme={null} implementation "com.google.android.gms:play-services-location:21.0.1" ``` Make sure that the Android SDK version matches the version in the `radar-capacitor` module's `build.gradle`. > [!NOTE] > > When upgrading the SDK, ensure the Android SDK version is updated to match the plugin's pinned version. For details on the latest SDK releases, see the [releases page](https://github.com/radarlabs/capacitor-radar/releases) on GitHub. Add the SDK to your project, preferably using Gradle. Finally, initialize the SDK and the plugin in `onCreate()` in `MainActivity.java`, passing in your Radar publishable API key: ```java theme={null} import android.os.Bundle; import com.getcapacitor.BridgeActivity; import io.radar.sdk.Radar; public class MainActivity extends BridgeActivity { @Override public void onCreate(Bundle savedInstanceState) { Radar.initialize(this, publishableKey); super.onCreate(savedInstanceState); } } ``` > [!WARNING] > > Note that `Radar.initialize(this, publishableKey)` must be called before `super.onCreate(savedInstanceState)` on Capacitor v4 and higher because of changes to [plugin loading](https://capacitorjs.com/docs/updating/4-0#change-registerplugin-order). For background tracking without a foreground service, and if targeting API level `29` or higher, Radar also requires the `ACCESS_BACKGROUND_LOCATION` permission. You must add the `ACCESS_BACKGROUND_LOCATION` permission to your manifest manually: ```xml theme={null} ``` ## Integrate ### Import module First, import the module: ```javascript theme={null} import { Radar } from 'capacitor-radar'; ``` ### Identify user To identify the user when logged in, call: ```javascript theme={null} Radar.setUserId(userId); ``` where `userId` is a stable unique ID for the user. To set an optional dictionary of custom metadata for the user, call: ```javascript theme={null} Radar.setMetadata(metadata); ``` where `metadata` is a JSON object with up to 16 keys and values of type string, boolean, or number. Finally, to set an optional description for the user, displayed in the dashboard, call: ```javascript theme={null} Radar.setDescription(description); ``` where `description` is a string. You only need to call these functions once, as these settings will be persisted across app sessions. Learn about platform-specific implementations of these functions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Request permissions Before tracking the user's location, the user must have granted location permissions for the app. To determine the whether user has granted location permissions for the app, call: ```javascript theme={null} Radar.getLocationPermissionsStatus().then((result) => { // do something with result.status }); ``` `result.status` will be a string, one of: * **`GRANTED_BACKGROUND`** * **`GRANTED_FOREGROUND`** * **`NOT_DETERMINED`** * **`DENIED`** To request location permissions for the app, call: ```javascript theme={null} Radar.requestLocationPermissions({ background: true }); ``` where `background` is a boolean indicating whether to request background location permissions or foreground location permissions. Learn about platform-specific permissions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Foreground tracking Once you have initialized the SDK and the user has granted permissions, you can track the user's location. To track the user's location in the foreground, call: ```javascript theme={null} Radar.trackOnce().then((result) => { // do something with result.location, result.events, result.user.geofences }).catch((err) => { // optionally, do something with err }); ``` `err` will be a string, one of: * **`ERROR_PUBLISHABLE_KEY`**: SDK not initialized * **`ERROR_PERMISSIONS`**: location permissions not granted * **`ERROR_LOCATION`**: location services error or timeout (10 seconds) * **`ERROR_NETWORK`**: network error or timeout (10 seconds) * **`ERROR_BAD_REQUEST`**: bad request (missing or invalid params) * **`ERROR_UNAUTHORIZED`**: unauthorized (invalid API key) * **`ERROR_PAYMENT_REQUIRED`**: payment required (organization disabled or usage exceeded) * **`ERROR_FORBIDDEN`**: forbidden (insufficient permissions or no beta access) * **`ERROR_NOT_FOUND`**: not found * **`ERROR_RATE_LIMIT`**: too many requests ([rate limit](/api#track) exceeded) * **`ERROR_SERVER`**: internal server error * **`ERROR_UNKNOWN`**: unknown error Learn about platform-specific implementations of this function in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Background tracking On iOS and Android, once you have initialized the SDK and the user has granted permissions, you can start tracking the user's location in the background. For background tracking, the SDK supports custom tracking options as well as three presets: * **`EFFICIENT`**: A low frequency of location updates and lowest battery usage. On Android, avoids Android vitals bad behavior thresholds. * **`RESPONSIVE`**: A medium frequency of location updates and low battery usage. Suitable for most consumer use cases. * **`CONTINUOUS`**: A high frequency of location updates and higher battery usage. Suitable for on-demand use cases (e.g., delivery tracking) and some consumer use cases (e.g., order ahead, "mall mode"). Learn about platform-specific implementations of these presets in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). To start tracking the user's location in the background, call one of: ```javascript theme={null} Radar.startTrackingEfficient(); Radar.startTrackingResponsive(); Radar.startTrackingContinuous(); ``` You only need to call these methods once, as these settings will be persisted across app sessions. Though we recommend using presets for most use cases, you can customize the tracking options. See the [tracking options reference](/sdk/tracking). ```javascript theme={null} // optionally adjust foreground service options for android Radar.setForegroundServiceOptions({ options: { text: "Location tracking started", title: "Location updates", updatesOnly: false, importance: 2, activity: 'com.yourapp.MainActivity' } }); Radar.startTrackingCustom({ options: { desiredStoppedUpdateInterval: 180, fastestStoppedUpdateInterval: 15, desiredMovingUpdateInterval: 60, fastestMovingUpdateInterval: 15, desiredSyncInterval: 10, desiredAccuracy: 'high', stopDuration: 140, stopDistance: 70, sync: 'all', replay: 'none', useStoppedGeofence: true, showBlueBar: true, foregroundServiceEnabled: true } }); ``` To determine whether tracking has been started, call: ```javascript theme={null} Radar.isTracking(); ``` To stop tracking the user's location in the background (e.g., when the user logs out), call: ```javascript theme={null} Radar.stopTracking(); ``` Learn about platform-specific implementations of these functions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). To listen for events, location updates, and errors, you can add event listeners: ```javascript theme={null} Radar.addListener('clientLocation', (result) => { // do something with result.location, result.stopped, result.source }); Radar.addListener('location', (result) => { // do something with result.location, result.user }); Radar.addListener('events', (result) => { // do something with result.events, result.user }); Radar.addListener('error', (result) => { // do something with result.err }); Radar.addListener('log', (result) => { // do something with result.message }); ``` > [!WARNING] > > Listeners should be set only once and before tracking begins. Add event listeners outside of your view lifecycle if you want them to work when the app is in the background. Capacitor event listeners will only fire while the Capacitor WebView and JavaScript engine are alive. When the Android activity is killed (e.g., swiped away), these services will shut down. To process locations in the background, implement the native event emitters (`RadarDelegate` on [iOS](/sdk/ios#listening-for-events-with-a-delegate), `RadarReceiver` on [Android](/sdk/android#listening-for-events-with-a-receiver)) or use Radar's server-side [integrations](/integrations). ### Mock tracking On iOS and Android, you can simulate a sequence of location updates for testing. For example, to simulate a sequence of 10 location updates every 3 seconds by car from an `origin` to a `destination`, we can call: ```javascript theme={null} Radar.mockTracking({ origin: { latitude: 40.714708, longitude: -74.035807 }, destination: { latitude: 40.717410, longitude: -74.053334 }, mode: 'car', steps: 10, interval: 3 }); ``` ### Trip tracking To start a trip to a destination, call: ```javascript theme={null} Radar.startTrip({ options: { tripOptions: { externalId: '299', destinationGeofenceTag: 'store', destinationGeofenceExternalId: '123', mode: 'car' as RadarRouteMode }, trackingOptions: { desiredStoppedUpdateInterval: 30, fastestStoppedUpdateInterval: 30, desiredMovingUpdateInterval: 30, fastestMovingUpdateInterval: 30, desiredSyncInterval: 20, desiredAccuracy: 'high' as RadarTrackingOptionsDesiredAccuracy, stopDuration: 0, stopDistance: 0, replay: "none", sync: "all", showBlueBar: true, syncGeofences: false, syncGeofencesLimit: 0, beacons: false, foregroundServiceEnabled: true } } }).then((result) => { // do something with result.status }); ``` Later, complete the trip by calling: ```javascript theme={null} Radar.completeTrip().then((result) => { // do something with result.status }); ``` Or cancel the trip by calling: ```javascript theme={null} Radar.cancelTrip().then((result) => { // do something with result.status }); ``` If tracking was disabled before the trip started, it will stop after the trip ends. Otherwise, it will revert to the tracking options in use before the trip started. Learn more about [trip tracking](/geofencing/trips). ### Manual tracking You can manually update the user's location by calling: ```javascript theme={null} Radar.trackOnce({ latitude: 39.2904, longitude: -76.6122, accuracy: 65 }, (result) => { // do something with result.status, result.location, result.events, result.user }); ``` Learn about platform-specific implementation of this function in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Other APIs The Capacitor plugin also exposes APIs for geocoding, search, and distance. #### Geocoding With the [forward geocoding API](/api#forward-geocode), geocode an address, converting address to coordinates: ```javascript theme={null} Radar.geocode({ query: '20 jay st brooklyn ny' }, (result) => { // do something with result.status, result.addresses }); ``` With the [reverse geocoding API](/api#reverse-geocode), reverse geocode a location, converting coordinates to address: ```javascript theme={null} Radar.reverseGeocode({ latitude: 40.783826, longitude: -73.975363 }, (result) => { // do something with result.status, result.addresses }); ``` With the [IP geocoding API](/api#ip-geocode), geocode the device's current IP address, converting IP address to city, state, and country: ```javascript theme={null} Radar.ipGeocode((result) => { // do something with result.status, result.address }); ``` #### Search With the [autocomplete API](/api#autocomplete), autocomplete partial addresses and place names, sorted by relevance: ```javascript theme={null} Radar.autocomplete({ query: 'brooklyn roasting', near: { latitude: 40.783826, longitude: -73.975363 }, limit: 10 }, (result) => { // do something with result.status, result.addresses }); ``` With the [geofence search API](/api#search-geofences), search for geofences near a location, sorted by distance: ```javascript theme={null} Radar.searchGeofences({ radius: 1000, tags: ['venue'], limit: 10 }, (result) => { // do something with result.status, result.geofences }); ``` With the [places search API](/api#search-places), search for places near a location, sorted by distance: ```javascript theme={null} Radar.searchPlaces({ near: { latitude: 40.783826, longitude: -73.975363 }, radius: 1000, chains: ['starbucks'], limit: 10 }, (result) => { // do something with result.status, result.places }); ``` #### Distance With the [distance API](/api#distance), calculate the travel distance and duration from an origin to a destination: ```javascript theme={null} Radar.getDistance({ origin: { latitude: 40.78382, longitude: -73.97536 }, destination: { latitude: 40.70390, longitude: -73.98670 }, modes: [ 'foot', 'car' ], units: 'imperial' }, (result) => { // do something with result.status, result.routes }); ``` ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # Cordova plugin Source: https://docs.radar.com/sdk/cordova Install and integrate the Radar Cordova plugin to add location tracking, geofencing, and trip tracking to your Cordova app. This is the documentation for the Cordova plugin. Before integrating, read the [native SDK documentation](https://docs.radar.com/sdk) to familiarize yourself with the platform. See the source on GitHub [here](https://github.com/radarlabs/cordova-plugin-radar). Or, see the `@radarlabs/cordova-plugin-radar` package on npm [here](https://www.npmjs.com/package/@radarlabs/cordova-plugin-radar). ## Install Install the Cordova plugin: ```javascript theme={null} cordova plugin add @radarlabs/cordova-plugin-radar ``` Before writing any JavaScript, you must integrate the Radar SDK with your iOS and Android apps as described in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). On iOS, you must add location usage descriptions and background modes to your `Info.plist`. Initialize the SDK in `application:didFinishLaunchingWithOptions:` in `AppDelegate.m`, passing in your Radar publishable API key: ```c theme={null} #import @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [Radar initializeWithPublishableKey:publishableKey]; // ... } ``` On Android, you must add the Google Play Services library to your project, then add the SDK to your project, preferably using Gradle. Finally, initialize the SDK in `onCreate()` in `MainActivity.java`, passing in your Radar publishable API key: ```kotlin theme={null} import io.radar.sdk.Radar; public class MainActivity extends CordovaActivity { @Override public void onCreate() { super.onCreate(); Radar.initialize(this, publishableKey); // ... } } ``` ## Integrate ### Initialize When your app starts, initialize the SDK with your publishable key. Use your `Test Publishable` key for testing and non-production environments. Use your `Live Publishable` key for production environments. > [!WARNING] > > 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. ```swift theme={null} cordova.plugins.radar.initialize(publishableKey); ``` ### Identify user To identify the user when logged in, call: ```swift theme={null} cordova.plugins.radar.setUserId(userId); ``` where `userId` is a stable unique ID for the user. To set an optional dictionary of custom metadata for the user, call: ```swift theme={null} cordova.plugins.radar.setMetadata(metadata); ``` where `metadata` is a JSON object with up to 16 keys and values of type string, boolean, or number. Finally, to set an optional description for the user, displayed in the dashboard, call: ```swift theme={null} cordova.plugins.radar.setDescription(description); ``` where `description` is a string. You only need to call these functions once, as these settings will be persisted across app sessions. Learn about platform-specific implementations of these functions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Request permissions Before tracking the user's location, the user must have granted location permissions for the app. To determine the whether user has granted location permissions for the app, call: ```javascript theme={null} cordova.plugins.radar.getPermissionsStatus((status) => { // do something with status }); ``` `status` will be a string, one of: * **`GRANTED_BACKGROUND`** * **`GRANTED_FOREGROUND`** * **`DENIED`** * **`UNKNOWN`** To request location permissions for the app, call: ```javascript theme={null} cordova.plugins.radar.requestPermissions(background); ``` where `background` is a boolean indicating whether to request background location permissions or foreground location permissions. Learn about platform-specific permissions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Foreground tracking Once you have initialized the SDK and the user has granted permissions, you can track the user's location. To track the user's location in the foreground, call: ```javascript theme={null} cordova.plugins.radar.trackOnce((result) => { // do something with result.status, result.location, result.events, result.user}); ``` `status` will be a string, one of: * **`SUCCESS`**: success * **`ERROR_PUBLISHABLE_KEY`**: SDK not initialized * **`ERROR_PERMISSIONS`**: location permissions not granted * **`ERROR_LOCATION`**: location services error or timeout (10 seconds) * **`ERROR_NETWORK`**: network error or timeout (10 seconds) * **`ERROR_BAD_REQUEST`**: bad request (missing or invalid params) * **`ERROR_UNAUTHORIZED`**: unauthorized (invalid API key) * **`ERROR_PAYMENT_REQUIRED`**: payment required (organization disabled or usage exceeded) * **`ERROR_FORBIDDEN`**: forbidden (insufficient permissions or no beta access) * **`ERROR_NOT_FOUND`**: not found * **`ERROR_RATE_LIMIT`**: too many requests ([rate limit](/api#track) exceeded) * **`ERROR_SERVER`**: internal server error * **`ERROR_UNKNOWN`**: unknown error Learn about platform-specific implementations of this function in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### 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. For background tracking, the SDK supports custom tracking options as well as three presets: * **`EFFICIENT`**: A low frequency of location updates and lowest battery usage. On Android, avoids Android vitals bad behavior thresholds. * **`RESPONSIVE`**: A medium frequency of location updates and low battery usage. Suitable for most consumer use cases. * **`CONTINUOUS`**: A high frequency of location updates and higher battery usage. Suitable for on-demand use cases (e.g., delivery tracking) and some consumer use cases (e.g., order ahead, "mall mode"). Learn about platform-specific implementations of these presets in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). To start tracking the user's location in the background, call one of: ```javascript theme={null} cordova.plugins.radar.startTrackingEfficient(); cordova.plugins.radar.startTrackingResponsive(); cordova.plugins.radar.startTrackingContinuous(); ``` You only need to call these methods once, as these settings will be persisted across app sessions. Though we recommend using presets for most use cases, you can customize the tracking options. See the [tracking options reference](/sdk/tracking). ```javascript theme={null} // optionally adjust foreground service options for android cordova.plugins.radar.setForegroundServiceOptions({ options: { text: "Location tracking started", title: "Location updates", updatesOnly: false, importance: 2, activity: 'com.yourapp.MainActivity' } }); cordova.plugins.radar.startTrackingCustom({ desiredStoppedUpdateInterval: 180, desiredMovingUpdateInterval: 60, desiredSyncInterval: 50, desiredAccuracy: 'high', stopDuration: 140, stopDistance: 70, sync: 'all', replay: 'none', showBlueBar: true, foregroundServiceEnabled: true }); ``` To determine whether tracking has been started, call: ```javascript theme={null} cordova.plugins.radar.isTracking(); ``` To stop tracking the user's location in the background (e.g., when the user logs out), call: ```javascript theme={null} cordova.plugins.radar.stopTracking(); ``` Learn about platform-specific implementations of these functions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). To listen for events, location updates, and errors, you can add event listeners: ```javascript theme={null} cordova.plugins.radar.onClientLocation((location, stopped, source) => { // do something with location, stopped, source }); cordova.plugins.radar.onLocation((location, user) => { // do something with location, user }); cordova.plugins.radar.onEvents((events, user) => { // do something with events, user }); cordova.plugins.radar.onError((err) => { // do something with err }); ``` > [!WARNING] > > Listeners should be set only once and before tracking begins. Add event listeners outside of your view lifecycle if you want them to work when the app is in the background. You can also remove event listeners: ```javascript theme={null} cordova.plugins.radar.offClientLocation(); cordova.plugins.radar.offLocation(); cordova.plugins.radar.offEvents(); cordova.plugins.radar.offError(); ``` ### Trip tracking On iOS and Android, to start a trip to a destination, call: ```javascript theme={null} cordova.plugins.radar.startTrip({ externalId: '299', destinationGeofenceTag: 'store', destinationGeofenceExternalId: '123', mode: 'car' }).then((result) => { // do something with result.status }); cordova.plugins.radar.startTrackingContinuous(); ``` Update information about the trip. Status can be set to 'unknown' to leave the status unchanged as it will update via location tracking. ```javascript theme={null} cordova.plugins.radar.updateTrip({ status:'arrived', options: { externalId: '299', metadata: { parkingSpot: '5' } } }).then((result) => { // do something with result.status }); ``` Later, to complete the trip and stop tracking, call: ```javascript theme={null} cordova.plugins.radar.completeTrip().then((result) => { // do something with result.status }); cordova.plugins.radar.stopTracking(); ``` Or, to cancel the trip and stop tracking, call: ```javascript theme={null} cordova.plugins.radar.cancelTrip().then((result) => { // do something with result.status }); cordova.plugins.radar.stopTracking(); ``` Learn more about [trip tracking](/geofencing/trips). ### Manual tracking You can manually update the user's location by calling: ```javascript theme={null} cordova.plugins.radar.trackOnce({ latitude: 39.2904, longitude: -76.6122, accuracy: 65}, (result) => { // do something with result.status, result.location, result.events, result.user}); ``` Learn about platform-specific implementation of this function in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Other APIs The Cordova plugin also exposes APIs for geocoding, search, and distance. #### Geocoding With the [forward geocoding API](/api#forward-geocode), geocode an address, converting address to coordinates: ```javascript theme={null} cordova.plugins.radar.geocode('20 jay st brooklyn ny', (result) => { // do something with result.status, result.addresses }); ``` With the [reverse geocoding API](/api#reverse-geocode), reverse geocode a location, converting coordinates to address: ```javascript theme={null} cordova.plugins.radar.reverseGeocode({ latitude: 40.783826, longitude: -73.975363 }, (result) => { // do something with result.status, result.addresses }); ``` With the [IP geocoding API](/api#ip-geocode), geocode the device's current IP address, converting IP address to city, state, and country: ```javascript theme={null} cordova.plugins.radar.ipGeocode((result) => { // do something with result.status, result.address }); ``` #### Search With the [autocomplete API](/api#autocomplete), autocomplete partial addresses and place names, sorted by relevance: ``` cordova.plugins.radar.autocomplete({ query: 'brooklyn roasting', near: { latitude: 40.783826, longitude: -73.975363 }, limit: 10 }, (result) => { // do something with result.status, result.addresses }); ``` With the [geofence search API](/api#search-geofences), search for geofences near a location, sorted by distance: ``` cordova.plugins.radar.searchGeofences({ radius: 1000, tags: ['venue'], limit: 10 }, (result) => { // do something with result.status, result.geofences }); ``` With the [places search API](/api#search-places), search for places near a location, sorted by distance: ``` cordova.plugins.radar.searchPlaces({ near: { latitude: 40.783826, longitude: -73.975363 }, radius: 1000, chains: ['starbucks'], limit: 10 }, (result) => { // do something with result.status, result.places }); ``` #### Distance With the [distance API](/api#distance), calculate the travel distance and duration from an origin to a destination: ``` cordova.plugins.radar.getDistance({ origin: { latitude: 40.78382, longitude: -73.97536 }, destination: { latitude: 40.70390, longitude: -73.98670 }, modes: [ 'foot', 'car' ], units: 'imperial' }, (result) => { // do something with result.status, result.routes }); ``` #### Matrix With the [matrix API](/api#matrix), calculate the travel distance and duration between multiple origins and destinations for up to 25 routes: ``` cordova.plugins.radar.getMatrix({ origins: [ { latitude: 40.78382, longitude: -73.97536 } ], destinations: [ [ { latitude: 40.70390, longitude: -73.98670 }, { latitude: 40.73237, longitude: -73.94884 } ] ], mode: 'car', units: 'imperial' }, (result) => { // do something with result.status, result.matrix }); ``` ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # Flutter package Source: https://docs.radar.com/sdk/flutter Install and integrate the Radar Flutter package to add location tracking, geofencing, and trip tracking to your Flutter app. This is the documentation for the Flutter package. Before integrating, read the [native SDK documentation](https://docs.radar.com/sdk) to familiarize yourself with the platform. See the source on GitHub [here](https://github.com/radarlabs/flutter-radar). Or, see the `flutter_radar` package on pub.dev [here](https://pub.dev/packages/flutter_radar). ## Install Add the package to your `pubspec.yaml` file: ```yaml theme={null} dependencies: flutter_radar: ^3.12.4 ``` Then, update dependencies: ```bash theme={null} flutter pub get ``` ### iOS Change to the `ios/` directory. In the `Podfile`, add `platform :ios, '10.0'` or higher to your target. On iOS, you must add location usage descriptions and background modes to your `Info.plist`. Initialize the SDK in `application:didFinishLaunchingWithOptions:` in `AppDelegate.m` or `AppDelegate.swift`, passing in your Radar publishable API key. ```swift Swift theme={null} import UIKit import Flutter import RadarSDK @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Radar.initialize(publishableKey: "prj_test_pk_...") GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } ``` ```objc Objective-C theme={null} #import "AppDelegate.h" #import "GeneratedPluginRegistrant.h" #import @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [GeneratedPluginRegistrant registerWithRegistry:self]; [Radar initializeWithPublishableKey:"prj_test_pk_..."]; return [super application:application didFinishLaunchingWithOptions:launchOptions]; } @end ``` ### Android On Android, add the Radar Android SDK to the `dependencies` section of your Android app's `build.gradle` file. Ensure the Android SDK version matches the version of your Radar Flutter package. ```gradle theme={null} dependencies { implementation 'io.radar:sdk:3.18.+' } ``` > [!NOTE] > > When upgrading the SDK, ensure the Android SDK version is updated to match the plugin's pinned version. For details on the latest SDK releases, see the [releases page](https://github.com/radarlabs/flutter-radar/releases) on GitHub. Initialize the SDK in `onCreate()` in `MainApplication.java`, passing in your Radar publishable API key. If your Flutter Android app is in Kotlin, add a `Application.kt` file and reference this as the application name in your Android manifest. ```java Java theme={null} import io.flutter.app.FlutterApplication; import io.flutter.view.FlutterMain; import io.radar.sdk.Radar; public class MainApplication extends FlutterApplication { @Override public void onCreate() { super.onCreate(); Radar.initialize(this, "prj_test_pk_..."); FlutterMain.startInitialization(this); } } ``` ```kotlin Kotlin theme={null} import io.flutter.app.FlutterApplication import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.PluginRegistry import io.flutter.plugins.GeneratedPluginRegistrant import io.radar.sdk.Radar class Application : FlutterApplication(), PluginRegistry.PluginRegistrantCallback { override fun onCreate() { super.onCreate() Radar.initialize(this, "prj_test_pk_...") } override fun registerWith(registry: PluginRegistry) { GeneratedPluginRegistrant.registerWith(FlutterEngine(this)) } } ``` For background tracking without a foreground service, and if targeting API level `29` or higher, Radar also requires the `ACCESS_BACKGROUND_LOCATION` permission. You must add the `ACCESS_BACKGROUND_LOCATION` permission to your manifest manually: ```xml theme={null} ``` ## Integrate ### Import module First, import the package: ```dart theme={null} import 'package:flutter_radar/flutter_radar.dart'; ``` ### Initialize When your app starts, initialize the SDK with your publishable key. Use your `Test Publishable` key for testing and non-production environments. Use your `Live Publishable` key for production environments. > [!WARNING] > > 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. ```dart theme={null} Radar.initialize(publishableKey); ``` ### Identify user To identify the user when logged in, call: ```dart theme={null} Radar.setUserId(userId); ``` where `userId` is a stable unique ID for the user. To set an optional dictionary of custom metadata for the user, call: ```dart theme={null} Radar.setMetadata(metadata); ``` where `metadata` is a map with up to 16 keys and values of type string, boolean, or number. Finally, to set an optional description for the user, displayed in the dashboard, call: ```dart theme={null} Radar.setDescription(description); ``` where `description` is a string. You only need to call these functions once, as these settings will be persisted across app sessions. Learn about platform-specific implementations of these functions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Request permissions Before tracking the user's location, the user must have granted location permissions for the app. To determine the whether user has granted location permissions for the app, call: ```dart theme={null} String status = await Radar.getPermissionsStatus(); ``` `status` will be a string, one of: * **`GRANTED_FOREGROUND`** * **`GRANTED_BACKGROUND`** * **`DENIED`** * **`NOT_DETERMINED`** To request location permissions for the app, call: ```dart theme={null} String status = await Radar.requestPermissions(background); ``` where `background` is a boolean indicating whether to request background location permissions or foreground location permissions. Learn about platform-specific permissions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Foreground tracking Once you have initialized the SDK and the user has granted permissions, you can track the user's location. To track the user's location in the foreground, call: ```dart theme={null} var res = await Radar.trackOnce(); // do something with res['status'], res['location'], res['events'], res['user'] ``` Learn about platform-specific implementations of this function in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Background tracking On iOS and Android, once you have initialized the SDK and the user has granted permissions, you can start tracking the user's location in the background. For background tracking, the SDK supports custom tracking options as well as three presets: * **`EFFICIENT`**: A low frequency of location updates and lowest battery usage. On Android, avoids Android vitals bad behavior thresholds. * **`RESPONSIVE`**: A medium frequency of location updates and low battery usage. Suitable for most consumer use cases. * **`CONTINUOUS`**: A high frequency of location updates and higher battery usage. Suitable for on-demand use cases (e.g., delivery tracking) and some consumer use cases (e.g., order ahead, "mall mode"). Learn about platform-specific implementations of these presets in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). To start tracking the user's location in the background, call one of: ```dart theme={null} Radar.startTracking('efficient'); Radar.startTracking('responsive'); Radar.startTracking('continuous'); ``` You only need to call these methods once, as these settings will be persisted across app sessions. Though we recommend using presets for most use cases, you can customize the tracking options. See the [tracking options reference](/sdk/tracking). ```dart theme={null} // optionally adjust foreground service options for Android Radar.setForegroundServiceOptions({ 'text': "Location tracking started", 'title': "Location updates", 'importance': 2, 'updatesOnly': false, 'activity': 'com.yourapp.MainActivity' }); Radar.startTrackingCustom({ desiredStoppedUpdateInterval: 180, desiredMovingUpdateInterval: 60, desiredSyncInterval: 50, desiredAccuracy: 'high', stopDuration: 140, stopDistance: 70, sync: 'all', replay: 'none', showBlueBar: true, foregroundServiceEnabled: true }); ``` To determine whether tracking has been started, call: ```dart theme={null} Radar.isTracking(); ``` To stop tracking the user's location in the background (e.g., when the user logs out), call: ```dart theme={null} Radar.stopTracking(); ``` Learn about platform-specific implementations of these functions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). To listen for events, location updates, and errors, you can add event listeners: ```dart theme={null} @pragma('vm:entry-point') static void onClientLocation(Map result) { // do something with result.location } @pragma('vm:entry-point') static void onLocation(Map result) { // do something with result.location, result.user } @pragma('vm:entry-point') static void onEvents(Map result) { // do something with result.events, result.user } @pragma('vm:entry-point') static void onError(Map err) { // do something with err } Radar.onClientLocation(onClientLocation); Radar.onLocation(onLocation); Radar.onEvents(onEvents); Radar.onError(onError); ``` > [!WARNING] > > Listeners should be set only once and before tracking begins. Add event listeners outside of your view lifecycle if you want them to work when the app is in the background. ### Mock tracking On iOS and Android, you can simulate a sequence of location updates for testing. For example, to simulate a sequence of 10 location updates every 3 seconds by car from an `origin` to a `destination`, we can call: ```dart theme={null} Radar.mockTracking( origin: {'latitude': 40.714708, 'longitude': -74.035807}, destination: {'latitude': 40.717410, 'longitude': -74.053334}, mode: 'car', steps: 10, interval: 3 ); ``` ### Trip tracking On iOS and Android, to start a trip to a destination, call: ```dart theme={null} Radar.startTrip( tripOptions: { "externalId": '299', "destinationGeofenceTag": 'store', "destinationGeofenceExternalId": '123', "mode": 'car' }, trackingOptions: { "desiredStoppedUpdateInterval": 30, "fastestStoppedUpdateInterval": 30, "desiredMovingUpdateInterval": 30, "fastestMovingUpdateInterval": 30, "desiredSyncInterval": 20, "desiredAccuracy": "high", "sync": "all", "showBlueBar": true, "foregroundServiceEnabled": true } ); ``` Later, to complete the trip, call: ```dart theme={null} Radar.completeTrip(); ``` Or, to cancel the trip, call: ```dart theme={null} Radar.cancelTrip(); ``` If tracking was disabled before the trip started, it will stop after the trip ends. Otherwise, it will revert to the tracking options in use before the trip started. Learn more about [trip tracking](/geofencing/trips). ### Manual tracking You can manually update the user's location by calling: ```dart theme={null} var res = await Radar.trackOnce({ 'latitude': 39.2904, 'longitude': -76.6122, 'accuracy': 65 }); // do something with res['status'], res['location'], res['events'], res['user'] ``` Learn about platform-specific implementation of this function in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Location metadata The SDK can also pass along information like motion activity detection, speed and heading via the location metadata field. Learn about platform-specific implementation of this function in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Other APIs The Flutter package also exposes APIs for geocoding, search, and distance. #### Geocoding With the [forward geocoding API](/api#forward-geocode), geocode an address, converting address to coordinates: ```dart theme={null} var res = await Radar.geocode('20 jay st brooklyn ny'); // do something with res['status'], res['addresses'] ``` With the [reverse geocoding API](/api#reverse-geocode), reverse geocode a location, converting coordinates to address: ```dart theme={null} var res = await Radar.reverseGeocode({ 'latitude': 40.783826, 'longitude': -73.975363, 'accuracy': 65 }); // do something with res['status'], res['addresses'] ``` With the [IP geocoding API](/api#ip-geocode), geocode the device's current IP address, converting IP address to city, state, and country: ```dart theme={null} var res = await Radar.ipGeocode(); // do something with res['status'], res['address'] ``` #### Search With the [autocomplete API](/api#autocomplete), autocomplete partial addresses and place names, sorted by relevance: ```dart theme={null} var res = await Radar.autocomplete( query: 'brooklyn roasting', near: {'latitude': 40.783826, 'longitude': -73.975363}, limit: 10 ); // do something with res['status'], res['addresses'] ``` With the [geofence search API](/api#search-geofences), search for geofences near a location, sorted by distance: ```dart theme={null} var res = await Radar.searchGeofences( near: {'latitude': 40.783826, 'longitude': -73.975363}, radius: 1000, tags: ['venue'], limit: 10 ); // do something with res['status'], res['geofences'] ``` With the [places search API](/api#search-places), search for places near a location, sorted by distance: ```dart theme={null} var res = await Radar.searchPlaces( near: {'latitude': 40.783826, 'longitude': -73.975363}, radius: 1000, chains: ['starbucks'], limit: 10 ); // do something with res['status'], res['places'] ``` #### Distance With the [distance API](/api#distance), calculate the travel distance and duration from an origin to a destination: ```dart theme={null} var res = await Radar.getDistance( origin: {'latitude': 40.78382, 'longitude': -73.97536}, destination: {'latitude': 40.70390, 'longitude': -73.98670}, modes: ['foot', 'car'], units: 'imperial' ); // do something with res['status'], res['routes'] ``` ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # iOS SDK Source: https://docs.radar.com/sdk/ios Install and integrate the Radar iOS SDK to add geofencing, location tracking, trip tracking, and geocoding to your iOS app. The Radar SDK abstracts away cross-platform differences between location services, allowing you to add geofencing, location tracking, trip tracking, geocoding, and search to your apps with just a few lines of code. Learn how to integrate the iOS SDK below. You can also see the [source](https://github.com/radarlabs/radar-sdk-ios) and a [detailed SDK reference](https://radarlabs.github.io/radar-sdk-ios/Classes/Radar.html) on GitHub. ## Install SDK The best way to install the SDK is via [Swift Package Manager](https://www.swift.org/documentation/package-manager/). > [!NOTE] > > For details on the latest SDK releases, see the [**releases page**](https://github.com/radarlabs/radar-sdk-ios/releases) on GitHub. You can also star ⭐️ and watch 👀 the repo. The SDK is small and typically adds less than 500 KB to your compiled app. ### Swift Package Manager In Xcode, go to *File* > *Swift Packages* > *Add Package Dependency*. Enter `https://github.com/radarlabs/radar-sdk-ios-spm.git` for the *Package Repository URL*. This URL points to our [SPM optimized repo](https://github.com/radarlabs/radar-sdk-ios-spm), which has a smaller binary size to facilitate faster build times. **Note:** we recommend pinning the minor version you're installing as we occasionally introduce breaking changes in new minor versions. You can pin the minor version using the range operator: ```text theme={null} .package(url: "https://github.com/radarlabs/radar-sdk-ios-spm.git", "3.45.0"..<"3.46.0") ``` > [!NOTE] > > Only select `RadarSDK` unless you are also intending to use the location metadata feature. Refer to [**this section**](#location-metadata) for more information. ### Carthage Install [Carthage](https://github.com/Carthage/Carthage) by adding the following to your `Cartfile`: ```text theme={null} github "radarlabs/radar-sdk-ios" ~> 3.45.0 ``` Then, run `carthage update` and 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. Download [the current release](https://github.com/radarlabs/radar-sdk-ios/releases), unzip the package, and drag `RadarSDK.xcframework` into your Xcode project. It will automatically appear in the *Frameworks, Libraries, and Embedded Content* section of your target settings. Switch *Do Not Embed* to *Embed & Sign*. ## Dependencies The SDK depends on Apple's `CoreLocation` framework. In your target settings, go to *General* > *Frameworks, Libraries, and Embedded Content* and add `CoreLocation` if you haven't already. The SDK currently supports iOS 15 and higher. ## Initialize SDK When your app starts, initialize the SDK with your publishable API key, found on the [Settings page](https://dashboard.radar.com/settings). Use your `Test Publishable` key for testing and non-production environments. Use your `Live Publishable` key for production environments. > [!WARNING] > > 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. ```swift Swift theme={null} import UIKit import RadarSDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Radar.initialize(publishableKey: "prj_test_pk_...") return true } } ``` ```c Objective-C theme={null} #import "AppDelegate.h" @import RadarSDK; @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [Radar initializeWithPublishableKey:@"prj_test_pk_..."]; return YES; } @end ``` ### Network timeout To override the default network timeout, set `networkTimeoutInterval` (in seconds) on `RadarInitializeOptions`. The extended timeout used for longer-running requests is automatically set to 2.5x this value. Values are clamped to `[1, 300]` seconds. ```swift Swift theme={null} let radarInitializeOptions = RadarInitializeOptions() radarInitializeOptions.networkTimeoutInterval = 30 Radar.initialize(publishableKey: "prj_test_pk_...", options: radarInitializeOptions) ``` ```c Objective-C theme={null} RadarInitializeOptions *radarInitializeOptions = [[RadarInitializeOptions alloc] init]; radarInitializeOptions.networkTimeoutInterval = 30; [Radar initializeWithPublishableKey:@"prj_test_pk_..." options:radarInitializeOptions]; ``` ## Request permissions Radar respects [standard iOS location permissions](https://developer.apple.com/documentation/corelocation/requesting_authorization_for_location_services). For foreground tracking or trip tracking with continuous mode, the app's location authorization status must be `kCLAuthorizationStatusAuthorizedWhenInUse` or`kCLAuthorizationStatusAuthorizedAlways`. For background tracking or geofencing with responsive mode, the app's location authorization status must be `kCLAuthorizationStatusAuthorizedAlways`. > [!NOTE] > > If your app already requests the necessary location permissions, you can skip this step. Before requesting permissions, you must add location usage strings to your `Info.plist` file. For foreground permissions, you must add a value for `NSLocationWhenInUseUsageDescription` (*Privacy - Location When In Use Usage Description*). For background permissions, you must add a value for `NSLocationAlwaysAndWhenInUseUsageDescription` (*Privacy - Location Always and When In Use Usage Description*). These strings are displayed in permissions prompts. ![Request Permissions Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/sdk/request-permissions.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=8ab47ae4a0f22e329c9075cff7e3c32b) To request foreground permissions, call `requestWhenInUseAuthorization`on a `CLLocationManager` instance. To request background permissions in the app, make sure the user has granted foreground permissions first, then call `requestAlwaysAuthorization` on a `CLLocationManager` instance. To request foreground location permissions and then immediately request background location permissions: ```swift Swift theme={null} import UIKit import RadarSDK import CoreLocation @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate { let locationManager = CLLocationManager() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Radar.initialize(publishableKey: "prj_test_pk_...") self.locationManager.delegate = self self.requestLocationPermissions() return true } func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { self.requestLocationPermissions() } func requestLocationPermissions() { let status = self.locationManager.authorizationStatus if status == .notDetermined { self.locationManager.requestWhenInUseAuthorization() } else if status == .authorizedWhenInUse { self.locationManager.requestAlwaysAuthorization() } } } ``` ```c Objective-C theme={null} // AppDelegate.h #import #import @interface AppDelegate : UIResponder @end // AppDelegate.m #import "AppDelegate.h" @import RadarSDK; @interface AppDelegate () @property (strong, nonatomic) CLLocationManager *locationManager; @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [Radar initializeWithPublishableKey:@"prj_test_pk_..."]; self.locationManager = [CLLocationManager new]; self.locationManager.delegate = self; [self requestLocationPermissions]; return YES; } - (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager { [self requestPermissions]; } - (void)requestPermissions { CLAuthorizationStatus status = self.locationManager.authorizationStatus; if (status == kCLAuthorizationStatusNotDetermined) { [self.locationManager requestWhenInUseAuthorization]; } else if (status == kCLAuthorizationStatusAuthorizedAlways) { [self.locationManager requestAlwaysAuthorization]; } } @end ``` > [!NOTE] > > Build and run the app to make sure permissions prompts are displayed! > [!NOTE] > > Not seeing permissions prompts? First, make sure your location manager is in memory when you request permissions. Second, make sure you've added location usage strings to your `Info.plist` file. Finally, check your device settings to make sure you haven't already granted location permissions ### Background modes If you are planning to use `RadarTrackingOptions.presetContinuous` or `RadarTrackingOptions.presetResponsive`, or if you are planning to [range beacons by UUID only](/geofencing/beacons#ranging-by-uuid-only), you must enable the *Location updates* and *Background fetch* background modes. In your project settings, go to *Signing & Capabilities*, add *Background Modes*, and turn on *Location updates* and *Background fetch*. Note that this requires additional justification during App Store review. Learn more [below](#submit-to-app-store). ![Background Modes Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/sdk/background-modes.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=7a20ffae1206dfb6c64d1943a3724c75) ## Foreground tracking Once the user has granted foreground permissions, you can track the user's location in the foreground. To track the user's location once in the foreground, call: ```swift Swift theme={null} Radar.trackOnce { (status: RadarStatus, location: CLLocation?, events: [RadarEvent]?, user: RadarUser?) in // do something with location, events, user } ``` ```c Objective-C theme={null} [Radar trackOnceWithCompletionHandler:^(RadarStatus status, CLLocation *location, NSArray *events, RadarUser *user) { // do something with 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: * `.success`: success * `.errorPublishableKey`: SDK not initialized * `.errorPermissions`: location permissions not granted * `.errorLocation`: location services error or timeout (10 seconds) * `.errorNetwork`: network error or timeout (10 seconds) * `.errorBadRequest`: bad request (missing or invalid params) * `.errorUnauthorized`: unauthorized (invalid API key) * `.errorPaymentRequired`: payment required (organization disabled or usage exceeded) * `.errorForbidden`: forbidden (insufficient permissions) * `.errorNotFound`: not found * `.errorRateLimit`: too many requests ([rate limit](/api#track) exceeded) * `.errorServer`: internal server error * `.errorUnknown`: unknown error > [!WARNING] > > Build and run the app, then find your user on the [**Users page**](https://dashboard.radar.com/geofencing/users)! To trigger an event, you'll need to [**create a geofence**](https://dashboard.radar.com/geofencing/geofences) if you haven't already. Not seeing your user on the Users page? Check `status` in the `completionHandler` to see what went wrong. ## Background tracking for geofencing Once you have initialized the SDK and the user has authorized background permissions, you can start tracking the user's location in the background. The SDK supports custom tracking options as well as three presets. For geofencing, we recommend using `RadarTrackingOptions.presetResponsive`. This preset detects whether the device is stopped or moving. When moving, it tells the SDK to send location updates to the server every 2-3 minutes. When stopped, it tells the SDK to shut down to save battery. Once stopped, the device will need to move more than 100 meters to wake up and start moving again. Assuming the user has authorized background permissions, background tracking will work even if the app has been backgrounded or killed, as iOS location services will wake up the app to deliver events. > [!WARNING] > > Note that location updates may be delayed by if the device has connectivity issues, low battery, or wi-fi disabled. > [!NOTE] > > Though we recommend using presets for most use cases, you can modify the presets. See the [**tracking options reference**](/sdk/tracking). To start tracking for geofencing, call: ```swift Swift theme={null} Radar.startTracking(trackingOptions: RadarTrackingOptions.presetResponsive) ``` ```c Objective-C theme={null} [Radar startTrackingWithOptions:RadarTrackingOptions.presetResponsive]; ``` To determine whether tracking has been started, call: ```swift Swift theme={null} Radar.isTracking() ``` ```c Objective-C theme={null} [Radar isTracking]; ``` To stop tracking (e.g., when the user logs out), call: ```swift Swift theme={null} Radar.stopTracking() ``` ```c Objective-C theme={null} [Radar stopTracking]; ``` You only need to call these methods once, as these settings will be persisted across app sessions. > [!WARNING] > > To test, go for a walk or a drive! Not seeing location updates or events? Remember that, once stopped, the device will need to move more than 100 meters to wake up and start moving again. Also, check your device settings to make sure you've granted background location permissions. > [!NOTE] > > Don't forget! You can always find your user on the [**Users page**](https://dashboard.radar.com/geofencing/users) or events on the [**Events page**](https://dashboard.radar.com/geofencing/events). To trigger an event, you'll need to [**create a geofence**](https://dashboard.radar.com/geofencing/geofences) if you haven't already. ## Background tracking for trips For trips, we recommend using `RadarTrackingOptions.presetContinuous`. This preset tells the SDK to send location updates to the server every 30 seconds, regardless of whether the device is moving. > [!NOTE] > > By default, this preset shows the flashing blue status bar while tracking. If the flashing blue status bar is shown, only foreground permissions are required for tracking. Tracking for the duration of a trip is started or updated by including tracking options in the `startTrip` call: ```swift Swift theme={null} Radar.startTrip(options: tripOptions, trackingOptions: .presetContinuous) { (status: RadarStatus, trip: RadarTrip?, events: [RadarEvent]?) in if status == .success { // do something } else { // handle error } } ``` ```c Objective-C theme={null} [Radar startTripWithOptions:tripOptions trackingOptions:RadarTrackingOptions.presetContinuous completionHandler:^(RadarStatus status, RadarTrip * _Nullable trip, NSArray * _Nullable events) { if (status == RadarStatusSuccess) { // do something } else { // handle error } }]; ``` > [!NOTE] > > Not seeing the flashing blue status bar while tracking? Make sure you've added the Location updates background mode in your project settings. If tracking was disabled before the trip started, it will stop after the trip ends. Otherwise, it will revert to the tracking options in use before the trip started: ```swift Swift theme={null} // complete trip Radar.completeTrip() // cancel trip Radar.cancelTrip() ``` ```c Objective-C theme={null} // complete trip [Radar completeTrip]; // cancel trip [Radar cancelTrip]; ``` Learn more about starting, completing, and canceling trips in the [trip tracking documentation](/geofencing/trips). > [!NOTE] > > Don't forget! You can always find your user on the [**Users page**](https://dashboard.radar.com/geofencing/users) or events on the [**Events page**](https://dashboard.radar.com/geofencing/events). To trigger an event, you'll need to [**create a geofence**](https://dashboard.radar.com/geofencing/geofences) or [**start a trip**](https://docs.radar.com/trip-tracking) if you haven't already. Also, check your device settings to make sure you've granted location permissions. ## Mock tracking for testing Can't go for a walk or a drive? You can simulate a sequence of location updates. For example, to simulate a sequence of 10 location updates every 3 seconds by car from an origin to a destination, call: ```swift Swift theme={null} Radar.mockTracking( origin: CLLocation(latitude: 40.714708, longitude: -74.035807), destination: CLLocation(latitude: 40.717410, longitude: -74.053334), mode: .car, steps: 10, interval: 3) { (status: RadarStatus, location: CLLocation?, events: [RadarEvent]?, user: RadarUser?) in // do something with location, events, user } ``` ```c Objective-C theme={null} [Radar mockTrackingWithOrigin:origin destination:destination mode:RadarRouteModeCar steps:steps interval:1 completionHandler:^(RadarStatus status, CLLocation *location, NSArray *events, RadarUser *user) { }]; ``` > [!NOTE] > > Don't forget! You can always find your user on the [**Users page**](https://dashboard.radar.com/geofencing/users) or events on the [**Events page**](https://dashboard.radar.com/geofencing/events). To trigger an event, you'll need to [**create a geofence**](https://dashboard.radar.com/geofencing/geofences) if you haven't already. ## Location metadata The SDK can also pass along information like motion activity detection, speed and heading via the location metadata field. Turn on `useMotion` in your `sdkConfiguration` to enable this feature. To collect motionActivity, you must include a value for `Privacy - Motion Usage Description` in your `info.plist` and install the `RadarSDKMotion` companion module. Your app will request permission for Motion Activity data in the first track call. Add the `RadarSDKMotion` package product to your target via SPM. ## Listening for events with a delegate To listen for events, location updates, and errors client-side, set a `RadarDelegate`. 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 Swift theme={null} import UIKit import RadarSDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, RadarDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { Radar.initialize(publishableKey: "prj_test_pk_...") 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 didUpdateClientLocation(_ location: CLLocation, stopped: Bool, source: RadarLocationSource) { // do something with location, stopped, source } func didFail(status: RadarStatus) { // do something with status } func didLog(message: String) { // print message for debug logs } } ``` ```c Objective-C theme={null} #import "AppDelegate.h" @import RadarSDK; @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [Radar initializeWithPublishableKey:@"prj_test_pk_..."]; [Radar setDelegate:self]; return YES; } - (void)didReceiveEvents:(NSArray *)events user:(RadarUser *)user { // do something with events, user } - (void)didUpdateLocation:(CLLocation *)location user:(RadarUser *)user { // do something with location, user } - (void)didUpdateClientLocation:(CLLocation *)location stopped:(BOOL)stopped source:(RadarLocationSource)source { // do something with location, stopped, source } - (void)didFailWithStatus:(RadarStatus)status { // do something with status } - (void)didLogMessage:(NSString *_Nonnull)message { // print message for debug logs } @end ``` > [!WARNING] > > The `RadarDelegate` should be instantiated only once and set before tracking begins. > [!NOTE] > > To listen for events server-side instead, add a [**webhook**](https://docs.radar.com/integrations/webhooks) or enable an [**integration**](https://docs.radar.com/integrations). ## Manual tracking If you want to manage location services yourself, you can manually update the user's location instead by calling: ```swift Swift theme={null} Radar.trackOnce( location: location ) { (status: RadarStatus, location: CLLocation?, events: [RadarEvent]?, user: RadarUser?) in // do something with location, events, user } ``` ```c Objective-C theme={null} [Radar trackOnceWithLocation:location completionHandler:^(RadarStatus status, CLLocation *location, NSArray *events, RadarUser *user) { // do something with location, events, user }]; ``` where `location` is a `CLLocation` instance with a valid latitude, longitude, and horizontal accuracy. ## Identify user The SDK automatically collects `installId` (a GUID generated on fresh install) and `deviceId` ([IDFV](https://developer.apple.com/documentation/uikit/uidevice/1620059-identifierforvendor)). You can also assign a custom `userId`, also called *External ID* in the dashboard. To set a custom `userId`, call: ```swift Swift theme={null} Radar.setUserId(userId) ``` ```c Objective-C theme={null} [Radar setUserId:userId]; ``` where `userId` is a stable unique ID for the user. > [!WARNING] > > Do not send any PII, like names, email addresses, or publicly available IDs, for `userId`. See [**privacy best practices**](https://docs.radar.com/faqs#what-are-privacy-best-practices-for-radar) for more information. To set a dictionary of custom metadata for the user, call: ```swift Swift theme={null} Radar.setMetadata(metadata) ``` ```c Objective-C theme={null} [Radar setUserId:userId]; ``` where `metadata` is a dictionary with up to 16 keys and values of type string, boolean, or number. Finally, to set an optional description for the user, displayed in the dashboard, call: ```swift Swift theme={null} Radar.setDescription(description) ``` ```c Objective-C theme={null} [Radar setDescription:description]; ``` You only need to call these methods once, as these settings will be persisted across app sessions. Learn more about when Radar creates new user records [here](https://docs.radar.com/faqs#what-are-privacy-best-practices-for-radar). ## Debug logging By default, only critical errors are logged to the console. To enable debug logging, call: ```swift Swift theme={null} Radar.setLogLevel(RadarLogLevel.debug) ``` ```c Objective-C theme={null} [Radar setLogLevel:RadarLogLevelDebug]; ``` To log app lifecycle events, call the respective Radar methods in the `AppDelegate` lifecycle methods: ```swift Swift theme={null} import UIKit import RadarSDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, RadarDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { Radar.initialize(publishableKey: "prj_test_pk_...") Radar.setDelegate(self) return true } func applicationWillResignActive(_ application: UIApplication) { // existing code Radar.logResigningActive() } func applicationDidEnterBackground(_ application: UIApplication) { // existing code Radar.logBackgrounding() } func applicationWillTerminate(_ application: UIApplication) { // existing code Radar.logTermination() } } ``` ```c Objective-C theme={null} #import "AppDelegate.h" @import RadarSDK; @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [Radar initializeWithPublishableKey:@"prj_test_pk_..."]; [Radar setDelegate:self]; return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // existing code [Radar logResigningActive]; } - (void)applicationDidEnterBackground:(UIApplication *)application { // existing code [Radar logBackgrounding]; } - (void)applicationWillTerminate:(UIApplication *)application { // existing code [Radar logTermination]; } @end ``` > [!NOTE] > > Contact your customer success manager to enable logging app lifecycle events. ## 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 in your App Store review notes. If using `RadarTrackingOptions.presetResponsive`, add something like: *This app uses the Radar SDK ([https://radar.com](https://radar.com)) to (insert use case here). The Radar SDK requires the background location mode to support polygon geofences and nearby place detection, which cannot be accomplished with region monitoring or visit monitoring.* Or, if using `RadarTrackingOptions.presetContinuous`, add something like *This app uses the Radar SDK ([https://radar.com](https://radar.com)) to (insert use case here). The Radar SDK requires the location background mode for live trip tracking and live ETAs.* Learn more about this requirement in section 2.5.4 of the App Store Review Guidelines [here](https://developer.apple.com/app-store/review/guidelines/#software-requirements). ## Other APIs The iOS SDK also exposes APIs for beacons, anonymous context, geocoding, search, and distance. ### Beacons If the user has granted location permissions, you can range and monitor [beacons](/geofencing/beacons). To range beacons in the foreground, call: ```swift Swift theme={null} Radar.trackOnce(desiredAccuracy: .high, beacons: true) { (status: RadarStatus, location: CLLocation?, events: [RadarEvent]?, user: RadarUser?) in // do something with user.beacons } ``` ```c Objective-C theme={null} [Radar trackOnceWithDesiredAccuracy:RadarTrackingOptionsDesiredAccuracyHigh beacons:YES completionHandler:^(RadarStatus status, CLLocation *location, NSArray *events, RadarUser *user) { // do something with user.beacons }]; ``` To monitor beacons in the background, update your tracking options: ```swift Swift theme={null} let trackingOptions = RadarTrackingOptions.presetResponsive trackingOptions.beacons = true Radar.startTracking(trackingOptions: trackingOptions) ``` ```c Objective-C theme={null} RadarTrackingOptions *trackingOptions = RadarTrackingOptions.presetResponsive; trackingOptions.beacons = YES; [Radar startTrackingWithOptions:trackingOptions]; ``` If you call `Radar.trackVerified(beacons: true)`, you can call `Radar.startRangingBeacons()` to range beacons continuously in the foreground, so location checks don't wait for a new ranging window. Call `Radar.stopRangingBeacons()` when you no longer need beacons. Learn more about [ranging beacons with location checks](/geofencing/fraud#ranging-beacons). ```swift Swift theme={null} Radar.startRangingBeacons() Radar.stopRangingBeacons() ``` ```c Objective-C theme={null} [Radar startRangingBeacons]; [Radar stopRangingBeacons]; ``` ### Geocoding With the [forward geocoding API](/api#forward-geocode), geocode an address, converting address to coordinates: ```swift Swift theme={null} Radar.geocode( address: "20 jay st brooklyn ny" ) { (status: RadarStatus, addresses: [RadarAddress]?) in // do something with addresses } ``` ```c Objective-C theme={null} [Radar geocodeAddress:@"20 jay st brooklyn ny" completionHandler:^(RadarStatus status, NSArray *addresses) { // do something with addresses }]; ``` With the [reverse geocoding API](/api#reverse-geocode), reverse geocode a location, converting coordinates to address: ```swift Swift theme={null} Radar.reverseGeocode( location: location ) { (status: RadarStatus, addresses: [RadarAddress]?) in // do something with addresses } ``` ```c Objective-C theme={null} [Radar reverseGeocodeLocation:location completionHandler:^(RadarStatus status, NSArray *addresses) { // do something with addresses }]; ``` With the [IP geocoding API](/api#ip-geocode), geocode the device's current IP address, converting IP address to city, state, and country: ```swift Swift theme={null} Radar.ipGeocode { (status: RadarStatus, address: RadarAddress, proxy: Bool) in // do something with address, proxy } ``` ```c Objective-C theme={null} [Radar ipGeocodeWithCompletionHandler:^(RadarStatus status, RadarAddress *address, BOOL proxy) { // do something with address, proxy }]; ``` ### Search With the [autocomplete API](/api#autocomplete), autocomplete partial addresses and place names, sorted by relevance: ```swift Swift theme={null} Radar.autocomplete( query: "brooklyn roasting", near: location, limit: 10 ) { (status: RadarStatus, addresses: [RadarAddress]?) in // do something with addresses } ``` ```c Objective-C theme={null} [Radar autocompleteQuery:@"brooklyn roasting" near:location limit:10 completionHandler:^(RadarStatus status, NSArray *addresses) { // do something with addresses }]; ``` With the [geofence search API](/api#search-geofences), search for geofences near a location, sorted by distance: ```swift Swift theme={null} Radar.searchGeofences( near: location, radius: 1000, // meters tags: ["store"], metadata: nil, limit: 10 ) { (status: RadarStatus, location: CLLocation?, geofences: [RadarGeofence]?) in // do something with geofences } ``` ```c Objective-C theme={null} [Radar searchGeofencesNear:location radius:1000 // meters tags:@[@"store"] metadata:nil limit:100 completionHandler:^(RadarStatus status, CLLocation *location, NSArray *geofences) { // do something with geofences }]; ``` With the [places search API](/api#search-places), search for places near a location, sorted by distance: ```swift Swift theme={null} Radar.searchPlaces( near: location, radius: 1000, // meters chains: ["starbucks"], categories: nil, groups: nil, limit: 10 ) { (status: RadarStatus, location: CLLocation?, places: [RadarPlace]?) in // do something with places } ``` ```c Objective-C theme={null} [Radar searchGeofencesNear:location radius:1000 // meters chains:@[@"starbucks"] categories:nil groups:nil limit:100 completionHandler:^(RadarStatus status, CLLocation *location, NSArray *places) { // do something with places }]; ``` With the [address validation API](/api#validate-an-address) (currently in beta), validate a structured address in the US or Canada: ```swift Swift theme={null} Radar.validateAddress( address: address ) { (status: RadarStatus, address: RadarAddress?, result: ValidationResult) in // do something with validation result and address } ``` ```c Objective-C theme={null} [Radar validateAddress:address completionHandler:^(RadarStatus status, RadarAddress *address, ValidationResult result) { // do something with validation result and address }]; ``` ### Distance With the [distance API](/api#distance), calculate the travel distance and duration between an origin and a destination: ```swift Swift theme={null} Radar.getDistance( origin: origin, destination: destination, modes: [.foot, .car], units: .imperial ) { (status: RadarStatus, routes: RadarRoutes?) in // do something with routes } ``` ```c Objective-C theme={null} [Radar getDistanceFromOrigin:origin destination:destination modes:RadarRouteModeFoot | RadarRouteModeCar units:RadarRouteUnitsImperial completionHandler:^(RadarStatus status, RadarRoutes *routes) { // do something with routes }]; ``` ### Matrix With the [matrix API](/api#matrix), calculate the travel distance and duration between multiple origins and destinations for up to 25 routes: ```swift Swift theme={null} Radar.getMatrix( origins: origins, destinations: destinations, mode: .car, units: .imperial ) { (status: RadarStatus, matrix: RadarRouteMatrix?) in // do something with matrix.routeBetween(originIndex:destinationIndex:) } ``` ```c Objective-C theme={null} [Radar getMatrixFromOrigins:origin destinations:destinations mode:RadarRouteModeCar units:RadarRouteUnitsImperial completionHandler:^(RadarStatus status, RadarRouteMatrix *matrix) { // do something with [matrix routeBetweenOriginIndex:destinationIndex:] }]; ``` ### Conversions With the [conversions API](/api#log-a-conversion), log a conversion, such as a purchase or signup, to analyze alongside your app's location activity: ```swift Swift theme={null} Radar.logConversion( name: name, metadata: metadata, ) { (status: RadarStatus, event: RadarEvent?) in // do something with the conversion event } // conversion with revenue Radar.logConversion( name: name, revenue: revenue, metadata: metadata, ) { (status: RadarStatus, event: RadarEvent?) in // do something with the conversion event } ``` ```c Objective-C theme={null} [Radar logConversionWithName:name metadata:metadata completionHandler:^(RadarStatus status, RadarEvent *event) { // do something with the conversion event }]; // conversion with revenue [Radar logConversionWithName:name revenue:revenue metadata:metadata completionHandler:^(RadarStatus status, RadarEvent *event) { // do something with the conversion event }]; ``` Radar can associate `opened_app` events with a notification that was clicked on to open the app. To set this up automatically, set the relevant flag on the initialization options. ```swift Swift theme={null} import UIKit import RadarSDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let radarInitializeOptions = RadarInitializeOptions() radarInitializeOptions.autoLogNotificationConversions = true Radar.initialize(publishableKey: "prj_test_pk_...", options: radarInitializeOptions) return true } } ``` ```c Objective-C theme={null} #import "AppDelegate.h" @import RadarSDK; @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { RadarInitializeOptions *radarInitializeOptions = [[RadarInitializeOptions alloc] init]; radarInitializeOptions.autoLogNotificationConversions = YES; [Radar initializeWithPublishableKey:@"prj_test_pk_..." options:radarInitializeOptions]; return YES; } @end ``` Alternatively, perform the manual setup: ```swift Swift theme={null} func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async { Radar.logConversion(response: response) } ``` ```c Objective-C theme={null} - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { [Radar logConversionWithNotificationResponse:response]; completionHandler(); } ``` ### User tags With the [user tag API](/geofencing/campaigns#campaign-targeting), you can configure [campaigns](/geofencing/campaigns) to only target users with the corresponding tags: ```swift Swift theme={null} Radar.addTags(["tag1", "tag2"]) Radar.removeTags(["tag1", "tag2"]) Radar.setTags(["tag1", "tag2"]) Radar.getTags() ``` ```objc Objective-C theme={null} [Radar addTags:@[@"tag1", @"tag2"]]; [Radar removeTags:@[@"tag1", @"tag2"]]; [Radar setTags:@[@"tag1", @"tag2"]]; [Radar getTags]; ``` # MAUI SDK Source: https://docs.radar.com/sdk/maui Install and integrate the Radar MAUI and Xamarin package to add location tracking, geofencing, and trip tracking to your .NET app. This is the documentation for the MAUI package. Before integrating, read the [native SDK documentation](/sdk/sdk) to familiarize yourself with the platform. ## Install Install the package from [NuGet](https://www.nuget.org/packages/RadarIO.Xamarin/): ```bash theme={null} Install-Package RadarIO.Xamarin ``` > [!NOTE] > > RadarIO.Xamarin supports both Xamarin and MAUI bindings. If you have an iOS and an Android project, add the package to each project. ## Integrate ### Initialize First, initialize the SDK: ```csharp theme={null} using RadarIO; using static RadarIO.RadarSingleton; namespace MyProject { public class Example { void Example () { RadarSingleton.Initialize(new RadarSDKImpl()); Radar.Initialize(publishableKey); } } } ``` ### Identify user To identify the user when logged in, call: ```csharp theme={null} Radar.UserId = userId; ``` where `userId` is a stable unique ID for the user. To set an optional dictionary of custom metadata for the user, call: ```csharp theme={null} Radar.Metadata = metadata; ``` where `metadata` is a `JSONObject` with up to 16 keys and values of type string, boolean, or number. Finally, to set an optional description for the user, displayed in the dashboard, call: ```csharp theme={null} Radar.Description = description; ``` where `description` is a string. You only need to call these functions once, as these settings will be persisted across app sessions. Learn about platform-specific implementations of these functions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Request permissions Before tracking the user's location, the user must have granted location permissions for the app. See the [MAUI Permissions docs](https://learn.microsoft.com/en-us/dotnet/maui/platform-integration/appmodel/permissions) to learn how to check and request permissions. ### Foreground tracking Once you have initialized the SDK and the user has granted permissions, you can track the user's location. To track the user's location in the foreground, call: ```csharp theme={null} var (status, location, events, user) = await Radar.TrackOnce(); ``` Learn about platform-specific implementations of this function in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Background tracking On iOS and Android, once you have initialized the SDK and the user has granted permissions, you can start tracking the user's location in the background. For background tracking, the SDK supports custom tracking options as well as three presets: * **`TrackingOptionsEfficient`**: A low frequency of location updates and lowest battery usage. On Android, avoids Android vitals bad behavior thresholds. * **`TrackingOptionsResponsive`**: A medium frequency of location updates and low battery usage. Suitable for most consumer use cases. * **`TrackingOptionsContinuous`**: A high frequency of location updates and higher battery usage. Suitable for on-demand use cases (e.g., delivery tracking) and some consumer use cases (e.g., order ahead, "mall mode"). Learn about platform-specific implementations of these presets in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). To start tracking the user's location in the background, call one of: ```csharp theme={null} Radar.StartTracking(Radar.TrackingOptionsEfficient); Radar.StartTracking(Radar.TrackingOptionsResponsive); Radar.StartTracking(Radar.TrackingOptionsContinuous); ``` You only need to call these methods once, as these settings will be persisted across app sessions. Though we recommend using presets for most use cases, you can customize the tracking options. See the [tracking options reference](/sdk/tracking). ```csharp theme={null} RadarTrackingOptions trackingOptions = Radar.TrackingOptionsContinuous; trackingOptions.DesiredStoppedUpdateInterval = 180; trackingOptions.DesiredStoppedUpdateInterval = 60; trackingOptions.DesiredSyncInterval = 50; trackingOptions.DesiredAccuracy = RadarTrackingOptionsDesiredAccuracy.High; trackingOptions.StopDuration = 140; trackingOptions.StopDistance = 70; trackingOptions.Sync = RadarTrackingOptionsSync.All; trackingOptions.Replay = RadarTrackingOptionsReplay.None; Radar.StartTracking(trackingOptions); ``` To determine whether tracking has been started, call: ```csharp theme={null} Radar.IsTracking; ``` To stop tracking the user's location in the background (e.g., when the user logs out), call: ```csharp theme={null} Radar.StopTracking(); ``` Learn about platform-specific implementations of these functions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). To listen for events, location updates, and errors, you can add event listeners: ```csharp theme={null} Radar.ClientLocationUpdated += (result) => { // do something with result.location, result.stopped, result.source }; Radar.LocationUpdated += (result) => { // do something with result.location, result.user }; Radar.EventsReceived += (result) => { // do something with result.events, result.user }; Radar.Error += (err) => { // do something with err }; ``` > [!WARNING] > > Listeners should be set only once and before tracking begins. ### Mock tracking On iOS and Android, you can simulate a sequence of location updates for testing. For example, to simulate a sequence of 10 location updates every 3 seconds by car from an `origin` to a `destination`, we can call: ```csharp theme={null} RadarLocation origin = new() { Latitude = 40.714708, Longitude = -74.035807 }; RadarLocation destination = new() { Latitude = 40.717410, Longitude = -74.053334 }; Radar.MockTracking(origin, destination, RadarRouteMode.Car, 10, 3, data => { System.Console.WriteLine($"{data.Location.Latitude} {data.Location.Longitude}"); }); ``` ### Trip tracking On iOS and Android, to start a trip to a destination, call: ```csharp theme={null} RadarTripOptions tripOptions = new() { ExternalId = "299", DestinationGeofenceTag = "store", DestinationGeofenceExternalId = "123", Mode = RadarRouteMode.Car }; await Radar.StartTrip(tripOptions); Radar.StartTracking(Radar.TrackingOptionsContinuous); ``` Later, to complete the trip and stop tracking, call: ```csharp theme={null} await Radar.CompleteTrip(); Radar.StopTracking(); ``` Or, to cancel the trip and stop tracking, call: ```csharp theme={null} await Radar.CancelTrip(); Radar.StopTracking(); ``` Learn more about [trip tracking](/geofencing/trips). ### Manual tracking You can manually update the user's location by calling: ```csharp theme={null} RadarLocation loc = new() { Latitude = 40.714708, Longitude = -74.035807, Accuracy = 65 }; var (status, location, events, user) = await Radar.TrackOnce(loc); ``` Learn about platform-specific implementation of this function in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Other APIs The MAUI SDK also exposes APIs for geocoding, search, and distance. #### Geocoding With the [forward geocoding API](/api#forward-geocode), geocode an address, converting address to coordinates: ```csharp theme={null} var (status, addresses) = await Radar.Geocode("20 jay st brooklyn ny"); ``` With the [reverse geocoding API](/api#reverse-geocode), reverse geocode a location, converting coordinates to address: ```csharp theme={null} RadarLocation loc = new() { Latitude = 40.714708, Longitude = -74.035807 }; var (status, addresses) = await Radar.ReverseGeocode(loc); ``` With the [IP geocoding API](/api#ip-geocode), geocode the device's current IP address, converting IP address to city, state, and country: ```csharp theme={null} var (status, address, proxy) = await Radar.IpGeocode(); ``` #### Search With the [autocomplete API](/api#autocomplete), autocomplete partial addresses and place names, sorted by relevance: ```csharp theme={null} RadarLocation near = new() { Latitude = 40.714708, Longitude = -74.035807 }; var (status, addresses) = await Radar.Autocomplete("brooklyn roasting", near, 10); ``` With the [geofence search API](/api#search-geofences), search for geofences near a location, sorted by distance: ```csharp theme={null} RadarLocation near = new() { Latitude = 40.714708, Longitude = -74.035807 }; var (status, location, geofences) = await Radar.SearchGeofences(near, 1000, new string[] { "venue" }, limit: 10); ``` With the [places search API](/api#search-places), search for places near a location, sorted by distance: ```csharp theme={null} RadarLocation near = new() { Latitude = 40.714708, Longitude = -74.035807 }; var (status, location, places) = await Radar.SearchPlaces(near, 1000, new string[] { "starbucks" }, null, null, 10); ``` #### Distance With the [distance API](/api#distance), calculate the travel distance and duration from an origin to a destination: ```csharp theme={null} RadarLocation origin = new() { Latitude = 40.78382, Longitude = -73.97536 }; RadarLocation destination = new() { Latitude = 40.70390, Longitude = -73.98670 }; var (status, routes) = await Radar.GetDistance(origin, destination, new[] { RadarRouteMode.Foot, RadarRouteMode.Car }, RadarRouteUnits.Imperial); ``` #### Matrix With the [matrix API](/api#matrix), calculate the travel distances and durations between multiple origins and destinations for up to 25 routes: ```csharp theme={null} var (status, routes) = await Radar.GetDistance(origins, destinations, new[] { RadarRouteMode.Car }, RadarRouteUnits.Imperial); ``` ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # React Native SDK Source: https://docs.radar.com/sdk/react-native Install and integrate the Radar React Native SDK to add location tracking, geofencing, and trip tracking to your React Native app. This is the documentation for the React Native module. Before integrating, read the [native SDK documentation](https://docs.radar.com/sdk) to familiarize yourself with the platform. See the source on GitHub [here](https://github.com/radarlabs/react-native-radar). Or, see the `react-native-radar` package on npm [here](https://www.npmjs.com/package/react-native-radar). The SDK currently supports React Native `0.60.0` and higher. ## Install Install the package from npm: ```bash theme={null} npm install --save react-native-radar ``` If you're using Expo, your build process must facilitate the installation of native modules. This is the default behavior with prebuild and autolinking. Then, install the [iOS SDK](/sdk/ios). Change to the `ios/` directory. In the `Podfile`, update `platform :ios` to `10.0` or higher. Then, run `pod install`. Learn about [autolinking](https://github.com/react-native-community/cli/blob/master/docs/autolinking.md). Before writing any JavaScript, you must integrate the Radar SDK with your iOS and Android apps as described in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### iOS You must add location usage descriptions and background modes to your `Info.plist`. For foreground permissions, you must add a value for `NSLocationWhenInUseUsageDescription` *(Privacy - Location When In Use Usage Description)*. For background permissions, you must add a value for `NSLocationAlwaysAndWhenInUseUsageDescription` *(Privacy - Location Always and When In Use Usage Description)*. These strings are displayed in permissions prompts. ![](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/sdk/f2vbu16fzuly/66LUD7W9uTt7f2H5pMmpBp/1e5a2bb2baaf79328e88c3ea47a7f6ff/permissions.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=cd1d20f197db651000cfc17c30a494ce) If you are planning to leverage background tracking, such as responsive or continuous mode, in your project settings, go to *Signing & Capabilities*, add *Background Modes*, and turn on *Background fetch* and *Location updates*. Note that this requires additional justification during App Store review. [Learn more](/sdk/ios#submit-to-app-store). ![Background Modes Pn](https://mintcdn.com/radarlabs/CuPuqjYnZpb8PqvH/images/sdk/background-modes.png?fit=max\&auto=format\&n=CuPuqjYnZpb8PqvH\&q=85\&s=7a20ffae1206dfb6c64d1943a3724c75) ### Android You must add Google Play Services Location to your app's `build.gradle` file *(use version 21.0.1 or higher)*. ```gradle theme={null} implementation "com.google.android.gms:play-services-location:21.0.1" ``` For background tracking without a foreground service, and if targeting API level `29` or higher, Radar also requires the `ACCESS_BACKGROUND_LOCATION` permission. You must add the `ACCESS_BACKGROUND_LOCATION` permission to your manifest manually: ```xml theme={null} ``` ### Expo You can also use our Expo plugin to take care of the native setup. Add `react-native-radar` to `plugins` in `app.json` and specify one or more of the plugin options below: ```json theme={null} { "expo": { ... "plugins": [ [ "react-native-radar", { // boolean to enable iOS fraud detection, defaults to false "iosFraud": true, // string used in iOS NSLocationWhenInUseUsageDescription prompt, required for foreground location permissions "iosNSLocationWhenInUseUsageDescription": "Your foreground location usage description.", // string used in iOS NSLocationAlwaysAndWhenInUseUsageDescription prompt, required for background location permissions "iosNSLocationAlwaysAndWhenInUseUsageDescription": "Your background location usage description.", // boolean to enable iOS background location mode, required for .presetContinuous and .presetResponsive, defaults to false "iosBackgroundMode": true, // boolean to enable automatic deep link handling for Radar notification taps on iOS, defaults to false "iosAutoHandleNotificationDeepLinks": true, // boolean to enable automatic conversion logging for Radar notification taps on iOS, defaults to false "iosAutoLogNotificationConversions": true, // boolean to enable Android fraud detection, defaults to false "androidFraud": true, // boolean to enable Android background location permissions, defaults to false "androidBackgroundPermission": true, // boolean to enable Android foreground location permissions, defaults to false "androidFineLocationPermission": true, // boolean to enable motion activity detection, defaults to false "addRadarSDKMotion": true, // string used in iOS NSMotionUsageDescription prompt, defaults to "This app uses the motion service to provide motion-based services." "iosNSMotionUsageDescription": "Your motion usage description." } ], [ "expo-build-properties", { ... "ios": { ... "useFrameworks": "static" } } ], // optional, only required if using Radar Maps [ "@maplibre/maplibre-react-native" ] ] } } ``` ## Integrate ### Import module First, import the module: ```javascript theme={null} import Radar from 'react-native-radar'; ``` ### Initialize When your app starts, initialize the SDK with your publishable key. Use your `Test Publishable` key for testing and non-production environments. Use your `Live Publishable` key for production environments. > [!WARNING] > > 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. ```javascript theme={null} Radar.initialize(publishableKey); ``` If using [Fraud](/geofencing/fraud), pass `true` as the second argument to enable fraud detection, and pass initialization options as the third argument. For example, to enable fraud detection on `Radar.trackVerified()` requests: ```javascript theme={null} Radar.initialize(publishableKey, true, {}); ``` See [Fraud](/geofencing/fraud#react-native) for how to install the fraud plugins. ### Identify user To identify the user when logged in, call: ```javascript theme={null} Radar.setUserId(userId); ``` where `userId` is a stable unique ID for the user. To set an optional dictionary of custom metadata for the user, call: ```javascript theme={null} Radar.setMetadata(metadata); ``` where `metadata` is a JSON object with up to 16 keys and values of type string, boolean, or number. Finally, to set an optional description for the user, displayed in the dashboard, call: ```javascript theme={null} Radar.setDescription(description); ``` where `description` is a string. You only need to call these functions once, as these settings will be persisted across app sessions. Learn about platform-specific implementations of these functions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Debug logging By default, only critical errors are logged to the console. To enable debug logging, call: ```javascript theme={null} Radar.setLogLevel('debug'); ``` Logging app lifecycle events is done in native platform code. Instructions for doing so on iOS can be found in the [iOS SDK documentation](/sdk/ios#debug-logging). Logging app lifecycle events on Android happens automatically without any additional setup. > [!NOTE] > > Contact your customer success manager to enable logging app lifecycle events. ### Request permissions Before tracking the user's location, the user must have granted location permissions for the app. To determine the whether user has granted location permissions for the app, call: ```javascript theme={null} Radar.getPermissionsStatus().then((status) => { // do something with status }); ``` `status` will be a string, one of: * **`GRANTED_BACKGROUND`** * **`GRANTED_FOREGROUND`** * **`NOT_DETERMINED`** * **`DENIED`** To request location permissions for the app, call: ```javascript theme={null} Radar.requestPermissions(background).then((status) => { // do something with status }); ``` where `background` is a boolean indicating whether to request background location permissions or foreground location permissions. On iOS and Android, the user needs to grant foreground location permissions first before you can prompt for background location permissions: ```javascript theme={null} // request foreground location permissions Radar.requestPermissions(false).then((status) => { // request background location permissions Radar.requestPermissions(true).then((status) => { // do something with status }).catch((err) => { // optionally, do something with err }); }).catch((err) => { // optionally, do something with err }); ``` Learn about platform-specific permissions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). > [!NOTE] > > Build and run the app to make sure permissions prompts are displayed! ### Foreground tracking Once you have initialized the SDK and the user has granted permissions, you can track the user's location. To track the user's location in the foreground, call: ```javascript theme={null} Radar.trackOnce().then((result) => { // do something with result.location, result.events, result.user }).catch((err) => { // optionally, do something with err }); ``` `err` will be a string, one of: * **`ERROR_PUBLISHABLE_KEY`**: SDK not initialized * **`ERROR_PERMISSIONS`**: location permissions not granted * **`ERROR_LOCATION`**: location services error or timeout (10 seconds) * **`ERROR_NETWORK`**: network error or timeout (10 seconds) * **`ERROR_BAD_REQUEST`**: bad request (missing or invalid params) * **`ERROR_UNAUTHORIZED`**: unauthorized (invalid API key) * **`ERROR_PAYMENT_REQUIRED`**: payment required (organization disabled or usage exceeded) * **`ERROR_FORBIDDEN`**: forbidden (insufficient permissions or no beta access) * **`ERROR_NOT_FOUND`**: not found * **`ERROR_RATE_LIMIT`**: too many requests ([rate limit](/api#track) exceeded) * **`ERROR_SERVER`**: internal server error * **`ERROR_UNKNOWN`**: unknown error Learn about platform-specific implementations of this function in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### 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. For background tracking, the SDK supports custom tracking options as well as three presets: * **`EFFICIENT`**: A low frequency of location updates and lowest battery usage. On Android, avoids Android vitals bad behavior thresholds. * **`RESPONSIVE`**: A medium frequency of location updates and low battery usage. Suitable for most consumer use cases. * **`CONTINUOUS`**: A high frequency of location updates and higher battery usage. Suitable for on-demand use cases (e.g., delivery tracking) and some consumer use cases (e.g., order ahead, "mall mode"). Learn about platform-specific implementations of these presets in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). To start tracking the user's location in the background, call one of: ```javascript theme={null} Radar.startTrackingEfficient(); Radar.startTrackingResponsive(); Radar.startTrackingContinuous(); ``` You only need to call these methods once, as these settings will be persisted across app sessions. Though we recommend using presets for most use cases, you can customize the tracking options. See the [tracking options reference](/sdk/tracking). ```javascript theme={null} // optionally adjust foreground service options for android Radar.setForegroundServiceOptions({ options: { text: "Location tracking started", title: "Location updates", updatesOnly: false, importance: 2, activity: 'com.yourapp.MainActivity' } }); Radar.startTrackingCustom({ desiredStoppedUpdateInterval: 180, fastestStoppedUpdateInterval: 15, desiredMovingUpdateInterval: 60, fastestMovingUpdateInterval: 15, desiredSyncInterval: 10, desiredAccuracy: 'high', stopDuration: 140, stopDistance: 70, sync: 'all', replay: 'none', useStoppedGeofence: true, showBlueBar: true, foregroundServiceEnabled: true }); ``` To determine whether tracking has been started, call: ```javascript theme={null} Radar.isTracking(); ``` To stop tracking the user's location in the background (e.g., when the user logs out), call: ```javascript theme={null} Radar.stopTracking(); ``` Learn about platform-specific implementations of these functions in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). To listen for events, location updates, and errors, you can add event listeners: ```javascript theme={null} Radar.onClientLocationUpdated((result) => { // do something with result.location }); Radar.onLocationUpdated((result) => { // do something with result.location, result.user }); Radar.onEventsReceived((result) => { // do something with result.events, result.user }); Radar.onError((err) => { // do something with err }); ``` > [!WARNING] > > Listeners should be set only once and before tracking begins. Add event listeners outside of your component lifecycle (e.g., outside of `componentDidMount`) if you want them to work when the app is in the background. You can also remove event listeners: ```javascript theme={null} Radar.onClientLocationUpdated(null); Radar.onLocationUpdated(null); Radar.onEventsReceived(null); Radar.onError(null); ``` ### Battery usage Because React Native loads and parses your JavaScript bundle on each app launch, and because background tracking may launch the app in the background, background tracking with the React Native module can increase battery usage. On iOS, the app loads and parses the JavaScript bundle when the app is launched. If you do not want to receive events in JavaScript and you want to disable this in the background, check `launchOptions` for the `UIApplicationLaunchOptionsLocationKey` to conditionally parse and load the JavaScript bundle. Learn more about this key [here](https://developer.apple.com/documentation/uikit/uiapplication/launchoptionskey/location?language=objc). On Android, a receiver in the React Native module loads and parses the JavaScript bundle when the app is launched in the background. If you do not want to receive events in JavaScript and you want to disable this, add an override to your manifest: ```xml theme={null} ``` ### Trip tracking To start a trip to a destination, call: ```javascript theme={null} Radar.startTrip({ tripOptions: { externalId: '299', destinationGeofenceTag: 'store', destinationGeofenceExternalId: '123', mode: 'car' }, trackingOptions:{ desiredStoppedUpdateInterval: 30, fastestStoppedUpdateInterval: 30, desiredMovingUpdateInterval: 30, fastestMovingUpdateInterval: 30, desiredSyncInterval: 20, desiredAccuracy: "high", stopDuration: 0, stopDistance: 0, replay: "none", sync: "all", showBlueBar: true, syncGeofences: false, syncGeofencesLimit: 0, beacons: false, foregroundServiceEnabled: true } }).then((result) => { // do something with result.status }); ``` Update information about the trip. Status can be set to 'unknown' to leave the status unchanged as it will update via location tracking. ```javascript theme={null} Radar.updateTrip({ status:'arrived', options: { externalId: '299', metadata: { parkingSpot: '5' } } }).then((result) => { // do something with result.status }); ``` Later, complete the trip by calling: ```javascript theme={null} Radar.completeTrip().then((result) => { // do something with result.status }); ``` Or, cancel the trip by calling: ```javascript theme={null} Radar.cancelTrip().then((result) => { // do something with result.status }); ``` If tracking was disabled before the trip started, it will stop after the trip ends. Otherwise, it will revert to the tracking options in use before the trip started. Learn more about [trip tracking](/geofencing/trips). ### Manual tracking You can manually update the user's location by calling: ```javascript theme={null} Radar.trackOnce({ latitude: 39.2904, longitude: -76.6122, accuracy: 65 }).then((result) => { // do something with result.events, result.user }).catch((err) => { // optionally, do something with err }); ``` Learn about platform-specific implementation of this function in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Location metadata The SDK can also pass along information like motion activity detection, speed and heading via the location metadata field. Enable this feature with the Expo plugin by adding the following line into the app.json: ```json theme={null} { "expo":{ ... "plugins": [ [ "react-native-radar", { ... "addRadarSDKMotion":true } ], // optional, only required when you are also using Radar maps ["@maplibre/maplibre-react-native"] ] } } ``` Learn about platform-specific implementation of this function in the [iOS SDK documentation](/sdk/ios) and [Android SDK documentation](/sdk/android). ### Other APIs The React Native module also exposes APIs for geocoding, search, and distance. #### Geocoding With the [forward geocoding API](/api#forward-geocode), geocode an address, converting address to coordinates: ```javascript theme={null} Radar.geocode('20 jay st brooklyn ny').then((result) => { // do something with result.addresses }).catch((err) => { // optionally, do something with err }); ``` With the [reverse geocoding API](/api#reverse-geocode), reverse geocode a location, converting coordinates to address: ```javascript theme={null} Radar.reverseGeocode({ latitude: 40.783826, longitude: -73.975363 }).then((result) => { // do something with result.addresses }).catch((err) => { // optionally, do something with err }); ``` With the [IP geocoding API](/api#ip-geocode), geocode the device's current IP address, converting IP address to city, state, and country: ```javascript theme={null} Radar.ipGeocode().then((result) => { // do something with result.address }).catch((err) => { // optionally, do something with err }); ``` #### Search With the [autocomplete API](/api#autocomplete), autocomplete partial addresses and place names, sorted by relevance: ```javascript theme={null} Radar.autocomplete({ query: 'brooklyn roasting', near: { latitude: 40.783826, longitude: -73.975363 }, limit: 10 }).then((result) => { // do something with result.addresses }).catch((err) => { // optionally, do something with err }); ``` With the [geofence search API](/api#search-geofences), search for geofences near a location, sorted by distance: ```javascript theme={null} Radar.searchGeofences({ radius: 1000, tags: ['venue'], limit: 10 }).then((result) => { // do something with result.geofences }).catch((err) => { // optionally, do something with err }); ``` With the [places search API](/api#search-places), search for places near a location, sorted by distance: ```javascript theme={null} Radar.searchPlaces({ near: { latitude: 40.783826, longitude: -73.975363 }, radius: 1000, chains: ['starbucks'], limit: 10 }).then((result) => { // do something with result.places }).catch((err) => { // optionally, do something with err }); ``` #### Distance With the [distance API](/api#distance), calculate the travel distance and duration from an origin to a destination: ```javascript theme={null} Radar.getDistance({ origin: { latitude: 40.78382, longitude: -73.97536 }, destination: { latitude: 40.70390, longitude: -73.98670 }, modes: [ 'foot', 'car' ], units: 'imperial' }).then((result) => { // do something with result.routes }).catch((err) => { // optionally, do something with err }); ``` #### Matrix With the [matrix API](/api#matrix), calculate the travel distance and duration between multiple origins and destinations for up to 25 routes: ```javascript theme={null} Radar.getMatrix({ origins: [ { latitude: 40.78382, longitude: -73.97536 }, { latitude: 40.70390, longitude: -73.98670 } ], destinations: [ { latitude: 40.64189, longitude: -73.78779 }, { latitude: 35.99801, longitude: -78.94294 } ], mode: 'car', units: 'imperial' }).then((result) => { // do something with result.matrix }).catch((err) => { // optionally, do something with err }); ``` #### Conversions With the [conversions API](/api#log-a-conversion), log a conversion, such as a purchase or signup, to analyze alongside your app's location activity: ```javascript theme={null} Radar.logConversion( name, metadata ).then((result) => { // do something with result.event }).catch((err) => { // optionally, do something with err }); // conversion with revenue Radar.logConversion( name, revenue, metadata ).then((result) => { // do something with result.event }).catch((err) => { // optionally, do something with err }); ``` To enable logging of app opens through notifications taps on iOS, perform the following native setup in the app's AppDelegate: ```objc theme={null} - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.moduleName = @"main"; self.initialProps = @{}; BOOL result = [super application:application didFinishLaunchingWithOptions:launchOptions]; RadarInitializeOptions *options = [RadarInitializeOptions new]; options.autoLogNotificationConversions = YES; [Radar nativeSetup:options]; return result; } ``` #### User tags With the [user tag API](/geofencing/campaigns#campaign-targeting), you can configure [campaigns](/geofencing/campaigns) to only target users with the corresponding tags: ```java Javascript theme={null} Radar.addTags(new String[]{"tag1", "tag2"}); Radar.removeTags(new String[]{"tag1", "tag2"}); Radar.setTags(new String[]{"tag1", "tag2"}); Radar.getTags(); ``` ### Notification options On Android, you can call `setNotificationOptions` to set the icon and the background color of the foreground service and event notifications: ```javascript theme={null} // Set both foreground service and event notifications Radar.setNotificationOptions({ iconString: 'icon_1', iconColor: 'color_1' }); // Or, set the foreground service notification and event notifications separately Radar.setNotificationOptions({ foregroundServiceIconString: "icon_1", foregroundServiceIconColor: "color_1", eventIconString: "icon_2", eventIconColor: "color_2", }); ``` iOS defaults to the standard notification icon. ### Maps and UI kits The React Native SDK also has UI components for maps and address autocomplete. Learn more in the [Maps Platform documentation](/maps/overview). ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # Remote SDK configuration Source: https://docs.radar.com/sdk/remote-configuration Configure Radar SDK tracking remotely from the dashboard by OS and environment, without shipping an app update. Starting in SDK versions `3.16.0`, the SDK can be remotely configured through the [dashboard](https://dashboard.radar.com/settings#sdk-configuration). Configurations are targeted by OS and environment. With these configuration options, a typical tracking implementation requires only calling `Radar.initialize()` and, optionally, `Radar.setUserId()`. ### Track once on initialize When enabled, the SDK will automatically perform a `Radar.trackOnce()` call when the app is launched or foregrounded. ### Start tracking on initialize When enabled, the SDK will automatically start tracking with `Radar.startTracking()` when the app is launched. ### Log level Set the SDK log level. Overrides any log level set client side. ## Remotely set tracking options You can remotely set SDK [tracking options](/sdk/tracking) with either the default presets or a custom configuration. Remotely setting tracking options overrides any client-side specified tracking options. In addition to the general tracking options, on-trip tracking options apply when a user is on a trip and in-geofence tracking options allow you to dictate different tracking options for when users are in geofences with the tags specified. ### Custom tracking options Custom configurations should declare all tracking options in JSON. Example custom tracking options are below. ```json iOS theme={null} { "desiredStoppedUpdateInterval": 3600, "desiredMovingUpdateInterval": 150, "desiredSyncInterval": 10, "desiredAccuracy": "high", "stopDuration": 140, "stopDistance": 70, "sync": "all", "replay": "none", "showBlueBar": false, "useStoppedGeofence": true, "stoppedGeofenceRadius": 100, "useMovingGeofence": true, "movingGeofenceRadius": 200, "syncGeofences": true, "useVisits": true, "useSignificantLocationChanges": true, "beacons": false } ``` ```json Android theme={null} { "desiredStoppedUpdateInterval": 3600, "fastestStoppedUpdateInterval": 150, "desiredMovingUpdateInterval": 150, "fastestMovingUpdateInterval": 20, "desiredSyncInterval": 10, "desiredAccuracy": 2, "stopDuration": 140, "stopDistance": 70, "sync": 2, "replay": 0, "useStoppedGeofence": true, "stoppedGeofenceRadius": 100, "useMovingGeofence": true, "movingGeofenceRadius": 200, "syncGeofences": true, "syncGeofencesLimit": 10, "beacons": true, "foregroundServiceEnabled": false } ``` # Overview Source: https://docs.radar.com/sdk/sdk Overview of the Radar SDK for adding geofencing, location tracking, trip tracking, geocoding, and routing to iOS, Android, web, and cross-platform apps. The Radar SDK abstracts away cross-platform differences between location services, allowing you to add geofencing, location tracking, trip tracking, geocoding, and routing to your apps and websites with just a few lines of code. Note that you can use our [Waypoint apps](/waypoint) 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. ## Platforms > [card] [iOS](/sdk/ios) > [card] [Android](/sdk/android) > [card] [React Native](/sdk/react-native) > [card] [Web](/sdk/web) > [card] [Cordova](/sdk/cordova) > [card] [Capacitor](/sdk/capacitor) > [card] [Flutter](/sdk/flutter) > [card] [Maui](/sdk/maui) # Silent push Source: https://docs.radar.com/sdk/silent-push Use silent push notifications to request a fresh location from a device through the Radar API on iOS and Android. Silent push notifications allow us to remotely request a fresh location from a user. Radar supports requesting these locations through an API endpoint, starting with iOS and Android SDK version `3.24.0`. There are two types of silent push notifications that can be sent to a device: regular app silent push and location service extension push. **App silent push** can be used to wake the app to perform a track if the app is in the foreground or background. This can be used to restart tracking if tracking was stopped due to device memory or CPU resource constraints. However the silent push notification will not work if the app has been manually killed by the user. **Location extension service** can be used to request a location for devices even if the app was manually terminated. The app will wake for \~30 seconds to respond to the request and perform a track request with a fresh location. The location extension service acts as a separate app, so it can only restart continuous tracking for 30 seconds before the extension is shutdown. ## Radar dashboard setup [Obtain an encryption key for APN](https://developer.apple.com/help/account/keys/create-a-private-key) (Apple push notification). Navigate to Settings tab, and enable push notifications. Then enter in the app's bundle ID, team ID, key ID, and key for iOS. Enter the project ID, client email, and private key for Android. Then save the settings. Your private key should begin and end with `-----BEGIN/END PRIVATE KEY-----`, include this in your key. ## Build configuration ### Native iOS and Android For iOS, Add the "Push Notifications" app capabilities, and turn on "Remote notifications" in the "Background Modes" capability. For Android, [Add Firebase to your project](https://firebase.google.com/docs/android/setup) and then generate a service account from the Firebase console. You'll need the account details to send silent push notifications. Add the following firebase messaging service configuration to your project ``` ... ... ``` Add firebase messaging dependency to gradle ``` dependencies { ... implementation platform('com.google.firebase:firebase-bom:34.5.0') implementation "com.google.firebase:firebase-messaging" } ``` ### React Native The Android manifest service entry and Gradle dependencies above are for native Android projects only. For React Native, the `react-native-radar` package automatically registers `RadarFirebaseMessagingService` in your `AndroidManifest.xml`. For iOS, add `"remote-notification"` to `UIBackgroundModes` in your `Info.plist`. If using Expo, add it to `app.json`: ```json theme={null} { "expo": { "ios": { "infoPlist": { "UIBackgroundModes": ["remote-notification"] } } } } ``` Add the "Push Notifications" capability in Xcode under *Signing & Capabilities*. For Android, install `@react-native-firebase/messaging` and ensure you have [added Firebase to your Android project](https://firebase.google.com/docs/android/setup) with the `google-services` plugin applied: ```bash theme={null} npm install --save @react-native-firebase/app @react-native-firebase/messaging ``` For location extension service support (iOS), see [Location extension service setup](#location-extension-service-setup-ios-only). ## App setup (automated setup) Initialize Radar with `RadarInitializeOptions.silentPush = true`. ```swift Swift theme={null} import RadarSDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // initialization Radar with the silent push option let radarInitializeOptions = RadarInitializeOptions() radarInitializeOptions.silentPush = true Radar.initialize(publishableKey: "prj_test_pk_...", options: radarInitializeOptions) return true } } ``` ```kotlin Kotlin theme={null} import com.google.firebase.FirebaseApp import io.radar.sdk.Radar import io.radar.sdk.RadarInitializeOptions class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { // first the firebase app needs to be initialized FirebaseApp.initializeApp(this) // initialization Radar with the silent push option val radarInitializeOptions = RadarInitializeOptions( silentPush = true, ) Radar.initialize(this, "prj_test_pk_...", radarInitializeOptions) } } ``` ```javascript React Native theme={null} import Radar from 'react-native-radar'; import { Platform } from 'react-native'; import { getMessaging, getToken, onTokenRefresh } from '@react-native-firebase/messaging'; Radar.initialize('prj_test_pk_...', false, { silentPush: Platform.OS === 'ios', }); async function registerPushToken() { if (Platform.OS === 'android') { const messaging = getMessaging(); const token = await getToken(messaging); if (token) { Radar.setPushNotificationToken(token); } onTokenRefresh(messaging, (newToken) => { Radar.setPushNotificationToken(newToken); }); } } registerPushToken(); ``` On iOS, `silentPush: true` handles push token registration automatically. On Android, you must also pass the FCM token to Radar via `Radar.setPushNotificationToken()`. ## Manual setup Initialize Radar, register for silent push notifications and pass the push token to Radar. ```swift Swift theme={null} import UIKit import RadarSDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // initialize Radar, silent push option defaults to false Radar.initialize(publishableKey: "prj_test_pk_...") application.registerForRemoteNotifications() return true } func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult { await Radar.didReceivePushNotificationPayload(userInfo) return .newData } } ``` ```kotlin Kotlin theme={null} class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { // first the firebase app needs to be initialized FirebaseApp.initializeApp(this) // initialize Radar, silent push option defaults to false Radar.initialize(this, "prj_test_pk_...") // register push notification with firebase, then pass the push token to Radar FirebaseMessaging.getInstance().token.addOnSuccessListener { token -> Radar.setPushNotificationToken(token) } } } ``` ```javascript React Native theme={null} import Radar from 'react-native-radar'; import { Platform } from 'react-native'; import { getMessaging, getToken, onTokenRefresh } from '@react-native-firebase/messaging'; Radar.initialize('prj_test_pk_...'); async function registerPushToken() { if (Platform.OS === 'android') { const messaging = getMessaging(); const token = await getToken(messaging); if (token) { Radar.setPushNotificationToken(token); } onTokenRefresh(messaging, (newToken) => { Radar.setPushNotificationToken(newToken); }); } } registerPushToken(); ``` ## Location extension service setup (iOS only) The location extension service requires a native `CLLocationPushServiceExtension` target, an [app group](https://developer.apple.com/documentation/Xcode/configuring-app-groups) shared between the main app and the extension, and the `com.apple.developer.location.push` entitlement on both targets. ### Build configuration Add the following capabilities to both the main app target and the location push extension target: * **App Groups** — use a shared group (e.g., `group.yourApp.data`) * **Push Notifications** Add the `com.apple.developer.location.push` entitlement to both targets. For React Native with Expo, you can configure this in `app.json`: ```json theme={null} { "expo": { "ios": { "entitlements": { "com.apple.security.application-groups": ["group.yourApp.data"], "com.apple.developer.location.push": true } } } } ``` The location push extension is a native iOS target and must be created in Xcode (or with a tool like `@bacons/apple-targets` for Expo). The extension target needs the `RadarSDK` pod, `CoreLocation` framework, and the same App Group and `com.apple.developer.location.push` entitlements. ### Main app setup Initialize Radar, set the app group, and start monitoring for location extension pushes. ```swift Swift theme={null} import UIKit import RadarSDK @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { let locationManager = CLLocationManager() func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let radarInitializeOptions = RadarInitializeOptions() radarInitializeOptions.silentPush = true // (or true if you only want location extension) Radar.initialize(publishableKey: "prj_test_pk_...", options: radarInitializeOptions) Radar.setAppGroup("group.yourApp.data") locationManager.startMonitoringLocationPushes() { data, error in Radar.setLocationExtensionToken(data?.map { String(format: "%02x", $0) }.joined()) } return true } } ``` ```javascript React Native theme={null} import Radar from 'react-native-radar'; Radar.setAppGroup('group.yourApp.data'); Radar.initialize('prj_test_pk_...', false, { silentPush: true }); ``` > [!NOTE] > > `CLLocationManager.startMonitoringLocationPushes()` is not exposed by the React Native SDK. You need to bridge this call natively using either a custom Expo Module, a React Native native module, or by calling it from your `AppDelegate`. Once you have the token, pass it to Radar from JavaScript: ```javascript React Native theme={null} Radar.setLocationExtensionToken(token); ``` ### Extension setup Create a `CLLocationPushServiceExtension` target. When a location payload is received, initialize Radar using the shared app group and pass the payload to the SDK. ```swift Swift theme={null} import CoreLocation import RadarSDK class LocationPushService: NSObject, CLLocationPushServiceExtension { func didReceiveLocationPushPayload(_ payload: [String : Any], completion: @escaping () -> Void) { Radar.initialize(withAppGroup: "group.yourApp.data") Radar.didReceivePushNotificationPayload(payload, completionHandler: completion) } } ``` This extension code is the same whether your main app is native Swift or React Native. ## Usage Silent push or location extension push notifications can be triggered by sending a POST API request to the `/users/refresh` endpoint. See the [API reference](/api#send-remote-track-requests-to-users) for full details. ## iOS Environments APNs operate in two separate environments for production and non-production app builds. When using the live Radar environment, Radar sends silent push notifications to the production APN environment, and when using the test Radar environment, Radar sends silent push notifications to the non-production environment. When using the live Radar environment, your device must be in a production build, and vice versa. You will receive "BadDeviceToken" if there is a mismatch. # Tracking options reference Source: https://docs.radar.com/sdk/tracking Reference for Radar SDK background tracking options, including the EFFICIENT, RESPONSIVE, and CONTINUOUS presets and custom parameters. For background tracking, Radar's SDK supports custom tracking options as well as three presets: `EFFICIENT`, `RESPONSIVE`, and `CONTINUOUS`. #### Configuring tracking options While it's recommended to use one of the three optimized presets, custom parameters can also be passed at the time of tracking initialization. Additionally, you can also choose to forgo setting background tracking options as part of SDK initialization and override to any of the three preset on the Radar dashboard using [Remote Tracking Options](/sdk/remote-configuration#remotely-set-tracking-options). ```swift Swift theme={null} let trackingOptions = RadarTrackingOptions.presetResponsive trackingOptions.beacons = true Radar.startTracking(trackingOptions: trackingOptions) ``` ```objc Objective-C theme={null} RadarTrackingOptions *trackingOptions = RadarTrackingOptions.presetResponsive; trackingOptions.beacons = YES; [Radar startTrackingWithOptions:trackingOptions]; ``` ```java Java theme={null} RadarTrackingOptions trackingOptions = RadarTrackingOptions.RESPONSIVE; trackingOptions.beacons = true; Radar.startTracking(trackingOptions); ``` ```kotlin Kotlin theme={null} val trackingOptions = RadarTrackingOptions.RESPONSIVE trackingOptions.beacons = true Radar.startTracking(trackingOptions) ``` #### Tracking states The SDK has two states: **stopped** and **moving**. After a location update is made, a user then occupies one of these two states. Tracking Options can be customized to alter the frequency of updates when a user is either stopped or moving. While less common to adjust, `stopDuration` and `stopDistance` are Tracking Options that alter the intervals after which a user is assumed to be stopped. ## iOS ### iOS options * **`desiredStoppedUpdateInterval`**: Determines the desired location update interval in seconds when stopped. Use `0` to shut down when stopped. Defaults to `0`. * **`desiredMovingUpdateInterval`**: Determines the desired location update interval in seconds when moving. Defaults to `0`. **Note that location updates may be delayed significantly by Low Power Mode, or if the device has connectivity issues, low battery, or wi-fi disabled.** * **`desiredSyncInterval`**: Determines the desired sync interval in seconds. Defaults to `0`. * **`desiredAccuracy`**: Determines the desired accuracy of location updates. `.high` uses `kCLLocationAccuracyBest`, `.medium` uses `kCLLocationAccuracyHundredMeters`, `.low` uses `kCLLocationAccuracyKilometer`. Defaults to `.medium`. * **`stopDuration`**: With `stopDistance`, determines the duration in seconds after which the device is considered stopped. Defaults to `0`. * **`stopDistance`**: With `stopDuration`, determines the distance in meters within which the device is considered stopped. Defaults to `0`. * **`startTrackingAfter`**: Determines when to start tracking. Use `nil` to start tracking when `startTracking` is called. * **`stopTrackingAfter`**: Determines when to stop tracking. Use `nil` to track until `stopTracking` is called. * **`replay`**: Determines which failed location updates to replay to the server. `.all` replays all location updates including those collected offline, `.replayStops` replays failed stops, `.replayNone` replays no location updates. Defaults to `.replayNone`. * **`syncLocations`**: Determines which location updates to sync to the server. `.all` syncs all location updates to the server, `.stopsAndExits` syncs only stops and exits to the server, `.events` only syncs location updates that will generate an event, `.none` syncs no location updates to the server. Defaults to `.all`. When using `.events`, the SDK only syncs location updates that would generate one of the events below. Each product (Geofences, Places, or Beacons) must be enabled *and* the corresponding event types must be selected in your Radar dashboard settings (e.g., Settings > Geofences > Event types) for those locations to sync: * Geofences: `user.entered_geofence`, `user.exited_geofence`, `user.dwelled_in_geofence` * Places: `user.entered_place`, `user.exited_place` * Beacons: `user.entered_beacon`, `user.exited_beacon` * **`showBlueBar`**: Determines whether the [flashing blue status bar](https://developer.apple.com/documentation/corelocation/cllocationmanager/2923541-showsbackgroundlocationindicator) is shown when tracking. Defaults to `false`. * **`useStoppedGeofence`**: Determines whether to use the [iOS region monitoring service (geofencing)](https://developer.apple.com/documentation/corelocation/monitoring_the_user_s_proximity_to_geographic_regions) to create a client-side geofence "bubble" around the device's current location when stopped. Defaults to `false`. * **`stoppedGeofenceRadius`**: Determines the radius in meters of the client-side geofence "bubble" around the device's current location when stopped. Use smaller values (e.g., `100` meters) for faster exit events or larger values (e.g., `200` meters) to avoid jumpy exits while stopped. Defaults to `0`. * **`useMovingGeofence`**: Determines whether to use the [iOS region monitoring service (geofencing)](https://developer.apple.com/documentation/corelocation/monitoring_the_user_s_proximity_to_geographic_regions) to create a client-side geofence "bubble" around the device's current location when moving. Defaults to `false`. * **`movingGeofenceRadius`**: Determines the radius in meters of the client-side geofence "bubble" around the device's current location when moving. Defaults to `0`. * **`syncGeofences`**: Determines whether to sync nearby geofences from the server to the client to improve responsiveness. Defaults to `false`. * **`useVisits`**: Determines whether to use the [iOS visit monitoring service](https://developer.apple.com/documentation/corelocation/clvisit). Defaults to `false`. * **`useSignificantLocationChanges`**: Determines whether to use the [iOS significant location change service](https://developer.apple.com/documentation/corelocation/cllocationmanager/1423531-startmonitoringsignificantlocati?language=objc). Defaults to `false`. * **`beacons`**: Determines whether to monitor beacons. Defaults to `false`. ### iOS presets * **`RadarTrackingOptions.presetContinuous`**: Updates about every 30 seconds while moving or stopped. Moderate battery usage. Shows the flashing blue status bar during tracking. * **`RadarTrackingOptions.presetResponsive`**: Updates about every 2.5 minutes when moving and shuts down when stopped to save battery. Once stopped, the device will need to move more than 100 meters to wake up and start moving again. Low battery usage. Requires the `location` background mode. * **`RadarTrackingOptions.presetEfficient`**: Uses the [iOS visit monitoring service](https://developer.apple.com/documentation/corelocation/clvisit) to update only on stops and exits. Once stopped, the device will need to move several hundred meters and trigger a visit departure to wake up and start moving again. Lowest battery usage. | Option | Efficient | Responsive | Continuous | | - | - | - | - | | **`desiredStoppedUpdateInterval`** | `0` | `0` | `30` | | **`desiredMovingUpdateInterval`** | `0` | `150` | `30` | | **`desiredSyncInterval`** | `0` | `20` | `20` | | **`desiredAccuracy`** | `.medium` | `.medium` | `.high` | | **`stopDuration`** | `0` | `140` | `140` | | **`stopDistance`** | `0` | `70` | `70` | | **`startTrackingAfter`** | `nil` | `nil` | `nil` | | **`stopTrackingAfter`** | `nil` | `nil` | `nil` | | **`replay`** | `.stops` | `.stops` | `.none` | | **`syncLocations`** | `.all` | `.all` | `.all` | | **`showBlueBar`** | `false` | `false` | `true` | | **`useStoppedGeofence`** | `false` | `true` | `false` | | **`stoppedGeofenceRadius`** | `0` | `100` | `0` | | **`useMovingGeofence`** | `false` | `true` | `false` | | **`movingGeofenceRadius`** | `0` | `100` | `0` | | **`syncGeofences`** | `true` | `true` | `true` | | **`useVisits`** | `true` | `true` | `false` | | **`useSignificantLocationChanges`** | `false` | `true` | `false` | | **`beacons`** | `false` | `false` | `false` | ## Android ### Android options * **`desiredStoppedUpdateInterval`**: Determines the desired location update interval in seconds when stopped. Use `0` to shut down when stopped. Defaults to `0`. * **`fastestStoppedUpdateInterval`**: Determines the fastest location update interval in seconds when stopped. Defaults to `0`. * **`desiredMovingUpdateInterval`**: Determines the desired location update interval in seconds when moving. Defaults to `0`. [******Note that location updates may be delayed significantly by Doze Mode, App Standby, and Background Location Limits, or if the device has connectivity issues, low battery, or wi-fi disabled. To avoid these restrictions, you can start a foreground service.******](https://developer.android.com/about/versions/oreo/background-location-limits) * **`fastestMovingUpdateInterval`**: Determines the fastest location update interval in seconds when moving. Defaults to `0`. * **`desiredSyncInterval`**: Determines the desired sync interval in seconds. Defaults to `0`. * **`desiredAccuracy`**: Determines the desired accuracy of location updates. `HIGH` uses `PRIORITY_HIGH_ACCURACY`, `MEDIUM` uses `PRIORITY_BALANCED_POWER_ACCURACY`, `LOW` uses `PRIORITY_LOW_POWER`, `NONE` uses `PRIORITY_NO_POWER`. Defaults to `MEDIUM`. * **`stopDuration`**: With `stopDistance`, determines the duration in seconds after which the device is considered stopped. Defaults to `0`. * **`stopDistance`**: With `stopDuration`, determines the distance in meters within which the device is considered stopped. Defaults to `0`. * **`startTrackingAfter`**: Determines when to start tracking. Use `null` to start tracking when `startTracking()` is called. * **`stopTrackingAfter`**: Determines when to stop tracking. Use `null` to track until `stopTracking()` is called. * **`replay`**: Determines which failed location updates to replay to the server. `ALL` replays all location updates including those collected offline, `STOPS` replays failed stops, `NONE` replays no location updates. Defaults to `NONE`. * **`sync`**: Determines which location updates to sync to the server. `ALL` syncs all location updates to the server, `STOPS_AND_EXITS` syncs only stops and exits to the server, `EVENTS` only syncs location updates that will generate an event, `NONE` syncs no location updates to the server. Defaults to `STOPS_AND_EXITS`. When using `EVENTS`, the SDK only syncs location updates that would generate one of the events below. Each product (Geofences, Places, or Beacons) must be enabled *and* the corresponding event types must be selected in your Radar dashboard settings (e.g., Settings > Geofences > Event types) for those locations to sync: * Geofences: `user.entered_geofence`, `user.exited_geofence`, `user.dwelled_in_geofence` * Places: `user.entered_place`, `user.exited_place` * Beacons: `user.entered_beacon`, `user.exited_beacon` * **`useStoppedGeofence`**: Determines whether to create a [client-side geofence](https://developer.android.com/training/location/geofencing) "bubble" around the device's current location when stopped. Defaults to `false`. * **`stoppedGeofenceRadius`**: Determines the radius in meters of the client-side geofence "bubble" around the device's current location when stopped. Use smaller values (e.g., `100` meters) for faster exit events or larger values (e.g., `200` meters) to avoid jumpy exits while stopped. Defaults to `0`. * **`useMovingGeofence`**: Determines whether to create a [client-side geofence](https://developer.android.com/training/location/geofencing) "bubble" around the device's current location when moving. Defaults to `false`. * **`movingGeofenceRadius`**: Determines the radius in meters of the client geofence around the device's current location when moving. Defaults to `0`. * **`syncGeofences`**: Determines whether to sync nearby geofences from the server to the client to improve responsiveness. Defaults to `false`. * **`syncGeofencesLimit`**: Determines how many nearby geofences to sync from the server to the client when `syncGeofences` is enabled. Defaults to `0`. * **`foregroundService`**: If set, starts a [foreground service](https://developer.android.com/guide/components/foreground-services) and shows a notification during tracking. Deprecated in Android SDK [3.4.1](https://github.com/radarlabs/radar-sdk-android/blob/master/MIGRATION.md#33x-to-34x). * **`foregroundServiceEnabled`**: If set, starts a [foreground service](https://developer.android.com/guide/components/foreground-services) and shows a notification during tracking. Defaults to `false`. In Android SDK 4.0.0 and later, requires declaring `RadarForegroundService` in your app manifest. Geofencing does not require a foreground service, and Google Play no longer accepts geofencing as a foreground service use case. See [foreground services and Google Play policy](/sdk/android#foreground-services-and-google-play-policy). * **`beacons`**: Determines whether to monitor beacons. Defaults to `false`. ### Android foreground service options To avoid [Background Location Limits](https://developer.android.com/about/versions/oreo/background-location-limits), you can start a foreground service and show a notification during tracking. If using Android SDK \< [3.4.1](https://github.com/radarlabs/radar-sdk-android/releases/tag/3.1.9), set `trackingOptions.foregroundService` to an instance of `RadarTrackingOptionsForegroundService`. If using Android SDK >= [3.4.1](https://github.com/radarlabs/radar-sdk-android/blob/master/MIGRATION.md#33x-to-34x), use `Radar.setForegroundServiceOptions()` to customize the foreground service notification appearance passing in an instance of `RadarTrackingOptionsForegroundService`. Only use a foreground service for use cases that Google Play allows, such as trips or user-initiated location sharing, not geofencing. See [foreground services and Google Play policy](/sdk/android#foreground-services-and-google-play-policy). * **`text`**: Determines the notification text. Defaults to `"Location tracking started"`. * **`title`**: Determines the notification title. Optional. * **`icon`**: Determines the notification icon via Android's identifier for the resource (e.g., `2131558400`). Optional, defaults to `iconString`. Deprecated in Android SDK [3.8.14](https://github.com/radarlabs/radar-sdk-android/releases/tag/3.8.14). * **`iconString`**: Determines the notification icon, like `R.drawable.ic_your_icon`. Optional, defaults to `applicationContext.applicationInfo.icon`. * **`iconColor`**: Determines the color of the notification icon. Optional. * **`updatesOnly`**: Determines when to show the notification. Use `false` to show the notification always, use `true` to show the notification only during location updates. Optional, defaults to `false`. * **`activity`**: Determines the activity to start when the notification is tapped, like `"com.yourapp.MainActivity"`. Optional. * **`importance`**: Determines the importance of the notification, one of `android.app.NotificationManager.IMPORTANCE_*`. Optional, defaults to `android.app.NotificationManager.IMPORTANCE_DEFAULT`. * **`id`**: Determines the id of the notification. Optional, defaults to `20160525`. * **`channelName`**: Determines the name of the notification channel. Optional, defaults to `"Location Services"`. ```kotlin Kotlin theme={null} Radar.setForegroundServiceOptions(RadarTrackingOptions.RadarTrackingOptionsForegroundService( text="Text", title="Title", iconString="your_icon_name", updatesOnly=true, )) ``` ```javascript React Native theme={null} Radar.setForegroundServiceOptions({ text: "Text", title: "Title", iconString: 'your_icon_name', updatesOnly: true, }); ``` ### Android presets * **`RadarTrackingOptions.CONTINUOUS`**: Updates about every 30 seconds while moving or stopped. Starts a foreground service. Moderate battery usage. Intended for trips and live tracking, not geofencing. See [foreground services and Google Play policy](/sdk/android#foreground-services-and-google-play-policy). * **`RadarTrackingOptions.RESPONSIVE`**: Updates about every 2.5 minutes while moving and shuts down when stopped to save battery. Once stopped, the device will need to move more than 100 meters to wake up and start moving again. Low battery usage, but may exceed Android vitals bad behavior thresholds for [excessive wakeups](https://developer.android.com/topic/performance/vitals/wakeup.html) and [excessive wi-fi scans](https://developer.android.com/topic/performance/vitals/bg-wifi.html). * **`RadarTrackingOptions.EFFICIENT`**: Updates as fast as every 6 minutes while moving and periodically when stopped. Once stopped, the device will need to move more than 100 meters and wait for at least 15 minutes to wake up and start moving again. Lowest battery usage and will not exceed Android vitals bad behavior thresholds. | Option | Efficient | Responsive | Continuous | | - | - | - | - | | **`desiredStoppedUpdateInterval`** | `3600` | `0` | `30` | | **`fastestStoppedUpdateInterval`** | `1200` | `0` | `30` | | **`desiredMovingUpdateInterval`** | `1200` | `150` | `30` | | **`fastestMovingUpdateInterval`** | `360` | `30` | `30` | | **`desiredSyncInterval`** | `140` | `20` | `20` | | **`desiredAccuracy`** | `MEDIUM` | `MEDIUM` | `HIGH` | | **`stopDuration`** | `140` | `140` | `140` | | **`stopDistance`** | `70` | `70` | `70` | | **`startTrackingAfter`** | `null` | `null` | `null` | | **`stopTrackingAfter`** | `null` | `null` | `null` | | **`replay`** | `STOPS` | `STOPS` | `NONE` | | **`sync`** | `ALL` | `ALL` | `ALL` | | **`useStoppedGeofence`** | `false` | `true` | `false` | | **`stoppedGeofenceRadius`** | `0` | `100` | `0` | | **`useMovingGeofence`** | `false` | `true` | `false` | | **`movingGeofenceRadius`** | `0` | `100` | `0` | | **`syncGeofences`** | `true` | `true` | `true` | | **`syncGeofencesLimit`** | `10` | `10` | `0` | | **`foregroundServiceEnabled`** | `false` | `false` | `true` | | **`beacons`** | `false` | `false` | `false` | # Web SDK Source: https://docs.radar.com/sdk/web Install and integrate the Radar Web SDK to add location tracking, geocoding, maps, and address autocomplete to your website. This is the documentation for the Radar Web SDK. The source can be found on GitHub [here](https://github.com/radarlabs/radar-sdk-js). Or, see the `radar-sdk-js` package on npm [here](https://www.npmjs.com/package/radar-sdk-js). ## Install In an HTML page, add the SDK script: ```html theme={null} ``` If you use Maps or Autocomplete UI, add the corresponding plugin scripts: ```html theme={null} {/* maps plugin (auto-registers) */} {/* autocomplete plugin (auto-registers) */} ``` In a web app, install the package from npm: ```bash theme={null} npm install radar-sdk-js ``` If you use Maps or Autocomplete UI, install the corresponding plugins: ```bash theme={null} # maps (requires maplibre-gl as a peer dep) npm install @radarlabs/plugin-maps maplibre-gl # autocomplete npm install @radarlabs/plugin-autocomplete ``` Then, import the library and register any plugins: ```javascript theme={null} import Radar from 'radar-sdk-js'; // for maps import { createMapsPlugin } from '@radarlabs/plugin-maps'; import '@radarlabs/plugin-maps/dist/radar-maps.css'; Radar.registerPlugin(createMapsPlugin()); // for autocomplete import { createAutocompletePlugin } from '@radarlabs/plugin-autocomplete'; import '@radarlabs/plugin-autocomplete/dist/radar-autocomplete.css'; Radar.registerPlugin(createAutocompletePlugin()); ``` ## Setup ### Initialize Initialize the library with your publishable API key, found on the [Settings page](https://dashboard.radar.com/settings): ```javascript theme={null} Radar.initialize('prj_live_pk_...'); ``` > [!NOTE] > > You must initialize the library before calling any other functions. Optionally, you can specify configuration options: The initialize call takes an optional second argument that is an object with additional configuration options. ```javascript theme={null} Radar.initialize('prj_live_pk_...', { /* custom options here */}); ``` Available options include: | Name | Default | Possible values | Description | | - | - | - | - | | `logLevel` | `error` | `none`, `info`, `warn`, `error` | Determines the log level for console logging. Defaults to `error` when using a test publishable key. | | `cacheLocationMinutes` | `null` | number | Determines whether to reuse previous location updates. A cache ttl in minutes. If `null` or `0`, will always request a new location. | | `locationMaximumAge` | `null` | number | Determines whether to use old browser locations. A maximum age in milliseconds. If `null` or `0`, will always request a new location. See [getCurrentPosition options()](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/getCurrentPosition). | | `locationTimeout` | `30000` | number | The number of milliseconds to wait for a location update before an error is thrown. Defaults to 30 seconds. | | `networkTimeoutInterval` | `10` | number | The number of seconds to wait for a network request before an error is thrown. | | `trackVerifiedAutoFailover` | `false` | `true`, `false` | Determines whether `Radar.trackVerified()` should automatically retry on the secondary verified host when the primary verified host fails. Requires `@radarlabs/plugin-fraud`. | | `desiredAccuracy` | `high` | `high`, `medium`, `low` | Determines the desired accuracy of location updates. Note that higher accuracy can result in slower response times. | | `debug` | `false` | `true`, `false` | Determines whether to include the raw API response body on results, as `response`. Defaults to `true` when using a test publishable key. | ## Geofencing ### Identify user To identify the user when logged in, call: ```javascript theme={null} Radar.setUserId(userId); ``` where `userId` is a stable unique ID for the user. To set an optional dictionary of custom metadata for the user, call: ```javascript theme={null} Radar.setMetadata(metadata); ``` where `metadata` is a JSON object with up to 16 keys and values of type string, boolean, or number. Finally, to set an optional description for the user, displayed in the dashboard, call: ```javascript theme={null} Radar.setDescription(description); ``` where `description` is a string. You only need to call these functions once, as these settings will be persisted across browser sessions. Learn more about when Radar creates new user records [here](/faqs#what-is-a-unique-user-when-does-radar-create-a-new-user-record). ### Foreground tracking Once you have initialized the SDK and the user has granted permissions, you can track the user's location. The SDK uses the [HTML5 geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/Using_geolocation) to determine the user's location. To track the user's location, call: ```javascript theme={null} Radar.trackOnce() .then((result) => { const { location, user, events } = result; // do something with location, user, or events }) .catch((err) => { // handle error }); ``` If the request fails, `err` will be one of: * **`RadarPublishableKeyError`**: SDK not initialized * **`RadarLocationPermissionsError`**: location permissions not granted * **`RadarLocationError`**: location services error or timeout (10 seconds) * **`RadarTimeoutError`**: network timeout (10 seconds) * **`RadarBadRequestError`**: bad request (missing or invalid params) * **`RadarUnknownError`**: unauthorized (invalid API key) * **`RadarPaymentRequiredError`**: payment required (organization disabled or usage exceeded) * **`RadarForbiddenError`**: forbidden (insufficient permissions or no beta access) * **`RadarNotFoundError`**: not found * **`RadarRateLimitError`**: too many requests ([rate limit](/api#track) exceeded) * **`RadarServerError`**: internal server error * **`RadarUnknownError`**: unknown error If the error is the result of a failed API call, `err` will include an HTTP response code and the API response body: ```javascript theme={null} err.code; // HTTP response code err.response; // API response body ``` ### Manual tracking Alternatively, you can manually update the user's location with any location by calling: ```javascript theme={null} Radar.trackOnce({ latitude: 39.2904, longitude: -76.6122, accuracy: 65 }).then((result) => { const { location, user, events } = result; // do something with location, user, or events }).catch((err) => { // handle error }); ``` ## Maps ### Geocoding With the [forward geocoding API](/api#forward-geocode), geocode an address, converting address to coordinates: ```javascript theme={null} Radar.forwardGeocode({ query: '841 broadway, new york, ny' }) .then((result) => { const { addresses } = result; // do something with addresses }) .catch((err) => { // handle error }); ``` With the [reverse geocoding API](/api#reverse-geocode), reverse geocode a location, converting coordinates to address: ```javascript theme={null} Radar.reverseGeocode({ latitude: 40.783826, longitude: -73.975363 }) .then((result) => { const { addresses } = result; // do something with addresses }) .catch((err) => { // handle error }); ``` With the [IP geocoding API](/api#ip-geocode), geocode the device's current IP address, converting IP address to city, state, and country: ```javascript theme={null} Radar.ipGeocode() .then((result) => { const { ip, address, proxy } = result; // do something with results }) .catch((err) => { // handle error }); ``` ### Search With the [autocomplete API](/api#autocomplete), autocomplete partial addresses and place names, sorted by relevance: ```javascript theme={null} Radar.autocomplete({ query: '841 bro', near: { latitude: 40.783826, longitude: -73.975363 }, limit: 10 }).then((result) => { const { addresses } = result; // do something with addresses }).catch((err) => { // handle error }); ``` With the [geofence search API](/api#search-geofences), search for geofences near a location, sorted by distance: ```javascript theme={null} Radar.searchGeofences({ radius: 1000, tags: ['venue'], limit: 10 }).then((result) => { const { geofences } = result; // do something with geofences }).catch((err) => { // handle error }); ``` With the [places search API](/api#search-places), search for places near a location, sorted by distance: ```javascript theme={null} Radar.searchPlaces({ near: { latitude: 40.783826, longitude: -73.975363 }, radius: 1000, chains: ['starbucks'], limit: 10 }).then((result) => { const { places } = result; // do something with places }).catch((err) => { // handle error }); ``` With the [address validation API](/api#validate-an-address), validate a structured address in the US or Canada: ```javascript theme={null} Radar.validateAddress({ addressLabel: '841 BROADWAY', city: 'NEW YORK', stateCode: 'NY', postalCode: '10003', countryCode: 'US', }).then((response) => { const { address, result } = response; // do something with validated address result }).catch((err) => { // handle error }); ``` ### Distance With the [distance API](/api#distance), calculate the travel distance and duration between two locations: ```javascript theme={null} Radar.distance({ origin: { latitude: 40.78382, longitude: -73.97536 }, destination: { latitude: 40.70390, longitude: -73.98670 }, modes: [ 'foot', 'car' ], units: 'imperial' }).then((result) => { const { routes } = result; const { geodesic, foot, bike, car } = routes; // do something with distance result }).catch((err) => { // handle error }); ``` ### Matrix With the [matrix API](/api#matrix), calculate the travel distances and durations between multiple origins and destinations for up to 25 routes: ```javascript theme={null} Radar.matrix({ origins: [{ latitude: 40.70390, longitude: -73.98690 }], destinations: [{ latitude: 40.70390, longitude: -73.98690 }, { latitude: 40.73237, longitude: -73.94884 }], mode: 'car', units: 'imperial' }).then((result) => { const { origins, destinations, matrix } = result; matrix.forEach((matrixResult) => { const { distance, duration, originIndex, destinationIndex } = matrixResult; // do something with matrix result }); }).catch((err) => { // handle error }); ``` ## Maps and UI kits The React Native SDK also has UI components for maps and address autocomplete. Learn more in the [Maps Platform documentation](/maps/overview). ## Request IDs Every API response includes an `X-Radar-Request-ID` header with a unique identifier for the request. The Web SDK surfaces this identifier as `meta.requestId` on the API response body. If a request fails, get the request ID from the API response body on the error: ```javascript theme={null} Radar.trackOnce() .catch((err) => { const requestId = err.response?.meta?.requestId; }); ``` When the SDK is initialized with the `debug` option enabled, the API response body is also included on successful results, as `response`: ```javascript theme={null} Radar.initialize('prj_live_pk_...', { debug: true }); Radar.trackOnce() .then((result) => { const requestId = result.response?.meta?.requestId; }); ``` If you contact support about a specific API call, include the request ID. The request ID allows us to quickly find and debug the exact request. ## Support Have questions? We're here to help! Contact us at [radar.com/support](https://radar.com/support). # Tutorials Source: https://docs.radar.com/tutorials Step-by-step tutorials and quickstarts for building with Radar's SDKs and APIs. Get to `Hello, world!` faster with tutorials and quickstarts! Or, get started with the [documentation overview](https://docs.radar.com/), [SDK reference](https://docs.radar.com/sdk), or [API reference](https://docs.radar.com/api). ## Tutorials * [**Building a Live Activity for trip tracking**](/tutorials/building-a-live-activity-for-trip-tracking) * Create a Live Activity with [Trips](/geofencing/trips) data and the [Radar iOS SDK](/sdk/ios). * [**Building a web store locator**](https://docs.radar.com/tutorials/building-a-web-store-locator) * Use [Radar Maps](https://docs.radar.com/maps/maps), [IP geocoding](https://docs.radar.com/api#ip-geocode), [autocomplete](https://docs.radar.com/maps/autocomplete), and [matrix API](https://docs.radar.com/api#matrix) to build a web store locator. * [**Building a workforce management experience**](https://docs.radar.com/tutorials/building-a-workforce-management-experience) * Use [geofencing](https://docs.radar.com/geofencing/geofences), [trip tracking](https://docs.radar.com/geofencing/trips), and [route matching](https://docs.radar.com/api#route-match) to power your workforce management experience * [**Building an on-premise mode**](/tutorials/building-an-on-premise-mode) * Use the [iOS](/sdk/ios), [Android](/sdk/android), [Web](/sdk/web), or [React Native](/sdk/react-native) SDK with [geofences](/geofencing/geofences) to build an in-app experience when a user is in a geofence. * [**Showing a notification when a user enters a geofence**](/tutorials/showing-a-notification-when-a-user-enters-a-geofence) * Use the [iOS SDK](/sdk/ios) and [geofences](/geofencing/geofences) to show a notification when a user enters a geofence. * [**Building an app with location-enabled curbside pickup**](/tutorials/building-an-app-with-location-enabled-curbside-pickup) * Use the [iOS SDK](/sdk/ios), [geofences](/geofencing/geofences), and [trip tracking](/geofencing/trips) to build a "McRadar's" app with location-enabled curbside pickup. * [**Building a delivery tracking app**](/tutorials/building-a-delivery-tracking-app) * Use [trip tracking](/geofencing/trips) to build an iOS delivery tracking app with live location, ETAs, and update notifications. * [**Building a store locator on iOS**](/tutorials/building-a-store-locator-on-ios) * Use the [iOS SDK](/sdk/ios), [forward geocode API](/api#forward-geocode), and [geofence search API](/api#search-geofences) to build a store locator with a map. * [**Localizing a website based on current country or city**](/tutorials/localizing-a-website-based-on-current-country-or-city) * Use the [web SDK](/sdk/web) and [IP geocoding API](/api#ip-geocode) to localize a website based on current country or city. * [**Logging and analyzing where conversions occur**](/tutorials/logging-and-analyzing-where-conversions-occur) * Log conversions using the [iOS](/sdk/ios) and [Android](/sdk/android) SDKs to analyze the location context of key customer interactions. * [**Migrating from Google Maps**](/tutorials/migrate-from-google-maps) * Migrate Google Maps powered features in your application to use Radar Maps and our full suite of enterprise-ready geocoding, search, and routing APIs. * [**Displaying Radar Maps with React Native**](/tutorials/displaying-radar-maps-with-react-native) * Display Radar Maps with Radar's React Native SDK. * [**Displaying Radar Maps with Flutter**](/tutorials/displaying-radar-maps-with-flutter) * Display Radar Maps with Radar's Flutter SDK. * [**Create a custom map style**](/tutorials/create-a-custom-map-style) * Create a custom maps style with Radar Maps Studio. * [**Building Place-based push notifications**](/tutorials/building-place-based-push-notifications) * Use the Radar SDKs and [Places](/geofencing/places) to power a location triggered experience. ## Support Have questions or ideas for tutorials? Contact us at [radar.com/support](https://radar.com/support). # Waypoint Source: https://docs.radar.com/waypoint Use the Radar Waypoint apps for iOS and Android to test Radar before integrating the SDK, or to compare against your own implementation. You can use our Radar Waypoint apps for iOS and Android to test Radar before integrating the [SDK](/sdk/ios), or to test your implementation of Radar side-by-side with a complete implementation. > [card] [Download on the App Store](https://apps.apple.com/us/app/radar-waypoint/id6449200427) > [card] [Download on Google Play](https://play.google.com/store/apps/details?id=com.radarwaypoint) ## Instructions To get started, you'll need a Radar account. Don't have a Radar account yet? [Sign up](https://radar.com/signup) first. 1. Download the app. 2. Open the app and enter your email address associated with the Radar account. 3. Copy the 6 digit code sent to your email into the app. 4. Grant notification permissions and location permissions by following the onboarding prompts. 5. After completing onboarding, you should see your location on the map in the Waypoint app along with your user on the [Users page](https://dashboard.radar.com/geofencing/users) in the dashboard. If you are in a geofence or at a place, you will see events in the app and see events on the [Events page](https://dashboard.radar.com/geofencing/events) in the dashboard. 6. To generate a new track call in the foreground, tap the refresh button! 7. To track in the background, move more than 100 meters! > [!NOTE] > > Note that location updates may be delayed significantly by [Android Doze Mode](https://developer.android.com/training/monitoring-device-state/doze-standby) and App Standby, [iOS Low Power Mode](https://support.apple.com/en-us/101604), or if the device has connectivity issues, low battery, or wi-fi disabled. 8. To try out different presets, open the *Settings* screen. Then, select the *Tracking Options* preset to use, one of *Efficient*, *Responsive*, or *Continuous*. Learn about [iOS tracking presets](/sdk/tracking#ios-presets) and [Android tracking presets](/sdk/tracking#android-presets). You can also set *Custom Tracking Options* via [Remote SDK Configurations](/sdk/remote-configuration). Manage the notifications you want to receive, including *Events* (events received from Radar), *Locations* (location updates sent to Radar), and *Errors* (network, location, and permissions errors). ![Android Ios Waypoint Pn](https://mintcdn.com/radarlabs/f_3pYOJsnyPEyNca/images/android-ios-waypoint.png?fit=max\&auto=format\&n=f_3pYOJsnyPEyNca\&q=85\&s=3869c82d3c5726fb5bb0a095663939b4) ## Examples ### Testing on-premise mode 1. To get started, make sure you've opted-in to foreground or "while in use" permissions and notifications are enabled. Click on the settings icon on the top right to ensure Waypoint is configured correctly (See image A below). 2. Create [geofences](/geofencing/geofences#dashboard) in Radar. 3. Open Waypoint and navigate to the "My Location" tab. You should see "Not in a geofence". Travel to a configured geofence (See image B below). 4. After entering the geofence, open Waypoint, navigate to the "My Location" tab. Waypoint should display "Welcome to \". You should also receive a notification "Entered geofence \" (See image C below). > [card] Image A > [card] Image B > [card] Image C ### Testing Trips 1. To get started, make sure you've opted-in to foreground or "While in use" permissions and notifications are enabled. (See image A below) 2. Create [geofences](/geofencing/geofences#dashboard) in Radar. 3. Once you open Waypoint, you should see geofences nearby you. Click "Go" to start a trip to one of the configured geofences. Select your mode of travel from the options provided. Start navigating to your destination geofence. (See image B below) 4. Events & notifications to expect as you travel to the destination geofence (See image C below): * *user.started\_trip* -> "Started trip" notification from Waypoint * *user.approaching\_trip\_destination* -> "Approaching destination" notification from Waypoint * Note, *approaching threshold* can be configured on the Radar dashboard. Navigate to "Settings" on top right -> "Trips" on the left sidebar -> "Approaching threshold (minutes)" * *user.arrived\_at\_trip\_destination* / *user.entered\_geofence* -> "Arrived" 5. Once you've arrived at the geofence, you can click either the "x" or button on the bottom of the screen. (See image D below) * *user.stopped\_trip* -> "Stopped trip" notification from Waypoint 6. Analyze trip updates/events on Radar dashboard. Navigate to "Geofencing" -> "Trips" -> click on trip you'd like to analyze -> "Debugger" on top right to view the trip data. (See image E below) > [card] Image A > [card] Image B > [card] Image C1 > [card] Image C2 > [card] Image C3 > [card] Image D > [card] Image E ## Testing background mode 1. To get started, make sure you've opted-in to background or "Always allow" permissions and notifications are enabled. You'll have to navigate to your device settings to enable background tracking and toggle the "Background tracking" option in Waypoint. Click on the settings icon on the top right to ensure Waypoint is configured correctly. (See image A below) 2. Create [geofences](/geofencing/geofences#dashboard) in Radar. 3. Open Waypoint and navigate to "My Location" tab. You should see "Not in a geofence". Travel to a configured geofence. (See image B below) 4. After entering the geofence, you should receive an entry notification while Waypoint is closed and/or your device is shut off. Once you open Waypoint, navigate to "My Location" tab. As shown below, Waypoint should show "Welcome to \". (See image C below) > [card] Image A > [card] Image B > [card] Image C ## Testing Beacons Note: You can test beacons in either foreground or background mode. 1. To get started, ensure the following settings are enabled (See image A below): * Opt-in to foreground or background permissions. * Ensure notifications are enabled. * Once you click on the settings icon on the top right, you can toggle "Beacons" on. This should prompt you to allow Bluetooth permissions. Alternatively, use [remote SDK configuration](/sdk/remote-configuration) & set *beacons* to *true*. Once done, you should see the "Beacons" toggle enabled within the Waypoint settings page. 2. Create [beacons](/geofencing/beacons) in Radar. 3. Open Waypoint and navigate to "My Location" tab. You should see "No Beacons Found". (See image B below) 4. After entering the beacon radius, open Waypoint, navigate to "My Location" tab. As shown below, Waypoint should show "\" under the "Beacons" section. You should also receive a notification "Entered beacon \". (See image C below) > [card] Image A > [card] Image B > [card] Image C ## Support Have questions or difficulties with Waypoint? Contact us at [radar.com/support](https://radar.com/support).