Map

enetx/surf README

title
enetx/surf README
fetched
2026-05-06

SURF - Advanced Go HTTP Client

Repo: enetx/surf Language: Go (100%) License: MIT Stars: 1.7k (88 forks) Required Go version: 1.25+

SURF is an advanced HTTP client library for Go featuring Chrome/Firefox browser impersonation, HTTP/3 with QUIC fingerprinting, JA3/JA4 TLS emulation, and anti-bot bypass capabilities for web automation and scraping.

Key Features

Browser Impersonation

  • Mimics Chrome v145 and Firefox v148 fingerprints accurately
  • Cross-platform: Windows, macOS, Linux, Android, iOS
  • Automatic header ordering and browser-specific values
  • WebKit form boundary generation matching real browsers

Advanced TLS & Security

  • Custom JA3/JA4 fingerprint configuration via HelloID and HelloSpec
  • Full HTTP/3 over QUIC support with complete browser fingerprinting
  • HTTP/2 with customizable SETTINGS frames and window sizes
  • DNS-over-TLS (DoT)
  • Proxy: HTTP, HTTPS, SOCKS4, SOCKS5 with UDP for HTTP/3
  • Certificate pinning

Performance & Reliability

  • Connection pooling with singleton pattern
  • Configurable automatic retry logic
  • Response body caching
  • Streaming support (large responses + SSE)
  • Automatic decompression (gzip, deflate, brotli, zstd)

Developer Experience

  • Standard library compatibility (converts to *net/http.Client)
  • Fluent, chainable API
  • Extensible middleware system with priority support
  • Strong typing with generics via enetx/g
  • Comprehensive debug mode
  • Full context.Context integration

Installation

go get -u github.com/enetx/surf

Usage

Basic GET

resp := surf.NewClient().Get("https://api.github.com/users/github").Do()
if resp.IsErr() {
    log.Fatal(resp.Err())
}
fmt.Println(resp.Ok().Body.String().Unwrap())

Browser Impersonation

client := surf.NewClient().Builder().Impersonate().Chrome().Build().Unwrap()

client := surf.NewClient().Builder().Impersonate().RandomOS().Firefox().Build().Unwrap()

client := surf.NewClient().Builder().Impersonate().IOS().Chrome().Build().Unwrap()

HTTP/3

client := surf.NewClient().Builder().
    Impersonate().Chrome().
    ForceHTTP3().
    Build().Unwrap()

resp := client.Get("https://cloudflare-quic.com/").Do()
fmt.Printf("Protocol: %s\n", resp.Ok().Proto) // HTTP/3.0

Custom JA3

client := surf.NewClient().Builder().JA().Chrome().Build().Unwrap()
client := surf.NewClient().Builder().JA().Randomized().Build().Unwrap()

HTTP/2 Settings

client := surf.NewClient().Builder().
    HTTP2Settings().
    HeaderTableSize(65536).
    EnablePush(0).
    InitialWindowSize(6291456).
    Set().
    Build().Unwrap()

Proxies

client := surf.NewClient().Builder().Proxy("http://proxy.example.com:8080").Build().Unwrap()

// SOCKS5 UDP for HTTP/3
client := surf.NewClient().Builder().
    Proxy("socks5://127.0.0.1:1080").
    ForceHTTP3().
    Build().Unwrap()

Sessions

client := surf.NewClient().Builder().Session().Build().Unwrap()
client.Post("https://example.com/login").Body(credentials).Do()
resp := client.Get("https://example.com/dashboard").Do()

Middleware

client := surf.NewClient().Builder().
    With(func(req *surf.Request) error {
        req.AddHeaders("X-Custom-Header", "value")
        return nil
    }).
    Build().Unwrap()

Multipart Upload

mp := surf.NewMultipart().
    Field("description", "Multiple files").
    File("document", g.NewFile("/path/to/doc.pdf")).
    FileBytes("data", "data.json", g.Bytes(`{"key": "value"}`)).
    FileString("text", "note.txt", "Hello, World!")

resp := surf.NewClient().Post("https://api.example.com/upload").Multipart(mp).Do()

Streaming + SSE

resp := surf.NewClient().Get("https://example.com/large-file").Do()
stream := resp.Ok().Body.Stream()
defer stream.Close()
scanner := bufio.NewScanner(stream)
for scanner.Scan() {
    fmt.Println(scanner.Text())
}

// SSE
resp.Ok().Body.SSE(func(event *sse.Event) bool {
    fmt.Printf("Event: %s, Data: %s\n", event.Event, event.Data)
    return true
})

Standard library compatibility

surfClient := surf.NewClient().Builder().Impersonate().Chrome().Session().Build().Unwrap()
stdClient := surfClient.Std()
resp, err := stdClient.Get("https://api.example.com")

Preserved when using Std(): JA3/TLS fingerprinting, HTTP/2/3 settings, browser headers, ordered headers, cookies/sessions, proxy, custom headers, timeout, redirect policies, request/response middleware.

Lost when using Std(): retry logic, response body caching, remote address tracking, request timing.

Other features

  • H2C (HTTP/2 Cleartext): .H2C()
  • Custom DNS: .DNS("8.8.8.8:53")
  • DNS-over-TLS: .DNSOverTLS().Cloudflare()
  • Unix sockets: .UnixSocket("/var/run/docker.sock")
  • Interface binding: .InterfaceAddr("192.168.1.100")
  • Raw HTTP requests: client.Raw(rawRequest, "https").Do()
  • Retry: .Retry(3, 2*time.Second)
  • Body caching: .CacheBody()

Architecture

  • Result type pattern: operations return g.Result[T]; explicit error handling without panic.
  • Middleware system: request, response, and client-level with priority-based ordering.
  • Fluent builder: method chaining for client construction.
  • Connection pooling: singleton pattern for connection reuse.
  • Compatibility layer: convertable to *net/http.Client retaining most features.
  • Fingerprinting foundation: built on uTLS (refraction-networking) for JA3/JA4, quic-go for QUIC.

HTTP/3 & QUIC

  • Complete QUIC fingerprinting matching Chrome/Firefox
  • Header ordering preserved for browser-like sequences
  • SOCKS5 UDP proxy support for HTTP/3
  • Automatic fallback to HTTP/2 with HTTP proxies
  • DNS integration with custom DNS and DoT
  • JA4QUIC support with Initial Packet + TLS ClientHello

Dependencies

  • enetx/http: enhanced HTTP functionality
  • quic-go: HTTP/3 & QUIC
  • uTLS (refraction-networking): TLS fingerprinting
  • enetx/g: generic utilities, Result type