Humanize policy (3-layer model)¶
Human-like interaction (cursor movement, typing cadence, scroll bursts) is the single
biggest anti-detection lever after the fingerprint itself. Ghostvault exposes a
3-layer model for deciding whether a given gv_fill_input / gv_click_element call
is humanized, so you can tune it from "let the agent decide" all the way up to "force it
on everywhere, agent cannot disable".
The three layers¶
| Layer | Where it lives | Granularity | Example |
|---|---|---|---|
| Layer 1 — per-call | The humanize arg on each tool |
One call | gv_fill_input(..., humanize=True) |
| Layer 2 — per-account | The account's humanize_policy advanced key |
One account | gv_update_account_config(..., reset_keys=["humanize_policy"]) |
| Layer 3 — global | GHOSTVAULT_HUMANIZE_POLICY env var |
Whole server | .env: GHOSTVAULT_HUMANIZE_POLICY=always |
Layer 1 — the agent decides (per-call)¶
Every interactive tool (gv_fill_input, gv_click_element, gv_scroll) takes a
humanize argument. The tool's own docstring contains a Decision Guide that tells
the agent when to turn it on — for example, the gv_fill_input guide says:
- Google / SSO login forms (email, password) → ALWAYS
- Captcha-protected form fields → ALWAYS
- Banking / payment forms → ALWAYS
- 2FA / OTP code fields → optional
- Search boxes on trusted sites → optional
This is the default mode (GHOSTVAULT_HUMANIZE_POLICY=off) and preserves backward
compatibility — the agent is fully in charge of every call.
Layer 2 — per-account policy¶
Set an account's humanize_policy advanced key to lock down behavior for that account
regardless of what the agent passes:
await gv.update_account_config(
account_id,
# "off" | "recommended" | "always"
device_config=None, # not used here
reset_keys=None,
# ... the trick: humanize_policy lives in the GHOSTVAULT_LAYER_KEYS advanced dict,
# so it's set via the advanced flags path, not device_config.
)
In practice humanize_policy is an advanced key (it lives in GHOSTVAULT_LAYER_KEYS,
not the raw Camoufox schema), so it's set via the standard advanced-flags path on
gv_update_account_config — pass it the same way you'd pass humanize or locale.
Per-account defaults
Two related advanced keys work the same way and give you per-account control without
a policy:
- humanize_typing — default humanize flag for gv_fill_input
- humanize_clicks — default humanize flag for gv_click_element
- default_typing_wpm — default typing speed (40–150)
- default_mistake_rate — default typo rate (0–0.05)
Layer 3 — global default¶
Set GHOSTVAULT_HUMANIZE_POLICY in .env (or the env block of your MCP client config)
to change the server-wide default. Per-account humanize_policy (Layer 2) always wins
over this.
Resolution order¶
The policy is resolved per call by _resolve_humanize_policy() in
src/ghostvault/tools.py:
| Precedence | Source | How to set |
|---|---|---|
| 1 (highest) | Per-account humanize_policy |
gv_update_account_config |
| 2 | Global GHOSTVAULT_HUMANIZE_POLICY |
.env |
| 3 (fallback) | "off" |
(built-in default) |
The effective policy is one of "off" | "recommended" | "always". Once the policy is
known, the per-call humanize argument is resolved by _enforce_humanize():
| Policy | humanize arg not passed |
humanize=True |
humanize=False |
|---|---|---|---|
always |
True (forced) |
True (forced) |
True (forced — agent cannot disable) |
recommended |
True (default on) |
True |
False (agent can turn off) |
off |
per-account default (humanize_typing / humanize_clicks), else False |
True |
False |
In short:
always= the safety position. Humanize is forced on; the agent literally cannot disable it. Use this for your most sensitive accounts.recommended= the "secure by default" position. Humanize is on unless the agent explicitly opts out — the inverse of Layer 1.off= the agent decides, with per-account defaults as a fallback.
Enforcement semantics¶
The enforced humanize flag is echoed in every gv_fill_input / gv_click_element
response so you can audit what actually happened:
{
"clicked": "Next",
"humanize": true,
"title": "Welcome",
"url": "https://accounts.google.com/..."
}
Both the gv_fill_input and gv_click_element docstrings explicitly warn the agent:
If the account's
humanize_policyis"always", humanize is forced on regardless of what you pass here.
This means even a model that tries to pass humanize=False on a login form (whether by
mistake or because it's optimizing for speed) cannot disable humanization when the policy
is always.
Examples¶
Example 1 — global "recommended", agent opts out once¶
.env:
A trusted internal dashboard's search box — agent opts out for speed:
Result: humanize is false (the agent's explicit false wins under recommended).
A Google login form — agent leaves the default:
Result: humanize is true (default-on under recommended).
Example 2 — per-account "always", agent tries to disable¶
Agent later calls:
Result: humanize is true — the policy forces it on, the agent's false is ignored.
Example 3 — global "off" (default), per-account defaults do the work¶
.env:
Per-account config:
await gv.update_account_config(
account_id,
# These are advanced (GHOSTVAULT_LAYER) keys:
humanize_typing=True, # but how? see note below
)
Setting GHOSTVAULT_LAYER_KEYS
humanize_typing, humanize_clicks, default_typing_wpm, default_mistake_rate,
and humanize_policy are all members of GHOSTVAULT_LAYER_KEYS. They're set through
the same advanced-flags surface as locale / humanize on
gv_update_account_config — there's no separate argument. The
Programmatic SDK update_account_config accepts them as keyword args.
With the policy at off, the agent's per-call value (or the per-account default if the
agent doesn't pass one) decides — the original backward-compatible behavior.
Where to set what¶
| You want… | Set |
|---|---|
| The agent to decide every call | GHOSTVAULT_HUMANIZE_POLICY=off (default) |
| Humanize on by default everywhere, agent can opt out | GHOSTVAULT_HUMANIZE_POLICY=recommended |
| Humanize forced on everywhere, agent cannot disable | GHOSTVAULT_HUMANIZE_POLICY=always |
| One specific account to force humanize | gv_update_account_config(..., humanize_policy="always") |
| A default typing speed for one account | gv_update_account_config(..., default_typing_wpm=65) |
Related pages¶
- All environment variables —
GHOSTVAULT_HUMANIZE_POLICYand friends - Programmatic SDK —
update_account_configreference - Human-like typing & clicks — practical recipes