httpcloak

package module
v1.6.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 3, 2026 License: MIT Imports: 25 Imported by: 1

README

httpcloak

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:            +    │
└─────────────────────────────────┘

vs curl_cffi

┌────────────────────────────────┬────────────────────────────────┐
│        BOTH LIBRARIES          │       HTTPCLOAK ONLY           │
├────────────────────────────────┼────────────────────────────────┤
│                                │                                │
│  + TLS fingerprint (JA3/JA4)   │  + HTTP/3 fingerprinting       │
│  + HTTP/2 fingerprint          │  + ECH (encrypted SNI)         │
│  + Post-quantum TLS            │  + MASQUE proxy                │
│  + Bot score: 99               │  + Domain fronting             │
│                                │  + Certificate pinning         │
│                                │  + Go, Python, Node.js, C#     │
│                                │                                │
└────────────────────────────────┴────────────────────────────────┘

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 r = await session.get("https://example.com");
console.log(r.statusCode, r.protocol);

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

// Custom headers
const r = 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 r = session.Get("https://example.com");
Console.WriteLine($"{r.StatusCode} {r.Protocol}");

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

// Custom headers
var r = 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.

client := httpcloak.NewClient("chrome-latest",
    httpcloak.WithConnectTo("public-cdn.com", "actual-backend.internal"),
)

📌 Certificate Pinning

client.PinCertificate("sha256/AAAA...",
    httpcloak.PinOptions{IncludeSubdomains: true})

🪝 Request Hooks

client.OnPreRequest(func(req *http.Request) error {
    req.Header.Set("X-Custom", "value")
    return nil
})

client.OnPostResponse(func(resp *httpcloak.Response) {
    log.Printf("Got %d from %s", resp.StatusCode, resp.FinalURL)
})

⏱️ Request Timing

fmt.Printf("DNS: %dms, TCP: %dms, TLS: %dms, Total: %dms\n",
    resp.Timing.DNSLookup,
    resp.Timing.TCPConnect,
    resp.Timing.TLSHandshake,
    resp.Timing.Total)

🔄 Protocol Selection

session = httpcloak.Session(preset="chrome-latest", http_version="h3")  # Force HTTP/3
session = httpcloak.Session(preset="chrome-latest", http_version="h2")  # Force HTTP/2
session = httpcloak.Session(preset="chrome-latest", http_version="h1")  # Force HTTP/1.1

Auto mode tries HTTP/3 first, falls back gracefully.

🖥️ TCP/IP Fingerprinting

Anti-bot systems inspect TCP SYN packet parameters (TTL, Window Size, MSS, Window Scale) to verify your claimed OS matches. A request claiming Chrome on Windows but with Linux TCP parameters (TTL=64) is instantly flagged.

httpcloak automatically sets the correct TCP/IP fingerprint for each preset's platform. You can also override manually:

session = httpcloak.Session(
    preset="chrome-latest-windows",
    tcp_ttl=128,           # Windows=128, Linux/macOS=64
    tcp_window_size=64240, # Windows=64240, Linux/macOS=65535
    tcp_window_scale=8,    # Windows=8, Linux=7, macOS=6
    tcp_mss=1460,          # Standard Ethernet MTU
)

Go:

client := client.NewClient("chrome-latest-windows",
    client.WithTCPFingerprint(fingerprint.TCPFingerprint{
        TTL: 128, MSS: 1460, WindowSize: 64240, WindowScale: 8, DFBit: true,
    }),
)

Node.js:

const session = new httpcloak.Session({
    preset: "chrome-latest-windows",
    tcpTtl: 128,
    tcpWindowSize: 64240,
    tcpWindowScale: 8,
});

C#:

var session = new Session(
    preset: Presets.Chrome145Windows,
    tcpTtl: 128,
    tcpWindowSize: 64240,
    tcpWindowScale: 8
);

Built-in platform profiles: Windows (TTL=128, WS=8), Linux (TTL=64, WS=7), macOS (TTL=64, WS=6).

🔀 Runtime Proxy Switching

Switch proxies mid-session without creating new connections. Perfect for proxy rotation.

session = httpcloak.Session(preset="chrome-latest")

# Start with direct connection
r = session.get("https://api.ipify.org")
print(f"Direct IP: {r.text}")

# Switch to proxy 1
session.set_proxy("http://proxy1.example.com:8080")
r = session.get("https://api.ipify.org")
print(f"Proxy 1 IP: {r.text}")

# Switch to proxy 2
session.set_proxy("socks5://proxy2.example.com:1080")
r = session.get("https://api.ipify.org")
print(f"Proxy 2 IP: {r.text}")

# Back to direct
session.set_proxy("")

Split proxy configuration - use different proxies for HTTP/2 and HTTP/3:

session = httpcloak.Session(preset="chrome-latest")

# TCP proxy for HTTP/1.1 and HTTP/2
session.set_tcp_proxy("http://tcp-proxy.example.com:8080")

# UDP proxy for HTTP/3 (requires SOCKS5 UDP ASSOCIATE or MASQUE)
session.set_udp_proxy("socks5://udp-proxy.example.com:1080")

# Check current configuration
print(session.get_tcp_proxy())  # TCP proxy URL
print(session.get_udp_proxy())  # UDP proxy URL

📋 Header Order Customization

Control the order headers are sent for advanced fingerprinting scenarios.

session = httpcloak.Session(preset="chrome-latest")

# Get the current header order (from preset)
print(session.get_header_order())

# Set custom header order
session.set_header_order([
    "accept-language", "sec-ch-ua", "accept",
    "sec-fetch-site", "sec-fetch-mode", "user-agent",
    "sec-ch-ua-platform", "sec-ch-ua-mobile"
])

# Make request with custom order
r = session.get("https://example.com")

# Reset to preset's default order
session.set_header_order([])

JavaScript:

session.setHeaderOrder(["accept-language", "sec-ch-ua", "accept", ...]);
console.log(session.getHeaderOrder());
session.setHeaderOrder([]);  // Reset to default

C#:

session.SetHeaderOrder(new[] { "accept-language", "sec-ch-ua", "accept", ... });
Console.WriteLine(string.Join(", ", session.GetHeaderOrder()));
session.SetHeaderOrder(null);  // Reset to default

Go:

c.SetHeaderOrder([]string{"accept-language", "sec-ch-ua", "accept", ...})
fmt.Println(c.GetHeaderOrder())
c.SetHeaderOrder(nil)  // Reset to default

📤 Streaming & Uploads

# Stream large downloads
stream = session.get_stream("https://example.com/large-file.zip")
print(f"Size: {stream.content_length} bytes")

with open("file.zip", "wb") as f:
    while True:
        chunk = stream.read(8192)
        if not chunk:
            break
        f.write(chunk)
stream.close()

# Iterator pattern
for chunk in session.get_stream(url).iter_content(chunk_size=8192):
    process(chunk)

# Multipart upload
r = session.post(url, files={
    "file": ("filename.jpg", file_bytes, "image/jpeg")
})

🔒 Authentication

# Basic auth
r = httpcloak.get("https://api.example.com/data",
    auth=("username", "password"),
    preset="chrome-latest"
)

# Session-level auth
session = httpcloak.Session(
    preset="chrome-latest",
    auth=("username", "password")
)

⏰ Timeouts & Retries

# Timeout
session = httpcloak.Session(preset="chrome-latest", timeout=30)

# Per-request timeout
r = session.get("https://slow-api.com/data", timeout=60)
// Go: Timeout and retry configuration
client := client.NewClient("chrome-latest",
    client.WithTimeout(30 * time.Second),
    client.WithRetry(3),  // Retry 3 times on 429, 500, 502, 503, 504
    client.WithRetryConfig(
        5,                      // Max retries
        500 * time.Millisecond, // Min backoff
        10 * time.Second,       // Max backoff
        []int{429, 503},        // Status codes to retry
    ),
)

🚫 Redirect Control

// Disable automatic redirects
client := client.NewClient("chrome-latest",
    client.WithoutRedirects(),
)

resp, _ := client.Get(ctx, "https://example.com/redirect", nil)
fmt.Println(resp.StatusCode)              // 302
fmt.Println(resp.GetHeader("location"))   // Redirect URL

🔃 Refresh (Browser Page Refresh)

Simulates a browser page refresh - closes all TCP/QUIC connections but keeps TLS session cache intact. On next request, connections use TLS resumption (like a real browser).

session = httpcloak.Session(preset="chrome-latest")

# Make some requests
session.get("https://example.com/page1")
session.get("https://example.com/page2")

# Simulate browser refresh (F5)
session.refresh()

# Next request uses TLS resumption, looks like returning visitor
session.get("https://example.com/page1")

Go:

session := httpcloak.NewSession("chrome-latest")
session.Get(ctx, "https://example.com")
session.Refresh()  // Close connections, keep TLS cache
session.Get(ctx, "https://example.com")  // TLS resumption

Node.js:

session.refresh();

C#:

session.Refresh();

🌐 Warmup (Browser Page Load)

Simulates a real browser page load - fetches the HTML page and all its subresources (CSS, JS, images, fonts) with realistic headers, priorities, and timing. After warmup, the session has TLS session tickets, cookies, and cache headers populated.

session = httpcloak.Session(preset="chrome-latest")

# Fetches page + subresources with realistic browser behavior
session.warmup("https://example.com")

# Subsequent requests look like follow-up navigation from a real user
r = session.get("https://example.com/api/data")

Go:

session := httpcloak.NewSession("chrome-latest")
session.Warmup(ctx, "https://example.com")
session.Get(ctx, "https://example.com/api/data")  // Looks like real user

Node.js:

session.warmup("https://example.com");

C#:

session.Warmup("https://example.com");

🔀 Fork (Parallel Browser Tabs)

Creates N sessions that share cookies and TLS session caches with the parent but have independent connections. This simulates multiple browser tabs - same cookies, same TLS resumption tickets, same fingerprint, but independent TCP/QUIC connections for parallel requests.

session = httpcloak.Session(preset="chrome-latest")
session.warmup("https://example.com")

# Create 10 parallel "tabs" sharing cookies + TLS cache
tabs = session.fork(10)
for i, tab in enumerate(tabs):
    threading.Thread(
        target=lambda t, n: t.get(f"https://example.com/page/{n}"),
        args=(tab, i)
    ).start()

Go:

session := httpcloak.NewSession("chrome-latest")
session.Warmup(ctx, "https://example.com")

tabs := session.Fork(10)
for i, tab := range tabs {
    go func(t *httpcloak.Session, n int) {
        t.Get(ctx, fmt.Sprintf("https://example.com/page/%d", n))
    }(tab, i)
}

Node.js:

session.warmup("https://example.com");
const tabs = session.fork(10);
await Promise.all(tabs.map((tab, i) => tab.get(`https://example.com/page/${i}`)));

C#:

session.Warmup("https://example.com");
var tabs = session.Fork(10);
await Task.WhenAll(tabs.Select((tab, i) =>
    Task.Run(() => tab.Get($"https://example.com/page/{i}"))
));

🌍 Local Address Binding

Bind outgoing connections to a specific local IP address. Essential for IPv6 rotation scenarios where you have multiple IPs assigned to your machine.

# Bind to specific IPv6 address
session = httpcloak.Session(
    preset="chrome-latest",
    local_address="2001:db8::1"
)

# All requests use this source IP
r = session.get("https://api.ipify.org")
print(r.text)  # Shows 2001:db8::1

# IPv4 works too
session = httpcloak.Session(
    preset="chrome-latest",
    local_address="192.168.1.100"
)

Go:

session := httpcloak.NewSession("chrome-latest",
    httpcloak.WithLocalAddress("2001:db8::1"),
)

Node.js:

const session = new httpcloak.Session({
    preset: "chrome-latest",
    localAddress: "2001:db8::1"
});

C#:

var session = new Session(
    preset: Presets.Chrome145,
    localAddress: "2001:db8::1"
);

Note: When a local address is set, target IPs are automatically filtered to match the address family (IPv6 local → only IPv6 targets).

🔑 TLS Key Logging

Write TLS session keys to a file for traffic decryption in Wireshark. Works with HTTP/1.1, HTTP/2, and HTTP/3.

session = httpcloak.Session(
    preset="chrome-latest",
    key_log_file="/tmp/keys.log"
)

# Make requests - keys written to file
session.get("https://example.com")

# In Wireshark: Edit → Preferences → Protocols → TLS → (Pre)-Master-Secret log filename

Go:

session := httpcloak.NewSession("chrome-latest",
    httpcloak.WithKeyLogFile("/tmp/keys.log"),
)

Node.js:

const session = new httpcloak.Session({
    preset: "chrome-latest",
    keyLogFile: "/tmp/keys.log"
});

C#:

var session = new Session(
    preset: Presets.Chrome145,
    keyLogFile: "/tmp/keys.log"
);

Also supports SSLKEYLOGFILE environment variable (standard NSS Key Log Format).


API Reference

Python

import httpcloak

# Module-level functions
httpcloak.get(url, **kwargs)
httpcloak.post(url, **kwargs)
httpcloak.put(url, **kwargs)
httpcloak.patch(url, **kwargs)
httpcloak.delete(url, **kwargs)
httpcloak.head(url, **kwargs)
httpcloak.options(url, **kwargs)

# Session class
session = httpcloak.Session(
    preset="chrome-latest",       # Browser preset (default)
    proxy="socks5://...",      # Proxy URL
    timeout=30,                # Timeout in seconds
    http_version="h3",         # Force protocol: h1, h2, h3, auto
    ech_config_domain="cloudflare-ech.com",  # ECH config source domain
    auth=("user", "pass"),     # Basic auth
)

# Session methods
session.get(url, **kwargs)
session.post(url, data=None, json=None, **kwargs)
session.get_stream(url)        # Streaming download
session.close()

# Proxy switching
session.set_proxy(url)         # Set both TCP and UDP proxy
session.set_tcp_proxy(url)     # Set TCP proxy only (H1/H2)
session.set_udp_proxy(url)     # Set UDP proxy only (H3)
session.get_proxy()            # Get current proxy
session.get_tcp_proxy()        # Get current TCP proxy
session.get_udp_proxy()        # Get current UDP proxy

# Header order customization
session.set_header_order(order)  # Set custom header order (list of lowercase names)
session.get_header_order()       # Get current header order

# Session persistence (0-RTT resumption)
session.save("session.json")   # Save to file
session = Session.load("session.json")  # Load from file
data = session.marshal()       # Export as string
session = Session.unmarshal(data)  # Import from string

# Response object
response.status_code           # HTTP status
response.ok                    # True if status < 400
response.text                  # Body as string
response.content               # Body as bytes
response.json()                # Parse JSON
response.headers               # Response headers
response.protocol              # h1, h2, or h3
response.url                   # Final URL
response.raise_for_status()    # Raise on 4xx/5xx

Go

import "github.com/sardanioss/httpcloak/client"

// Client creation
c := client.NewClient("chrome-latest",
    client.WithTimeout(30 * time.Second),
    client.WithProxy("socks5://..."),
    client.WithRetry(3),
    client.WithoutRedirects(),
    client.WithInsecureSkipVerify(),
)
defer c.Close()

// Request methods
resp, err := c.Get(ctx, url, headers)
resp, err := c.Post(ctx, url, body, headers)
resp, err := c.Put(ctx, url, body, headers)
resp, err := c.Delete(ctx, url, headers)

// Advanced request
resp, err := c.Do(ctx, &client.Request{
    Method:        "GET",
    URL:           url,
    Headers:       map[string][]string{},
    Body:          io.Reader,
    Params:        map[string]string{},
    ForceProtocol: client.ProtocolHTTP3,
    FetchMode:     client.FetchModeCORS,
    Referer:       "https://example.com",
})

// Proxy switching
c.SetProxy(url)            // Set both TCP and UDP proxy
c.SetTCPProxy(url)         // Set TCP proxy only (H1/H2)
c.SetUDPProxy(url)         // Set UDP proxy only (H3)
c.GetProxy()               // Get current proxy
c.GetTCPProxy()            // Get current TCP proxy
c.GetUDPProxy()            // Get current UDP proxy

// Session persistence (0-RTT resumption)
c.Save("session.json")     // Save to file
c, _ = client.Load("session.json")  // Load from file
data, _ := c.Marshal()     // Export as string
c, _ = client.Unmarshal(data)  // Import from string

// Response object
resp.StatusCode
resp.Protocol
resp.Headers
resp.Body           // io.ReadCloser
resp.Text()         // (string, error)
resp.Bytes()        // ([]byte, error)
resp.JSON(&v)       // error
resp.GetHeader(key) // string
resp.IsSuccess()    // bool
resp.IsRedirect()   // bool

Node.js

import httpcloak from "httpcloak";

// Session creation
const session = new httpcloak.Session({
    preset: "chrome-latest",
    proxy: "socks5://...",
    timeout: 30000,
    httpVersion: "h3",
});

// Async methods
await session.get(url, options)
await session.post(url, { json, data, headers })
await session.put(url, options)
await session.delete(url, options)

// Sync methods
session.getSync(url, options)
session.postSync(url, options)
session.close()

// Proxy switching
session.setProxy(url)          // Set both TCP and UDP proxy
session.setTcpProxy(url)       // Set TCP proxy only (H1/H2)
session.setUdpProxy(url)       // Set UDP proxy only (H3)
session.getProxy()             // Get current proxy
session.getTcpProxy()          // Get current TCP proxy
session.getUdpProxy()          // Get current UDP proxy
session.proxy                  // Property accessor (get/set)

// Session persistence (0-RTT resumption)
session.save("session.json")   // Save to file
session = httpcloak.Session.load("session.json")  // Load from file
const data = session.marshal() // Export as string
session = httpcloak.Session.unmarshal(data)  // Import from string

// Response object
response.statusCode
response.ok
response.text
response.json()
response.headers
response.protocol

C#

using HttpCloak;

// Session creation
var session = new Session(
    preset: Presets.Chrome145,
    proxy: "socks5://...",
    timeout: 30
);

// Request methods
session.Get(url, headers)
session.Post(url, body, headers)
session.PostJson<T>(url, data, headers)
session.Put(url, body, headers)
session.Delete(url)
session.Dispose()

// Proxy switching
session.SetProxy(url)          // Set both TCP and UDP proxy
session.SetTcpProxy(url)       // Set TCP proxy only (H1/H2)
session.SetUdpProxy(url)       // Set UDP proxy only (H3)
session.GetProxy()             // Get current proxy
session.GetTcpProxy()          // Get current TCP proxy
session.GetUdpProxy()          // Get current UDP proxy
session.Proxy                  // Property accessor (get/set)

// Session persistence (0-RTT resumption)
session.Save("session.json")   // Save to file
var session = Session.Load("session.json")  // Load from file
var data = session.Marshal()   // Export as string
var session = Session.Unmarshal(data)  // Import from string

// Response object
response.StatusCode
response.Ok
response.Text
response.Json<T>()
response.Headers
response.Protocol

Browser Presets

Preset Platform PQ H3
chrome-146 Auto
chrome-146-windows Windows
chrome-146-macos macOS
chrome-146-linux Linux
chrome-146-ios iOS
chrome-146-android Android
chrome-145 Auto
chrome-145-windows Windows
chrome-145-macos macOS
chrome-145-linux Linux
chrome-145-ios iOS
chrome-145-android Android
chrome-144 Auto
chrome-144-windows Windows
chrome-144-macos macOS
chrome-144-linux Linux
chrome-143 Auto
chrome-143-windows Windows
chrome-143-macos macOS
chrome-143-linux Linux
chrome-141 Auto
chrome-133 Auto
firefox-133 Auto
safari-18 macOS
safari-18-ios iOS
safari-17-ios iOS
chrome-146-ios iOS
chrome-145-ios iOS
chrome-144-ios iOS
chrome-143-ios iOS
chrome-146-android Android
chrome-145-android Android
chrome-144-android Android
chrome-143-android Android

PQ = Post-Quantum (X25519MLKEM768) · H3 = HTTP/3


Custom Preset Edit Points

Any field below is editable in the JSON spec produced by describe_preset (see the Build Any Browser Fingerprint From JSON section above for the workflow):

Path What it controls
preset.tls.ja3 JA3 string (cipher suites, extensions, curves)
preset.http2.akamai H2 SETTINGS / WINDOW_UPDATE / PRIORITY / pseudo-order shorthand
preset.http2.priority_table[dest] Per-resource-type H2 stream priority (sec-fetch-dest → urgency)
preset.http2.hpack_header_order HPACK encoding order
preset.http2.settings_order SETTINGS frame ID order
preset.http2.pseudo_order HTTP/2 pseudo-header order
preset.http3 HTTP/3 / QUIC parameters
preset.tcp TCP/IP fingerprint
preset.headers.values / preset.headers.order Header values and request order

Round-trip is byte-equal — describe_preset → mutate JSON → load_preset_from_json → run → describe_preset returns identical bytes.


Testing Tools

Tool Tests
tls.peet.ws JA3, JA4, HTTP/2 Akamai
quic.browserleaks.com HTTP/3 QUIC fingerprint
cf.erisa.uk Cloudflare bot score
cloudflare.com/cdn-cgi/trace ECH status, TLS version

Dependencies

Custom forks for browser-accurate fingerprinting:


Documentation

Full docs at httpcloak.dev. Some entry points:

  • Getting Started — first request, presets, common options.
  • Fingerprinting — JA3 / JA4 / Akamai shorthand, JSON preset builder, per-resource priority.
  • Proxies — HTTP CONNECT, SOCKS5, SOCKS5 UDP, MASQUE, source-address binding.
  • Connection LifecycleRefresh, Warmup, Fork, save / restore.
  • Recipes — multi-proxy rotation, custom Chrome from tls.peet, long-running scrapers, Wireshark debugging, Local Proxy server.
  • Reference — every option, every preset, the JSON spec, architecture map.
  • Bindings — Go / Python / Node.js / .NET specifics.

LLM-friendly indexes for AI agents: llms.txt and llms-full.txt.


Connect


MIT License

Documentation

Overview

Package httpcloak provides an HTTP client with perfect browser TLS/HTTP fingerprinting.

httpcloak allows you to make HTTP requests that are indistinguishable from real browsers, bypassing TLS fingerprinting, HTTP/2 fingerprinting, and header-based bot detection.

Basic usage:

client := httpcloak.New("chrome-146")
defer client.Close()

resp, err := client.Get(ctx, "https://example.com")
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(resp.Body))

With options:

client := httpcloak.New("chrome-146",
    httpcloak.WithTimeout(30*time.Second),
    httpcloak.WithProxy("http://user:pass@proxy:8080"),
)

Index

Constants

View Source
const (
	// HeaderUpstreamProxy is the header name for per-request proxy override (HTTP only).
	// For HTTPS/CONNECT requests, use Proxy-Authorization header instead.
	HeaderUpstreamProxy = "X-Upstream-Proxy"

	// HeaderTLSOnly is the header name for per-request TLS-only mode override.
	// When set to "true", TLS fingerprinting is applied but preset HTTP headers are skipped.
	// When set to "false", normal mode is used (preset headers applied).
	// If not set, uses the proxy's global TLSOnly setting.
	HeaderTLSOnly = "X-HTTPCloak-TlsOnly"

	// HeaderSession is the header name for per-request session selection.
	// When set, the proxy uses the specified session ID to route the request.
	// Sessions must be registered via RegisterSession() before use.
	// Example: X-HTTPCloak-Session: my-session-id
	HeaderSession = "X-HTTPCloak-Session"

	// HeaderScheme upgrades HTTP requests to HTTPS with TLS fingerprinting.
	// When set to "https", LocalProxy converts http:// URLs to https:// and uses
	// Session.DoStream() with full fingerprinting. This allows standard HTTP proxy
	// clients to get HTTPS fingerprinting without using CONNECT tunneling.
	// Example: X-HTTPCloak-Scheme: https
	HeaderScheme = "X-HTTPCloak-Scheme"

	// ProxyAuthScheme is the authentication scheme for upstream proxy selection.
	// Format: "Proxy-Authorization: HTTPCloak http://user:pass@proxy:8080"
	// This works for both HTTP and HTTPS (CONNECT) requests since Proxy-Authorization
	// is sent with CONNECT requests by standard HTTP clients.
	ProxyAuthScheme = "HTTPCloak"
)

Variables

This section is empty.

Functions

func BuildMultipart added in v1.6.1

func BuildMultipart(fields []MultipartField) ([]byte, string, error)

BuildMultipart encodes fields into a multipart/form-data body. Returns the encoded body bytes and the Content-Type header value (including boundary).

func Presets

func Presets() []string

Presets returns available fingerprint presets

func SetKeyLogWriter added in v1.6.7

func SetKeyLogWriter(w io.Writer)

SetKeyLogWriter installs a process-global writer that the lib uses to emit TLS keylog lines (NSS keylog format). Pass nil to disable.

This is the io.Writer-flavoured sibling of WithSessionKeyLogFile, which takes a file path. Use SetKeyLogWriter when the destination is something other than a file: a ring buffer, an S3 multipart uploader, a syslog pipe, etc. Setting a writer affects every TLS handshake the binary performs from the moment it's set.

func ValidateSessionFile added in v1.6.7

func ValidateSessionFile(path string) error

ValidateSessionFile validates a session file without loading it. Returns nil if the file at path is a valid httpcloak session blob, or a descriptive error otherwise. Useful for pre-flight checks before LoadSession on user-supplied paths.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is an HTTP client with browser fingerprint spoofing

func New

func New(preset string, opts ...Option) *Client

New creates a new HTTP client with the specified browser fingerprint.

Available presets:

  • "chrome-latest" (recommended), "chrome-latest-windows", "chrome-latest-linux", "chrome-latest-macos"
  • "chrome-146", "chrome-145", "chrome-144", "chrome-143", "chrome-141", "chrome-133"
  • "firefox-latest", "firefox-133"
  • "safari-latest", "safari-18"
  • "chrome-latest-ios", "safari-latest-ios"
  • "chrome-latest-android"

The -latest aliases always resolve to the newest version in the library.

Example:

client := httpcloak.New("chrome-latest")
defer client.Close()

func (*Client) Close

func (c *Client) Close()

Close releases all resources held by the client

func (*Client) Do

func (c *Client) Do(ctx context.Context, req *Request) (*Response, error)

Do executes an HTTP request

func (*Client) Get

func (c *Client) Get(ctx context.Context, url string) (*Response, error)

Get performs a GET request

func (*Client) GetWithHeaders

func (c *Client) GetWithHeaders(ctx context.Context, url string, headers map[string][]string) (*Response, error)

GetWithHeaders performs a GET request with custom headers

func (*Client) Post

func (c *Client) Post(ctx context.Context, url string, body io.Reader, contentType string) (*Response, error)

Post performs a POST request

func (*Client) PostForm

func (c *Client) PostForm(ctx context.Context, url string, body []byte) (*Response, error)

PostForm performs a POST request with form data

func (*Client) PostJSON

func (c *Client) PostJSON(ctx context.Context, url string, body []byte) (*Response, error)

PostJSON performs a POST request with JSON body

func (*Client) PostMultipart added in v1.6.1

func (c *Client) PostMultipart(ctx context.Context, url string, fields []MultipartField) (*Response, error)

PostMultipart performs a POST request with multipart/form-data body.

type CookieInfo added in v1.6.1

type CookieInfo = session.CookieState

CookieInfo represents a cookie with full metadata (domain, path, expiry, etc.)

type CustomFingerprint added in v1.6.1

type CustomFingerprint struct {
	// JA3 is a JA3 fingerprint string.
	// Format: TLSVersion,CipherSuites,Extensions,EllipticCurves,PointFormats
	// Example: "771,4865-4866-4867-49195-49199,0-23-65281-10-11-35-16-5-13-18-51-45-43-27-17513-21,29-23-24,0"
	JA3 string

	// Akamai is an Akamai HTTP/2 fingerprint string.
	// Format: SETTINGS|WINDOW_UPDATE|PRIORITY|PSEUDO_HEADER_ORDER
	// Example: "1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p"
	Akamai string

	// SignatureAlgorithms overrides the default signature algorithms for the JA3 spec.
	// Valid values: "ecdsa_secp256r1_sha256", "rsa_pss_rsae_sha256", "rsa_pkcs1_sha256",
	// "ecdsa_secp384r1_sha384", "rsa_pss_rsae_sha384", "rsa_pkcs1_sha384",
	// "rsa_pss_rsae_sha512", "rsa_pkcs1_sha512"
	SignatureAlgorithms []string

	// ALPN overrides the default ALPN protocols. Default: ["h2", "http/1.1"]
	ALPN []string

	// CertCompression overrides the cert compression algorithms.
	// Valid values: "brotli", "zlib", "zstd"
	CertCompression []string

	// PermuteExtensions randomly permutes the TLS extension order.
	PermuteExtensions bool
}

CustomFingerprint configures custom TLS (JA3) and HTTP/2 (Akamai) fingerprints. This overrides the preset's fingerprint for fine-grained control.

type LocalProxy added in v1.5.8

type LocalProxy struct {
	// contains filtered or unexported fields
}

LocalProxy is an HTTP proxy server that forwards requests through httpcloak sessions with TLS fingerprinting.

Architecture: - For HTTP requests: Forwards through httpcloak Session (fingerprinting applied) - For HTTPS (CONNECT): Tunnels TCP (client does TLS, fingerprinting via upstream proxy only)

Usage with C# HttpClient:

proxy := httpcloak.StartLocalProxy(8080, "chrome-146")
defer proxy.Stop()
// Configure HttpClient to use http://localhost:8080 as proxy

func StartLocalProxy added in v1.5.8

func StartLocalProxy(port int, opts ...LocalProxyOption) (*LocalProxy, error)

StartLocalProxy creates and starts a local HTTP proxy on the specified port. The proxy forwards requests through httpcloak sessions with TLS fingerprinting.

Example:

proxy, err := httpcloak.StartLocalProxy(8080, httpcloak.WithProxyPreset("chrome-146"))
if err != nil {
    log.Fatal(err)
}
defer proxy.Stop()
fmt.Printf("Proxy running on port %d\n", proxy.Port())

func (*LocalProxy) GetSession added in v1.5.8

func (p *LocalProxy) GetSession(sessionID string) *Session

GetSession returns a registered session by ID. Returns nil if the session is not found.

func (*LocalProxy) IsRunning added in v1.5.8

func (p *LocalProxy) IsRunning() bool

IsRunning returns whether the proxy is running

func (*LocalProxy) ListSessions added in v1.5.8

func (p *LocalProxy) ListSessions() []string

ListSessions returns all registered session IDs.

func (*LocalProxy) Port added in v1.5.8

func (p *LocalProxy) Port() int

Port returns the port the proxy is listening on

func (*LocalProxy) RegisterSession added in v1.5.8

func (p *LocalProxy) RegisterSession(sessionID string, session *Session) error

RegisterSession registers a session with the given ID for per-request session selection. The session can then be selected via the X-HTTPCloak-Session header. Returns an error if a session with the same ID already exists.

Example:

session := httpcloak.NewSession("chrome-146", httpcloak.WithSessionProxy("..."))
proxy.RegisterSession("session-1", session)
// Client can now use: X-HTTPCloak-Session: session-1

func (*LocalProxy) Stats added in v1.5.8

func (p *LocalProxy) Stats() map[string]interface{}

Stats returns proxy statistics

func (*LocalProxy) Stop added in v1.5.8

func (p *LocalProxy) Stop() error

Stop stops the local proxy server gracefully

func (*LocalProxy) UnregisterSession added in v1.5.8

func (p *LocalProxy) UnregisterSession(sessionID string) *Session

UnregisterSession removes a session from the registry. The session is NOT closed - caller is responsible for closing it. Returns the session if found, nil otherwise.

type LocalProxyConfig added in v1.5.8

type LocalProxyConfig struct {
	// Port to listen on (0 = auto-select)
	Port int

	// Browser fingerprint preset (default: chrome-146)
	Preset string

	// Request timeout
	Timeout time.Duration

	// Maximum concurrent connections
	MaxConnections int

	// Upstream proxy (optional)
	TCPProxy string
	UDPProxy string

	// TLSOnly mode: only apply TLS fingerprinting, pass HTTP headers through unchanged.
	// Useful when the client (e.g., Playwright) already provides authentic browser headers.
	TLSOnly bool

	// SessionCacheBackend is an optional distributed cache for TLS sessions.
	// Enables session sharing across multiple LocalProxy instances.
	SessionCacheBackend transport.SessionCacheBackend

	// SessionCacheErrorCallback is called when backend operations fail.
	SessionCacheErrorCallback transport.ErrorCallback
}

LocalProxyConfig holds configuration for the local proxy

type LocalProxyOption added in v1.5.8

type LocalProxyOption func(*LocalProxyConfig)

LocalProxyOption configures the local proxy

func WithProxyMaxConnections added in v1.5.8

func WithProxyMaxConnections(n int) LocalProxyOption

WithProxyMaxConnections sets the maximum concurrent connections

func WithProxyPreset added in v1.5.8

func WithProxyPreset(preset string) LocalProxyOption

WithProxyPreset sets the browser fingerprint preset

func WithProxySessionCache added in v1.5.8

func WithProxySessionCache(backend transport.SessionCacheBackend, errorCallback transport.ErrorCallback) LocalProxyOption

WithProxySessionCache sets a distributed TLS session cache backend for the proxy. This enables TLS session ticket sharing across multiple proxy instances.

func WithProxyTLSOnly added in v1.5.8

func WithProxyTLSOnly() LocalProxyOption

WithProxyTLSOnly enables TLS-only mode where only TLS fingerprinting is applied. HTTP headers from the client pass through unchanged - useful when using Playwright or other browsers that already provide authentic headers.

func WithProxyTimeout added in v1.5.8

func WithProxyTimeout(d time.Duration) LocalProxyOption

WithProxyTimeout sets the request timeout

func WithProxyUpstream added in v1.5.8

func WithProxyUpstream(tcpProxy, udpProxy string) LocalProxyOption

WithProxyUpstream sets upstream proxy URLs for the httpcloak session

type Manager added in v1.6.7

type Manager = session.Manager

Manager is an in-process registry for many sessions at once. It's the right tool for worker pools, multi-tenant scrapers, or any service that needs to look up sessions by external ID with bounded concurrency and idle eviction. Re-exported from the session subpackage so callers don't have to import it directly. See the connection-lifecycle/session-manager chapter for usage.

func NewManager added in v1.6.7

func NewManager() *Manager

NewManager constructs a fresh session Manager with the package defaults (max 100 concurrent sessions, 30-minute idle timeout, 1-minute cleanup interval). Override the bounds with Manager.SetMaxSessions and Manager.SetSessionTimeout.

type MultipartField added in v1.6.1

type MultipartField struct {
	Name        string // Form field name
	Value       string // Text value (used when Filename is empty)
	Filename    string // If set, this field is a file upload
	Content     []byte // File content (used when Filename is set)
	ContentType string // MIME type for file uploads (default: application/octet-stream)
}

MultipartField represents a single field in a multipart/form-data body. For text fields, set Name and Value. For file uploads, set Name, Filename, Content, and optionally ContentType (defaults to application/octet-stream).

type Option

type Option func(*clientConfig)

Option configures the Client

func WithProxy

func WithProxy(proxyURL string) Option

WithProxy sets an HTTP/HTTPS/SOCKS5 proxy

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the request timeout

type RedirectInfo added in v1.5.1

type RedirectInfo struct {
	StatusCode int
	URL        string
	Headers    map[string][]string // Multi-value headers
}

RedirectInfo contains information about a redirect response

type Request

type Request struct {
	Method  string
	URL     string
	Headers map[string][]string // Multi-value headers (matches http.Header)
	Body    io.Reader           // Streaming body for uploads
	Timeout time.Duration

	// TLSOnly is a per-request override for TLS-only mode.
	// When set to true, preset HTTP headers are NOT applied - only TLS fingerprinting is used.
	// When nil, the session's TLSOnly setting is used.
	// This is useful for LocalProxy where each request can have different TLS-only settings
	// via the X-HTTPCloak-TlsOnly header.
	TLSOnly *bool

	// FollowRedirects, when non-nil, overrides the session's follow-redirects
	// policy for this single request. Set to &true to follow redirects on this
	// request, &false to surface the 3xx response back to the caller. When nil,
	// the session-level setting is used.
	FollowRedirects *bool

	// DisableConditionalCache, when true, skips ETag / If-Modified-Since handling
	// for this single request: no cache validators are injected on the way out
	// and any ETag / Last-Modified on the response is not stored in the session
	// cache. Useful for forcing a fresh fetch without touching the session-wide
	// setting.
	DisableConditionalCache bool
}

Request represents an HTTP request

type Response

type Response struct {
	StatusCode int
	Headers    map[string][]string // Multi-value headers (matches http.Header)
	Body       io.ReadCloser       // Streaming body - call Close() when done
	FinalURL   string
	Protocol   string
	History    []*RedirectInfo
	// contains filtered or unexported fields
}

Response represents an HTTP response

func (*Response) Bytes added in v1.5.3

func (r *Response) Bytes() ([]byte, error)

Bytes reads and returns the entire response body. The body can only be read once unless cached.

func (*Response) Close added in v1.5.3

func (r *Response) Close() error

Close closes the response body.

func (*Response) GetHeader added in v1.5.3

func (r *Response) GetHeader(key string) string

GetHeader returns the first value for the given header key.

func (*Response) GetHeaders added in v1.5.3

func (r *Response) GetHeaders(key string) []string

GetHeaders returns all values for the given header key.

func (*Response) JSON added in v1.5.3

func (r *Response) JSON(v interface{}) error

JSON decodes the response body into the given interface.

func (*Response) Text added in v1.5.3

func (r *Response) Text() (string, error)

Text reads and returns the response body as a string.

type Session

type Session struct {
	// contains filtered or unexported fields
}

Session represents a persistent HTTP session with cookie management

func LoadSession added in v1.5.5

func LoadSession(path string) (*Session, error)

LoadSession loads a session from a file

func NewSession

func NewSession(preset string, opts ...SessionOption) *Session

NewSession creates a new persistent session with cookie management

func UnmarshalSession added in v1.5.5

func UnmarshalSession(data []byte) (*Session, error)

UnmarshalSession loads a session from JSON bytes

func (*Session) ClearCache added in v1.6.7

func (s *Session) ClearCache()

ClearCache drops the conditional-request cache (ETag / Last-Modified entries). Cookies and TLS tickets are not affected.

func (*Session) ClearCookies added in v1.6.1

func (s *Session) ClearCookies()

ClearCookies removes all cookies from the session

func (*Session) Close

func (s *Session) Close()

Close closes the session and releases resources

func (*Session) ConditionalCacheEnabled added in v1.6.7

func (s *Session) ConditionalCacheEnabled() bool

ConditionalCacheEnabled reports whether the session is currently injecting and storing ETag / If-Modified-Since validators.

func (*Session) DeleteCookie added in v1.6.1

func (s *Session) DeleteCookie(name, domain string)

DeleteCookie removes cookies by name. If domain is empty, removes from all domains.

func (*Session) Do

func (s *Session) Do(ctx context.Context, req *Request) (*Response, error)

Do executes a request within the session, maintaining cookies

func (*Session) DoStream added in v1.5.3

func (s *Session) DoStream(ctx context.Context, req *Request) (*StreamResponse, error)

DoStream executes an HTTP request and returns a streaming response The caller is responsible for closing the response when done Note: Streaming does NOT support redirects - use Do() for redirect handling

func (*Session) DoWithBody added in v1.5.3

func (s *Session) DoWithBody(ctx context.Context, req *Request, bodyReader io.Reader) (*Response, error)

DoWithBody executes a request with an io.Reader as the body for streaming uploads

func (*Session) FollowRedirects added in v1.6.7

func (s *Session) FollowRedirects() bool

FollowRedirects reports the session's current redirect-following policy. Per-request overrides via Request.FollowRedirects don't change this value.

func (*Session) Fork added in v1.6.0

func (s *Session) Fork(n int) []*Session

Fork creates n new sessions that share cookies and TLS session caches with the parent, but have independent connections. This simulates multiple browser tabs — same cookies, same TLS resumption tickets, same fingerprint, but independent TCP/QUIC connections for parallel requests.

func (*Session) Get

func (s *Session) Get(ctx context.Context, url string) (*Response, error)

Get performs a GET request within the session

func (*Session) GetCookies

func (s *Session) GetCookies() []CookieInfo

GetCookies returns all cookies stored in the session with full metadata.

Note: In bindings (Node.js, Python, .NET), GetCookies currently returns a flat name-value map for backward compatibility, with a deprecation warning. In a future release, all bindings will change to return the same []CookieInfo format as this Go method. GetCookiesDetailed already returns this format in all bindings.

func (*Session) GetCookiesDetailed added in v1.6.1

func (s *Session) GetCookiesDetailed() []CookieInfo

GetCookiesDetailed returns all cookies with full metadata (domain, path, expiry, etc.)

func (*Session) GetHeaderOrder added in v1.5.8

func (s *Session) GetHeaderOrder() []string

GetHeaderOrder returns the current header order. Returns preset's default order if no custom order is set.

func (*Session) GetProxy added in v1.5.8

func (s *Session) GetProxy() string

GetProxy returns the current proxy URL (unified proxy or TCP proxy)

func (*Session) GetStream added in v1.5.3

func (s *Session) GetStream(ctx context.Context, url string) (*StreamResponse, error)

GetStream performs a streaming GET request

func (*Session) GetStreamWithHeaders added in v1.5.3

func (s *Session) GetStreamWithHeaders(ctx context.Context, url string, headers map[string][]string) (*StreamResponse, error)

GetStreamWithHeaders performs a streaming GET request with custom headers

func (*Session) GetTCPProxy added in v1.5.8

func (s *Session) GetTCPProxy() string

GetTCPProxy returns the current TCP proxy URL

func (*Session) GetTransport added in v1.6.7

func (s *Session) GetTransport() *transport.Transport

GetTransport returns the underlying transport. Escape hatch for advanced transport-level access; the lib reserves the right to evolve the transport surface between releases.

func (*Session) GetUDPProxy added in v1.5.8

func (s *Session) GetUDPProxy() string

GetUDPProxy returns the current UDP proxy URL

func (*Session) IdleTime added in v1.6.7

func (s *Session) IdleTime() time.Duration

IdleTime returns time since the session last serviced a request.

func (*Session) IsActive added in v1.6.7

func (s *Session) IsActive() bool

IsActive reports whether the session is still usable. False once Close has run.

func (*Session) Marshal added in v1.5.5

func (s *Session) Marshal() ([]byte, error)

Marshal exports session state to JSON bytes

func (*Session) MaxRedirects added in v1.6.7

func (s *Session) MaxRedirects() int

MaxRedirects reports the session's current redirect cap.

func (*Session) Refresh added in v1.5.10

func (s *Session) Refresh()

Refresh closes all connections but keeps TLS session caches and cookies intact. This simulates a browser page refresh - new TCP/QUIC connections but TLS resumption. If a switchProtocol was configured, the session switches to that protocol.

func (*Session) RefreshWithProtocol added in v1.6.0

func (s *Session) RefreshWithProtocol(protocol string) error

RefreshWithProtocol closes all connections and switches to a new protocol. The protocol change persists for future Refresh() calls as well. Valid protocols: "h1", "h2", "h3", "auto".

func (*Session) Save added in v1.5.5

func (s *Session) Save(path string) error

Save exports session state (cookies, TLS sessions) to a file

func (*Session) SetConditionalCacheEnabled added in v1.6.7

func (s *Session) SetConditionalCacheEnabled(enabled bool)

SetConditionalCacheEnabled toggles the session's ETag / If-Modified-Since handling at runtime. When false, the session stops injecting cache validators on outgoing requests and stops storing them from responses. Pair with ClearCache to also wipe any previously-stored validators.

func (*Session) SetCookie

func (s *Session) SetCookie(cookie CookieInfo)

SetCookie sets a cookie in the session with full metadata

func (*Session) SetFollowRedirects added in v1.6.7

func (s *Session) SetFollowRedirects(enabled bool)

SetFollowRedirects toggles the session's redirect-following policy at runtime. A per-request Request.FollowRedirects override still wins over this value for that one request.

func (*Session) SetHeaderOrder added in v1.5.8

func (s *Session) SetHeaderOrder(order []string)

SetHeaderOrder sets a custom header order for all requests. Pass nil or empty slice to reset to preset's default order. Order should contain lowercase header names.

func (*Session) SetMaxRedirects added in v1.6.7

func (s *Session) SetMaxRedirects(max int)

SetMaxRedirects updates the session's redirect cap at runtime. Values of zero or below are ignored, leaving the prior cap (or the default of 10) in place.

func (*Session) SetProxy added in v1.5.8

func (s *Session) SetProxy(proxyURL string)

SetProxy sets or updates the proxy for all protocols (HTTP/1.1, HTTP/2, HTTP/3) This closes existing connections and recreates transports with the new proxy Pass empty string to switch to direct connection

func (*Session) SetSessionIdentifier added in v1.5.8

func (s *Session) SetSessionIdentifier(sessionId string)

SetSessionIdentifier sets a session identifier for TLS cache key isolation. This is used when the session is registered with a LocalProxy to ensure TLS sessions are isolated per proxy/session configuration in distributed caches.

func (*Session) SetTCPProxy added in v1.5.8

func (s *Session) SetTCPProxy(proxyURL string)

SetTCPProxy sets the proxy for TCP protocols (HTTP/1.1, HTTP/2)

func (*Session) SetUDPProxy added in v1.5.8

func (s *Session) SetUDPProxy(proxyURL string)

SetUDPProxy sets the proxy for UDP protocols (HTTP/3 via SOCKS5 or MASQUE)

func (*Session) Stats added in v1.6.7

func (s *Session) Stats() session.SessionStats

Stats returns a snapshot of session counters and timestamps.

func (*Session) Touch added in v1.6.7

func (s *Session) Touch()

Touch resets the idle timer to now without issuing a request.

func (*Session) Warmup added in v1.6.0

func (s *Session) Warmup(ctx context.Context, url string) error

Warmup simulates a real browser page load to warm TLS sessions, cookies, and cache state. Fetches the HTML page and its subresources (CSS, JS, images) with realistic headers, priorities, and timing.

type SessionOption

type SessionOption func(*sessionConfig)

SessionOption configures a session

func WithConnectTo added in v1.5.2

func WithConnectTo(requestHost, connectHost string) SessionOption

WithConnectTo sets a host mapping for domain fronting. Requests to requestHost will connect to connectHost instead. The TLS SNI and Host header will still use requestHost.

func WithCustomFingerprint added in v1.6.1

func WithCustomFingerprint(fp CustomFingerprint) SessionOption

func WithDisableECH added in v1.6.0

func WithDisableECH() SessionOption

WithDisableECH disables ECH (Encrypted Client Hello) lookup for faster first request. ECH is an optional privacy feature that adds ~15-20ms to first connection. Disabling it has no security impact, only privacy implications.

func WithDisableHTTP3 added in v1.6.5

func WithDisableHTTP3() SessionOption

WithDisableHTTP3 disables HTTP/3 (QUIC) while keeping H1/H2 auto-negotiation. Use this when QUIC is unreliable on your network or when binding to a local address that doesn't support UDP.

func WithECHFrom added in v1.5.2

func WithECHFrom(domain string) SessionOption

WithECHFrom sets a domain to fetch ECH config from. Instead of fetching ECH from the target domain's DNS, the config will be fetched from this domain. Useful for Cloudflare domains - use "cloudflare-ech.com" to get ECH config that works for any Cloudflare-proxied domain.

func WithEnableSpeculativeTLS added in v1.6.0

func WithEnableSpeculativeTLS() SessionOption

WithEnableSpeculativeTLS enables the speculative TLS optimization for proxy connections. When enabled, the CONNECT request and TLS ClientHello are sent together, saving one round-trip (~25% faster). Disabled by default due to compatibility issues with some proxies.

func WithForceHTTP1 added in v1.0.1

func WithForceHTTP1() SessionOption

WithForceHTTP1 forces HTTP/1.1 protocol

func WithForceHTTP2 added in v1.0.1

func WithForceHTTP2() SessionOption

WithForceHTTP2 forces HTTP/2 protocol

func WithForceHTTP3 added in v1.1.1

func WithForceHTTP3() SessionOption

WithForceHTTP3 forces HTTP/3 protocol (QUIC)

func WithInsecureSkipVerify added in v1.0.1

func WithInsecureSkipVerify() SessionOption

WithInsecureSkipVerify disables SSL certificate verification

func WithKeyLogFile added in v1.6.0

func WithKeyLogFile(path string) SessionOption

WithKeyLogFile sets the path to write TLS key log for Wireshark decryption. This overrides the global SSLKEYLOGFILE environment variable for this session.

func WithLocalAddrIP added in v1.6.6

func WithLocalAddrIP(ip net.IP) SessionOption

WithLocalAddrIP is the net.IP-typed equivalent of WithLocalAddress. Pass the parsed IP directly when you already have a net.IP value (e.g. when rotating from a precomputed pool). Same semantics: nil is a no-op so callers building options conditionally don't accidentally clobber a previously-set address.

func WithLocalAddress added in v1.6.0

func WithLocalAddress(addr string) SessionOption

WithLocalAddress binds outgoing connections to a specific local IP address. Useful for IPv6 rotation when you have a large IPv6 prefix and want to rotate source IPs per session. On Linux, freebind is automatically applied so you can bind to any address from a routed prefix without configuring each one on the interface. Supports both IPv4 and IPv6 addresses (e.g., "192.168.1.100" or "2001:db8::1").

func WithQuicIdleTimeout added in v1.5.8

func WithQuicIdleTimeout(d time.Duration) SessionOption

WithQuicIdleTimeout sets the QUIC connection idle timeout. Default is 30 seconds (matches Chrome). Connections are closed after this duration of inactivity. Set higher values if you need longer-lived HTTP/3 connections with gaps between requests.

func WithRedirects added in v1.0.1

func WithRedirects(follow bool, maxRedirects int) SessionOption

WithRedirects configures redirect behavior

func WithRetry added in v1.0.1

func WithRetry(count int) SessionOption

WithRetry enables retry with default settings

func WithRetryConfig added in v1.0.1

func WithRetryConfig(count int, waitMin, waitMax time.Duration, retryOnStatus []int) SessionOption

WithRetryConfig configures retry behavior

func WithSessionCache added in v1.5.8

func WithSessionCache(backend transport.SessionCacheBackend, errorCallback transport.ErrorCallback) SessionOption

WithSessionCache sets a distributed TLS session cache backend. This enables TLS session ticket sharing across multiple instances (e.g., via Redis). The errorCallback is optional and will be called when backend operations fail.

func WithSessionPreferIPv4 added in v1.1.2

func WithSessionPreferIPv4() SessionOption

WithSessionPreferIPv4 makes the session prefer IPv4 addresses over IPv6. Use this on networks with poor IPv6 connectivity.

func WithSessionProxy

func WithSessionProxy(proxyURL string) SessionOption

WithSessionProxy sets a proxy for the session

func WithSessionTCPProxy added in v1.5.3

func WithSessionTCPProxy(proxyURL string) SessionOption

WithSessionTCPProxy sets a proxy for TCP-based protocols (HTTP/1.1 and HTTP/2). Use this with WithSessionUDPProxy for split proxy configuration.

func WithSessionTimeout

func WithSessionTimeout(d time.Duration) SessionOption

WithSessionTimeout sets the timeout for session requests

func WithSessionUDPProxy added in v1.5.3

func WithSessionUDPProxy(proxyURL string) SessionOption

WithSessionUDPProxy sets a proxy for UDP-based protocols (HTTP/3 via MASQUE). Use this with WithSessionTCPProxy for split proxy configuration.

func WithSwitchProtocol added in v1.6.0

func WithSwitchProtocol(protocol string) SessionOption

WithSwitchProtocol sets the protocol to switch to after Refresh(). This enables warming up TLS tickets on one protocol (e.g. H3) then serving requests on another (e.g. H2) with TLS session resumption. Valid values: "h1", "h2", "h3".

func WithTCPFingerprint added in v1.6.1

func WithTCPFingerprint(fp fingerprint.TCPFingerprint) SessionOption

WithCustomFingerprint sets a custom TLS/HTTP2 fingerprint for the session. When JA3 is set, TLS-only mode is automatically enabled (preset HTTP headers are skipped). WithTCPFingerprint overrides individual TCP/IP fingerprint fields from the preset. Only non-zero fields are applied; zero fields keep the preset default.

func WithTLSOnly added in v1.5.8

func WithTLSOnly() SessionOption

WithTLSOnly enables TLS-only mode. In this mode, the preset's TLS fingerprint is used but its default HTTP headers are NOT applied. You must set all headers manually per-request. Useful when you need full control over HTTP headers while keeping the TLS fingerprint.

func WithoutConditionalCache added in v1.6.7

func WithoutConditionalCache() SessionOption

WithoutConditionalCache disables the session's ETag / If-Modified-Since handling for the lifetime of the session. When set, the session never injects If-None-Match or If-Modified-Since headers and never stores those validators from responses.

Useful for benchmarking, fingerprint testing, or any workflow that needs every request to hit the origin fresh regardless of prior responses. Toggle the same state at runtime with Session.SetConditionalCacheEnabled, or skip the cache for a single request via Request.DisableConditionalCache.

func WithoutCookieJar added in v1.6.6

func WithoutCookieJar() SessionOption

WithoutCookieJar disables the session's internal cookie jar entirely. When set, Set-Cookie headers from responses are NOT stored and the jar's contents are NOT injected as Cookie headers on subsequent requests — cookie management is left fully to the caller via per-request headers.

Useful when an application maintains its own cookie store (database, shared cache across sessions) and wants the lib to be byte-transparent about cookies. Combine with the regular `headers={"Cookie": "..."}` kwarg to inject your own jar's contents per request.

Caller-provided Cookie headers always pass through regardless of this option — only the auto-injection from the internal jar is suppressed.

func WithoutRedirects added in v1.0.1

func WithoutRedirects() SessionOption

WithoutRedirects disables automatic redirect following

func WithoutRetry added in v1.0.5

func WithoutRetry() SessionOption

WithoutRetry explicitly disables retry

type StreamResponse added in v1.5.3

type StreamResponse struct {
	StatusCode    int
	Headers       map[string][]string
	FinalURL      string
	Protocol      string
	ContentLength int64 // -1 if unknown (chunked encoding)
	// contains filtered or unexported fields
}

StreamResponse represents a streaming HTTP response where the body is read incrementally. Use this for large file downloads.

func (*StreamResponse) Close added in v1.5.3

func (r *StreamResponse) Close() error

Close closes the response body - must be called when done

func (*StreamResponse) Read added in v1.5.3

func (r *StreamResponse) Read(p []byte) (n int, err error)

Read reads data from the response body

func (*StreamResponse) ReadAll added in v1.5.3

func (r *StreamResponse) ReadAll() ([]byte, error)

ReadAll reads the entire response body into memory This defeats the purpose of streaming but is useful for small responses

func (*StreamResponse) ReadChunk added in v1.5.3

func (r *StreamResponse) ReadChunk(size int) ([]byte, error)

ReadChunk reads up to size bytes from the response

Directories

Path Synopsis
Package client provides an HTTP client with browser TLS/HTTP fingerprint spoofing.
Package client provides an HTTP client with browser TLS/HTTP fingerprint spoofing.
examples
go-examples/basic command
Example: Basic HTTP requests with httpcloak
Example: Basic HTTP requests with httpcloak
go-examples/browserleaks-ech command
Example: ECH + 0-RTT test with browserleaks using HTTP/3
Example: ECH + 0-RTT test with browserleaks using HTTP/3
go-examples/cloudflare command
Example: Multiple requests to Cloudflare trace endpoint
Example: Multiple requests to Cloudflare trace endpoint
go-examples/custom-fingerprint command
Example: Custom JA3 & Akamai Fingerprinting with httpcloak
Example: Custom JA3 & Akamai Fingerprinting with httpcloak
go-examples/high-performance command
Example: High-Performance Downloads
Example: High-Performance Downloads
go-examples/quic-idle-timeout command
Example: QUIC Idle Timeout Configuration
Example: QUIC Idle Timeout Configuration
go-examples/session command
Example: Session management with cookies
Example: Session management with cookies
go-examples/session-resumption command
Example: Session Resumption (0-RTT)
Example: Session Resumption (0-RTT)
go-examples/streaming command
Example: Streaming Downloads with httpcloak
Example: Streaming Downloads with httpcloak
go-examples/tls-only command
Example: TLS-Only Mode with httpcloak
Example: TLS-Only Mode with httpcloak
go-examples/warmup-and-fork command
Warmup & Fork: Browser-Like Page Load and Parallel Tab Simulation
Warmup & Fork: Browser-Like Page Load and Parallel Tab Simulation
Package protocol defines the JSON-shaped session configuration types that the cgo entry points in bindings/clib consume from the language SDKs.
Package protocol defines the JSON-shaped session configuration types that the cgo entry points in bindings/clib consume from the language SDKs.
keylog.go provides TLS key logging for traffic analysis with Wireshark.
keylog.go provides TLS key logging for traffic analysis with Wireshark.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL