Skip to main content
The SDK reports signals about the device the capture was made on. device_policy decides what each signal does to the decision. These checks apply to every transaction type — a BIOMETRIC_ONLY step-up is evaluated for device integrity exactly like a full onboarding.
Every field takes REJECT, WARN or IGNORE.

Fields

string
default:"REJECT"
The device is rooted, jailbroken, or running under a debugger.Emits COMPROMISED_DEVICE. The strongest signal in this group: root access lets an attacker feed synthetic camera frames into the capture. Keep this at REJECT unless you have a specific reason not to.
string
default:"WARN"
The device has developer mode enabled.Emits DEVELOPER_MODE_ENABLED. Weak on its own — plenty of ordinary users enable it and forget. WARN is the sensible default; it records the signal without punishing a legitimate user for a setting they toggled a year ago.
string
default:"REJECT"
The capture was made on an emulator or simulator.Emits EMULATOR_DETECTED. A real person photographing a real document does not do it from an emulator. Set this to IGNORE only while you test on an emulator yourself, and remember to change it back before real users arrive.
string
default:"WARN"
The connection is routed through a VPN, a proxy or Tor.Emits VPN_OR_PROXY_DETECTED. Consumer VPNs are common and often corporate policy, so REJECT here will cost you legitimate users. Consider WARN unless your risk model specifically calls for it.
string
default:"REJECT"
The reported GPS location is simulated.Emits MOCK_LOCATION_DETECTED. Unlike developer mode, mock location has essentially no innocent explanation on a consumer device.
string
default:"WARN"
The country derived from GPS does not match the country derived from the IP address.Emits GEO_IP_MISMATCH. Legitimate causes are common — travellers, border regions, carrier routing that exits in another country — so this is a weak signal on its own.

When a signal is missing

A policy can only act on a signal the device actually reported. Some are unavailable by platform (root_detected is meaningless on iOS), and location signals depend on the user granting permission. When a policy is active (not IGNORE) but its signal is missing, chmod emits a WARN issue rather than silently passing the check: These never change the decision — they tell you a rule you configured did not get the chance to run.

GPS policies need location permission

on_gps_mock_location and on_gps_ip_location_mismatch depend on GPS coordinates, which the user has to grant. That permission is controlled by the SDK configuration, not by this policy:
If you enable a GPS policy but the SDK never asks for location, chmod emits CONFIG_GPS_POLICY_WITHOUT_PERMISSION — a warning that your two halves disagree. When location was never requested or the user denied it, geolocation is null in the result and you get one of: Both are INFO. Neither changes the decision.
Asking for location has a real cost: it is an extra permission prompt early in the flow, and some users drop out there. Enable it when the GPS policies genuinely matter to you, not by default.

Where the signals appear

Every reported signal comes back in the result under result_data.metadata, whatever the decision was:
This is why device issues carry no details: everything that triggered them is already in metadata, so you can audit a decision without a second call.