TLS-Chameleon
TLS-Chameleon is a modern Python HTTP networking stack with pluggable browser-fingerprint backends, structured fingerprint research tooling, diagnostics, and reproducible experiments — behind a simple, requests-like API.
What it IS: an HTTP client · a fingerprint-aware networking toolkit · a diagnostic system · a protocol-research framework.
What it is NOT: a Cloudflare/WAF bypass guarantee · a CAPTCHA solver · an anonymity or stealth product. Detection outcomes depend on many factors outside any client library's control.
🆕 What's New in v3.1.0
-
Chameleon/AsyncChameleon— the spec'd high-level API: WHAT vs HOW separation.from tls_chameleon import Chameleon client = Chameleon(profile="chrome_124_linux", backend="curl", seed=42) r = client.get("https://example.com")
-
Owned response objects — responses no longer proxy backend internals; an explicit surface (
status_code/text/content/headers/cookies/url/history/ ok/json()/raise_for_status()+.magnet/.trace) with self-documenting errors. -
ProxyConfig— typed proxy description (str| dict | dataclass), normalized once. -
SessionState— backend-independent session snapshots. -
Expanded truthful capabilities — every backend now reports
http1,tls_customization,websocket,fingerprint_capturetoo. -
chameleon compare-backends— alias of the benchmark runner for curl/native/httpx comparison. -
docs/research/— protocol & fingerprint analyses produced with our own tooling. -
seed=accepted everywhere as alias ofrandom_seed=.
🆕 What's New in v3.0.0
- Pluggable transport architecture —
curl,native(primp/rustls) andhttpxbackends behind one interface, auto-selected (curl → native → httpx) with graceful degradation. curl_cffi is optional, never architectural. - Structured fingerprint system — typed models, registry over 48 profiles, validator (rejects impossible/inconsistent configs), explainable similarity scoring, field-level diffing, live capture via TLS echo endpoints.
- Diagnostics —
response.trace,inspect_url(),doctor()with check-by-check verdicts; every output automatically redacted. - Adaptive engine — bounded/expiring/thread-safe domain memory with
explainable selection (
client.profile_for(domain)); header-consistency engine; deterministic randomization viarandom_seed. - CLI —
chameleon get / inspect / doctor / capture / diff / fingerprint / benchmark / version, all major commands with stable--json. - Reproducible benchmarks — real local-server harness, stored methodology, no invented numbers.
- Honest capability reporting —
client.capabilities.tls_fingerprint_spoofing,.http3, ... always reflect what the active backend actually does.
🚀 Features
- Three interchangeable backends
curl— curl-impersonate (curl_cffi): full JA3/JA4/H2 fingerprint controlnative— primp/rustls stack: browser impersonation without libcurlhttpx— honest fallback: standard OpenSSL TLS (no JA3 spoofing)
- 48+ versioned profiles: Chrome, Firefox, Safari, Edge across
Windows 10/11, macOS, Linux, iOS, Android — plus a deterministic
generative engine (
gen://family/os/major/tier/seed) - Fingerprint research toolkit: registry · validation · similarity · diff · live capture
- Diagnostics & doctor: protocol/backend/timing traces, observed-vs-profile comparison, actionable recommendations
- Adaptive behavior: per-domain profile learning (bounded, expiring, thread-safe, disableable), header casing/order morphing, WAF detection with retry/backoff/rotation
- Deterministic randomization: same seed ⇒ identical variants, cipher order and jitter — reproducible experiments
- Resilience: proxy/profile pools, rate limiting, ghost mode,
on_retryhooks - Magnet module 🧲: emails, tables, forms, JSON-LD, deep extraction of
JWTs/API keys; optional AI providers (
[ai]extra)
📦 Install
pip install tls-chameleon # core: works out of the box via httpx
pip install tls-chameleon[curl] # + curl-impersonate backend (JA3 spoofing)
pip install tls-chameleon[native] # + primp/rustls backend (JA3 spoofing, no curl)
pip install tls-chameleon[all] # everything
Backend honesty: without
[curl]or[native]you get the httpx fallback — standard OpenSSL TLS, no JA3 spoofing. The active backend and its true capabilities are always inspectable:
from tls_chameleon import TLSSession
client = TLSSession()
print(client.engine) # "curl" | "native" | "httpx"
print(client.capabilities.http3) # only if truly available
print(client.capabilities.tls_fingerprint_spoofing) # False on httpx!
Pluggable architecture
Public API (TLSSession / AsyncSession — unchanged names since v2)
│
tls_chameleon.transport.factory # auto / curl / native / httpx (+ custom)
│
Transport interface # duck-typed sessions, capability reports
├─ CurlTransport ← only module importing curl_cffi
├─ PrimpTransport ← only module importing primp
└─ HttpxTransport ← only module importing httpx
Backends are strictly isolated (enforced by tests). Custom backends plug in
via tls_chameleon.transport.register_transport.
⚡ Quick Start
from tls_chameleon import Chameleon # v3.1 high-level API
client = Chameleon(profile="chrome_130_win11") # WHAT: the fingerprint
# backend auto-selected: HOW
with client:
r = client.get("https://example.com", trace=True)
print(r.status_code, r.trace.protocol)
print(client.capabilities.to_dict())
Classic aliases still work: TLSSession / Session / AsyncSession.
Async:
import asyncio
from tls_chameleon import AsyncSession
async def main():
async with AsyncSession(profile="chrome_130_win11") as session:
r = await session.get("https://example.com", trace=True)
print(r.trace.protocol, r.trace.timing_ms)
asyncio.run(main())
CLI:
chameleon inspect https://example.com --json
chameleon doctor https://example.com --echo-endpoint https://tls.peet.ws/api/clean
chameleon capture https://tls.peet.ws/api/all --raw --json
chameleon fingerprint list --browser chrome
chameleon diff capture_a.json capture_b.json
🔬 Fingerprint System
from tls_chameleon import (
FingerprintRegistry, validate_fingerprint,
FingerprintSimilarity, diff_fingerprints, capture,
)
reg = FingerprintRegistry()
fp = reg.get("chrome_120_win11") # lazy lookup over all built-ins
issues = validate_fingerprint(fp) # structural + provenance checks
result = FingerprintSimilarity().compare(fp, reg.get("firefox_120_win11"))
print(result.total, result.layers) # explainable, weighted scoring
report = diff_fingerprints(fp, reg.get("firefox_120_win11"))
print(report.to_text()) # SAME/DIFFERENT per field + score
# Live capture: what does the network ACTUALLY see?
res = capture(session=client.session) # via TLS echo endpoint
print(res.fingerprint.tls.ja3_hash) # source="captured", timestamped
Provenance is explicit — every fingerprint is labeled
captured, documented or synthetic; synthetic data can never be marked
verified (enforced by the validator).
🩺 Diagnostics
from tls_chameleon import inspect_url, doctor
print(inspect_url("https://example.com", client).to_text())
report = doctor("https://example.com",
echo_endpoint="https://tls.peet.ws/api/clean")
print(report.to_text())
# [ ✓] Connection: h2 response 200 in 76ms
# [ ✓] Backend: backend 'curl' performs real TLS impersonation
# [ ⚠] Fingerprint (JA4): observed JA4 differs from profile ...
# Verdict: WARN
Traces attach to responses on demand — headers always redacted:
r = client.get(url, trace=True)
r.trace.backend / .protocol / .timing_ms / .request_headers
Unobservable fields stay None with an explanatory note — never guessed.
🧠 Adaptive Engine
client = TLSSession(adaptive=True, adaptive_ttl=3600, random_seed=12345)
client.profile_for("example.com")
# {'profile': 'chrome_130_win11', 'reason': 'learned after 3 successful
# request(s); 12s ago', 'confidence': 0.6, 'last_used': ...}
Domain memory is LRU-bounded, TTL-expiring, thread-safe, stores only
domain → profile (never credentials), and explains itself. Same seed +
config ⇒ byte-identical fingerprint choices for reproducible runs.
📚 Profiles
| Browser | Versions | OS |
|---|---|---|
| Chrome | 120–130, android, latest | win10/win11/macos/linux/android |
| Firefox | 120–124 | win10/win11/macos/linux |
| Safari | iOS 16/17, macOS 13/14 | ios/macos |
| Edge | 120, 124 | win10/win11 |
chameleon fingerprint list # or: list_available_profiles()
chameleon fingerprint show chrome_130_win11 --json
chameleon fingerprint validate my_profile.json
Generative fingerprints for research/fuzzing:
TLSSession(profile="gen://chrome/win11/124/balanced/7") — deterministic
per seed, always labeled synthetic.
🛠 API Reference (selection)
| Parameter | Type | Default | Description |
|---|---|---|---|
profile |
str |
None |
Profile name (e.g., 'chrome_124_linux') — the WHAT |
backend / engine |
str |
'auto' |
The HOW: 'curl', 'native', 'httpx'; auto-selects best installed (backend= on Chameleon, engine= everywhere) |
random_seed / seed |
Any |
None |
Deterministic randomization seed (seed= on Chameleon) |
randomize / randomize_ciphers |
bool |
False |
Variant generation / cipher-order shuffle |
adaptive / adaptive_ttl |
bool / float |
True / None |
Domain-memory learning + expiry seconds |
http2 / http3 |
bool |
None |
Protocol preferences (backend-dependent) |
verify |
bool |
True |
Certificate verification (never disabled silently) |
proxies / proxies_pool |
dict/str/list |
None |
Proxy config / rotation pool |
rotate_profiles / on_block |
list / str |
None / 'rotate' |
Block recovery: rotate/proxy/both/none |
rate_limit |
float |
None |
Max req/sec per domain |
ghost_mode |
bool |
False |
Timing jitter + payload padding |
Handy members: client.capabilities, client.profile_for(domain),
session.get_fingerprint_info(), response.trace,
save_cookies/load_cookies/export_session/import_session,
plus the Magnet extractors (response.magnet.*) and submit_form().
🖥 CLI
| Command | Purpose | Exit codes |
|---|---|---|
chameleon get URL [--trace] |
Spoofed request, redacted output | 0 ok / 1 error |
chameleon inspect URL |
One-request structured report | 0 / 1 |
chameleon doctor URL |
Connection/backend/profile/header checks | 0 (warn ok) / 1 fail |
chameleon capture [URL] |
Network-observed fingerprint | 0 / 1 |
chameleon diff A.json B.json |
Field-level fingerprint diff | 0 / 1 |
chameleon fingerprint list|show|validate |
Registry operations | 0 / 1 |
chameleon benchmark |
Reproducible local benchmarks | 0 / 3* |
chameleon compare-backends |
Same runner — curl vs native vs httpx | 0 / 3* |
chameleon version |
Version info | 0 |
All major commands accept --json with stable, documented schemas.
(*3 = feature pending its phase.)
📊 Benchmarks
Real local-server measurements only — methodology and limitations in
docs/BENCHMARK_METHODOLOGY.md, a labeled
sample run in docs/BENCHMARK_SNAPSHOT.md.
Absolute numbers are machine-specific; compare within a single report.
📖 Documentation
| Doc | Contents |
|---|---|
docs/ARCHITECTURE_AUDIT_3_0_1.md |
3.1 spec-to-code audit (gaps M1–M8) |
docs/ARCHITECTURE_AUDIT.md |
v2 audit + v3 migration plan |
docs/research/index.md |
fingerprint & protocol analyses (JA4, H2) |
docs/NATIVE_BACKEND_RESEARCH.md |
backend candidates, decision record |
docs/BENCHMARK_METHODOLOGY.md |
what the benchmark measures |
docs/migration/curl_cffi.md |
coming from raw curl_cffi |
CHANGELOG.md |
full v3.x change list |
🤝 Contributing
Issues and Pull Requests welcome!
🌟 Credits
Built on curl_cffi, primp, and httpx.
☕ Support / Donate
If you found this library useful, buy me a coffee!
📜 License
MIT
🚨 Is this library failing on a specific site?
Please open an issue with the URL! I need test cases to improve the fingerprinting logic.
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 tls_chameleon-3.1.1.tar.gz.
File metadata
- Download URL: tls_chameleon-3.1.1.tar.gz
- Upload date:
- Size: 132.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
adef2b4d3d9233be1a024952dad2153e9a018833002d34d362e8b2548d6d7d2d
|
|
| MD5 |
682cce244c0e29ea8fe4322d3d09f6f3
|
|
| BLAKE2b-256 |
0fc929e9b17af383f9cfe8b86c528756d4d52f8aed9f02ae4a6ff0646da65814
|
File details
Details for the file tls_chameleon-3.1.1-py3-none-any.whl.
File metadata
- Download URL: tls_chameleon-3.1.1-py3-none-any.whl
- Upload date:
- Size: 121.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0334f5730f072927cfc50fc2d6a30e2b5addafb7afaee5ad0ad7e6667953a63e
|
|
| MD5 |
57806162015509ca0bec425233240c51
|
|
| BLAKE2b-256 |
9f7367249c55952a7677a43d590855a7f29df44937a73676e30e5e7173193a32
|