Core conceptsRules

Rules

Go beyond toggles with a safe, composable boolean grammar over every signal field — compiled to an AST, never eval'd.

Toggles cover the common case. Rules cover the rest: when you want a decision to depend on a specific path, country, detection ID, or behavioral threshold, you write a rule. A rule is a boolean expression over signal fields plus an action to take when it matches.

Rules are evaluated before toggles in the resolution order: the first active rule that matches and carries a terminating action (block/challenge) wins, and its name appears in the verdict reason.

Safety

Rule expressions are a constrained grammar, not code. At save time each expression is parsed and validated into an abstract syntax tree (AST); the verdict path walks the stored AST. There is no eval, no method calls, no code execution — an invalid or out-of-grammar expression is rejected with a 422 when you create the rule, never at evaluation time.

Grammar

expr      := orExpr
orExpr    := andExpr ( "OR" andExpr )*
andExpr   := unary  ( "AND" unary )*
unary     := "NOT" unary | "(" expr ")" | predicate
predicate := comparison | boolField
comparison:= field op value
boolField := verified_bot | js_detection.passed | static_resource   (bare truthiness)
op        := "==" | "!=" | "<" | "<=" | ">" | ">=" | "in" | "not in"
value     := number | "quoted string" | "[" list "]" | true | false | null

Allow-listed fields

score, band, verified_bot, verified_bot_category, js_detection.passed, static_resource, detection_ids, path, ip, country, ua, behavioral.mouse_entropy, behavioral.scroll_velocity, behavioral.visibility_changes, behavioral.first_input_delay_ms.

Any field outside this list is rejected. See Signals & fields for each field's meaning and type.

Operators by type

Field typeFieldsOperators
Numericscore, behavioral.*== != < <= > >=
Booleanverified_bot, js_detection.passed, static_resource== != (or bare)
Stringpath, country, ua, verified_bot_category, band== != in not in
Arraydetection_idsin / not in (membership)

Examples

score < 30 AND path == "/login" AND NOT verified_bot
→ block

detection_ids in [50331648, 50331651] AND NOT verified_bot
→ block

band == "likely_automated" AND country in ["RU", "CN"]
→ challenge

behavioral.mouse_entropy < 0.2 AND behavioral.visibility_changes == 0
→ challenge

Creating a rule

Send the expression text and an action. Botect compiles and validates it before storing.

curl -X POST https://api.botect.ai/v1/projects/123/rules \
  -H "Authorization: Bearer YOUR_ACCOUNT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Protect login from bots",
    "expression": "score < 30 AND path == "/login" AND NOT verified_bot",
    "action": "block",
    "sort_order": 10
  }'

See Create a rule for the full request and response. Rules are listed in sort_order (ascending) and evaluated in that order.

Always guard enforcement rules with AND NOT verified_bot unless you specifically intend to act on verified crawlers — otherwise a misconfigured rule could block Google or an AI crawler you want indexing your site.

Evaluation

When a verdict is read, active rules run in sort_order. The first rule whose expression matches and whose action is terminating (block/challenge) wins; log/delay/allow actions follow their own semantics and may not stop evaluation. The matched rule populates the verdict reason (and the recorded block) so you can always trace why a request was acted on.

Changing a rule busts the project's verdict cache so it takes effect within the cache window.