rtfox-browser
Undetected Chrome browser driver with SOCKS5 proxy, captcha solving and multiprocessing support.
Based on
This project is a fork of undetected-chromedriver by @UltrafunkAmsterdam.
We took the core Chrome driver stealth patching logic as a base and extended it with:
- SOCKS5 proxy support with authentication
- Built-in captcha solving module with plugin API
- Multiprocessing isolation (per-worker profiles and binaries)
- On-the-fly proxy replacement without browser restart
- Structured logging via loguru
- Improved cleanup and shutdown handling
Original project is licensed under GPL-3.0 — this fork inherits the same license.
Features
- 🛡️ Bypasses CloudFlare / hCaptcha / Imperva detection out of the box
- 🔒 SOCKS5 / HTTP / HTTPS proxy support with authentication
- 🔄 On-the-fly proxy replacement via
proxy_replacement()— no restart needed - 🧩 Built-in captcha solving module (2 solvers included)
- ⚙️ Custom captcha solver API — share your own solvers
- 🚀 Multiprocessing support
- 🖥️ Cross-platform: Linux, macOS, Windows
Installation
pip install rtfox-browser
Quick start
import rtfox_browser as uc
driver = uc.Chrome()
driver.get("https://example.com")
driver.quit()
Proxy
SOCKS5 with authentication
driver = uc.Chrome(
proxy={
"host": "1.2.3.4",
"port": 1080,
"type": "socks5",
"user": "username",
"pass": "password",
}
)
HTTP proxy (no auth)
driver = uc.Chrome(
proxy={
"host": "1.2.3.4",
"port": 8080,
"type": "http",
}
)
Named keyword arguments (alternative style)
from rtfox_browser.proxy_types import ProxyType
driver = uc.Chrome(
proxy_host="1.2.3.4",
proxy_port=1080,
proxy_type=ProxyType.SOCKS5,
proxy_user="username",
proxy_pass="password",
)
Proxy exceptions
| Exception | Cause |
|---|---|
ProxyError |
Base class for all proxy errors |
ProxyConnectionError |
Failed to connect to proxy (invalid host/port) |
ProxyAuthError |
Wrong login or password |
ProxyTimeoutError |
Proxy does not respond within timeout |
ProxyInvalidAddressError |
Malformed host or port format |
ProxyConfigError |
Missing or invalid proxy configuration fields |
from rtfox_browser.exceptions import (
ProxyError,
ProxyConnectionError,
ProxyAuthError,
ProxyTimeoutError,
ProxyInvalidAddressError,
ProxyConfigError,
)
try:
driver = uc.Chrome(proxy={
"host": "1.2.3.4",
"port": 1080,
"type": "socks5",
"user": "username",
"pass": "password",
})
except ProxyConfigError:
print("Invalid or incomplete proxy config")
except ProxyInvalidAddressError:
print("Malformed host or port")
except ProxyAuthError:
print("Wrong credentials")
except ProxyTimeoutError:
print("Proxy timed out")
except ProxyConnectionError:
print("Could not connect to proxy")
except ProxyError:
print("General proxy failure")
On-the-fly proxy replacement
Replace the active proxy at any time without restarting Chrome. A local transparent tunnel is always running, so switching works even on sessions started without a proxy.
driver = uc.Chrome()
# Switch to a new proxy
driver.proxy_replacement({
"host": "5.6.7.8",
"port": 1080,
"type": "socks5",
"user": "alice",
"pass": "secret",
})
# Switch to direct connection (no proxy)
driver.proxy_replacement(None)
# Named-argument style
driver.proxy_replacement(
host="5.6.7.8",
port=1080,
proxy_type="socks5",
user="alice",
password="secret",
)
By default proxy_replacement() clears browser cache and cookies after switching so Chrome opens fresh connections through the new proxy. Pass clear_connections=False to skip this step.
Multiprocessing
Each worker gets its own isolated Chrome profile and chromedriver binary.
worker_id is optional — if omitted, a random UUID is assigned automatically. Pass it explicitly only if you want predictable names in logs or file paths.
from multiprocessing import Pool
import rtfox_browser as uc
def run_worker(worker_id):
driver = uc.Chrome(worker_id=worker_id)
driver.get("https://example.com")
driver.quit()
with Pool(4) as pool:
pool.map(run_worker, ["w1", "w2", "w3", "w4"])
Without explicit worker_id:
def run_worker(_):
driver = uc.Chrome() # worker_id auto-assigned as UUID
driver.get("https://example.com")
driver.quit()
with Pool(4) as pool:
pool.map(run_worker, range(4))
Captcha solving
rtfox-browser includes a captcha module with 2 built-in solvers.
Solvers are loaded automatically from a solvers/ directory in your working directory.
Setup
from rtfox_browser.captcha import CaptchaService
driver = uc.Chrome()
captcha = CaptchaService(api_key="YOUR_2CAPTCHA_KEY", driver=driver)
# Check available solvers
print(captcha.available())
# ['ebay_hcaptcha', 'aws_image']
Solve a captcha
driver.get("https://example.com")
captcha.ebay_hcaptcha()
Custom solvers directory
captcha = CaptchaService(
api_key="YOUR_KEY",
driver=driver,
solvers_dir="/path/to/your/solvers",
)
Creating your own captcha solver
Drop a file into the solvers/ folder — it will be picked up automatically. No registration needed.
1. Create solvers/my_solver.py:
from rtfox_browser.captcha import BaseCaptchaSolver
class MySolver(BaseCaptchaSolver):
name = "my_captcha" # becomes the method name on CaptchaService
def solve(self, **kwargs) -> bool:
driver = self.driver # Selenium WebDriver
api_key = self.api_key # 2captcha API key
# your solving logic here
...
return True # True = solved, False = failed
2. Use it:
captcha = CaptchaService(api_key="KEY", driver=driver)
captcha.my_captcha()
3. Or register manually at runtime:
captcha.register(MySolver)
captcha.my_captcha()
BaseCaptchaSolver API
| Property | Type | Description |
|---|---|---|
name |
str |
Method name exposed on CaptchaService |
self.driver |
WebDriver |
The active browser instance |
self.api_key |
str |
API key passed to CaptchaService |
solve(**kwargs) |
bool |
Your solving logic, return True on success |
ProxyConfig reference
You can construct proxy config directly using ProxyConfig:
from rtfox_browser.proxy_types import ProxyConfig, ProxyType
# From a dict
config = ProxyConfig.from_dict({
"host": "1.2.3.4",
"port": 8080,
"type": "socks5",
"user": "alice",
"pass": "secret",
})
# From named arguments
config = ProxyConfig.from_args(
host="1.2.3.4",
port=8080,
proxy_type=ProxyType.SOCKS5,
user="alice",
password="secret",
)
# Pass directly to Chrome
driver = uc.Chrome(proxy=config)
# Or use for proxy_replacement
driver.proxy_replacement(config)
Supported proxy types: socks5, http, https.
Cross-platform support
| OS | Supported |
|---|---|
| Linux | ✅ |
| macOS | ✅ |
| Windows | ✅ |
Community
💬 Telegram: @rtf_labs_studio 🎥 YouTube: RTF Labs Studio
License
GPL-3.0 © rtf-labs-studio
Metadata
Release files for rtfox-browser 0.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| rtfox_browser-0.0.2.tar.gz | 36.6 kB | Without provenance | Details for rtfox_browser-0.0.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| rtfox_browser-0.0.2-py3-none-any.whl | Python 3 | none | any | Details for rtfox_browser-0.0.2-py3-none-any.whl |
Total release size: 74.5 kB
Release files / rtfox_browser-0.0.2.tar.gz
| Download URL | rtfox_browser-0.0.2.tar.gz |
|---|---|
| Size | 36.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
17724e76c9e389774949994dc06c68eb20f5497c2677f74757f71a92d27cc9e4
|
|
BLAKE2b-256 checksum How to use checksums |
9ac03bde1507cf604a6de234b3ead21e9f85254c0fbf1e1ff4174dc16abaad72
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / rtfox_browser-0.0.2-py3-none-any.whl
| Download URL | rtfox_browser-0.0.2-py3-none-any.whl |
|---|---|
| Size | 37.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
60b0f8dc981dae6665440b00e2636d5620dbb3c12942459008aa3b10881e1aa3
|
|
BLAKE2b-256 checksum How to use checksums |
5f47967e81278bf3e867a0e8937e5a44039be2e244e545f5fe78a43528550e8f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Security for rtfox-browser 0.0.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.