Home

Awesome

<img src="https://i.imgur.com/enUBkXt.png" align="center"> <h1 align="center">Camoufox</h1> <h4 align="center">A stealthy, minimalistic, custom build of Firefox for web scraping 🦊</h4> <p align="center"> Camoufox is an open source anti-detect browser for robust fingerprint injection & anti-bot evasion. </p> <p align="center"> <a href="https://ko-fi.com/Z8Z2EFH5A"> <img src="https://ko-fi.com/img/githubbutton_sm.svg"> </a> </p>

[!NOTE] All of the latest documentation is avaliable at camoufox.com.

Camoufox is the most modern, effective & future-proof open source solution for avoiding bot detection and intelligent fingerprint rotation. It outperforms most commercial anti-bot browsers.


<a href="https://scrapfly.io/?utm_source=github&utm_medium=sponsoring&utm_campaign=camoufox" target="_blank"> <img src="https://raw.githubusercontent.com/daijro/camoufox/main/assets/scrapfly.png" alt="Scrapfly.io" width="149"> </a>

Scrapfly is an enterprise-grade solution providing Web Scraping API that aims to simplify the scraping process by managing everything: real browser rendering, rotating proxies, and fingerprints (TLS, HTTP, browser) to bypass all major anti-bots. Scrapfly also unlocks the observability by providing an analytical dashboard and measuring the success rate/block rate in detail.


Features


Fingerprint Injection

In Camoufox, data is intercepted at the C++ implementation level, making the changes undetectable through JavaScript inspection.

To spoof fingerprint properties, pass a JSON containing properties to spoof to the Python interface:

>>> with Camoufox(config={"property": "value"}) as browser:

Config data not set by the user will be automatically populated using BrowserForge fingerprints, which mimic the statistical distribution of device characteristics in real-world traffic.

<details> <summary> Legacy documentation </summary>

The following properties can be spoofed:

<details> <summary> Navigator </summary>

Navigator properties can be fully spoofed to other Firefox fingerprints, and it is completely safe! However, there are some issues when spoofing Chrome (leaks noted).

PropertyNotes
navigator.userAgent
navigator.doNotTrack
navigator.appCodeName
navigator.appName
navigator.appVersion
navigator.oscpu
navigator.language
navigator.languages
navigator.platform
navigator.hardwareConcurrency
navigator.product
navigator.productSub
navigator.maxTouchPoints
navigator.cookieEnabled
navigator.globalPrivacyControl
navigator.appVersion
navigator.buildID
navigator.doNotTrack

Camoufox will automatically add the following default fonts associated your spoofed User-Agent OS (the value passed in navigator.userAgent).

Notes:

</details> <details> <summary> Cursor movement </summary>

Human-like Cursor movement

Camoufox has built-in support for human-like cursor movement. The natural motion algorithm was originally from rifosnake's HumanCursor, but has been rewritten in C++ and modified for more distance-aware trajectories.

Demo

<video src="https://github.com/user-attachments/assets/6d33d6af-3537-4603-bf24-6bd3f4f8f455" width="500px" autoplay loop muted></video>

Properties

PropertySupportedDescription
humanizeEnable/disable human-like cursor movement. Defaults to False.
humanize:maxTimeMaximum time in seconds for the cursor movement. Defaults to 1.5.
showcursorToggles the cursor highlighter. Defaults to True.

Notes:

</details> <details> <summary> Fonts </summary>

Adding Fonts

Fonts can be passed to be used in Camoufox through the fonts config property.

By default, Camoufox is bundled with the default Windows 11 22H2 fonts, macOS Sonma fonts, and Linux fonts used in the TOR bundle.

Camoufox will automatically add the default fonts associated your spoofed User-Agent OS (the value passed in navigator.userAgent):

Other fonts can be added by copying them into the fonts/ directory in Camoufox, or by installing them on your system.

Note: It is highly recommended that you randomly pass custom fonts to the fonts config property to avoid font fingerprinting!

Font Metrics

Camoufox has a built in mechanism to prevent fingerprinting by font metrics & unicode glyphs:

<img src="https://i.imgur.com/X9hLKhO.gif">

This works by shifting the spacing of each letter by a random value between 0-0.1px.

</details> <details> <summary> Screen </summary>
PropertyStatus
screen.availHeight
screen.availWidth
screen.availTop
screen.availLeft
screen.height
screen.width
screen.colorDepth
screen.pixelDepth
screen.pageXOffset
screen.pageYOffset

Notes:

</details> <details> <summary> Window </summary>
PropertyStatusNotes
window.scrollMinX
window.scrollMinY
window.scrollMaxX
window.scrollMaxY
window.outerHeightSets the window height.
window.outerWidthSets the window width.
window.innerHeightSets the inner viewport height.
window.innerWidthSets the inner viewport width.
window.screenX
window.screenY
window.history.length
window.devicePixelRatioWorks, but not recommended.

Notes:

</details> <details> <summary> Document </summary>

Spoofing document.body has been implemented, but it is more advicable to set window.innerWidth and window.innerHeight instead.

PropertyStatus
document.body.clientWidth
document.body.clientHeight
document.body.clientTop
document.body.clientLeft
</details> <details> <summary> HTTP Headers </summary>

Camoufox can override the following network headers:

PropertyStatus
headers.User-Agent
headers.Accept-Language
headers.Accept-Encoding

Notes:

</details> <details> <summary> Geolocation & Intl </summary>
PropertyStatusDescriptionRequired Keys
geolocation:latitudeLatitude to use.geolocation:longitude
geolocation:longitudeLongitude to use.geolocation:latitude
geolocation:accuracyAccuracy in meters. This will be calculated automatically using the decminal percision of geolocation:latitude & geolocation:longitude if not set.
timezoneSet a custom TZ timezone (e.g. "America/Chicago"). This will also change Date() to return the local time.
locale:languageSpoof the Intl API, headers, and system language (e.g. "en")locale:region
locale:regionSpoof the Intl API, headers, and system region (e.g. "US").locale:language
locale:scriptSet a custom script (e.g. "Latn"). Will be set automatically if not specified.

The Required Keys are keys that must also be set for the property to work.

Notes:

</details> <details> <summary> WebRTC IP </summary>

Camoufox implements WebRTC IP spoofing at the protocol level by modifying ICE candidates and SDP before they're sent.

PropertyStatusDescription
webrtc:ipv4IPv4 address to use
webrtc:ipv6IPv6 address to use

Notes:

</details> <details> <summary> WebGL </summary>

WebGL in Camoufox

WebGL is disabled in Camoufox by default. To enable it, set the webgl.disabled Firefox preference to false.

WebGL being disabled typically doesn't trigger detection by WAFs, so you generally don't need to be concerned about it. Only use WebGL when it's absolutely necessary for your specific use case.

Because I don't have a dataset of WebGL fingerprints to rotate against, WebGL fingerprint rotation is not implemented in the Camoufox Python library. If you need to spoof WebGL, you can do so manually with the following properties.

Demo site

This repository includes a demo site (see here) that prints your browser's WebGL parameters. You can use this site to generate WebGL fingerprints for Camoufox from other devices.

<img src="https://i.imgur.com/jwT5VqG.png">

Properties

Camoufox supports spoofing WebGL parameters, supported extensions, context attributes, and shader precision formats.

Note: Do NOT randomly assign values to these properties. WAFs hash your WebGL fingerprint and compare it against a dataset. Randomly assigning values will lead to detection as an unknown device.

PropertyDescriptionExample
webGl:rendererSpoofs the name of the unmasked WebGL renderer."NVIDIA GeForce GTX 980, or similar"
webGl:vendorSpoofs the name of the unmasked WebGL vendor."NVIDIA Corporation"
webGl:supportedExtensionsAn array of supported WebGL extensions (full list).["ANGLE_instanced_arrays", "EXT_color_buffer_float", "EXT_disjoint_timer_query", ...]
webGl2:supportedExtensionsThe same as webGl:supportedExtensions, but for WebGL2.["ANGLE_instanced_arrays", "EXT_color_buffer_float", "EXT_disjoint_timer_query", ...]
webGl:contextAttributesA dictionary of WebGL context attributes.{"alpha": true, "antialias": true, "depth": true, ...}
webGl2:contextAttributesThe same as webGl:contextAttributes, but for WebGL2.{"alpha": true, "antialias": true, "depth": true, ...}
webGl:parametersA dictionary of WebGL parameters. Keys must be GL enums, and values are the values to spoof them as.{"2849": 1, "2884": false, "2928": [0, 1], ...}
webGl2:parametersThe same as webGl:parameters, but for WebGL2.{"2849": 1, "2884": false, "2928": [0, 1], ...}
webGl:parameters:blockIfNotDefinedIf set to true, only the parameters in webGl:parameters will be allowed. Can be dangerous if not used correctly.true/false
webGl2:parameters:blockIfNotDefinedIf set to true, only the parameters in webGl2:parameters will be allowed. Can be dangerous if not used correctly.true/false
webGl:shaderPrecisionFormatsA dictionary of WebGL shader precision formats. Keys are formatted as "<shaderType>,<precisionType>".{"35633,36336": {"rangeMin": 127, "rangeMax": 127, "precision": 23}, ...}
webGl2:shaderPrecisionFormatsThe same as webGL:shaderPrecisionFormats, but for WebGL2.{"35633,36336": {"rangeMin": 127, "rangeMax": 127, "precision": 23}, ...}
webGl:shaderPrecisionFormats:blockIfNotDefinedIf set to true, only the shader percisions in webGl:shaderPrecisionFormats will be allowed.true/false
webGl2:shaderPrecisionFormats:blockIfNotDefinedIf set to true, only the shader percisions in webGl2:shaderPrecisionFormats will be allowed.true/false
</details> <details> <summary> AudioContext </summary>

Camoufox can spoof the AudioContext sample rate, output latency, and max channel count.

PropertyStatusDescription
AudioContext:sampleRateSpoofs the AudioContext sample rate.
AudioContext:outputLatencySpoofs the AudioContext output latency.
AudioContext:maxChannelCountSpoofs the AudioContext max channel count.

Here is a testing site: https://audiofingerprint.openwpm.com/

</details> <details> <summary> Addons </summary>

In the Camoufox Python library, addons can be loaded with the addons parameter:

from camoufox.sync_api import Camoufox

with Camoufox(addons=['/path/to/addon', '/path/to/addon2']) as browser:
    page = browser.new_page()

Camoufox will automatically download and use the latest uBlock Origin with custom privacy/adblock filters, and B.P.C. by default to help with ad circumvention.

You can also exclude default addons with the exclude_addons parameter:

from camoufox.sync_api import Camoufox
from camoufox import DefaultAddons

with Camoufox(exclude_addons=[DefaultAddons.UBO, DefaultAddons.BPC]) as browser:
    page = browser.new_page()
<details> <summary> Loading addons with the legacy launcher... </summary>

Addons can be loaded with the --addons flag.

Example:

./launcher --addons '["/path/to/addon", "/path/to/addon2"]'

Camoufox will automatically download and use the latest uBlock Origin with custom privacy/adblock filters, and B.P.C. by default to help with scraping.

You can also exclude default addons with the --exclude-addons flag:

./launcher --exclude-addons '["uBO", "BPC"]'
</details>
</details> <details> <summary> Miscellaneous (battery status, etc) </summary>
PropertyStatusDescription
pdfViewerSets navigator.pdfViewerEnabled. Please keep this on though, many websites will flag a lack of pdfViewer as a headless browser.
battery:chargingSpoofs the battery charging status.
battery:chargingTimeSpoofs the battery charging time.
battery:dischargingTimeSpoofs the battery discharging time.
battery:levelSpoofs the battery level.
</details> </details> <hr width=50>

Patches

What changes were made?

Fingerprint spoofing

Stealth patches

Anti font fingerprinting

Playwright support

Debloat/Optimizations

Addons

Stealth Performance

In Camoufox, all of Playwright's internal Page Agent Javascript is sandboxed and isolated. This makes it impossible for a page to detect the presence of Playwright through Javascript inspection.

Tests

Camoufox performs well against every major WAF I've tested. (Original test sites from Botright)

TestStatus
CreepJS✔️ 71.5%. Successfully spoofs all OS predictions.
Rebrowser Bot Detector✔️ All tests pass.
BrowserScan✔️ 100%. Spoofs all geolocation & locale proxy detection.
reCaptcha Score✔️
nopecha.com✔️
recaptcha-demo.appspot.com✔️ 0.9
berstend.github.io✔️ 0.9
DataDome✔️
DataDome bot bounty✔️ All test sites pass.
hermes.com✔️
Imperva✔️
ticketmaster.es✔️
Cloudflare✔️
Turnstile✔️
Interstitial✔️
WebRTC IP Spoofing✔️
Browserleaks WebRTC✔️ Spoofs public IP correctly.
CreepJS WebRTC✔️ Spoofs Host & STUN IP correctly.
BrowserScan WebRTC✔️ Spoofs Host & STUN IP correctly.
Font Fingerprinting✔️
Browserleaks Fonts✔️ Rotates all metrics.
CreepJS TextMetrics✔️ Rotates all metrics.
Incolumitas✔️ 0.8-1.0
SannySoft✔️
Fingerprint.com✔️
IpHey✔️
Bet365✔️

Camoufox does not fully support injecting Chromium fingerprints. Some WAFs (such as Interstitial) test for Spidermonkey engine behavior, which is impossible to spoof.

Playwright Usage

See here for documentation on Camoufox's Python interface.

It is strongly recommended to use the Camoufox Python library instead of the legacy launcher, which is now deprecated.

<details> <summary> See legacy launcher usage (deprecated) </summary>

Camoufox is fully compatible with your existing Playwright code. You only have to change your browser initialization:

browser = pw.firefox.launch(
  executable_path='/path/to/camoufox/launch',  # Path to the Camoufox launcher
  args=['--config', '/path/to/config.json'],   # File path or JSON string
)
<details> <summary> See full example script... </summary>
import asyncio
import json
from playwright.async_api import async_playwright

# Example config
CONFIG = {
 'window.outerHeight': 1056,
 'window.outerWidth': 1920,
 'window.innerHeight': 1008,
 'window.innerWidth': 1920,
 'window.history.length': 4,
 'navigator.userAgent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0',
 'navigator.appCodeName': 'Mozilla',
 'navigator.appName': 'Netscape',
 'navigator.appVersion': '5.0 (Windows)',
 'navigator.oscpu': 'Windows NT 10.0; Win64; x64',
 'navigator.language': 'en-US',
 'navigator.languages': ['en-US'],
 'navigator.platform': 'Win32',
 'navigator.hardwareConcurrency': 12,
 'navigator.product': 'Gecko',
 'navigator.productSub': '20030107',
 'navigator.maxTouchPoints': 10,
}

async def main():
    async with async_playwright() as p:
        # Create a Firefox instance to the launcher
        browser = await p.firefox.launch(
          # Pass in the Camoufox launcher and config JSON
          executable_path='/path/to/camoufox/launch',
          args=['--config', json.dumps(CONFIG)],
          # Launch in headful mode
          headless=False
        )
        # Continue as normal
        page = await browser.new_page()
        await page.goto('https://abrahamjuliot.github.io/creepjs/')
        await asyncio.sleep(10)
        await browser.close()

if __name__ == "__main__":
    asyncio.run(main())
</details> </details>

[!NOTE] The content below is intended for those interested in building & debugging Camoufox. For Playwright usage instructions, see here.

<h1 align="center">Build System</h1>

Overview

Here is a diagram of the build system, and its associated make commands:

graph TD
    FFSRC[Firefox Source] -->|make fetch| REPO

    subgraph REPO[Camoufox Repository]
        PATCHES[Fingerprint masking patches]
        ADDONS[uBlock & B.P.C.]
        DEBLOAT[Debloat/optimizations]
        SYSTEM_FONTS[Win, Mac, Linux fonts]
        JUGGLER[Patched Juggler]
    end

    subgraph Local
    REPO -->|make dir| PATCH[Patched Source]
    PATCH -->|make build| BUILD[Built]
    BUILD -->|make package-linux| LINUX[Linux Portable]
    BUILD -->|make package-windows| WIN[Windows Portable]
    BUILD -->|make package-macos| MAC[macOS Portable]
    end

This was originally based on the LibreWolf build system.

Build CLI

[!WARNING] Camoufox's build system is designed to be used in Linux. WSL will not work!

First, clone this repository with Git:

git clone --depth 1 https://github.com/daijro/camoufox
cd camoufox

Next, build the Camoufox source code with the following command:

make dir

After that, you have to bootstrap your system to be able to build Camoufox. You only have to do this one time. It is done by running the following command:

make bootstrap

Finally you can build and package Camoufox the following command:

python3 multibuild.py --target linux windows macos --arch x86_64 arm64 i686
<details> <summary> CLI Parameters </summary>
Options:
  -h, --help            show this help message and exit
  --target {linux,windows,macos} [{linux,windows,macos} ...]
                        Target platforms to build
  --arch {x86_64,arm64,i686} [{x86_64,arm64,i686} ...]
                        Target architectures to build for each platform
  --bootstrap           Bootstrap the build system
  --clean               Clean the build directory before starting

Example:
$ python3 multibuild.py --target linux windows macos --arch x86_64 arm64
</details>

Using Docker

Camoufox can be built through Docker on all platforms.

  1. Create the Docker image containing Firefox's source code:
docker build -t camoufox-builder .
  1. Build Camoufox patches to a target platform and architecture:
docker run -v "$(pwd)/dist:/app/dist" camoufox-builder --target <os> --arch <arch>
<details> <summary> How can I use my local ~/.mozbuild directory? </summary>

If you want to use the host's .mozbuild directory, you can use the following command instead to run the docker:

docker run \
  -v "$HOME/.mozbuild":/root/.mozbuild:rw,z \
  -v "$(pwd)/dist:/app/dist" \
  camoufox-builder \
  --target <os> \
  --arch <arch>
</details> <details> <summary> Docker CLI Parameters </summary>
Options:
  -h, --help            show this help message and exit
  --target {linux,windows,macos} [{linux,windows,macos} ...]
                        Target platforms to build
  --arch {x86_64,arm64,i686} [{x86_64,arm64,i686} ...]
                        Target architectures to build for each platform
  --bootstrap           Bootstrap the build system
  --clean               Clean the build directory before starting

Example:
$ docker run -v "$(pwd)/dist:/app/dist" camoufox-builder --target windows macos linux --arch x86_64 arm64 i686
</details>

Build artifacts will now appear written under the dist/ folder.


Development Tools

This repo comes with a developer UI under scripts/developer.py:

make edits

Patches can be edited, created, removed, and managed through here.

<img src="https://i.imgur.com/BYAN5J0.png">

How to make a patch

  1. In the developer UI, click Reset workspace.
  2. Make changes in the camoufox-*/ folder as needed. You can test your changes with make build and make run.
  3. After you're done making changes, click Write workspace to patch and save the patch file.

How to work on an existing patch

  1. In the developer UI, click Edit a patch.
  2. Select the patch you'd like to edit. Your workspace will be reset to the state of the selected patch.
  3. After you're done making changes, hit Write workspace to patch and overwrite the existing patch file.

Leak Debugging

This is a flow chart demonstrating my process for determining leaks without deobfuscating WAF Javascript. The method incrementally reintroduces Camoufox's features into Firefox's source code until the testing site flags.

This process requires a Linux system and assumes you have Firefox build tools installed (see here).

<details> <summary> See flow chart... </summary>
flowchart TD
    A[Start] --> B[Does website flag in the official Firefox?]
    B -->|Yes| C[Likely bad IP/rate-limiting. If the website fails on both headless and headful mode on the official Firefox distribution, the issue is not with the browser.]
    B -->|No| D["Run make ff-dbg(1) and build(2) a clean distribution of Firefox. Does the website flag in Firefox **headless** mode(4)?"]
    D -->|Yes| E["Does the website flag in headful mode(3) AND headless mode(4)?"]
    D -->|No| F["Open the developer UI(5), apply config.patch, then rebuild(2). Does the website still flag(3)?"]
    E -->|No| G["Enable privacy.resistFingerprinting in the config(6). Does the website still flag(3)?"]
    E -->|Yes| C
    G -->|No| H["In the config(6), enable FPP and start omitting overrides until you find the one that fixed the leak."]
    G -->|Yes| I[If you get to this point, you may need to deobfuscate the Javascript behind the website to identify what it's testing.]
    F -->|Yes| K["Open the developer UI, apply the playwright bootstrap patch, then rebuild. Does it still flag?"]
    F -->|No| J["Omit options from camoufox.cfg(6) and rerun(3) until you find the one causing the leak."]
    K -->|No| M[Juggler needs to be debugged to locate the leak.]
    K -->|Yes| L[The issue has nothing to do with Playwright. Apply the rest of the Camoufox patches one by one until the one causing the leak is found.]
    M --> I

Cited Commands

#CommandDescription
(1)make ff-dbgSetup vanilla Firefox with minimal patches.
(2)make buildBuild the source code.
(3)make runRuns the built browser.
(4)make run args="--headless https://test.com"Run a URL in headless mode. All redirects will be printed to the console to determine if the test passed.
(5)make editsOpens the developer UI. Allows the user to apply/undo patches, and see which patches are currently applied.
(6)make edit-cfgEdit camoufox.cfg in the default system editor.
</details>

Thanks