stygian-browser
High-performance, anti-detection browser automation library for Rust.
Built on the Chrome DevTools Protocol via
chromiumoxide with comprehensive stealth features
for bypassing modern anti-bot systems: Cloudflare, DataDome, PerimeterX, Akamai.
Features
| Feature | Description | Default |
|---|---|---|
stealth |
Navigation spoofing, canvas noise, WebGL randomization, CDP protection | ✓ |
tls-config |
TLS fingerprint profiling via rustls (requires stealth) |
— |
mcp |
MCP (Model Context Protocol) tools | — |
mcp-attach |
Attach to an existing browser via CDP WebSocket (browser_attach tool; requires mcp) |
— |
metrics |
Prometheus metrics exporter | — |
extract |
Structured data extraction via #[derive(Extract)] |
— |
similarity |
Similarity scoring for duplicate detection | — |
browserbase |
Optional Browserbase-managed acquisition stage integration (requires MCP/runtime opt-in) | — |
full |
All features enabled | — |
Installation
[]
= "*"
= { = "1", = ["full"] }
Enable (or disable) stealth features:
[]
# stealth is the default feature; disable for a minimal build
= { = "*", = false }
Enable optional Browserbase acquisition integration:
[]
= { = "*", = ["browserbase"] }
When enabled, runner-first acquisition can opt into a Browserbase-managed stage via request flags.
Set BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID in the runtime environment.
Quick Start
use ;
use Duration;
async
Configuration
BrowserConfig controls every aspect of browser launch, anti-detection, and pooling.
use ;
use PoolConfig;
use ;
use Duration;
let config = builder
// Browser basics
.headless
.window_size
// Use a specific Chrome binary
// .chrome_path("/usr/bin/google-chrome".into())
// Stealth level
.stealth_level
// Proxy (supports http/https/socks5)
// .proxy("http://user:pass@proxy.example.com:8080".to_string())
// WebRTC policy
.webrtc
// Pool settings
.pool
.build;
Environment Variable Overrides
All config values can be overridden at runtime without recompiling:
| Variable | Default | Description |
|---|---|---|
STYGIAN_CHROME_PATH |
auto-detect | Path to Chrome/Chromium binary |
STYGIAN_HEADLESS |
true |
false for headed mode |
STYGIAN_STEALTH_LEVEL |
advanced |
none, basic, advanced |
STYGIAN_POOL_MIN |
2 |
Minimum warm browser count |
STYGIAN_POOL_MAX |
10 |
Maximum concurrent browsers |
STYGIAN_POOL_ACQUIRE_TIMEOUT_SECS |
30 |
Seconds to wait for pool slot |
STYGIAN_CDP_FIX_MODE |
addBinding |
addBinding, isolatedWorld, enableDisable, none |
STYGIAN_PROXY |
— | Proxy URL |
STYGIAN_DISABLE_SANDBOX |
auto-detect | true to pass --no-sandbox (see note below) |
Stealth Levels
| Level | navigator spoof |
Canvas noise | WebGL random | CDP protection | Human behavior |
|---|---|---|---|---|---|
None |
— | — | — | — | — |
Basic |
✓ | — | — | ✓ | — |
Advanced |
✓ | ✓ | ✓ | ✓ | ✓ |
Trade-offs:
None— maximum performance, no evasion. Suitable for sites with no bot detection.Basic— hidesnavigator.webdriver, masks the headless UA, enables CDP protection. Fast; appropriate for most scraping workloads.Advanced— full fingerprint injection (canvas noise, WebGL, audio, fonts, hardware concurrency, device memory), human-like mouse/keyboard events. Adds ~10–30 ms overhead per page but passes all major detection suites.
Browser Pool
The pool maintains a configurable number of warm browser instances and enforces backpressure when all slots are occupied.
use ;
use PoolConfig;
use Duration;
# async
Browsers returned via BrowserHandle::release() go back into the pool automatically.
Browsers that fail their health check are discarded and replaced with fresh instances.
Anti-Detection Techniques
navigator Spoofing
- Overwrites
navigator.webdrivertoundefined - Patches
navigator.pluginswith a realisticPluginArray - Sets
navigator.languages,navigator.language,navigator.vendor - Aligns
navigator.hardwareConcurrencyandnavigator.deviceMemorywith the chosen device profile
Canvas Fingerprint Noise
Adds sub-pixel noise (<1 px) to HTMLCanvasElement.toDataURL() and
CanvasRenderingContext2D.getImageData() — indistinguishable visually but unique
per page load.
WebGL Randomisation
Randomises RENDERER and VENDOR WebGL parameter responses to prevent GPU-based
fingerprinting while keeping values plausible (real GPU family names are used).
CDP Leak Protection
The Chrome DevTools Protocol itself can expose automation. Three modes are
available via CdpFixMode:
| Mode | Protection | Compatibility |
|---|---|---|
AddBinding |
Wraps calls to hide Runtime.enable side-effects |
Best overall |
IsolatedWorld |
Runs injection in a separate execution context | Moderate |
EnableDisable |
Toggles enable/disable around each command | Broad |
Human-Like Behavior (Advanced only)
MouseSimulator generates Bézier-curve mouse paths with:
- Distance-aware step counts (12 steps for <100 px, up to 120 for >1000 px)
- Perpendicular control-point offsets for natural arc shapes
- Sub-pixel micro-tremor jitter (±0.3 px)
- 10–50 ms inter-event delays
TypingSimulator models:
- Per-key WPM variation (70–130 WPM base)
- Configurable typo-and-correct rate
- Burst/pause rhythm typical of humans
Integration with stygian-proxy
To use proxies from a stygian-proxy pool dynamically (at browser launch time):
use ProxyConfig;
use Arc;
async
When a browser is released after use, the proxy's circuit breaker is updated:
- Clean return to idle queue: proxy marked as success ✓
- Browser unhealthy: proxy marked as failure ✗
- Browser crashed: proxy marked as failure ✗
use ;
use ResourceFilter;
use Duration;
# async
WebRTC & Proxy
use ;
use ;
let config = builder
.proxy
.webrtc
.build;
WebRtcPolicy::BlockAll is the safest option for anonymous scraping — it prevents
any IP addresses from leaking via WebRTC peer connections.
MCP Behavior Policy Usage
When compiled with the mcp feature, you can apply structured anti-bot behavior
plans at runtime using browser_apply_behavior_json.
Accepted behavior shapes:
RuntimePolicyobject (direct policy payload)InvestigationBundleobject (uses nestedpolicy)Direct overrideobject (for simpleheadless/stealth_leveltuning)
Example: RuntimePolicy payload
Example: InvestigationBundle payload
Bind behavior to an active session by also passing session_id:
Response includes:
adapter_kind(RuntimePolicy,InvestigationBundle, orDirectOverrides)adapter_kind(runtime_policy,investigation_bundle, ordirect_overrides)plan(normalized behavior plan)effective_config(resolved browser config view)session_updatedflag
FAQ
Q: Does this work on macOS / Linux / Windows?
A: macOS and Linux are fully supported. Windows is validated in CI on windows-latest,
with runtime behavior depending on the chromiumoxide backend.
Q: Which Chrome versions are supported?
A: The library targets Chrome 120+. Older versions may work but stealth scripts are
only tested against current release channels.
Q: Can I use it without a display (CI/CD)?
A: Yes — the default config is headless: true. No display server is required.
Q: Does Advanced stealth guarantee Cloudflare bypass?
A: There is no guarantee. Cloudflare Turnstile and Bot Management use both
JavaScript signals and TLS/network-layer heuristics. Advanced stealth eliminates
all known JavaScript signals, which is necessary but may not be sufficient.
Q: How do I set a custom Chrome path?
A: Set STYGIAN_CHROME_PATH=/path/to/chrome or use
BrowserConfig::builder().chrome_path("/path/to/chrome".into()).build().
Q: Why does stats().idle always return 0?
A: idle is a lock-free approximation. The count is not maintained in the hot
acquire/release path to avoid contention. Use available and active instead.
Q: Should I set STYGIAN_DISABLE_SANDBOX=true?
A: Only inside a container (Docker, Kubernetes, etc.) where Chromium's renderer
sandbox cannot function due to missing user namespaces. This is auto-detected via
/.dockerenv and /proc/1/cgroup on Linux — you normally don't need to set it
explicitly. Never set this on a bare-metal host without an equivalent isolation
boundary; doing so removes a meaningful OS-level security layer.
For highest-security deployments, run each browser session in its own container and let the container runtime provide isolation — the sandbox flag will be set automatically inside the container.
Testing
# Pure-logic unit tests (no Chrome required)
# Integration tests (requires Chrome 120+)
# Run only ignored Chrome tests explicitly
# Measure coverage for logic units
Coverage notes: All tests that launch a real browser instance are annotated
#[ignore = "requires Chrome"] so the suite passes in CI without a Chrome binary.
Pure-logic coverage (config, stealth scripts, fingerprint generation, simulator math)
is high; overall line coverage is structurally bounded by the CDP requirement.
License
Licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-only).