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
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 | |
|---|---|---|---|
| rtfox_browser-0.0.2.tar.gz | 36.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rtfox_browser-0.0.2-py3-none-any.whl | Python 3 | none | any | Details |
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
|