Configuration

All browser behaviour is controlled through BrowserConfig. Every field can be set programmatically or overridden at runtime via environment variables — no recompilation needed.


Builder pattern

#![allow(unused)]
fn main() {
use stygian_browser::{BrowserConfig, HeadlessMode, StealthLevel};
use stygian_browser::config::PoolConfig;
use stygian_browser::webrtc::{WebRtcConfig, WebRtcPolicy};
use std::time::Duration;

let config = BrowserConfig::builder()
    // ── Browser ──────────────────────────────────────────────────────────
    .headless(true)
    .headless_mode(HeadlessMode::New)      // default; --headless=new shares headed rendering
    .window_size(1920, 1080)
    // .chrome_path("/usr/bin/google-chrome".into())   // auto-detect if omitted
    // .user_data_dir("/tmp/my-profile")   // omit for auto unique temp dir per instance

    // ── Stealth ───────────────────────────────────────────────────────────
    .stealth_level(StealthLevel::Advanced)

    // ── Network ───────────────────────────────────────────────────────────
    // .proxy("http://user:pass@proxy.example.com:8080".to_string())
    .webrtc(WebRtcConfig {
        policy: WebRtcPolicy::DisableNonProxied,
        ..Default::default()
    })

    // ── Pool ──────────────────────────────────────────────────────────────
    .pool(PoolConfig {
        min_size:        2,
        max_size:        10,
        idle_timeout:    Duration::from_secs(300),
        acquire_timeout: Duration::from_secs(10),
    })
    .build();
}

Field reference

Browser settings

FieldTypeDefaultDescription
headlessbooltrueRun without visible window
headless_modeHeadlessModeNewNew = --headless=new (full Chromium rendering, default since Chrome 112); Legacy = classic --headless flag for Chromium < 112
window_sizeOption<(u32, u32)>(1920, 1080)Browser viewport dimensions
chrome_pathOption<PathBuf>auto-detectPath to Chrome/Chromium binary
stealth_levelStealthLevelAdvancedAnti-detection level
proxyOption<String>NoneProxy URL (http://, https://, socks5://)
user_data_dirOption<PathBuf>auto-generatedPer-instance temp dir ($TMPDIR/stygian-<id>); set explicitly to share a persistent profile. Auto-generation prevents SingletonLock races between concurrent pools.
argsVec<String>[]Additional Chrome command-line flags

Pool settings (PoolConfig)

FieldTypeDefaultDescription
min_sizeusize2Browsers kept warm at all times
max_sizeusize10Maximum concurrent browsers
idle_timeoutDuration5 minEvict idle browser after this duration
acquire_timeoutDuration30 sMax wait for a pool slot

WebRTC settings (WebRtcConfig)

FieldTypeDefaultDescription
policyWebRtcPolicyDisableNonProxiedWebRTC IP leak policy
locationOption<ProxyLocation>NoneSimulated geo-location for WebRTC

WebRtcPolicy variants:

VariantBehaviour
AllowDefault browser behaviour — real IPs may leak
DisableNonProxiedBlock direct connections; only proxied paths allowed
BlockAllBlock all WebRTC — safest for anonymous scraping

Environment variable overrides

All config values can be overridden without touching source code:

VariableDefaultDescription
STYGIAN_CHROME_PATHauto-detectPath to Chrome/Chromium binary
STYGIAN_HEADLESStrueSet false for headed mode
STYGIAN_HEADLESS_MODEnewnew (--headless=new) or legacy (classic --headless for Chromium < 112)
STYGIAN_STEALTH_LEVELadvancednone, basic, advanced
STYGIAN_POOL_MIN2Minimum warm browsers
STYGIAN_POOL_MAX10Maximum concurrent browsers
STYGIAN_POOL_IDLE_SECS300Idle timeout before browser eviction
STYGIAN_POOL_ACQUIRE_SECS5Seconds to wait for a pool slot
STYGIAN_LAUNCH_TIMEOUT_SECS10Browser launch timeout
STYGIAN_CDP_TIMEOUT_SECS30Per-operation CDP timeout
STYGIAN_CDP_FIX_MODEaddBindingaddBinding, isolatedworld, enabledisable
STYGIAN_PROXYProxy URL
STYGIAN_PROXY_BYPASSComma-separated proxy bypass list (e.g. <local>,localhost)
STYGIAN_DISABLE_SANDBOXauto-detecttrue inside containers, false on bare metal

Examples

Minimal — fast text scraping

#![allow(unused)]
fn main() {
use stygian_browser::{BrowserConfig, StealthLevel};

let config = BrowserConfig::builder()
    .headless(true)
    .stealth_level(StealthLevel::None)  // no overhead
    .build();
}

Headed debugging session

#![allow(unused)]
fn main() {
let config = BrowserConfig::builder()
    .headless(false)
    .stealth_level(StealthLevel::Basic)
    .build();
}

Proxy with full stealth

#![allow(unused)]
fn main() {
use stygian_browser::webrtc::{WebRtcConfig, WebRtcPolicy};

let config = BrowserConfig::builder()
    .headless(true)
    .stealth_level(StealthLevel::Advanced)
    .proxy("socks5://user:pass@proxy.example.com:1080".to_string())
    .webrtc(WebRtcConfig { policy: WebRtcPolicy::BlockAll, ..Default::default() })
    .build();
}

Anti-detection for JS-heavy sites (X/Twitter, LinkedIn)

StealthLevel::Advanced combined with HeadlessMode::New is the most evasion-resistant configuration. HeadlessMode::New is the default since v0.1.11 — existing code elevates automatically.

#![allow(unused)]
fn main() {
use stygian_browser::{BrowserConfig, HeadlessMode, StealthLevel};
use stygian_browser::webrtc::{WebRtcConfig, WebRtcPolicy};

let config = BrowserConfig::builder()
    .headless(true)
    .headless_mode(HeadlessMode::New)   // default; shared rendering pipeline with headed Chrome
    .stealth_level(StealthLevel::Advanced)
    .webrtc(WebRtcConfig { policy: WebRtcPolicy::BlockAll, ..Default::default() })
    .build();
}

For Chromium ≥ 112 (all modern Chrome / Chromium builds), New is the right choice. Legacy falls back to the classic --headless flag which uses an older rendering pipeline — use it only when targeting Chromium < 112.

#![allow(unused)]
fn main() {
// Only needed for Chromium < 112
let config = BrowserConfig::builder()
    .headless_mode(HeadlessMode::Legacy)
    .build();
}