Skip to main content

TLS-Chameleon

TLSChameleom

PyPI version CI

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_capture too.

  • 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 of random_seed=.

🆕 What's New in v3.0.0

  • Pluggable transport architecturecurl, native (primp/rustls) and httpx backends 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.
  • Diagnosticsresponse.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 via random_seed.
  • CLIchameleon 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 reportingclient.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 control
    • native — primp/rustls stack: browser impersonation without libcurl
    • httpx — 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_retry hooks
  • 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!

zied

📜 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

tls_chameleon-3.1.1.tar.gz (132.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tls_chameleon-3.1.1-py3-none-any.whl (121.1 kB view details)

Uploaded Python 3

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

Hashes for tls_chameleon-3.1.1.tar.gz
Algorithm Hash digest
SHA256 adef2b4d3d9233be1a024952dad2153e9a018833002d34d362e8b2548d6d7d2d
MD5 682cce244c0e29ea8fe4322d3d09f6f3
BLAKE2b-256 0fc929e9b17af383f9cfe8b86c528756d4d52f8aed9f02ae4a6ff0646da65814

See more details on using hashes here.

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

Hashes for tls_chameleon-3.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0334f5730f072927cfc50fc2d6a30e2b5addafb7afaee5ad0ad7e6667953a63e
MD5 57806162015509ca0bec425233240c51
BLAKE2b-256 9f7367249c55952a7677a43d590855a7f29df44937a73676e30e5e7173193a32

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

3.1.1 This release

2 files

3.1.0

2 files

3.0.1

2 files

3.0.0

2 files

2.2.0

2 files

2.1.1

2 files

2.1.0

2 files

2.0.0

2 files

1.2.0

2 files

1.1.1

2 files

1.1.0

2 files

1.0.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page