Releases: fawadss1/scrapy-stealth
Release list
v0.8.1
Added
-
Adaptive rate limiting (auto-enabled)
Per-domain smart throttle on every stealth driver — no settings or meta flags.- Tracks HTTP 429,
Retry-After, and response latency per domain + driver. - AIMD spacing: backs off on rate limits, eases delay after success streaks.
- Behavioral timing jitter on
basic/turbois folded into the throttle wait. - Stats:
stealth/throttle/waits,stealth/throttle/wait_ms,
stealth/throttle/rate_limited,stealth/throttle/retry_after
(each with a{driver}breakdown where applicable).
New module:
scrapy_stealth/strategies/throttle.py. - Tracks HTTP 429,
v0.8.0
Added
-
Behavioral fingerprinting engine (auto-enabled)
Human-like interaction runs automatically on every stealth driver.browser— after each GET navigation: viewport emulation from the active
fingerprint profile (desktop vs mobile), Bezier-curved CDP mouse paths via
Input.dispatchMouseEvent(mouseMoved), CDP scroll (mouseWheel), and an
occasional keyboard nudge.basic/turbo— profile-seeded pre-request timing jitter (~30–350 ms);
no DOM is available on HTTP drivers, so mouse/scroll are not simulated there.
New package:
scrapy_stealth/behaviors/(engine,patterns,viewport,
noise,timing). Exports includesimulate_hover()for custom CDP mouse paths.
Changed
- Browser behavioral input — CDP instead of JavaScript
Mouse and scroll replay previously useddocument.dispatchEvent()(untrusted,
invisible to the OS cursor). They now use Chrome DevTools Protocol input events,
which anti-bot behavioral checks are more likely to treat as real browser input.
v0.7.1
Added
-
Smart Proxy Management
Per-domain proxy health tracking for turbo/basic engines: dead proxies (407,
CONNECT aborted, tunnel errors) and repeated blocks (403 by default) open a
temporary cooldown, skip the bad entry during rotation, and automatically
switch to the next proxy inSTEALTH_PROXIES. Telemetry is exposed in
crawler.stats:stealth/proxy/connection_failures,
stealth/proxy/cooldowns,stealth/proxy/rotations(each with a{driver}
breakdown), plusstealth/proxy/last_connection_failureand
stealth/proxy/last_cooldown(host:portonly — credentials never appear
in stats). Controlled bySTEALTH_PROXY_HEALTH,STEALTH_PROXY_CIRCUIT_AFTER,
STEALTH_PROXY_COOLDOWN_S, andSTEALTH_PROXY_CIRCUIT_CODES. -
STEALTH_RECYCLE_AFTER_BANSin Scrapy settings
The middleware now loadsSTEALTH_RECYCLE_AFTER_BANSfromsettings.pyor
spidercustom_settingson spider open (same pattern asSTEALTH_DRIVERand
STEALTH_PROXIES).
Fixed
- Smart Proxy Management — cooldown log spam
Repeated failures on a proxy already in cooldown no longer re-print the
cooldown warning on every request.
v0.7.0
Changed
- Random default browser profile
Removed staticDEFAULT_PROFILE(chrome_147). When no profile is set on a
request, engines pick a weighted random profile from the fingerprint pool via
ProfileRotator. Pin a profile withmeta["stealth"]["profile"]or
BasicEngine(profile="chrome_147").
Fixed
-
Browser driver — Cloudflare challenge wait on 403/503
The browser engine now runs the JS challenge wait loop on 403/503 interstitials
(e.g. Cloudflare “Just a moment” or “Performing security verification”), not
only on HTTP 2xx. Challenge pages poll for up toBROWSER_CHALLENGE_TIMEOUT_S
(default 30s) instead of returning challenge HTML immediately. -
Browser driver — JPG/PNG/binary asset bodies
Chrome’s built-in image viewer returns HTML (<img src="...jpg">) in the DOM.
Direct GET/HEAD to asset URLs (.jpg,.png,.gif,.pdf, …) now return
raw bytes: CDPNetwork.getResponseBodyfirst, then in-pagefetch()when the
network/DOM response is HTML. Prefers the latest 2xx network response over an
earlier 403 challenge body. Fixes CDN assets behind Cloudflare (e.g.
scdn.autodoc.de/.../*.jpg). -
wreq.emulationimport typo
Fixedfrom wreq.eulation import Profilein profile resolution that caused
startup failure with a misleading Visual C++ runtime error on Windows.
Added
-
BROWSER_CHALLENGE_TIMEOUT_S— max seconds to wait on JS challenge /
Cloudflare interstitial pages (default30.0). Configurable via settings /
scrapy_stealth.config.config. -
Cloudflare Turnstile / managed-challenge detection — expanded signatures
forchallenges.cloudflare.com,cf-turnstile, “Verify you are human”, and
“Performing security verification” titles. -
Turbo driver — HTTP/3 (QUIC) support
Opt-in viaconfig.HTTP3 = Trueormeta["stealth"]["http3"] = True.
Uses curl_cffiCurlHttpVersion.V3with HTTP/3-capable impersonate presets
(e.g.chrome150). Requires a UDP-capable proxy for QUIC. -
Turbo driver — browser header order
Turbo sends cookies through curl_cffi’s cookies API (not a rawCookie
header) so they don’t disrupt the header order applied by the impersonate
preset. -
Turbo impersonate presets bumped to
chrome150
Chromium-family profiles now map to curl_cffi’s latest Chrome preset. -
Dependency:
curl_cffi>=0.16.1
Required for HTTP/3 options and updated curl-impersonate backend.
v0.6.16
[0.6.16] - 2026-08-19
Changed
- Browser driver defaults to visible Chrome (
headless=False)
Explicitdriver="browser"anddriver="auto"browser fallback now open a visible
window by default. Setmeta={"stealth": {"headless": True}}orBROWSER_HEADLESS = True
to opt into headless mode.
Added
-
Browser cookie handoff
After each browser response, tab cookies are read via CDP and exposed on the response as
meta["stealth"]["browser_cookies"]andmeta["stealth"]["browser_cookie_header"].
WhenCOOKIES_ENABLEDandBROWSER_EXPORT_COOKIESare on (both default), cookies merge
into Scrapy's jar so follow-upbasic/turborequests reuse the session (login with
browser → scrape with turbo). Stats:stealth/browser_cookies_exported. -
Browser form POST — hidden field merge
Urlencoded POST bodies on the browser driver automatically merge hidden<form>fields
(e.g.csrf_token) from the loaded page before in-pagefetch(). -
driver="auto"POST fallback
When turbo/basic POST gets a JS challenge or session ban (403/429/503, Cloudflare, etc.),
middleware retries once with the browser driver using the same method, body, and headers.
Stats:stealth/fallbacks/method/post(andput,patch,delete). -
Proxy-Seller sponsor
README andAGENTS.mdnow include Proxy-Seller with affiliate link, promo codeFAWAD15, and logo assets underdocs/static/sponsors/.
v0.6.15
Added
-
POST / PUT / PATCH / DELETE on all drivers
basic,turbo, andbrowserhonor the same ScrapyRequestfields — method,
body,Cookie, and custom headers (Content-Type,Authorization, etc.). -
Single request builder for all drivers
build_stealth_request()inscrapy_stealth.utils.network.requestvalidates
and normalizes method, URL, body,Cookie, and custom headers once. Browser
POST uses in-pagefetch()viabrowser_http_fetch(). -
README and example spider
New “POST, headers, and cookies” section with live test URLs
(postman-echo.com,quotes.toscrape.com,jsonplaceholder.typicode.com).
examples/full_spider.pydemonstrates JSON POST on all three drivers and form
login via browser.
Fixed
-
Browser POST — same-origin setup
Load the target URL (GET), not the site root, before in-pagefetch(). Fixes
TypeError: Failed to fetchwhen the root redirects elsewhere
(e.g.postman-echo.com→www.postman.com). -
Browser POST — brotli decode error in Scrapy
Stripcontent-encodingandcontent-lengthfrom browser fetch responses; the
body fromarrayBuffer()is already decoded. -
Basic driver — POST body dropped
wreq expects raw bytes asbody=, notdata=(turbo/curl_cffi usesdata=).
AddedStealthRequestPayload.basic_http_kwargs()for the basic engine. -
Browser CDP headers on POST setup
Do not sendContent-Type/Content-Lengthvia CDP extra headers during
origin setup; they are set only on the in-pagefetch()call.
Changed
- Browser POST context verifies same-origin after navigation and checks for Chrome
error pages before runningfetch().
v0.6.14
Changed
-
PyPI wheel/sdist packaging
Ship onlyscrapy_stealthanddocs/static/logo.png(browser splash). Exclude
examples/,scripts/, sponsor assets, and other docs from installs. -
STEALTH_ENABLEDuses smart driver selection by default
When global stealth is on, the middleware injectsmeta["stealth"]["driver"] = "auto"
on requests that do not already specify a driver. HTTP impersonation (turboby default,
orSTEALTH_DRIVER) runs first; JS challenges and session bans retry once with the
browserdriver. -
STEALTH_DRIVERdefault is now"turbo"
driver="auto"and global stealth now start with the turbo driver for stronger TLS
impersonation. SetSTEALTH_DRIVER = "basic"for the lighter HTTP driver.
Removed
STEALTH_AUTO_FALLBACKsetting
Browser fallback is controlled solely bydriver="auto"(injected automatically when
STEALTH_ENABLED = True, or set per-request). Usemeta["stealth"]["fallback"] = False
to opt out for a single URL.
Fixed
- Browser splash logo showed a blank tab on startup
_splash_url()loadsdocs/static/logo.png(included in PyPI wheels for splash).
v0.6.14a1
Changed
Changed
-
STEALTH_ENABLEDuses smart driver selection by default
When global stealth is on, the middleware injectsmeta["stealth"]["driver"] = "auto"
on requests that do not already specify a driver. HTTP impersonation (turboby default,
orSTEALTH_DRIVER) runs first; JS challenges and session bans retry once with the
browserdriver. -
STEALTH_DRIVERdefault is now"turbo"
driver="auto"and global stealth now start with the turbo driver for stronger TLS
impersonation. SetSTEALTH_DRIVER = "basic"for the lighter HTTP driver.
Removed
STEALTH_AUTO_FALLBACKsetting
Browser fallback is controlled solely bydriver="auto"(injected automatically when
STEALTH_ENABLED = True, or set per-request). Usemeta["stealth"]["fallback"] = False
to opt out for a single URL.
Fixed
- Browser splash logo showed a blank tab on startup
_splash_url()loadsdocs/static/logo.pngonly (PyPI viaMANIFEST.ingraft docs).
v0.6.13
-
NodeMaven materials
Updated README andAGENTS.mdwith new copy, tracking links (Fawadss1readmegh,Fawadss1agentmdgh,Fawadss1tools), and the new horizontal banner (docs/static/sponsors/nodemaven-banner.png). -
Utils package layout
Reorganisedscrapy_stealth.utilsinto subpackages:core,detection,
network,browser,engine, andtelemetry. Import paths updated
(e.g.scrapy_stealth.utils.core.meta,scrapy_stealth.utils.network.proxy).
v0.6.12
Changed
- Middleware — drop deprecated
spiderarg fromprocess_request
Matches current Scrapy downloader middleware API: the spider is read from the
crawler saved infrom_crawler()(crawler.spider) instead of a method
argument. Removes theScrapyDeprecationWarningabout
StealthDownloaderMiddleware.process_request().
Added
- Smart browser selection (
STEALTH_AUTO_FALLBACK,driver="auto")
Whenbasicorturboreturns a JS challenge or session ban, the middleware
retries once with thebrowserdriver. The fallback always runs with
headless=Falsefor better evasion. Opt in globally with
STEALTH_AUTO_FALLBACK = True, per-request with
meta["stealth"]["driver"] = "auto", or opt out with
meta["stealth"]["fallback"] = False. Fallback counters appear under
stealth/fallbacksincrawler.stats.