cloudfetch
A Go HTTP client that gets past Cloudflare bot detection by sending a real browser's TLS fingerprint and matching headers.
- Fingerprints
- Chrome 133, Firefox 120, Safari 16.0, Edge 85
- Challenge solver
- Classic IUAM JS challenge, run in goja
- Transport
- HTTP/2 over ALPN, HTTP CONNECT proxies
- API
- Mirrors net/http: Do, Get, Post
Measured result
| Client | Response | Runs |
|---|---|---|
| curl | 403, challenge page | 1 |
| cloudfetch | 200, real page | 10 of 10 |
Conditions: one Cloudflare-protected site, a plain GET of its homepage, default Chrome profile, fresh and reused clients.
no challenge solved: the handshake alone got through
Characteristics
| Parameter | Value | Condition |
|---|---|---|
| IUAM pages solved | 3 of 3 | Recorded, known answers |
| Test coverage | 80% | Unit tests with -race |
| Turnstile, CAPTCHA | Not solved | Returned as an error |
Functional block diagram
What one request passes through. Pick a row in the table to mark its stage.
Your Go codeclient.Do(req)
*http.Request
cloudfetch
HeadersBrowser defaults
TLS ClientHellouTLS, Chrome 133
HTTP/2ALPN, x/net
Challenge solverIUAM, goja
ClientHello, h2
Cloudflare edgeClassifies the handshake
Allowed
OriginThe real page
| Stage | What it does | Why |
|---|---|---|
| Headers | Fills in the browser's own headers for the same version: User-Agent, Sec-CH-UA, Sec-Fetch-*. Headers set on the request still win. | A Chrome handshake with a Go User-Agent gives itself away. |
| TLS ClientHello | Reproduces the browser's ClientHello through uTLS: cipher suites, extensions and their order, GREASE values. | The edge classifies the handshake before any page loads. |
| HTTP/2 | Runs x/net's HTTP/2 client directly over the uTLS connection when ALPN picks h2. | net/http only speaks h2 over crypto/tls, and browsers always use h2. |
| Challenge solver | Detects the classic IUAM page, runs its arithmetic in goja, waits the required delay, then submits the answer. | Some sites still serve the classic challenge. |
Application notes and limits
How it was built, and where it stops working.
How cloudfetch gets past Cloudflare
Write-up · 2 November 2026Why Go's HTTP client is blocked on first contact, why the fix belongs in the TLS handshake, and what it took to run HTTP/2 and a JS challenge solver on top of it.
Read the write-up- Header order and HTTP/2 settingsThey come from Go, not the browser, so sites that fingerprint those can still tell.
- Newer JS challengesDetected, but the solver does not run their script, so they usually fail.
- Turnstile and CAPTCHAsNeed a real browser. cloudfetch returns ErrManagedChallenge or ErrCaptcha.
Revision history
| Rev | Date | Change |
|---|---|---|
| v0.2.0 | 29 Oct 2026 | API modelled on net/http: Do takes an *http.Request, sentinel errors, Browser presets, CloseIdleConnections. The IUAM solver passes real recorded pages. |
| v0.1.0 | 28 Oct 2026 | First release: browser TLS fingerprints, matching headers, IUAM solver, HTTP/2, proxies. |
Engineer of record
Vĩ Lê
Bio pending: role, focus and what I'm looking for go here.