httpcloak is a free, open source data extraction & web scraping project written in Go and released under MIT. It has 1,306 GitHub stars, 94 forks and 12 open issues, and was last pushed 16 days ago. On this registry it ranks #73 of 105 tracked projects in Data Extraction & Web Scraping, with 5 head-to-head comparisons available.

What is httpcloak?

httpcloak is an MIT-licensed Go HTTP client that makes outgoing requests identical to Chrome, Firefox, or Safari at the TLS, HTTP/2, HTTP/3, and header layers, and it is aimed at Go, Python, Node.js, and C# developers who scrape or integrate with sites that block clients on transport fingerprint rather than on User-Agent.

What it is

httpcloak is a browser-fingerprint HTTP client. Its core lives in Go at github.com/sardanioss/httpcloak, with the request client in the github.com/sardanioss/httpcloak/client package, and it ships bindings for Python, Node.js, and C# published as httpcloak on PyPI and npm and as HttpCloak on NuGet. Behaviour is selected through presets such as chrome-latest and Presets.Chrome145, which determine the emitted wire bytes for a request. Documentation sits at httpcloak.dev. The project sits in the Data & Analytics / Data Extraction & Web Scraping space, carries the MIT licence, and has 1,306 stars, 94 forks, and 12 open issues.

The problem it solves is that bot detection no longer stops at the User-Agent string. Modern detection fingerprints the TLS handshake, the HTTP/2 frames, the QUIC parameters, the order of headers, and whether the SNI is encrypted, and a single mismatch results in a block. A default standard-library HTTP client fails that check because its handshake was never shaped like a browser. httpcloak replaces that default client, and the manual fingerprint workaround around it, by emitting a full browser transport-layer fingerprint from a preset name.

Key capabilities

  • TLS emulation covering JA3 and JA4 fingerprints, GREASE randomization, post-quantum X25519MLKEM768, and ECH (Encrypted Client Hello) so that the SNI is encrypted rather than plaintext.
  • HTTP/2 emulation of SETTINGS frames, WINDOW_UPDATE values, and stream priorities using HPACK.
  • HTTP/3 and QUIC emulation of QUIC transport parameters and HTTP/3 GREASE frames.
  • TCP/IP stack emulation of TTL, MSS, and window values.
  • Header-layer emulation of Sec-Fetch-* coherence, Client Hints via Sec-Ch-UA, Accept and Accept-Language, header ordering, and cookie persistence.
  • Protocol support across HTTP/1.1, HTTP/2, and HTTP/3, with sessions, cookies, and proxies.
  • Custom presets built from JSON: capture the JA3 and Akamai fingerprint at tls.peet.ws/api/all in the target browser, register the spec, and get a preset that emits real wire bytes, inspectable through httpcloak.describe_preset.

Who uses it and how

  • Scraping and anti-bot teams working against sites behind Cloudflare and similar defences, where the TLS or HTTP/2 fingerprint, not the User-Agent, decides whether a request proceeds.
  • Python teams issuing httpcloak.get and httpcloak.post calls with preset="chrome-latest", passing JSON bodies or custom headers as needed.
  • Node.js teams holding a long-lived new httpcloak.Session({ preset: "chrome-latest" }) for async session.get and session.post calls, then session.close().
  • Go services constructing client.NewClient("chrome-latest"), calling c.Get(ctx, url, headers), and reading resp.Text() before defer c.Close().
  • C# teams using using var session = new Session(preset: Presets.Chrome145) with session.Get and session.PostJson.
  • Teams that need a browser the built-in presets do not cover, capturing a fingerprint once and reusing it as a registered preset.

Getting started

Install with the package manager for the target language: pip install httpcloak, npm install httpcloak, go get github.com/sardanioss/httpcloak, or dotnet add package HttpCloak. The first request in Python is httpcloak.get("https://example.com", preset="chrome-latest"), with full documentation at httpcloak.dev.

How it compares

The facts provided name no paid products that httpcloak replaces, and they name no peer tools in this category either, so within this registry it stands alone. Its distinguishing property is the licence and licence-free deployment model: it is MIT-licensed and self-hosted as a library, so there is no per-request billing surface and no vendor holding request data on the caller's behalf.

When to use it — and when not to

Adoption costs no infrastructure operation: there is no database, object storage, or SMTP service to run, because httpcloak is a client library that the application embeds. The real upkeep is presets — browser fingerprints drift as Chrome, Firefox, and Safari ship new releases, so a chrome-latest preset is only as good as the release it tracks, and a custom preset requires a manual capture from tls.peet.ws/api/all whenever the target browser changes. Projects that need a rendered DOM or JavaScript execution will still require a separate browser tool, since the documented surface is transport-level HTTP emulation, not page rendering.

project readme (upstream, from github) — read inline

Go Reference PyPI npm NuGet

Every Byte of your Request Indistinguishable from Chrome.

📖 Full documentation at httpcloak.dev



The Problem

Bot detection doesn't just check your User-Agent anymore.

It fingerprints your TLS handshake. Your HTTP/2 frames. Your QUIC parameters. The order of your headers. Whether your SNI is encrypted.

One mismatch = blocked.

The Solution

import httpcloak

r = httpcloak.get("https://target.com", preset="chrome-latest")

That's it. Full browser transport layer fingerprint.


What Gets Emulated

🔐 TLS Layer

  • JA3 / JA4 fingerprints
  • GREASE randomization
  • Post-quantum X25519MLKEM768
  • ECH (Encrypted Client Hello)

🚀 Transport Layer

  • HTTP/2 SETTINGS frames
  • WINDOW_UPDATE values
  • Stream priorities (HPACK)
  • QUIC transport parameters
  • HTTP/3 GREASE frames
  • TCP/IP stack (TTL, MSS, Window)

🧠 Header Layer

  • Sec-Fetch-* coherence
  • Client Hints (Sec-Ch-UA)
  • Accept / Accept-Language
  • Header ordering
  • Cookie persistence

Results

┌─────────────────────────────────┐
│  ECH (Encrypted Client Hello)   │
├─────────────────────────────────┤
│  WITHOUT:  sni=plaintext        │
│  WITH:     sni=encrypted   +    │
└─────────────────────────────────┘
┌─────────────────────────────────┐
│  HTTP/3 Fingerprint Match       │
├─────────────────────────────────┤
│  Protocol:        h3       +    │
│  QUIC Version:    1        +    │
│  Transport Params:         +    │
│  GREASE Frames:            +    │
└─────────────────────────────────┘

Install

pip install httpcloak        # Python
npm install httpcloak        # Node.js
go get github.com/sardanioss/httpcloak   # Go
dotnet add package HttpCloak # C#

Quick Start

Python

import httpcloak

# Simple request
r = httpcloak.get("https://example.com", preset="chrome-latest")
print(r.status_code, r.protocol)

# POST with JSON
r = httpcloak.post("https://httpbin.org/post",
    json={"key": "value"},
    preset="chrome-latest"
)

# Custom headers
r = httpcloak.get("https://httpbin.org/headers",
    headers={"X-Custom": "value"},
    preset="chrome-latest"
)

Go

import (
    "context"
    "github.com/sardanioss/httpcloak/client"
)

// Simple request
c := client.NewClient("chrome-latest")
defer c.Close()

resp, _ := c.Get(ctx, "https://example.com", nil)
body, _ := resp.Text()
fmt.Println(resp.StatusCode, resp.Protocol)

// POST with JSON
jsonBody := []byte(`{"key": "value"}`)
resp, _ = c.Post(ctx, "https://httpbin.org/post",
    bytes.NewReader(jsonBody),
    map[string][]string{"Content-Type": {"application/json"}},
)

// Custom headers
resp, _ = c.Get(ctx, "https://httpbin.org/headers", map[string][]string{
    "X-Custom": {"value"},
})

Node.js

import httpcloak from "httpcloak";

// Simple request
const session = new httpcloak.Session({ preset: "chrome-latest" });
const r1 = await session.get("https://example.com");
console.log(r1.statusCode, r1.protocol);

// POST with JSON
const r2 = await session.post("https://httpbin.org/post", {
    json: { key: "value" }
});

// Custom headers
const r3 = await session.get("https://httpbin.org/headers", {
    headers: { "X-Custom": "value" }
});

session.close();

C#

using HttpCloak;

// Simple request
using var session = new Session(preset: Presets.Chrome145);
var r1 = session.Get("https://example.com");
Console.WriteLine($"{r1.StatusCode} {r1.Protocol}");

// POST with JSON
var r2 = session.PostJson("https://httpbin.org/post",
    new { key = "value" }
);

// Custom headers
var r3 = session.Get("https://httpbin.org/headers",
    headers: new Dictionary<string, string> { ["X-Custom"] = "value" }
);

Features

🧬 Build Any Browser Fingerprint From JSON

Don't have a preset for your target browser? Capture once, use forever. Visit tls.peet.ws/api/all in the browser you want to mimic, paste the JA3 + Akamai fingerprint into a JSON spec, register it, and you have a brand-new preset that emits real wire bytes.

import json, httpcloak

# 1. Capture: visit tls.peet.ws/api/all in the browser, copy two fields.
PEET_JA3    = "771,4865-4866-4867-49195-49199-49196-49200-...,29-23-24,0"
PEET_AKAMAI = "1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p"

# 2. Start from any built-in preset, swap in the captured fingerprint.
spec = json.loads(httpcloak.describe_preset("chrome-latest"))
spec["preset"]["name"]            = "my-browser"
spec["preset"]["tls"]             = {"ja3": PEET_JA3}
spec["preset"]["http2"]["akamai"] = PEET_AKAMAI

# 3. Register, use like any built-in preset.
httpcloak.load_preset_from_json(json.dumps(spec))
session = httpcloak.Session(preset="my-browser")
r = session.get("https://target.com/")

describe_preset emits every effective field — TLS extensions, HTTP/2 SETTINGS order, HPACK encoding order, per-resource-type stream priority table, QUIC transport params, TCP/IP fingerprint, full header set — so anything you see in the JSON is editable. Mutated specs round-trip byte-equal through load_preset_from_json → run → describe_preset: same wire mechanics, just the values you changed.

Same workflow across all bindings:

Describe Load Unregister
Python httpcloak.describe_preset(name) httpcloak.load_preset_from_json(json) httpcloak.unregister_preset(name)
Node.js describePreset(name) loadPresetFromJSON(json) unregisterPreset(name)
.NET CustomPresets.Describe(name) CustomPresets.LoadFromJson(json) CustomPresets.Unregister(name)
Go fingerprint.Describe(name) fingerprint.LoadPresetFromJSON(json) fingerprint.Unregister(name)

Pool dozens of fingerprints with PresetPool (round-robin / random rotation, all bindings). Drill-down recipes — bumping a single H2 priority, inserting an HPACK header, importing a peet.ws capture, cleaning up — in examples/python-examples/17_tweak_fingerprint.py, examples/js-examples/18_tweak_fingerprint.js, and examples/csharp-examples/TweakFingerprint.cs.

🔐 ECH (Encrypted Client Hello)

Hides which domain you're connecting to from network observers.

session = httpcloak.Session(
    preset="chrome-latest",
    ech_config_domain="cloudflare-ech.com"  # Fetches ECH config from DNS
)

Cloudflare trace shows sni=encrypted instead of sni=plaintext. Use cloudflare-ech.com (the dedicated ECH domain) for any Cloudflare-fronted target.

⚡ Session Resumption (0-RTT)

TLS session tickets make you look like a returning visitor.

# Warm up on any Cloudflare site
session.get("https://cloudflare.com/")
session.save("session.json")

# Use on your target
session = httpcloak.Session.load("session.json")
r = session.get("https://target.com/")  # Bot score: 99

Cross-domain warming works because Cloudflare sites share TLS infrastructure.

🌐 HTTP/3 Through Proxies

Two methods for QUIC through proxies:

Method How it works
SOCKS5 UDP ASSOCIATE Proxy relays UDP packets. Most residential proxies support this.
MASQUE (CONNECT-UDP) RFC 9298. Tunnels UDP over HTTP/3. Premium providers only.
# SOCKS5 with UDP
session = httpcloak.Session(proxy="socks5://user:pass@proxy:1080")

# MASQUE
session = httpcloak.Session(proxy="masque://proxy:443")

Known MASQUE providers (auto-detected): Bright Data, Oxylabs, Smartproxy, SOAX.

Speculative TLS (opt-in): CONNECT + TLS ClientHello are sent together, saving one proxy round-trip (~25% faster). Enable for compatible proxies:

session = httpcloak.Session(proxy="socks5://...", enable_speculative_tls=True)

🎭 Domain Fronting

Connect to a different host than what appears in TLS SNI.

session := httpcloak.NewSession("chrome-latest",
    httpcloak.WithConnectTo("public-cdn.com", "actual-backend.internal"),
)
defer session.Close()

📌 Certificate Pinning &

readme truncated — read the full docs on github

Frequently asked questions

Is httpcloak free to use?

httpcloak is open source under the MIT licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does httpcloak do?

Go HTTP client with browser-identical TLS/HTTP2 fingerprinting. Bypass bot detection by perfectly mimicking Chrome, Firefox, and Safari at the cryptographic lev

What is httpcloak written in?

httpcloak is primarily written in Go. Its source is publicly available at https://github.com/sardanioss/httpcloak, and it has 1,306 GitHub stars.