Policies
A policy is a rule that turns checks into a verdict. It's a tree of conditions plus a list of verdicts: when the conditions match an evaluation, every verdict runs and the terminal one answers the request.
Policies are the v3 replacement for v2 environments. Where v2 leaned on fixed environment thresholds, v3 lets you write your own AND/OR conditions over any check and pick the verdict to apply.
Anatomy of a policy
- Name and description: for your own reference in the dashboard.
- Type:
developmentorproduction. A development policy is evaluated only for traffic from a development API key, and a production policy only for production keys. That lets you test rules without touching live traffic. - Enabled: turn a policy on or off without deleting it.
- Event types: which actions the policy applies to: any mix of
login,signup,access, and your custom actions. - Conditions: a nested AND/OR tree of comparisons over checks, lists, and metadata.
- Verdicts: what happens when the conditions match. One terminal verdict answers the request, and list verdicts can run alongside it.
- Priority: decides which policy wins when more than one matches. The highest-priority match takes effect.
What a policy does when it matches
A policy carries a list of verdicts and runs all of them. They come in two kinds:
- Terminal verdicts:
allow,deny,challenge,review,suspend. These answer the request, so a policy can carry at most one. Whichever you pick becomes the evaluation's verdict. - List verdicts:
add_to_listandremove_from_list. These don't answer anything, so you can stack as many as you need on top of the terminal verdict.
That lets one rule do the whole job. "Deny this signup and put the fingerprint on the blocklist" is one policy, not two that have to keep the same conditions in sync.
A policy made only of list verdicts is still valid. It reports the list mutation as its verdict and your server honors the action.
What conditions can check
Condition fields line up with the check inventory, grouped by category:
- General:
always, which matches unconditionally. Use it when the policy should fire on every event of the selected trigger; in the dashboard builder this is the "Always match (no conditions)" option. - Device:
device_count,computer_device_count,tablet_device_count,mobile_device_count,device_id. - Network:
impossible_travel,is_new_ip,ip_country,ip_is_vpn,ip_is_proxy,ip_is_tor,ip_is_hosting,ip_user_count,concurrent_sessions. - User:
is_new_user,is_email_verified,is_phone_verified,is_identity_verified,user_age_days,is_suspended,in_list(see Lists),user_external_id,user_email,metadata. - Email:
email_is_disposable,email_is_webmail,email_is_invalid,email_is_accept_all. - Fingerprint:
is_new_fingerprint,fingerprint_user_count,fp_ip_user_count. - Velocity:
event_countover a sliding window. - Risk:
risk, whether a given risk was raised on the evaluation, andrisk_severity, how severe it came out. See matching on risks. - Device integrity (native SDKs):
jailbroken_ios,rooted_android,is_simulator,is_emulator,debugger_attached,ui_testing. - Visitor (web SDK):
visitor, whether the input came from ahuman, anai_agentorautomation;visitor_declared, whether the request carried an agent identity;visitor_verified, whether that identity was verified by signature. An evaluation with nothing to judge has no visitor, so a "not equals" condition matches it. See Bots. - Group:
group, the user's assigned group (if you use groups).
Matching on risks
Rupt scores every risk before it walks your policies, so a condition can act on the outcome instead of re-listing the checks behind it. Two fields cover it:
riskmatches when a risk was raised on the evaluation, whatever its severity. Useeq/neqwith one risk, orin/not_inwith several. A risk is referenced by its definition id (what the dashboard stores) or, for the built-ins, by its name:ato,fake_account,account_sharing,scraping,linked_accounts,bot,tampering,anti_fingerprinting,incognito. Custom risks match by id.risk_severitycompares the severity a risk came out at. The value is{ "risk": "<id or name>", "severity": "high" }; leaveriskout to look at every risk raised on the evaluation.gteandltecompare against the highest severity among the qualifying risks,eqmatches when any qualifying risk has exactly that severity. Severities ranklow<medium<high<maximum.
A severity condition never matches when no qualifying risk was raised: absence of risk is not a severity, so lte: low does not fire on a clean evaluation. A risk only fires on the actions its definition triggers on, so a risk condition on an action the risk never evaluates will never match; check the risk's trigger in the dashboard if a policy stays quiet.
Matching on a risk is the shortcut; the underlying checks remain available when you want a surgical rule.
How matching works
When an evaluation runs, Rupt walks every enabled policy whose type matches the calling API key's environment and whose event type matches the action, in priority order, and tests each one's conditions against the derived checks. The highest-priority match wins; ties break toward the older policy. Order your rules so the most specific ones sit above the broad catch-alls.
The winning policy runs every verdict it carries, and its terminal verdict becomes the evaluation's verdict. If nothing matches, the verdict is allow.
Practical guidance
- Start broad and narrow as you learn. A first
loginpolicy that challenges whenimpossible_travelis true catches a lot with very few false positives. - Reach for specific checks when you want a surgical rule: deny on
is_simulatorin native flows, or challenge oncedevice_countcrosses a threshold. - Match on a risk when you want the whole picture: challenge when
risk_severityforatois at leasthigh, or review when any risk reachesmaximum. - Keep development and production policies separate by
type. The dashboard shows both side by side, and only the set matching the calling key is evaluated. - An
alwayscondition turns a policy into a catch-all for its trigger. Give it a lower priority than your specific rules so they keep winning.
- Need help? Contact support.
- Want to see Rupt in action? Request a demo.
- Questions? Talk to sales.
- Check out our changelog.
- Check our status page.
- LLM? Read llms.txt.