FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

HeadlessXLabs/hexium-browser: Stealth antidetect browser for Playwright — patched Chromium 151 with C++ persona, persistent profiles, humanize & GeoIP. launch() in, Chrome out. · GitHub

Repository files navigation


Launch like Chrome. Stay undetected.

Playwright in. Chrome 151 out. Built by HeadlessX Labs.

Sites see Google Chrome 151. You see Hexium Browser — a C++ persona compiled into Chromium, persistent disk profiles, humanize, and GeoIP locale. No JS injectors.


Headless Google search, new profile — examples/linux-native/google_search_human_headless_new_profile.py


Headed linux-native Allegro cookie consent — examples/linux-native/allegro_pl_headed_http_proxy_ephemeral_random_profile.py

Features

  • Playwright launch() — headed and --headless=new
  • Linux x86_64 binary in this alpha (Windows and macOS not supported yet)
  • Persistent disk profiles (real tabs, not Incognito)
  • C++ persona presets — Linux default linux-native; see Personas
  • Seeded fingerprint sample (fingerprint= or auto --hexium-seed=) — not a new GPU every page
  • Humanized mouse, keys, and scroll (humanize=True)
  • GeoIP timezone, locale, and WebRTC IP from the egress IP (on by default)
  • Chrome 151 web identity (User-Agent and related surface)

Depth lives in docs/. This README is the quickstart.

Launch

from hexium_browser import launch

browser = launch(headless=True)  # new ~/.hexium/profiles/hexium-session-* + new fingerprint
browser = launch(
    profile="Work",
    headless=True,
    proxy="http://user:pass@host:port",
    humanize=True,
    fingerprint="account-1",
)  # sticky ~/.hexium/profiles/Work

browser.new_page() opens a tab. Bare launch() is a new visitor each time; use profile="Work" or HEXIUM_USER_DATA_DIR to return to the same identity.

python examples/linux-chrome/linux_chrome_persona.py
python examples/windows-chrome/windows_chrome_persona.py --headed
python examples/linux-native/stealth_test.py
python examples/linux-native/open_google.py
python examples/linux-native/test_headless.py
python examples/windows-chrome/test_headless.py

Install

pip install hexium-browser
pip install 'hexium-browser[geoip]'   # timezone / locale / WebRTC from egress IP
hexium-browser fetch                  # Chrome 151 binary (Linux x86_64)

From this repo (if PyPI is not what you want):

pip install 'hexium-browser[geoip] @ git+https://github.com/HeadlessXLabs/hexium-browser.git@v0.1.1'
hexium-browser fetch

Requires Python 3.9+ and the Playwright driver (ships with the playwright package). Do not playwright install chromium — Hexium launches its own Chrome 151 binary.

GeoIP is on by default; without the extra, launch continues and timezone stays the sampled UTC.

Docker

Linux x86_64 only (linux/amd64). The image already has hexium-browser[geoip] and the Chrome 151 binary. The entrypoint starts Xvfb :99 so headed launch(headless=False) works without a monitor.

docker pull saifyxpro/hexium-browser:0.1.1
# or: docker pull saifyxpro/hexium-browser:latest

docker run --rm saifyxpro/hexium-browser:0.1.1 hexium-browser info --quick

docker run --rm saifyxpro/hexium-browser:0.1.1 python -c \
  "from hexium_browser import launch; b=launch(headless=True); p=b.new_page(); p.goto('https://example.com'); b.close()"

Keep a named profile on the host:

mkdir -p ~/.hexium/profiles
docker run --rm \
  -v ~/.hexium/profiles:/root/.hexium/profiles \
  saifyxpro/hexium-browser:0.1.1 \
  python -c "from hexium_browser import launch; b=launch(profile='Work', headless=True); b.close()"

Build locally from this repo:

docker build -t saifyxpro/hexium-browser .

CLI

hexium-browser fetch          # download the engine (API, then GitHub Releases)
hexium-browser install        # alias for fetch
hexium-browser info           # wrapper + binary diagnostics
hexium-browser info --quick   # skip launching chrome --version
hexium-browser info --json
hexium-browser info --proxy socks5://user:pass@host:1080
hexium-browser doctor         # alias for info
hexium-browser clear-cache    # delete ~/.hexium cached binaries
hexium-browser profiles       # list named profiles
hexium-browser profiles list
hexium-browser profiles new Work
hexium-browser profiles use Work
hexium-browser profiles last

Profiles

Hexium is a real Chrome user-data-dir, not Incognito. Bare launch() creates a new ~/.hexium/profiles/hexium-session-* and a new fingerprint. Named profiles stick. profiles use only records the last name for the CLI; launch() still needs profile="Work" (or HEXIUM_USER_DATA_DIR) to reopen it.

from hexium_browser import launch
launch()  # new identity
launch(profile="Work")  # returning visitor

The sampled persona sticks on a named profile until you pass a new fingerprint= or use another profile=.

Migrating from Playwright? One-line change:

- from playwright.sync_api import sync_playwright
- pw = sync_playwright().start()
- browser = pw.chromium.launch()
+ from hexium_browser import launch
+ browser = launch()

page = browser.new_page()
page.goto("https://example.com")
# ... rest of your code works unchanged

page.goto(), click(), fill(), locator(), and browser.close() are the same Playwright objects. Do not pass executable_path or channel. browser.new_page() is a tab on a persistent disk profile (not Incognito). If you used browser.new_context(), switch to launch(profile="Work") or keep calling new_page().

Why Hexium Browser?

  • JS stealth injectors break — they patch navigator in page JS. Detection sites look for the patch. Hexium does not inject stealth scripts.
  • Persona is compiled in — GPU, screen, UA, and hardware reporting follow a sampled Chrome persona at the C++ layer, plus a persistent profile on disk.
  • Same Playwright API — launch(), new_page(), click(), fill(). Swap the import.
  • Humanize is a flag — Bézier mouse, per-character typing, realistic scroll. Optional show_cursor=True for headed debug demos only.

Hexium does not solve CAPTCHAs. Bring your own proxy. Use the Playwright API you already know.

Test results

Captured 12–14 Sep 2026 against live oracles with Chrome 151. These are screenshots, not a guarantee that every site will score the same.

Shop / cookie-consent capture (headed linux-native, ephemeral session, HTTP proxy placeholders): Allegro “Dbamy o Twoją prywatność” — examples/linux-native/allegro_pl_headed_http_proxy_ephemeral_random_profile.py.


Headed Linux native — Allegro consent. Use headed + ephemeral + your own proxy for shops; do not run this flow headless.

Headless walk (examples/linux-native/test_headless.py, examples/windows-chrome/test_headless.py): headless-detector.vercel.app then Infosimples detect-headless.

Oracle What the capture shows
Headless detector (Linux, linux-native) 0.10 — Normal Browser
Headless detector (Win32, windows-chrome) 0.00 — Normal Browser
Infosimples detect-headless (both) WebDriver missing, Time Elapse passes. Yellow “Broken Image” is that page’s check, not Hexium.
reCAPTCHA v3 demo score 0.9
BrowserScan bot detection Normal
deviceandbrowserinfo.com You are human! (isBot: false)
bot.sannysoft.com WebDriver missing, window.chrome present, plugins 5, UA Chrome/151
Rebrowser bot detector no webdriver / no __pwInitScripts (some checks need a click to fire)
Linux linux-native — headless detector 0.10, Normal Browser Linux — Infosimples (Time Elapse pass)
windows-chrome — headless detector 0.00, Normal Browser windows-chrome — Infosimples (Time Elapse pass)
reCAPTCHA v3 demo — score 0.9 BrowserScan bot detection — Normal
deviceandbrowserinfo.com — “You are human!” bot.sannysoft.com — WebDriver missing, Chrome present, plugins 5
Rebrowser bot detector — no webdriver, no Playwright init scripts bot.incolumitas.com — examples/linux-native/stealth_test.py

whoer.net — headed, ephemeral random profile, rotating HTTP proxy (HEXIUM_PROXY). Captures from examples/*/whoer_headed_http_proxy_ephemeral_random_profile.py.

linux-native windows-chrome linux-chrome
CreepJS
CreepJS (noise=false) — examples/linux-native/stealth_test.py CreepJS — examples/linux-native/fingerprint_scan_test.py
fingerprint-scan.com


fingerprint-scan.com — examples/linux-native/fingerprint_scan_test.py

Stealth/oracle examples pass humanize=True and leave show_cursor off (default). Pass show_cursor=True only in headed debug demos such as humanize_click_demo.py.

Humanize

launch() defaults to humanize=True and show_cursor=False. Pass show_cursor=True in humanize_click_demo.py to see the blue debug ring.

from hexium_browser import launch

browser = launch(headless=False, humanize=True)
page = browser.new_page()
page.goto("https://example.com")
page.locator("#email").fill("user@example.com")
page.locator("button[type=submit]").click()
Interaction Playwright default humanize=True
Mouse Instant teleport Bézier curve, easing, slight overshoot
Clicks Instant Aim point + hold
Keyboard Instant fill Per-character timing
Scroll Jump Accelerate → cruise → decelerate
Humanize click demo Still
Same demo — virtual highlighter mid-path
Headed Google search Still
After the headed search — “Nextjs Latest version”
DABI interaction oracle Still
Same interaction run — still frame
Headless, reused profile Headless, fresh profile

Personas

launch(persona=…) or HEXIUM_PERSONA. Linux default is linux-native. Windows default is windows-native. macOS default is macos-native (alias mac-native). Pass windows-chrome or linux-chrome to sample. A *-native name that does not match this OS remaps to the host native. The engine binary alone uses the same host defaults.

Preset What sites see GPU / fonts When
linux-native This machine Host GPU, fonts, screen, CPU Linux default.
windows-native This Windows machine Host GPU, fonts, screen, CPU Windows default.
macos-native This macOS machine Host GPU/fonts macOS default. Alias mac-native. No macos-chrome.
linux-chrome Linux x86_64 + Chrome 151 Sampled screen/CPU/RAM; GPU/WebGL and fonts stay host (no Mesa/font jail) persona="linux-chrome"
windows-chrome Win32 + Chrome 151 Sampled D3D11 WebGL + Segoe pack. On Linux: known WebGL −5% pixel-vs-name tell (not claimed fixed). persona="windows-chrome" (alias windows-1080p)
from hexium_browser import launch

launch()                              # Linux: linux-native + GeoIP tz/lang
launch(persona="linux-chrome")        # Linux UA, sampled screen/CPU/RAM, host GPU/fonts
launch(persona="windows-chrome")      # Win32 UA + D3D + Segoe pack
launch(fingerprint="off")             # fingerprint patches off
launch(persona="windows-chrome", fingerprint="account-1")  # same machine next time

Windows-on-Linux needs the Segoe pack shipped in the wrapper (HEXIUM_FONTS_DIR overrides). Desktop UA-CH model is empty (stock Chrome 151). Do not cartesian OS×GPU — one OS + one joint sample.

python examples/linux-chrome/linux_chrome_persona.py
python examples/windows-chrome/windows_chrome_persona.py --headed

What is random vs sticky

A fingerprint seed picks one coherent device. Same seed → same machine. Bare launch() mints a new seed (and a new hexium-session-*). profile="Work" or fingerprint="account-1" reuses persona.json.

Surface Source Sticky with seed?
Screen (width/height/avail/DPR) Joint Chrome desktop sample Yes
hardwareConcurrency, deviceMemory Same sample (Windows desktop min 4 GB) Yes
WebGL vendor/renderer, WebGPU vendor/arch Same sample (windows-chrome only) Yes
UA-CH platformVersion (Win10 vs Win11) Same sample; clamped to 10.0.0 / 15.0.0 (never 19.0.0); UA rewritten to 151.0.7922.174 Yes
Fonts Fixed Windows pack on windows-chrome; host on linux-* Yes (not shuffled per page)
Timezone, locale, navigator.languages, WebRTC IP GeoIP from egress IP (default on) Follows the proxy/IP, not the seed
Canvas LSB noise Off unless args=["--hexium-noise=on"] Seed-stable if you turn it on
Mouse / keys / scroll humanize=True (default) No — new path each action (human_preset="default" or "careful")

GeoIP does not re-roll the GPU. Explicit timezone= / locale= always win over GeoIP.


linux-chrome persona on example.com (examples/linux-chrome/linux_chrome_persona.py)

Binary

Linux x86_64 only for this alpha. Windows and macOS are not supported yet — we are actively working on them. Thanks for your patience.

Archives are named Hexium + engine version + OS + arch:

Hexium-{VERSION}-{os}-{arch}.tar.gz

This ship:

Hexium-151.0.7922.174.1-linux-x64.tar.gz

Unpack it and you get hexium-v151.0.7922.174.1/chrome (same layout as ~/.hexium/hexium-v{VERSION}/). Point HEXIUM_BINARY_PATH at that chrome, or run hexium-browser fetch.

The tarball is attached once, on the engine release — not on Python vX.Y.Z tags:

hexium-browser fetch tries https://headlessx.dev/api/download first. On 404 it downloads:

https://github.com/HeadlessXLabs/hexium-browser/releases/download/Hexium-{VERSION}/Hexium-{VERSION}-linux-x64.tar.gz

If that version is gone, fetch takes the newest GitHub tag named Hexium-* (never the Python v0.1.0 tag).

Resolution order:

  1. HEXIUM_BINARY_PATH (alias HEXIUM_BINARY)
  2. $HEXIUM_OUT/hexium-v{VERSION}/chrome if it exists
  3. Cache under ~/.hexium/hexium-v{VERSION}/
  4. hexium-browser fetch — headlessx.dev API, then GitHub Releases Hexium-{VERSION}

Pin the engine with HEXIUM_VERSION.

Env Job
HEXIUM_DOWNLOAD_URL Primary download prefix (default https://headlessx.dev/api/download)
HEXIUM_VERSION Engine version (151.0.7922.174.1)
HEXIUM_BINARY_PATH Exact chrome path
HEXIUM_OUT Local out root
HEXIUM_CACHE_DIR Cache root (~/.hexium)
HEXIUM_GITHUB_REPO Releases repo (default HeadlessXLabs/hexium-browser)
hexium-browser fetch
hexium-browser info --quick

GeoIP

GeoIP is on by default. With hexium-browser[geoip], Hexium maps the egress IP (proxy exit, or the machine public IP when there is no proxy) to timezone, locale, languages, and --hexium-webrtc-ip=. Pass geoip=False to opt out. Explicit timezone= / locale= always win. Without the extra, launch continues and timezone stays the sampled UTC. Missing GeoLite2 still returns the exit IP so WebRTC does not leak LAN.

Docs

Doc What
Changelog 0.1.1 and later
Usage launch(), personas, GeoIP, humanize, profiles
CI Ubuntu Actions, Setup Hexium, pytest
Personas linux-native, linux-chrome, windows-native, windows-chrome, macos-native
Contributing Install, pytest, bug reports
Support How to file issues
Security Vulnerability reports
CLAUDE.md Agent / contributor product rules

Persona notes: linux-native · linux-chrome · windows-native · windows-chrome · macos-native

Troubleshooting

Still getting blocked on aggressive sites (DataDome, Turnstile)?

Some sites detect --headless=new even with the C++ persona. Run headed on a virtual display when you have no monitor:

# Install Xvfb (virtual framebuffer)
sudo apt install xvfb

# Start virtual display
Xvfb :99 -screen 0 1920x1080x24 &
export DISPLAY=:99
from hexium_browser import launch

# Headed Chrome + residential proxy
browser = launch(headless=False, proxy="http://your-residential-proxy:port")
page = browser.new_page()
page.goto("https://example.com")
browser.close()

That is a real headed window on Xvfb — no physical monitor. Combine with the config below. Pass show_cursor=False on stealth oracles (the highlighter is a DOM tell). Hexium does not solve CAPTCHAs.

Recommended config for anti-bot sites

Most blocks come from missing one of these three things, not from browser fingerprint detection:

from hexium_browser import launch

browser = launch(
    proxy="http://your-residential-proxy:port",  # residential IP — datacenter IPs get blocked by reputation alone
    geoip=True,      # default; timezone + locale follow the proxy exit IP
    headless=False,  # headed — some sites still detect --headless=new
    humanize=True,   # default; mouse, keys, scroll
)

geoip=True needs pip install 'hexium-browser[geoip]'. Without the extra, launch still works and timezone stays the sampled UTC.

If the proxy supports SOCKS5, prefer it — SOCKS5 tunnels raw TCP and avoids HTTP CONNECT issues some proxies have with HTTP/2:

browser = launch(
    proxy="socks5://user:pass@proxy:1080",
    geoip=True,
    headless=False,
    humanize=True,
)

Linux default persona is linux-native. Windows default is windows-native. macOS default is macos-native. windows-chrome uses the wrapper Segoe pack (HEXIUM_FONTS_DIR to override). Named profile= keeps the same fingerprint; a bare launch() is a new visitor each time.

Sites challenge fresh sessions but work after first visit

Some sites challenge first-time visitors with no cookies over HTTP/2. That is a Chromium / site behavior, not a Hexium-only tell. Warm cookies once on a named profile, then reuse it:

from hexium_browser import launch

# First run: warm up with --disable-http2
browser = launch(profile="Shop", args=["--disable-http2"])
page = browser.new_page()
page.goto("https://example.com")  # writes cookies into ~/.hexium/profiles/Shop
browser.close()

# Later runs — same profile, no --disable-http2
browser = launch(profile="Shop")
page = browser.new_page()
page.goto("https://example.com")  # returning visitor
browser.close()

A bare launch() is a new hexium-session-* every time, so cookies never come back. Pin profile= (or user_data_dir=) when you need a returning visitor.

For a one-shot session, launch(args=["--disable-http2"]) forces HTTP/1.1. Only use that flag on sites that need it — most are fine on HTTP/2. SOCKS5 (proxy="socks5://user:pass@host:port") avoids HTTP CONNECT entirely.

What's next

Python hexium_browser already ships (PyPI). First-party packages still to land (thin bindings over the same launch() contract — not a new fingerprint stack):

License

Last reviewed: 14 Sep 2026

Releases

Packages

Contributors

Languages


Back | FazBrowse Home | New Git URL