Your HTTP client has a TLS fingerprint. Antibot systems check it before anything else — before your headers, your cookies, your User-Agent. If your fingerprint screams "Python script," you're blocked before your request even reaches the server.
tlsprint tells you exactly what antibots see when you connect.
$ tlsprint
┌┬┐┬ ┌─┐┌─┐┬─┐┬┌┐┌┌┬┐
│ │ └─┐├─┘├┬┘││││ │
┴ ┴─┘└─┘┴ ┴└─┴┘└┘ ┴ v0.1.0
see what antibots see when you connect
──────────────────────────────────────────────────────────
TLS Fingerprint Analysis
source: tls.peet.ws
──────────────────────────────────────────────────────────
Identified as: Python requests 2.x
Bot risk: BURNED
Confidence: high (exact JA3 match)
Fingerprints
JA3: e7d705a3286e19ea42f587b344ee6865
JA4: t13d1412h2_e7d705a3286e_6773e2b9c46c
⚠ This client is trivially detected by antibots.
Most WAFs (Cloudflare, Akamai, DataDome) will block
or challenge you immediately based on TLS fingerprint.
Every TLS client hello contains a unique combination of cipher suites, extensions, and protocol versions. This gets hashed into a JA3 fingerprint (and the newer JA4 format). Antibot systems maintain databases of these hashes.
The problem: Python requests, Go net/http, aiohttp, httpx — they all have well-known fingerprints that are instantly flagged. Spoofing your User-Agent to look like Chrome does nothing if your TLS handshake says "I'm a Python script."
tlsprint checks your fingerprint against a database of known clients and tells you:
- What you look like (Chrome 120? Python requests? cURL?)
- Your risk level (safe / risky / burned)
- Your actual JA3 and JA4 hashes
- What to do about it if you're flagged
pip install git+https://github.com/notchaosuu/tlsprint.gitor clone it:
git clone https://github.com/notchaosuu/tlsprint.git
cd tlsprint
pip install -e .Zero dependencies. Just Python 3.9+.
tlsprinttlsprint --ja3 e7d705a3286e19ea42f587b344ee6865tlsprint --ja3 1d9a054bac1eef41f30d370f9bbb2ad2 --ja4 t13d1516h2_8daaf6152771_02713d6af862This is how you test any HTTP client — grab its fingerprint from tls.peet.ws, then pass it to tlsprint:
# get fingerprint from tls_client, requests, curl, whatever
import tls_client
session = tls_client.Session(client_identifier="chrome_120")
resp = session.get("https://tls.peet.ws/api/all")
data = resp.json()
print(f"JA3: {data['tls']['ja3_hash']}")
print(f"JA4: {data['tls'].get('ja4', '')}")# then check it
tlsprint --ja3 <hash> --ja4 <hash>tlsprint --curltlsprint --curl-path /usr/local/bin/curl-impersonate-chrometlsprint -vtlsprint --json | jq '.match.risk'tlsprint --local| Level | What it means |
|---|---|
| SAFE | Matches a real browser fingerprint. You'll pass TLS-level checks on Cloudflare, Akamai, DataDome, etc. |
| RISKY | Might pass basic setups but will get flagged by stricter antibot configs. |
| BURNED | Instant detection. Every major antibot has this fingerprint in their blocklist. |
If you're using Python and your fingerprint is burned:
- tls-client (Go library with Python bindings) — spoofs browser TLS fingerprints
- curl-impersonate — curl builds that impersonate Chrome/Firefox
- tls-requests — Python requests-compatible with custom fingerprints
- patchright — patched Playwright that avoids detection
Run tlsprint --curl-path /path/to/curl-impersonate-chrome after installing curl-impersonate to verify it actually works.
tlsprint ships with fingerprints for:
- Chrome, Firefox, Safari, Edge (multiple versions)
- Python requests, httpx, aiohttp, urllib3
- Go net/http
- Java HttpClient, OkHttp
- Node.js fetch, axios
- cURL (default + impersonate)
- Selenium, Puppeteer, Playwright
- tls-client, cycletls
- Scrapy, Mechanize
The database is in tlsprint/fingerprints.py. PRs welcome if you have hashes I'm missing.
- Connects to a TLS fingerprint echo service (tls.peet.ws, ja3er.com, or scrapfly)
- The service captures the raw TLS Client Hello from your connection
- Hashes it into JA3/JA4 format
- Compares against the local database of known client fingerprints
- Tells you what you look like and whether antibots will flag you
No data is stored. No accounts needed. The fingerprint services just echo back what they see.
- Bug bounty recon — check if your tools will get blocked before you start testing
- Scraping — verify your client passes TLS checks before hitting rate limits
- Security research — understand how antibot fingerprinting works
- CI/CD — add
tlsprint --jsonto your pipeline to catch TLS fingerprint regressions
MIT