Humanized Playwright browser with full anti-fingerprinting and TLS impersonation via curl-cffi
Project description
Phantomime
Phantomime is a humanized Playwright browser with full anti-fingerprinting and real Chrome TLS impersonation via curl-cffi. It mimics human behavior at every layer — mouse movement, typing, scrolling, idle activity — while spoofing the browser's hardware and software fingerprint so that automated sessions are indistinguishable from real users.
Features
- Canvas / WebGL fingerprint noise — deterministic per-session LCG, no canvas mutation
- TLS fingerprint — Chrome 124+ via
curl-cffi, bidirectional cookie sync with Playwright - Human mouse movement — cubic Bézier paths, overshooting, micro-tremor, Gaussian jitter
- Human typing — QWERTY typos with autocorrect, frustration errors, log-normal delays
- Scroll with inertia — progressive acceleration, matches browser physics
- Idle behavior — random moves, scrolls, hover clusters, micro-tremor
- 6 hardware profiles — Windows / macOS / Linux, OS-aware selection
- navigator / screen coherence —
platform,languages,plugins, Client Hints, battery, fonts - Network jitter — simulated via context-level route interception (covers Service Workers)
- Session warmup & history — visit referrer sites before the target
- Swarm execution —
run_swarm(asyncio) andrun_swarm_multiprocess(multiprocessing)
Installation
pip install phantomime
playwright install chromium
To use your system Chrome instead of Playwright's Chromium (better TLS):
pip install phantomime
# No playwright install needed
Quick start
import asyncio
from phantomime import HumanBrowser
async def main():
async with HumanBrowser(profile_dir="./my_profile", headless=True) as browser:
await browser.goto("https://example.com")
title = await browser.get_title()
print(title)
asyncio.run(main())
HumanBrowser parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
profile_dir |
str | Path |
"./hb_profile" |
Persistent profile directory. Its name seeds the fingerprint. |
headless |
bool |
False |
Headless mode via --headless=new (preserves GPU pipeline). |
locale |
str |
"es-ES" |
Browser locale — affects navigator.languages and Accept-Language. |
timezone |
str |
"Europe/Madrid" |
Timezone ID. Match with your proxy IP. |
proxy |
dict |
None |
{"server": "http://host:port", "username": "u", "password": "p"} |
slow_mo |
float |
0.0 |
Extra delay (ms) between Playwright actions. |
fixed_profile |
bool |
False |
Always use profile 0 (reproducible fingerprint). |
os_aware_profile |
bool |
True |
Pick a hardware profile matching the host OS. |
disable_service_workers |
bool |
False |
Disable Service Workers in Chromium. |
typo_rate |
float |
0.04 |
QWERTY typo probability per character. |
frustration_rate |
float |
0.01 |
Frustration-error probability per character. |
executable_path |
str |
None |
Path to system Chrome binary. None = Playwright's Chromium. |
Available methods
| Category | Methods |
|---|---|
| Lifecycle | launch, close, new_page |
| Navigation | goto, get_url, get_title, wait_for_url, go_back, go_forward |
| Interaction | click, type_text, select_option, press_key, hover, focus |
| Mouse | move_to, move_to_selector, micro_tremor, pre_drift_to |
| Scroll | scroll_down, scroll_up, scroll_to_element |
| HTTP (TLS) | fetch, sync_cookies_to_session, sync_cookies_from_session, sync_cookies |
| Extraction | get_text, get_all_text, get_attribute, is_visible, evaluate |
| Utilities | screenshot, wait_for, wait_between_actions, idle, warmup, enable_network_jitter, warm_history |
Direct HTTP with TLS fingerprint
Use fetch() when you need clean TLS without JS rendering (API calls, simple scraping). Cookies are synced automatically between Playwright and curl-cffi.
async with HumanBrowser(profile_dir="./profile") as browser:
await browser.goto("https://example.com") # log in via browser
response = await browser.fetch( # call API with same session
"https://api.example.com/data",
method="GET",
mode="xhr",
)
print(response.json())
mode controls Sec-Fetch-* headers — use "xhr", "cors", "navigate", or "no-cors" to match what a real browser would send.
Swarm execution
asyncio swarm (< 20 instances, same process)
from phantomime import HumanBrowser, run_swarm
async def scrape(browser: HumanBrowser, url: str) -> str:
await browser.goto(url)
return await browser.get_text("h1")
results = await run_swarm(
task=scrape,
items=["https://a.com", "https://b.com", "https://c.com"],
max_concurrent=3,
browser_kwargs={"headless": True},
)
Multiprocess swarm (large farms, full isolation)
import asyncio
from phantomime import HumanBrowser, run_swarm_multiprocess
def worker(url, profile_dir, browser_kwargs):
async def _inner():
async with HumanBrowser(profile_dir=profile_dir, **browser_kwargs) as browser:
await browser.goto(url)
return await browser.get_text("h1")
return asyncio.run(_inner())
if __name__ == "__main__":
results = run_swarm_multiprocess(
task_fn=worker,
items=["https://a.com", "https://b.com"],
max_workers=2,
browser_kwargs={"headless": True},
)
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file phantomime-9.0.1.tar.gz.
File metadata
- Download URL: phantomime-9.0.1.tar.gz
- Upload date:
- Size: 41.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c47710065c887b0eb7e9747fa6bc0d8680cf29e112b0e385ee549bee680c2f63
|
|
| MD5 |
195d2c7b17fb9854d0bf041ed11159a6
|
|
| BLAKE2b-256 |
8c97c32ad643d9369769e8a09e4c2a074bc0a1d13fbdb0e4e750b4d1db7a2032
|
File details
Details for the file phantomime-9.0.1-py3-none-any.whl.
File metadata
- Download URL: phantomime-9.0.1-py3-none-any.whl
- Upload date:
- Size: 24.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e6f6b2fb5fdbc9cd6f4928dbabbe871c053feb734be1ddd8597b51bacf7d4674
|
|
| MD5 |
1dd1260e64ae381736c8dbdfb090c7c5
|
|
| BLAKE2b-256 |
2404e073c08940b3ed2c7e478e97789706b523c6633d03590096af5230f54466
|