impersonate-http
A Go http.Client whose TLS handshake is byte-identical to a real browser's,
so requests survive JA3 / JA4 fingerprinting (Cloudflare, Akamai, DataDome,
PerimeterX, …) — no headless browser, no CGo, no curl.
client := impersonate.New(impersonate.Chrome)
resp, _ := client.Get("https://example.com")
That's it — a stock *http.Client. Use it exactly as you would http.DefaultClient.
Install
go get github.com/North-web-dev/impersonate-http
Profiles
Chrome, Firefox, Safari, Edge, IOS — each sets the matching uTLS
ClientHello and the browser's default headers (User-Agent, sec-ch-ua,
Accept, Sec-Fetch-*, …). Look one up by name:
client, ok := impersonate.NewByName("firefox")
Or plug the transport into an existing client:
c := &http.Client{Transport: impersonate.NewTransport(impersonate.Safari)}
Caller-set headers are never overwritten by a profile's defaults.
Verified
Fingerprints measured against tls.peet.ws:
| Profile |
JA4 |
JA3 |
| Chrome |
t13d1516h2_8daaf6152771_… |
1d03c132ce29d0d7936acc72f12dd7a7 |
| Firefox |
t13d1715h2_5b57614c22b0_… |
b5001237acdf006056b409cc433726b0 |
| Safari |
t13d2014h2_a09f3c656075_… |
773906b0efdefa24a7f2b8eb6985bf37 |
The t13d1516h2_8daaf6152771 Chrome core (version + cipher list + ALPN + cipher
hash) matches a genuine Chrome handshake. Profiles track uTLS's *_Auto
templates, so they follow the current stable browser as uTLS updates.
Scope — what's exact and what isn't
- ✅ TLS ClientHello (JA3, JA4) — byte-exact per profile. This is the primary
signal every major anti-bot stack fingerprints first.
- ✅ Default headers & values — browser-accurate.
- ⚠️ HTTP/2 frames (Akamai fingerprint) — v0.1 uses Go's
x/net/http2
stack, so the HTTP/2 SETTINGS/window/priority fingerprint is Go's, not the
browser's. A site that fingerprints the H2 layer can still tell. Browser-exact
HTTP/2 (custom SETTINGS order, WINDOW_UPDATE, header priority, pseudo-header
order) is the v0.2 roadmap.
- ⚠️ Header order — best-effort; Go's transport controls final ordering.
If your target only checks JA3/JA4 (the common case), v0.1 is enough. If it also
scores the HTTP/2 fingerprint, wait for v0.2 or combine with a browser.
How it works
Each connection is dialed with uTLS:
a raw TCP dial, then a UClient handshake using the profile's ClientHelloID.
ALPN is probed once per host to pick HTTP/2 or HTTP/1.1; the chosen transport
re-runs the uTLS handshake for every pooled connection, so keep-alive and
connection reuse work as usual.
Disclaimer
Provided as is, without warranty of any kind, for lawful automation,
testing, and research. You are solely responsible for complying with the terms
and laws that apply to the sites you access. The authors accept no liability for
misuse.
License
MIT — see LICENSE.