stealthreq
Generate human-like request behavior for scraping and security scanning. Applies realistic headers, timing jitter, and TLS fingerprint rotation to make automated requests resemble genuine browser traffic.
use ;
// Implement MutableRequest for your HTTP client
Why this exists
Scrapers and scanners get blocked by WAFs that look for automation signals. Missing Accept-Language headers. Static User-Agent strings. Perfectly consistent timing. Predictable TLS fingerprints.
stealthreq decouples the mutation logic from HTTP implementations. You implement a 1-method trait for your request type. The crate handles header selection, timing, and TLS profile rotation. Works with reqwest, hyper, ureq, or any other HTTP client.
MutableRequest trait
Libraries integrate by implementing MutableRequest:
This minimal interface keeps the crate HTTP-agnostic.
Header policies
HeaderPolicy manages pools of realistic browser values:
- 4 desktop and mobile User-Agent strings
- Accept-Language variants (en-US, en-GB, en-CA, fr-FR)
- Accept-Encoding preferences (gzip, deflate, br)
- Cache-Control directives
- Referer hosts
- Optional Pragma headers
The policy randomly selects headers up to a configurable budget, always preserving User-Agent.
Timing jitter
TimingJitter generates random delays between requests:
use ;
let policy = default
.with_timing; // 100-500ms delay
The AppliedRequestProfile includes the sampled delay. Your code sleeps before sending.
TLS fingerprint rotation
TlsRotationPolicy provides browser-like JA3 fingerprints:
| Profile | Description |
|---|---|
| chrome-desktop-121 | Chrome 121 on desktop |
| chrome-mobile-121 | Chrome 121 on mobile |
| firefox-desktop | Firefox desktop |
Each profile includes JA3 digest, ALPN order, cipher suites, and extension ordering. Bind these to your TLS stack configuration.
Configuration via TOML
use StealthProfileConfig;
let config = from_toml?;
let policy = config.build;
Deterministic profiles
Set a seed for reproducible behavior in tests:
let policy = default.with_seed;
// Same seed produces same headers, timing, and TLS profile
let applied1 = policy.apply?;
let applied2 = policy.apply?;
assert_eq!;
Contributing
Pull requests are welcome. There is no such thing as a perfect crate. If you find a bug, a better API, or just a rough edge, open a PR. We review quickly.
License
MIT. Copyright 2026 CORUM COLLECTIVE LLC.