End-to-end antibot-detection tests that verify a pip-installed camoufox release works correctly β both the Firefox binary and the Python package β using real proxies for each browser context.
- Python 3.9+
- Node.js (for building the TypeScript checks bundle via
esbuild) - At least one proxy in
proxies.txt
# 1. Add your proxies (see format below)
# 2. Run the test script β it handles everything else automatically
./run_tests.shrun_tests.sh will:
-
Install npm deps in
../build-tester/(foresbuild, first run only) -
Create a
.venvvirtualenv (first run only) -
Build a wheel from
../pythonliband install it (tests the actual packaged artifact) -
Phase 1 β run the suite against the locally compiled binary, auto-detected from:
- macOS:
../camoufox-*/obj-*-apple-darwin/dist/Camoufox.app/Contents/MacOS/camoufox - Linux:
../camoufox-*/obj-*-linux-*/dist/bin/camoufox-bin
Skipped (with a notice) if no local build is found. On macOS, the script also copies
properties.jsonfromCamoufox.app/Contents/Resources/intoMacOS/so pythonlib can locate it next to the binary. - macOS:
-
Phase 2 β download the official binary (
--browser-version, defaultofficial/stable) and run the suite against it -
Exit
0only if both phases pass
Use --binary local or --binary fetched to run only one phase.
Heads-up on Phase 2: if the latest
official/stableis much older than the local pythonlib (e.g. v135 binary vs pythonlib targeting v149+), the binary may not understand newer fingerprint patches and the test page can fail to produce results. Pin a newer binary with--browser-versionto avoid this.
Tests require real proxies. Each context gets its own proxy, and the WebRTC IP is automatically derived from the proxy server address.
Create proxies.txt in this directory with one proxy per line:
user:pass@domain:port
Example:
alice:secret123@proxy1.example.com:10000
bob:hunter2@proxy2.example.com:10000
alice:secret123@proxy1.example.com:10001
- Blank lines and lines starting with
#are ignored - Proxies are assigned round-robin across the 6 test profiles
- Fewer proxies than profiles is fine β they cycle
127.0.0.1andlocalhostare bypassed automatically so the local test-page server stays reachable
If you prefer to run steps individually:
# Install build-tester deps (once)
cd ../build-tester && npm install && cd ../service-tester
# Create and activate virtualenv
python3 -m venv .venv
source .venv/bin/activate
# Build wheel from local source and install it
pip install build
(cd ../pythonlib && rm -rf dist && python -m build --wheel -o dist)
pip install --force-reinstall ../pythonlib/dist/*.whl
# Download the browser binary
python -m camoufox fetch
# Run tests
python run_tests.py./run_tests.sh [options]
python run_tests.py [options]
--browser-version VER Camoufox version specifier (default: official/stable)
e.g. official/prerelease/146.0.1-beta.50
--profile-count N Number of profiles to test (1-6, default: 6)
--proxies PATH Path to proxies file (default: proxies.txt)
--headful Run with visible browser window
--no-cert Skip certificate generation
--save-cert PATH Save certificate text to a file
--secret KEY HMAC signing key for the certificate
--binary MODE Which binary to test: local | fetched | both (default: both)
(run_tests.sh only β orchestrates the two phases)
--executable-path PATH Run against a specific binary path
(run_tests.py only β used internally by phase 1)
6 browser contexts run simultaneously β 3 macOS profiles and 3 Linux profiles β each with:
- A unique fingerprint generated by camoufox via BrowserForge (navigator, screen, WebGL, fonts, voices, audio/canvas seeds)
- A distinct timezone
- Its own proxy, with WebRTC ICE candidates spoofed to the proxy's IP
Each context is scored across these categories:
| Category | What it checks |
|---|---|
| Automation Detection | Playwright/CDP artefacts |
| JS Engine | V8 vs SpiderMonkey signals |
| Lie Detection | Inconsistent property overrides |
| Firefox APIs | Firefox-specific API presence |
| Cross-Signal | Consistency across navigator, screen, etc. |
| CSS Fingerprint | CSS rendering fingerprint |
| Canvas Noise | Canvas hash uniqueness and stability |
| WebGL Render | WebGL rendering hash |
| Audio Integrity | AudioContext fingerprint |
| Font Platform | OS-consistent font availability |
| Speech Voices | Voice list matches declared OS |
| WebRTC | IP matches proxy server address |
| Stability | Fingerprint stable over time with other contexts open |
| Headless Detection | No headless mode signals |
| Grade | Meaning |
|---|---|
| A | All checks pass |
| B | 1β2 failures (minor) |
| C | 3β5 failures |
| D | 6β10 failures |
| F | 11+ failures |
A grade of A or B exits with code 0. Anything worse exits with code 1.
The cross-profile uniqueness section confirms each context has distinct audio, canvas, timezone, and screen fingerprints β verifying camoufox generates genuinely different identities per context.
If a check fails, fix it in the Python package (../pythonlib/camoufox/), not in the test. The test is intentionally a black-box validator β it only uses the public AsyncNewContext API and trusts camoufox to produce correct fingerprints.