Skip to main content

Fraud

With Fraud, you can detect GPS spoofing, proxy and VPN usage, and device tampering.

Along with Regions, you can also detect a user's country and state and mark specific regions as allowed or denied to comply with regulations.

Together, Fraud and Regions provide the following user context:

{  "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": "RI",    "name": "Rhode Island",    "passed": false,    "allowed": true,    "distanceToBorder": 192.3,    "inBufferZone": true,    "inExclusionZone": false  }}

Quickstart#

First, sign up for Radar and get an API key.

Then, enable Fraud on the Settings page.

From there, integrate the SDK, complete the steps below, and call Radar.trackVerified() or Radar.trackVerifiedToken(). 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, current place, or current country and state.

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() or Radar.trackVerifiedToken() instead. Radar will collect a variety of fraud signals and perform fraud and jurisdiction checks, calculating flags that you can use for fraud detection and geo-compliance in your app.

Fraud flags#

If you call Radar.trackVerified() or Radar.trackVerifiedToken(), 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).
  • 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 according to the Play Integrity API on Android or App Attest service on iOS.
  • inaccurate: Indicates whether the user's location accuracy is too low to pass verification.
  • sharing: Indicates whether the user is screen sharing (e.g., using TeamViewer).
  • proxy: Indicates whether the user's IP address is a known proxy or VPN.
  • verified: Indicates whether the request was made with SSL pinning configured successfully.

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.

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#

You can also manually block a user using the Mark as Blocked button on the user detail page.

If a user is blocked, user.fraud.blocked = true and user.fraud.passed = false, regardless of whether the user passes fraud checks.

Allowed states and countries#

With Regions, gaming customers can mark specific jurisdictions (i.e., countries and states) as allowed or denied to comply with regulations. For example, a sportsbook or daily fantasy sports app may only be allowed to operate in specific US states.

If you call Radar.trackVerified() or Radar.trackVerifiedToken(), 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.

Platform-specific configuration#

Android#

Initialize SDK#

To support the sharing flag on Android, pass fraud = true to Radar.initialize().

Radar.initialize(  context = this,  publishableKey = "prj_test_pk...",  fraud = true)

Play Integrity API#

To support the compromised flag on Android, enable the Play Integrity API on the Settings page.

If the user's device or app does not meet basic integrity checks, 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:

dependencies {    implementation 'com.google.android.play:integrity:1.2.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 version="1.0" encoding="utf-8"?><network-security-config>    <!-- for React Native -->    <domain-config cleartextTrafficPermitted="true">        <domain includeSubdomains="true">localhost</domain>    </domain-config>
    <!-- for SSL pinning -->    <domain-config cleartextTrafficPermitted="false">        <domain includeSubdomains="true">api-verified.radar.io</domain>        <pin-set>            <pin digest="SHA-256">15ktYXSSU2llpy7YyCgeqUKDBkjcimK/weUcec960sI=</pin>            <pin digest="SHA-256">15ktYXSSU2llpy7YyCgeqUKDBkjcimK/weUcec960sI=</pin>        </pin-set>    </domain-config></network-security-config>

Learn more about Network Security Configuration on Android.

iOS#

App Attest#

To support the compromised flag on iOS, enable App Attest and configure a list of valid App IDs (e.g., A1B2C3D4E5.com.yourapp.app1,A1B2C3D4E5.com.yourapp.app2) on the Settings page.

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:

<key>NSAppTransportSecurity</key><dict>    <key>NSAllowsArbitraryLoads</key>    <false/>    <key>NSPinnedDomains</key>    <dict>        <key>api-verified.radar.io</key>        <dict>            <key>NSIncludesSubdomains</key>            <true/>            <key>NSPinnedLeafIdentities</key>            <array>                <dict>                    <key>SPKI-SHA256-BASE64</key>                    <string>15ktYXSSU2llpy7YyCgeqUKDBkjcimK/weUcec960sI=</string>                </dict>                <dict>                    <key>SPKI-SHA256-BASE64</key>                    <string>15ktYXSSU2llpy7YyCgeqUKDBkjcimK/weUcec960sI=</string>                </dict>            </array>        </dict>    </dict></dict>

Learn more about SSL pinning on iOS.

Web and desktop#

The web SDK supports the mocked, proxy, and jumped flags with Radar.trackOnce().

On desktop, if the end user installs the Radar Verify Mac or Windows app, the web SDK also supports the sharing flag with Radar.trackVerified(). If Radar.trackVerified() returns ERROR_DESKTOP_APP, it means the Radar Verify app is not running.

Verifying user locations#

Once the above configuration is complete, you can verify a user's location with just a few lines of code.

Manual tracking#

Standard callback#

Call Radar.trackVerified() on app open, periodically, or before sensitive transactions. Then, check user.fraud.passed, user.state.allowed, and/or user.country.allowed to allow or deny access.

Radar.trackVerified { (status, location, events, user) in  if user?.fraud?.passed == true &&    user?.country?.allowed == true &&    user?.state?.allowed == true {    // allow access to feature  } else {    // deny access to feature, show error message  }}

Then, look up the user and check fraud flags server-side for an additional layer of verification.

curl "https://api.radar.io/v1/users/56db1f4613012711002229f4" \  -H "Authorization: prj_live_sk_..."

Token callback#

Alternatively, set a JSON Web Token (JWT) secret key on the Settings page.

Then, call Radar.trackVerifiedToken() to get a signed JWT containing a payload with user.fraud, user.state, and user.country instead. Send the JWT to your server to verify and decode it.

Radar.trackVerifiedToken { (status, token) in  // send token to server}

Finally, verify and decode the JWT server-side using your secret key and a JWT library. If the token is valid, check user.fraud.passed, user.state.passed, and/or user.country.passed in the payload to allow or deny access.

For example, in JavaScript:

const jwt = require('jsonwebtoken');
try {    const decoded = jwt.verify(token, SECRET_KEY);    const { user } = decoded;    // token is valid, check user.fraud, user.state, user.country to allow or deny access} catch(err) {    // token is invalid, deny access to feature, show error message}

Automatic tracking#

In addition to manually calling Radar.trackVerified() or Radar.trackVerifiedToken(), you can also call Radar.startTrackingVerified() and Radar will automatically verify the user's location at regular intervals or on network connection changes.

For example, to automatically verify the user's location every 5 minutes (300 seconds), without ranging beacons, and with token callbacks:

Radar.setVerifiedDelegate(delegate)
Radar.startTrackingVerified(token: true, interval: 300, beacons: false)
// in delegate
func didUpdateToken(_ token: String) {  // send token to server}

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.