Skip to content

Instantly share code, notes, and snippets.

@rubenvereecken
Created May 8, 2026 07:44
Show Gist options
  • Select an option

  • Save rubenvereecken/9e9196cd9e3dde15e72c9f4d43b45c9a to your computer and use it in GitHub Desktop.

Select an option

Save rubenvereecken/9e9196cd9e3dde15e72c9f4d43b45c9a to your computer and use it in GitHub Desktop.
Camoufox config — non-default features, HTTP/3 leak fix, fingerprint overrides
"""
Example Camoufox config — features that aren't on by default.
Ruben Vereecken, 2026-05-08
Usage:
python camoufox-example-config.py
python camoufox-example-config.py --proxy socks5://localhost:1082
python camoufox-example-config.py --proxy http://user:pass@host:port
python camoufox-example-config.py --proxy http://host:port --with-h3
"""
import random
import sys
from camoufox.async_api import AsyncCamoufox
from camoufox.fingerprints import generate_context_fingerprint, get_random_preset
TARGET_OS = "macos"
TEST_URL = "https://checker-test.proxyshard.com/"
def build_fingerprint(*, disable_h3: bool = True):
"""Build a full fingerprint config with our recommended overrides."""
preset = get_random_preset(os=TARGET_OS)
# config_overrides are applied BEFORE the init_script is rendered,
# so seed values (like fonts:spacing_seed) are baked into the JS.
ctx_fp = generate_context_fingerprint(
preset=preset,
os=TARGET_OS,
config_overrides={
# Disable font spacing perturbation — the noise pattern itself
# is detectable (population-marginal on fingerprint tests).
# Seed 0 triggers an early return in the C++ GetSeed().
"fonts:spacing_seed": 0,
# Spoof codec enumeration (canPlayType) to match target OS.
"media:spoof_codecs": True,
},
)
# Post-fingerprint config — merged after init_script is built.
extra_config = {
# A fresh browser always shows history.length=1, which is a signal.
"window.history.length": random.randint(1, 5),
}
config = {**ctx_fp["config"], **extra_config}
firefox_prefs = {}
if disable_h3:
# QUIC uses UDP. Most HTTP CONNECT / SOCKS5 proxies only tunnel TCP.
# Without this, the browser tries HTTP/3 over UDP which bypasses the
# proxy and leaks your real IP. This is the exact leak that
# checker-test.proxyshard.com catches.
firefox_prefs["network.http.http3.enable"] = False
return preset, ctx_fp, config, firefox_prefs
async def run(*, proxy: dict | None = None, disable_h3: bool = True):
preset, ctx_fp, config, firefox_prefs = build_fingerprint(disable_h3=disable_h3)
launch_kwargs = dict(
fingerprint_preset=preset,
os=TARGET_OS,
headless=False,
config=config,
firefox_user_prefs=firefox_prefs,
i_know_what_im_doing=True,
)
if proxy:
launch_kwargs["proxy"] = proxy
async with AsyncCamoufox(**launch_kwargs) as browser:
context = await browser.new_context(**ctx_fp["context_options"])
await context.add_init_script(ctx_fp["init_script"])
page = await context.new_page()
print(f"Navigating to {TEST_URL} ...")
print(f" HTTP/3 disabled: {disable_h3}")
print(f" Proxy: {proxy['server'] if proxy else 'none'}")
await page.goto(TEST_URL)
# Dismiss cookie banner if present
try:
accept_btn = page.locator("button:has-text('Accept all')")
if await accept_btn.count() > 0:
await accept_btn.first.click()
await page.wait_for_timeout(1_000)
except Exception:
pass
# Give the checker time to run its network tests
await page.wait_for_timeout(20_000)
# Extract the full visible text from the results area
results = await page.evaluate("""() => {
// Get all text content, structured by section
const sections = document.querySelectorAll('section, [class*="card"], [class*="Card"], [class*="panel"], [class*="result"]');
if (sections.length > 0) {
return Array.from(sections).map(s => s.innerText.trim().substring(0, 500));
}
return document.body.innerText.substring(0, 3000);
}""")
screenshot_name = f"proxyshard-{'h3-on' if not disable_h3 else 'h3-off'}.png"
screenshot_path = f"/tmp/{screenshot_name}"
await page.screenshot(path=screenshot_path, full_page=True)
print(f"\nScreenshot saved: {screenshot_path}")
print(f"\nPage results:\n{results}")
if __name__ == "__main__":
import asyncio
# Pass --proxy to route traffic through a proxy. Examples:
# --proxy socks5://localhost:1082
# --proxy http://user:pass@host:port
proxy = None
if "--proxy" in sys.argv:
idx = sys.argv.index("--proxy")
if idx + 1 < len(sys.argv):
proxy = {"server": sys.argv[idx + 1]}
# Pass --with-h3 to leave HTTP/3 enabled (to reproduce the leak)
disable_h3 = "--with-h3" not in sys.argv
asyncio.run(run(proxy=proxy, disable_h3=disable_h3))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment