This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Camoufox is an anti-detect fork of Firefox for web scraping and automation. This repo is not the Firefox source β it is a build system that fetches upstream Firefox, applies a stack of patches + code additions, and produces a hardened, fingerprint-spoofing browser. The distinguishing design choice is that fingerprint spoofing happens at the C++/Juggler implementation level, not via injected JavaScript, so it is invisible to page-side inspection.
The actual Firefox tree lives in camoufox-<version>-<release>/ (e.g. camoufox-150.0.2-beta.25/), created by the build. That directory is generated β never edit it directly to make lasting changes; changes there are captured as patches (see "Making patches" below).
upstream.sh pins version / release, and is sourced+exported by the Makefile, so those variables flow into every script.
The build system is designed for Linux. Windows and macOS binaries are cross-compiled from Linux β they are never built natively. (scripts/install-deps.sh covers macOS/Linux host dependencies for local make dir + bootstrap experimentation; a full production build path is Linux/Docker.)
bash scripts/install-deps.sh # install host build deps (Python β₯3.11, Rust, aria2, p7zip, go, msitools, wget, sqlite)
make dir # fetch Firefox source, extract, copy additions/settings, apply all patches β touches _READY
make bootstrap # install system deps (apt/dnf/pacman) + run `mach bootstrap` (one-time)
make build # ./mach build in the source dir
make run # run the built browser (wipes ~/.camoufox profile)
make run args="--headless https://test.com"
python3 multibuild.py --target linux windows macos --arch x86_64 arm64 i686 # full cross-platform build + packagemake dir is the pipeline that matters: setup (fetch tarball via aria2c β extract β copy-additions.sh) β python3 scripts/patch.py (applies every patch, writes mozconfig) β _READY. mach requires Python β₯ 3.11 (stdlib tomllib); older python3 crashes with ModuleNotFoundError: No module named 'tomllib'.
Docker is the portable path: docker build -t camoufox-builder . then docker run -v "$(pwd)/dist:/app/dist" camoufox-builder --target <os> --arch <arch>.
Packaging: make package-linux|package-macos|package-windows arch=<arch> (wraps scripts/package.py). Launcher (Go): make build-launcher arch=<arch> os=<os>.
Almost all browser-behavior changes are patches/*.patch (~49 patches: fingerprint-injection.patch, webgl-spoofing.patch, navigator-spoofing.patch, webrtc-ip-spoofing.patch, the playwright/ and librewolf/ and ghostery/ subdirs, etc.). Do not hand-edit patch files.
Use the developer UI instead:
make edits # launches scripts/developer.py β apply/undo/create/manage patches- New patch: in the UI "Reset workspace" β edit files in
camoufox-*/βmake build/make runto test β "Write workspace to patch". - Edit existing patch: "Edit a patch" (resets workspace to that patch's state) β edit β "Write workspace to patch" to overwrite.
Low-level equivalents: make patch ./patches/x.patch, make unpatch ./patches/x.patch, make workspace ./patches/x.patch, make revert (reset to unpatched tag), make diff (diff against first-checkpoint). The source dir is a git repo with unpatched / first-checkpoint / checkpoint tags used by these targets.
patches/β the diffs applied to Firefox source. This is where browser behavior is changed.additions/β whole files copied into the source tree (not diffs) byscripts/copy-additions.sh:additions/camoucfg/β the C++ config layer.MaskConfig.hppreads the spoofing config (fromCAMOU_CONFIGenv var /camoufox.cfg) that the patches consult at the C++ level;MouseTrajectories.hppis the human-cursor algorithm.additions/juggler/β Camoufox's patched Juggler (Firefox's Playwright automation protocol, the Firefox analog of CDP). This is where Playwright is made undetectable β the page agent runs in an isolated scope so injected automation JS is not visible to the page.
settings/βcamoufox.cfg,chrome.css,properties.json,camoucfg.jvv, prefs/policies. Copied into the source'slw/dir bycopy-additions.sh. Edit the built config withmake edit-cfg.scripts/βpatch.py(the patcher, LibreWolf-derived),developer.py(themake editsUI),package.py,copy-additions.sh,install-deps.sh.pythonlib/β thecamoufoxPyPI package: the Playwright-compatible Python interface that generates + injects fingerprints via BrowserForge and launches the binary.fingerprint-presets-v150.jsonholds real scraped fingerprints. This is the user-facing API; the browser binary is the backend.jsonvv/β JSON-with-validation format library used forcamoucfg.jvv(config schema).legacy/launcher/β Go launcher binary.assets/βbase.mozconfigand other build inputs.
Two suites, both required for PRs (they cover different layers):
build-tester/β tests the raw binary directly (bypasses the Python package); fingerprints injected viagenerate_context_fingerprint+addInitScriptandCAMOU_CONFIG. Run when changing patches / C++ / JS browser layer:cd build-tester && npm install && pip install -r requirements.txt python scripts/run_tests.py /path/to/camoufox-binary
service-tester/β tests the Python package / service layer.tests/β Playwright tests, run viamake tests(addheadful=truefor headful): points atcamoufox-*/obj-*/dist/bin/camoufox-bin.
ccache is enabled in the build config β install it for fast incremental rebuilds (cold ~40 min, incremental ~5 min).
- The
camoufox-*/source directory is regenerated β persist changes as patches, never as edits committed to that tree. - Keep the
Makefilediff clean againstmainunless a change genuinely belongs there β dependency setup lives inscripts/install-deps.sh, not the Makefile. - Every PR must be tied to a GitHub issue and pass both test suites (see
CONTRIBUTING.md).