Documentation
¶
Overview ¶
package illutls provides an HTTP client that simulates real browser TLS fingerprints and HTTP headers.
Illutls combines utls (for TLS ClientHello spoofing) with fhttp (for HTTP/2 frame-level fingerprint control) to present a complete, authentic browser identity on every connection.
Quick Start ¶
client, err := illutls.New(illutls.WithProfile("chrome-149-windows-10"))
if err != nil {
log.Fatal(err)
}
resp, err := client.Get("https://example.com")
Available Profiles ¶
Call ListProfiles() to see all registered browser profiles. Out of the box, Illutls ships with real-world fingerprints covering Chrome, Firefox, Edge, and Safari across Windows, macOS, Linux, Android, and iOS. If no profile is specified, it defaults to "chrome-149-windows-10".
Concurrency & Randomization ¶
Client is safe for concurrent use by multiple goroutines. Each TLS connection gets independently randomized GREASE values and extension shuffling, making repeat connections appear as natural browser traffic.
Features ¶
- Extension Shuffling: Randomizes TLS extension order per connection (enabled by default).
- ECH Support: Injects compliant GREASE payloads into the ECH extension (65037).
- Proxy Support: Route traffic through HTTP/SOCKS5 proxies via WithProxy().
Custom Profiles ¶
Use WithCustomProfile() to register your own BrowserProfile with a custom TLS spec, HTTP/2 settings, and header ordering.
Index ¶
- Variables
- func ApplyH2Settings(t *http2.Transport, s H2Settings, windowUpdate uint32, priority H2Priority, ...)
- func BuildHeaders(profile *BrowserProfile, req *http.Request) http.Header
- func BuildRawLanguageList(lang, country string) string
- func CloneClientHelloSpec(src *utls.ClientHelloSpec) *utls.ClientHelloSpec
- func GenerateAcceptLanguageHeader(rawLanguageList string) string
- func InjectECHPublicKey(spec *utls.ClientHelloSpec) error
- func ListProfiles() []string
- func MergeHeaders(dst, src http.Header)
- func RandomizeGREASE(spec *utls.ClientHelloSpec)
- func RegisterProfile(p *BrowserProfile)
- func ShuffleExtensions(spec *utls.ClientHelloSpec)
- type BrowserProfile
- type Client
- func (c *Client) Close()
- func (c *Client) Do(req *http.Request) (*http.Response, error)
- func (c *Client) Get(url string) (*http.Response, error)
- func (c *Client) Head(url string) (*http.Response, error)
- func (c *Client) NewRequest(method, url string, body io.Reader) (*http.Request, error)
- func (c *Client) Post(url, contentType string, body io.Reader) (*http.Response, error)
- func (c *Client) Profile() *BrowserProfile
- type H2Priority
- type H2Settings
- type H2StreamPriority
- type Option
- func WithCustomProfile(p *BrowserProfile) Option
- func WithDangerousJA4Randomization() Option
- func WithDisableKeepAlives() Option
- func WithDynamicProfile(seed any, params ...any) Option
- func WithLanguage(lang string) Option
- func WithMaxRedirects(n int) Option
- func WithPrebuiltHeaders() Option
- func WithProfile(name string) Option
- func WithProxy(proxyURL string) Option
- func WithReuseRequest() Option
- func WithShuffleExtensions(b bool) Option
- func WithTLSConfig(c *tls.Config) Option
- func WithTLSHandshakeTimeout(d time.Duration) Option
- func WithTimeout(d time.Duration) Option
- func WithoutRedirects() Option
- type Options
- type Transport
Constants ¶
This section is empty.
Variables ¶
var ( // ErrProfileNotFound is returned when a requested browser profile does not exist. ErrProfileNotFound = errors.New("illutls: browser profile not found") // ErrTLSHandshake is returned when the TLS connection fails. ErrTLSHandshake = errors.New("illutls: TLS handshake failed") // ErrH2Settings is returned when HTTP/2 settings cannot be applied. ErrH2Settings = errors.New("illutls: HTTP/2 settings application failed") // ErrInvalidProxy is returned when the provided proxy URL is invalid. ErrInvalidProxy = errors.New("illutls: invalid proxy URL") // ErrNilProfile is returned if a nil profile is provided to the transport. ErrNilProfile = errors.New("illutls: profile must not be nil") // ErrConnectionFailed is returned for general dial or connection errors. ErrConnectionFailed = errors.New("illutls: connection failed") )
var ErrHTTP11Negotiated = errors.New("http/1.1 negotiated")
Functions ¶
func ApplyH2Settings ¶
func ApplyH2Settings(t *http2.Transport, s H2Settings, windowUpdate uint32, priority H2Priority, priorities []H2StreamPriority)
ApplyH2Settings configures an fhttp http2.Transport to match the browser profile's HTTP/2 SETTINGS frame parameters.
func BuildHeaders ¶
func BuildHeaders(profile *BrowserProfile, req *http.Request) http.Header
BuildHeaders constructs the full HTTP header set for a request according to the profile's template and ordering rules.
Dynamic headers (:authority, :path, host, etc.) are filled from the request itself; static headers (user-agent, sec-ch-ua, accept-encoding, etc.) come from the profile definition.
func BuildRawLanguageList ¶
BuildRawLanguageList perfectly mimics Chrome's OS locale fallback algorithm. When an OS is set to a specific locale (e.g., "ja-JP"), Chrome builds the Accept-Language by taking the specific locale, then the base language, and appending English fallbacks.
func CloneClientHelloSpec ¶
func CloneClientHelloSpec(src *utls.ClientHelloSpec) *utls.ClientHelloSpec
CloneClientHelloSpec deep-copies a ClientHelloSpec so that GREASE randomization on one connection does not affect others.
func GenerateAcceptLanguageHeader ¶
GenerateAcceptLanguageHeader perfectly mimics Chromium's net::HttpUtil::GenerateAcceptLanguageHeader It takes a comma-separated list of languages (e.g. "ja,en-US,en") and applies descending q-values.
func InjectECHPublicKey ¶
func InjectECHPublicKey(spec *utls.ClientHelloSpec) error
func ListProfiles ¶
func ListProfiles() []string
ListProfiles returns the names of all registered profiles.
func MergeHeaders ¶
MergeHeaders copies src headers into dst without overwriting existing keys.
func RandomizeGREASE ¶
func RandomizeGREASE(spec *utls.ClientHelloSpec)
func RegisterProfile ¶
func RegisterProfile(p *BrowserProfile)
RegisterProfile adds a browser profile to the global registry. If a profile with the same name already exists it is overwritten.
func ShuffleExtensions ¶
func ShuffleExtensions(spec *utls.ClientHelloSpec)
Types ¶
type BrowserProfile ¶
type BrowserProfile struct {
// Name is a human-readable identifier, e.g. "Chrome 141 Windows".
Name string
// UserAgent is the User-Agent header string.
UserAgent string
// TLSSpec defines the TLS ClientHello parameters for utls.
// GREASE placeholders are randomized at connection time.
TLSSpec *utls.ClientHelloSpec
// H2Settings configures the HTTP/2 SETTINGS frame.
H2Settings H2Settings
// H2WindowUpdate is the WINDOW_UPDATE increment sent after SETTINGS.
H2WindowUpdate uint32
// H2Priority configures the PRIORITY field in HEADERS frames.
H2Priority H2Priority
// H2Priorities lists standalone PRIORITY frames emitted right after the SETTINGS
// frame — Firefox's placeholder dependency tree (streams 3/5/7/9/11/13). Leave
// empty for browsers that don't send them (e.g. Chrome). Mapped onto the fhttp
// http2.Transport.Priorities field.
H2Priorities []H2StreamPriority
// HeaderOrder defines the order of standard HTTP headers (lowercase).
HeaderOrder []string
// PHeaderOrder defines the order of HTTP/2 pseudo-headers.
PHeaderOrder []string
// Headers supplies default header values (sec-ch-ua, accept, etc.).
// Keys are canonical HTTP header names.
Headers map[string]string
}
BrowserProfile defines the complete fingerprint for a browser identity. It is immutable after creation 鈥?safe to share across goroutines.
func GenerateProfile ¶
func GenerateProfile(seed int64, platform string, majorVersion int, forceRandomizeJA4 bool) *BrowserProfile
GenerateProfile creates a deterministic BrowserProfile based on a seed. platform can be "windows", "mac", "linux", "android", "ios".
func GetProfile ¶
func GetProfile(name string) *BrowserProfile
GetProfile returns a registered profile by name, or nil if not found.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the main entry point for Illutls. It provides browser-identical HTTP requests with automatic TLS and header fingerprinting.
Client is safe for concurrent use by multiple goroutines.
func New ¶
New creates an Illutls Client configured with the given options.
Example:
client, err := illutls.New(illutls.WithProfile("Chrome 141 Windows"))
if err != nil {
log.Fatal(err)
}
defer client.Close()
resp, err := client.Get("https://example.com")
func (*Client) Do ¶
Do sends an HTTP request and returns an HTTP response. The caller is responsible for closing the response body.
func (*Client) NewRequest ¶
NewRequest creates a new HTTP request with the profile's headers pre-populated. The caller can override any header before calling Do().
func (*Client) Profile ¶
func (c *Client) Profile() *BrowserProfile
Profile returns the active BrowserProfile.
type H2Priority ¶
H2Priority corresponds to the PRIORITY field in an HTTP/2 HEADERS frame.
type H2Settings ¶
type H2Settings struct {
HeaderTableSize uint32
EnablePush uint32
MaxConcurrentStreams uint32
InitialWindowSize uint32
MaxFrameSize uint32
MaxHeaderListSize uint32
// NoRFC7540Priorities corresponds to SETTINGS_NO_RFC7540_PRIORITIES (0x09).
NoRFC7540Priorities uint32
// SettingsOrder explicitly defines the order of settings. If empty, a default order is used.
SettingsOrder []uint16
}
H2Settings corresponds to an HTTP/2 SETTINGS frame.
type H2StreamPriority ¶
H2StreamPriority is a standalone HTTP/2 PRIORITY frame in the profile's dependency-tree fingerprint. Firefox emits a fixed set right after SETTINGS (streams 3/5/7/9/11/13) to build its placeholder priority tree; real requests then depend on those placeholders.
type Option ¶
type Option func(*Options)
Option is a functional option for configuring a Client.
func WithCustomProfile ¶
func WithCustomProfile(p *BrowserProfile) Option
WithCustomProfile provides a user-defined BrowserProfile directly.
func WithDangerousJA4Randomization ¶
func WithDangerousJA4Randomization() Option
WithDangerousJA4Randomization enables persistent randomization of the JA4 hash by deterministically mutating the cipher suites based on the profile seed. WARNING: This is a highly dangerous feature. Modifying the cipher suite list breaks the authentic Chrome fingerprint. Advanced WAFs (Cloudflare, Akamai) may flag this as an anomaly. Use ONLY against primitive self-built WAFs that blindly block JA4 hashes based on frequency.
func WithDisableKeepAlives ¶
func WithDisableKeepAlives() Option
WithDisableKeepAlives disables HTTP keep-alive.
func WithDynamicProfile ¶
func WithLanguage ¶
WithLanguage handles Accept-Language generation with extreme flexibility: 1. "auto": Automatically infers language from Proxy IP using the embedded GeoIP MMDB. 2. "/path/to/geo.mmdb": Automatically infers language using the provided external MMDB. 3. "FR": Uses a 2-letter ISO country code to dynamically generate Chrome locale strings. 4. "ja,en-US,en": Uses the explicit raw language string. All generated strings are passed through Chrome's exact mathematical q-value algorithm.
func WithMaxRedirects ¶
WithMaxRedirects sets the maximum number of redirect hops.
func WithPrebuiltHeaders ¶
func WithPrebuiltHeaders() Option
WithPrebuiltHeaders caches the profile's static header set once and reuses it per request instead of rebuilding it each RoundTrip. Enable for high-throughput callers that set all dynamic/context headers (sec-fetch-*, cookie, referer) themselves.
func WithProfile ¶
WithProfile selects a registered browser profile by name.
func WithReuseRequest ¶
func WithReuseRequest() Option
WithReuseRequest skips the per-request defensive Clone inside RoundTrip to reduce allocations. Only enable when each *http.Request is freshly built and never reused or read concurrently by the caller after Do returns (e.g. load generators).
func WithShuffleExtensions ¶
WithShuffleExtensions dynamically randomizes the order of TLS extensions per connection to mimic Chrome's Extension Shuffling behavior and avoid TLS parroting.
func WithTLSConfig ¶
WithTLSConfig provides additional TLS configuration.
func WithTLSHandshakeTimeout ¶
WithTLSHandshakeTimeout sets the TLS handshake timeout.
func WithTimeout ¶
WithTimeout sets the total request timeout.
func WithoutRedirects ¶
func WithoutRedirects() Option
WithoutRedirects disables following HTTP redirects.
type Options ¶
type Options struct {
// ProfileName selects a registered BrowserProfile by name.
ProfileName string
// Profile is a user-supplied profile (takes precedence over ProfileName).
Profile *BrowserProfile
// Timeout is the total request timeout (default: 30s).
Timeout time.Duration
// TLSHandshakeTimeout limits the TLS handshake duration (default: 10s).
TLSHandshakeTimeout time.Duration
// ProxyURL is an optional HTTP/SOCKS5 proxy (e.g. "socks5://127.0.0.1:1080").
ProxyURL string
// TLSConfig provides additional tls.Config fields (e.g. InsecureSkipVerify).
// ServerName is automatically set per-request and should not be set here.
TLSConfig *tls.Config
// FollowRedirects controls whether the client follows HTTP redirects (default: true).
FollowRedirects bool
// MaxRedirects limits redirect hops (default: 10).
MaxRedirects int
// DisableKeepAlives disables HTTP keep-alive connections.
DisableKeepAlives bool
// ShuffleExtensions dynamically randomizes the order of TLS extensions per connection.
ShuffleExtensions bool
// GeoIPDBPath is the local path to the GeoLite2-Country.mmdb file.
GeoIPDBPath string
// RawLanguageList is the explicit raw language string to be parsed via Chrome's algorithm.
RawLanguageList string
// ForceRandomizeJA4 is a highly dangerous feature that persistently modifies the cipher suite
// list to generate a randomized JA4 hash, useful only against primitive blocklists.
ForceRandomizeJA4 bool
// Dynamic profile generation parameters (evaluated in New)
DynamicProfileSeed *int64
DynamicProfilePlatform string
DynamicProfileVersion int
// ReuseRequest skips the defensive req.Clone in RoundTrip to cut per-request
// allocations. Safe ONLY when the caller builds a fresh *http.Request per call and
// never reuses it or reads it concurrently after Do returns (e.g. high-throughput
// load generators). Default false keeps the clone for general-purpose correctness.
ReuseRequest bool
// PrebuildHeaders caches the profile's static header template once at Transport
// construction and reuses it per request, skipping the per-request BuildHeaders
// allocation + string scanning. Header ordering still follows the profile (merge
// semantics unchanged, so the fingerprint is identical). Safe ONLY when the caller
// supplies all dynamic/context headers (sec-fetch-*, cookie, referer) itself, since
// the cached template omits BuildHeaders' per-request API-request heuristics.
PrebuildHeaders bool
}
Options holds all configuration for a Client.
type Transport ¶
type Transport struct {
// contains filtered or unexported fields
}
func NewTransport ¶
func NewTransport(profile *BrowserProfile, opts *Options) (*Transport, error)
NewTransport creates a Transport for the given profile.