Skip to main content

Options

Every option you can pass to httpcloak.New(...) and httpcloak.NewSession(...), in one flat list. The topic pages (Proxies, Fingerprinting, Sessions) cover the reasoning; this page is the lookup table.

info

Flat reference. For why each option exists and when to reach for it, see the topic sections (Proxies, Fingerprinting, Sessions, etc.).

There are two construction surfaces. httpcloak.New(preset, ...Option) returns a stateless *Client and takes a small set of options. httpcloak.NewSession(preset, ...SessionOption) returns a stateful *Session that owns cookies, TLS resumption tickets, and header memory; that's where most of the surface lives.

If you're new, start with NewSession. New is the right call for one-shot scripts where state across requests doesn't matter.


Client options (httpcloak.New)​

The stateless Client exposes two options. Anything that needs state lives on NewSession.

SignatureDefaultWhat it does
WithTimeout(d time.Duration) Option30sPer-request timeout for client.Do, Get, Post, etc. Resets on every call.
WithProxy(url string) Option"" (no proxy)Single-protocol proxy URL (http://, https://, socks5://). Applied to every request. For per-protocol split routing, use NewSession with the TCP/UDP proxy options.

Session options (httpcloak.NewSession)​

The full session surface, grouped by category. Every constructor returns a SessionOption.

Lifecycle and cookies​

Session-level state. The cookie jar, header memory, and the protocol the session flips to after Refresh().

SignatureDefaultWhat it does
WithoutCookieJar() SessionOptionjar enabledDisables the internal cookie jar entirely. Set-Cookie is not stored, jar contents are not auto-injected as Cookie: headers. Caller-provided Cookie headers always pass through. Use when you have your own jar (database, shared cache). See Disabling the cookie jar.
WithoutConditionalCache() SessionOptioncache enabledDisables the session's ETag / If-Modified-Since handling for the session's lifetime. No validators get injected, no validators get stored. Runtime toggle: Session.SetConditionalCacheEnabled(bool). Per-request opt-out: Request.DisableConditionalCache bool. See Conditional Cache.
WithSwitchProtocol(proto string) SessionOption"" (no switch)Protocol the session switches to on the next Refresh(). Valid values: "h1", "h2", "h3". Useful for warming TLS on H3 then serving on H2 with resumption.
WithKeyLogFile(path string) SessionOptionSSLKEYLOGFILE envPer-session override for the TLS key log path. Wireshark / Chrome use this to decrypt captured traffic.

Network, proxies, local binding​

How outbound connections are made. Proxy routing, IP family preference, source-IP binding.

SignatureDefaultWhat it does
WithSessionProxy(url string) SessionOption""Single proxy URL applied to all protocols (TCP and UDP). Schemes: http://, https://, socks5://. See Proxies.
WithSessionTCPProxy(url string) SessionOption""TCP-only proxy (HTTP/1.1, HTTP/2). Pair with WithSessionUDPProxy for split routing.
WithSessionUDPProxy(url string) SessionOption""UDP-only proxy (HTTP/3 via SOCKS5 or MASQUE). Pair with WithSessionTCPProxy.
WithSessionPreferIPv4() SessionOptionIPv4/IPv6 racingForces IPv4 dial. Use on networks where IPv6 is broken or slow. Disables Happy Eyeballs racing.
WithLocalAddress(addr string) SessionOptionOS-chosenBinds outgoing connections to a specific local IP (v4 or v6). On Linux, freebind is auto-applied so any address from a routed prefix works without per-IP interface config. Useful for IPv6 rotation. Also restricts DNS lookups to the bound family, since the other one cannot be dialed from that socket. See DNS Cache.
WithLocalAddrIP(ip net.IP) SessionOptionOS-chosenSame as WithLocalAddress but takes a parsed net.IP. Nil is a no-op (so conditional builders don't clobber a previous value).
WithConnectTo(requestHost, connectHost string) SessionOptionno overrideDomain fronting: requests to requestHost connect to connectHost. SNI and Host: keep requestHost. Can be called multiple times for multiple mappings.
WithEnableSpeculativeTLS() SessionOptionoffSends CONNECT and TLS ClientHello together over a proxy, saving one round-trip (~25% speedup). Off by default because some HTTP proxies choke on it. Enable when you've validated the proxy supports it.

Protocol forcing​

Pin or disable specific HTTP versions.

SignatureDefaultWhat it does
WithForceHTTP1() SessionOptionautoForces HTTP/1.1. Implies WithDisableHTTP3().
WithForceHTTP2() SessionOptionautoForces HTTP/2. Implies WithDisableHTTP3().
WithForceHTTP3() SessionOptionautoForces HTTP/3 (QUIC). Fails on hosts that don't advertise H3.
WithDisableHTTP3() SessionOptionH3 enabled when preset supports itDisables HTTP/3 racing while keeping H1/H2 negotiation. Use when QUIC is unreliable on the network or you bound to an address that can't UDP.
WithTLSOnly() SessionOptionoffKeeps the preset's TLS fingerprint but skips its default HTTP headers. You set every header per-request. Auto-enabled when WithCustomFingerprint provides a JA3.

TLS, ECH, certificate verification​

SignatureDefaultWhat it does
WithInsecureSkipVerify() SessionOptionverify enabledSkips TLS certificate verification. Test-only, never ship this enabled.
WithVerifyPeerCertificate(fn func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error) SessionOptionnoneMirrors crypto/tls.Config.VerifyPeerCertificate. Runs after the normal certificate checks with the raw certificates and any chains that were built; returning an error aborts the handshake. This is the hook for certificate pinning. Pair with WithInsecureSkipVerify() to replace the default verification rather than add to it.
WithVerifyConnection(fn func(cs tls.ConnectionState) error) SessionOptionnoneMirrors crypto/tls.Config.VerifyConnection. Runs after WithVerifyPeerCertificate, on every handshake including resumptions. The state is the standard library type.
WithTLSConfig(cfg *tls.Config) SessionOptionnoneConvenience wrapper that reads the verification settings from a standard *tls.Config. Honoured: VerifyPeerCertificate, VerifyConnection, RootCAs, InsecureSkipVerify. Ignored: everything that shapes the ClientHello, including CipherSuites, MinVersion, MaxVersion, CurvePreferences, NextProtos and ServerName. Those come from the profile, and honouring them would silently change how the client looks on the wire. Prefer the two options above, which make the supported surface obvious.
WithDisableECH() SessionOptionECH attempted when DNS has itSkips the ECH (Encrypted Client Hello) HTTPS RR lookup. Saves ~15-20ms on first connect at the cost of the privacy bump ECH gives you.
WithECHFrom(domain string) SessionOptiontarget domainPulls ECH config from a different domain's DNS than the request target. Common pattern for Cloudflare: WithECHFrom("cloudflare-ech.com") works for any CF-fronted host.
WithSessionCache(backend, errCb) SessionOptionin-memoryPlugs a distributed TLS session cache (e.g. Redis). backend implements transport.SessionCacheBackend; errCb is called when the backend fails. Lets multiple processes share TLS resumption tickets.

Fingerprint customization​

SignatureDefaultWhat it does
WithCustomFingerprint(fp CustomFingerprint) SessionOptionpreset's defaultsOverride TLS (JA3) and HTTP/2 (Akamai) fingerprints. When JA3 is set, WithTLSOnly() is auto-enabled. The struct fields: JA3 (full string), Akamai (settings/window/priority/pseudo string), SignatureAlgorithms, ALPN, CertCompression, PermuteExtensions. See Custom fingerprints.
WithTCPFingerprint(fp fingerprint.TCPFingerprint) SessionOptionpreset's defaultsOverride TCP/IP fingerprint fields (TTL, MSS, window size, window scale, DF bit). Only non-zero fields apply; zero fields keep the preset value.

Timeouts and retries​

SignatureDefaultWhat it does
WithSessionTimeout(d time.Duration) SessionOption30sDefault per-request timeout. Each Do / Get can override via req.Timeout.
WithQuicIdleTimeout(d time.Duration) SessionOption30sQUIC idle timeout. Connections close after this much silence. Match Chrome's default unless you need long-lived H3 sessions across request gaps.
WithRetry(count int) SessionOptionretry offEnables retry with default backoff. count is total retry attempts (not including the first try).
WithoutRetry() SessionOptionretry offExplicitly disables retry. No-op if retry was never enabled.
WithRetryConfig(count int, waitMin, waitMax time.Duration, retryOnStatus []int) SessionOptionsee sourceFull retry config. waitMin/waitMax define exponential backoff bounds. retryOnStatus is the set of HTTP statuses that trigger a retry.

Redirects​

SignatureDefaultWhat it does
WithoutRedirects() SessionOptionfollow onDon't follow redirects. The first 3xx response returns to caller.
WithRedirects(follow bool, maxRedirects int) SessionOptionfollow=true, max=10Toggle follow + cap the chain. maxRedirects=0 with follow=true falls back to the package default.

Runtime toggles (no ctor option required) live on *Session: SetFollowRedirects(bool) / FollowRedirects(), SetMaxRedirects(int) / MaxRedirects(). Per-request override: set Request.FollowRedirects *bool before Do. See Conditional Cache for the parallel surface on ETag handling.

Stopping a chain on one specific hop​

Request.OnRedirect is called once per hop, before the follow-up request is built. It is the alternative to turning redirects off and re-implementing the chain yourself — you keep the method rewrite, the Referer policy, the cookie jar and the credential scrubbing, and still get to say no.

resp, err := s.Do(ctx, &httpcloak.Request{
Method: "POST", URL: checkout, Body: strings.NewReader(payload),
OnRedirect: func(r *httpcloak.Redirect) error {
if r.CrossOrigin {
return httpcloak.ErrUseLastResponse // stop, hand me the 3xx
}
return nil // follow it
},
})
ReturnResult
nilThe hop is followed.
ErrUseLastResponseThe chain stops. The 3xx becomes the response, with a nil error, exactly as if redirects had been off for that hop.
any other errorThe request fails with that error, unwrapped, so errors.Is against your own sentinel matches.

The *Redirect carries Hop (1-based), StatusCode, Headers (the 3xx's own — the only place to read a Set-Cookie or routing header the final response will not carry), From, To, ToURL(), Method (what the next hop will use, after the 301/302/303 rewrite to GET), CrossOrigin and SchemeDowngrade. Prefer the origin flags and ToURL() over substring-matching To: strings.Contains(To, "example.com") also passes for https://example.com.attacker.test.

Read those headers with GetHeader(name) / GetHeaders(name), which are case-insensitive. The raw Headers map is lowercase-keyed like every header map in the library, so Headers["Set-Cookie"] finds nothing while Headers["set-cookie"] works. Use the plural form for Set-Cookie, which can appear more than once:

for _, c := range r.GetHeaders("Set-Cookie") {
// ...
}

It is read-only. Writing to a field does not retarget the hop — a callback able to rewrite the target would run before the origin scrubbing, which is what stops Authorization following a redirect off-origin. It is not called for a 3xx with no Location (no hop to veto), nor for the hop that would exceed the cap (that fails with ErrTooManyRedirects), and never from DoStream, which does not follow redirects at all.

Bodies on 307 and 308​

Those two codes keep the method and the body, so the body has to be sent twice. For *bytes.Reader, *bytes.Buffer and *strings.Reader this is automatic. For a genuine stream — an *os.File, a pipe — set Request.GetBody to re-open it:

Body: f,
GetBody: func() (io.Reader, error) { return os.Open(path) },

Without it the hop fails with ErrBodyNotReplayable rather than being sent with an empty body, and the 3xx comes back alongside the error so you can read its Location and drive the rest of the chain yourself.

Custom fingerprint struct (CustomFingerprint)​

The value passed to WithCustomFingerprint. Defined in the root package.

FieldTypeNotes
JA3stringFull JA3 string: Version,Ciphers,Extensions,Curves,Formats. Setting this implies TLS-only mode.
AkamaistringAkamai HTTP/2 fingerprint: SETTINGS|WINDOW_UPDATE|PRIORITY|PSEUDO_ORDER. Example: 1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p.
SignatureAlgorithms[]stringNames like "ecdsa_secp256r1_sha256", "rsa_pss_rsae_sha256". Replaces the JA3 spec's default sig-algs.
ALPN[]stringDefault ["h2", "http/1.1"]. Override to limit (e.g. H1-only).
CertCompression[]stringOne or more of "brotli", "zlib", "zstd".
PermuteExtensionsboolWhen true, the TLS extension order is permuted per handshake (Chrome 110+ behavior).

Per-request options​

Fields on the Request struct override session-level settings for a single call. These don't go through SessionOption.

FieldTypeWhat it does
MethodstringHTTP method.
URLstringAbsolute URL.
Headersmap[string][]stringExtra headers (multi-value, matches http.Header). Caller-provided Cookie: always passes through.
Bodyio.ReaderStreaming body (no length needed for chunked).
Timeouttime.DurationPer-request timeout override.
TLSOnly*boolPer-request override for WithTLSOnly. nil falls back to the session setting. Useful for LocalProxy where each request has its own TLS-only flag via X-HTTPCloak-TlsOnly.

Session methods (mutators after construction)​

Methods on *Session itself, called after NewSession returns. These aren't SessionOption constructors and can't be passed at build time.

MethodWhat it does
SetProxy(url string)Replaces the unified proxy. Closes existing connections. Empty string switches to direct.
SetTCPProxy(url string)Replaces only the TCP proxy.
SetUDPProxy(url string)Replaces only the UDP proxy.
GetProxy() stringCurrent unified or TCP proxy URL.
GetTCPProxy() stringCurrent TCP proxy URL.
GetUDPProxy() stringCurrent UDP proxy URL.
SetHeaderOrder(order []string)Override the preset's header order. Lowercase names. Treated as a prefix: named headers lead, the preset's table covers the rest, anything left over is sorted. nil resets to preset default.
GetHeaderOrder() []stringCurrent header order, or preset default if no override.
SetSessionIdentifier(id string)TLS-cache key namespace. Used when a session is registered with LocalProxy so distributed caches isolate per-session tickets.
Warmup(ctx, url) errorSimulates a real browser page load: fetches HTML + CSS/JS/image subresources with realistic headers, priorities, and timing. Warms TLS, cookies, ticket cache.
Fork(n int) []*SessionCreate n child sessions sharing cookies and TLS cache but with independent connections. Mimics multiple browser tabs.
Refresh()Close all connections, keep TLS cache and cookies. Switches protocol if WithSwitchProtocol was set.
RefreshWithProtocol(proto string) errorSame as Refresh but switches to the given protocol. The change persists for future Refresh() calls. Valid: "h1", "h2", "h3", "auto".
Save(path string) errorPersist cookies + TLS sessions to a file.
Marshal() ([]byte, error)Persist cookies + TLS sessions to bytes.
Close()Release everything. Always defer this.

Cookie methods on *Session:

MethodWhat it does
GetCookies() []CookieInfoAll cookies with full metadata.
GetCookiesDetailed() []CookieInfoSame shape (the bindings split this; in Go they're identical).
SetCookie(c CookieInfo)Insert / replace a cookie with full metadata.
DeleteCookie(name, domain string)Delete by name. Empty domain wipes from every domain.
ClearCookies()Wipe the jar.

Package-level loaders, not methods on *Session:

FunctionWhat it does
LoadSession(path string) (*Session, error)Restore a session saved with Save.
UnmarshalSession(data []byte) (*Session, error)Restore a session from bytes saved with Marshal.
LoadSessionWithOptions(path string, opts *SessionLoadOptions)Same as LoadSession, plus the certificate verification hooks the file could not carry. Required when the saved session had any, otherwise the load fails.
UnmarshalSessionWithOptions(data []byte, opts *SessionLoadOptions)The in-memory form of the same.
Presets() []stringThe built-in preset names. Custom presets registered via fingerprint.Register(name, *Preset) go into a separate map and are NOT returned by Presets(). To resolve a name (built-in or custom) at runtime, use fingerprint.Get(name).

Top-level helpers​

Symbols in the root package that aren't options. Request and response types, multipart helpers, body readers.

SymbolWhat it does
BuildMultipart(fields []MultipartField) ([]byte, string, error)Encode a multipart/form-data body. Returns body bytes + the Content-Type header value (with boundary). Handles both text fields (Name, Value) and file fields (Name, Filename, Content, ContentType).
MultipartFieldStruct passed to BuildMultipart. Fields: Name, Value, Filename, Content, ContentType.
Request, Response, RedirectInfo, StreamResponseRequest/response shapes.
Response.Bytes() / Text() / JSON(v)Read the body once, with caching.
Response.GetHeader(key) / GetHeaders(key)Case-insensitive lookup (header keys are stored lowercase).
StreamResponse.Read / ReadChunk / ReadAll / CloseStreaming body reads. Streaming does not support redirects, use Do for redirect handling.

Defaults at a glance​

The values you get when no option is set.

SettingDefault
Request timeout30s
QUIC idle timeout30s
Cookie jarenabled
Redirect followon, max 10
Retryoff
HTTP/3enabled when preset supports it
ECH lookupon if the target's DNS publishes HTTPS RRs
Speculative TLSoff
TLS verifyon
Header orderpreset default
Local IP bindnone (OS-chosen)
IPv4/IPv6 preferenceracing (Happy Eyeballs)

If a default doesn't match what you expected, file an issue with the preset name and a tls.peet.ws/api/all capture.