Skip to content
Go net/http

How to use proxies in Go

In Go, set a proxy on an http.Transport: parse http://USERNAME:PASSWORD@HOST:PORT with url.Parse and pass it as Proxy: http.ProxyURL(proxyURL). Go sends the credentials as Proxy-Authorization automatically, including for HTTPS sites.

What you need

Go is a natural fit for high-concurrency scraping and monitoring, and CleanProxies ISP proxies come with unlimited bandwidth and threads, so the limit is your code, not the plan. This guide covers HTTP(S) and SOCKS5 with only the standard library.
  • An active CleanProxies plan: static ISP proxies for fixed US IPs, or rotating residential / mobile proxies for pools. The trial works too.
  • Your credential line from the dashboard's proxy manager: host (or IP), port, username and password.
  • Go 1.21 or later (any recent release works).
  • Only the standard library; golang.org/x/net/proxy is optional, for non-HTTP traffic over SOCKS5.

New to proxies? For the overview, read Using proxies with cURL, Python and Node.js and SOCKS5 vs HTTP proxies. This guide goes deeper on Go only.

Your CleanProxies credentials

Every CleanProxies product works over HTTP(S) and SOCKS5. This is what the dashboard gives you.
ProductLine in your dashboardNotes
Static ISP proxiesIP:PORT:USER:PASSOne line per dedicated IP. With IP whitelisting turned on, the line is just IP:PORT and no password is sent.
Rotating residential and mobileHOST:PORT:USER:PASSGenerated in the proxy manager. The username carries the location and session you pick, so generate a new list to change them.

Most tools want the same details as a URL: http://USERNAME:PASSWORD@HOST:PORT for HTTP(S) or socks5://USERNAME:PASSWORD@HOST:PORT for SOCKS5. The examples on this page use those placeholders; copy the host, port, username and password from your CleanProxies dashboard. To convert a whole list at once, paste it into the proxy list formatter.

How to set up CleanProxies in Go

  1. 1

    Build the proxy URL

    Turn your dashboard line into http://USERNAME:PASSWORD@HOST:PORT. Use url.UserPassword if the password has special characters, so it is escaped for you.
  2. 2

    Create one Transport per proxy

    Set Proxy: http.ProxyURL(u) on an http.Transport and wrap it in an http.Client with a timeout.
  3. 3

    Reuse the client

    A client and its transport are safe for concurrent use and pool connections, so create them once per proxy, not per request.
  4. 4

    Check the exit IP

    Request https://api.ipify.org and compare the result with the IP in your dashboard.

HTTP(S) proxy with net/http

main.goGo
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"time"
)

func main() {
	proxyURL := &url.URL{
		Scheme: "http",
		User:   url.UserPassword("USERNAME", "PASSWORD"),
		Host:   "HOST:PORT",
	}

	client := &http.Client{
		Timeout:   30 * time.Second,
		Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)},
	}

	resp, err := client.Get("https://api.ipify.org")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	ip, _ := io.ReadAll(resp.Body)
	fmt.Println("exit IP:", string(ip))
}

http.DefaultTransport already uses http.ProxyFromEnvironment, so a plain http.Get honours HTTPS_PROXY, HTTP_PROXY and NO_PROXY. Setting the proxy in code is clearer once you run more than one.

SOCKS5 proxy in Go

http.Transport understands socks5:// proxy URLs natively: the user info becomes the SOCKS5 username and password, and the hostname is sent to the proxy, so DNS is resolved on the proxy side.

SOCKS5 with net/http onlyGo
proxyURL := &url.URL{
	Scheme: "socks5",
	User:   url.UserPassword("USERNAME", "PASSWORD"),
	Host:   "HOST:PORT",
}

client := &http.Client{
	Timeout:   30 * time.Second,
	Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)},
}

For raw TCP connections that aren't HTTP, use proxy.SOCKS5("tcp", "HOST:PORT", &proxy.Auth{User: "USERNAME", Password: "PASSWORD"}, proxy.Direct) from golang.org/x/net/proxy and dial through it.

Spread goroutines across a list of ISP proxies

Give each proxy its own client and hand work out round-robin. Each ISP line is a 100% dedicated IP, so this pattern keeps the load per IP predictable.

Round-robin over proxies.txtGo
func loadClients(path string) ([]*http.Client, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, err
	}
	var clients []*http.Client
	for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") {
		parts := strings.SplitN(strings.TrimSpace(line), ":", 4) // IP:PORT:USER:PASS
		if len(parts) != 4 {
			continue
		}
		u := &url.URL{Scheme: "http", User: url.UserPassword(parts[2], parts[3]), Host: parts[0] + ":" + parts[1]}
		clients = append(clients, &http.Client{
			Timeout:   30 * time.Second,
			Transport: &http.Transport{Proxy: http.ProxyURL(u), MaxIdleConnsPerHost: 10},
		})
	}
	return clients, nil
}

// in your worker loop: client := clients[i%len(clients)]

A kept-alive connection stays on the exit IP it opened with. With rotating residential proxies, set DisableKeepAlives: true on the transport when you want every request to get a fresh IP.

Static ISP vs rotating residential in Go

Both products use the same setup. What changes is how long an IP stays with you.

Static ISP proxies

Each transport pins one dedicated US ISP IP for as long as you hold it, which suits logged-in sessions, API polling and monitoring that should come from one address.

Static ISP ProxiesAs low as $0.75/IP

Rotating residential proxies

Point one client at the rotating gateway line and new connections pick up new IPs. Generate a sticky list in the dashboard when a multi-step flow must stay on one IP, and keep keep-alives on for it.

Rotating Residential ProxiesAs low as $0.63/GB

Verify your exit IP

Run the HTTP example above: it prints the exit IP. Run it twice against a rotating residential line with keep-alives disabled and you should see two different addresses.

Open What is my IP? through the proxy to see the address and headers a website receives, or paste up to ten lines into the free proxy checker to test connectivity, latency and exit IP before you start.

Troubleshooting Go proxy errors

ProblemLikely causeFix
Proxy Authentication Required (407)Credentials missing from the URL, or a password with @/: that broke parsing.Build the URL with url.UserPassword instead of string concatenation.
proxyconnect tcp: dial tcp: i/o timeoutWrong host or port, or outbound traffic blocked.Test the same line with curl -x; check the port and your firewall.
x509: certificate signed by unknown authorityA corporate TLS inspector, or a proxy URL with the https scheme.Use the http scheme for the proxy. Never set InsecureSkipVerify to work around it.
Same IP on every request with a rotating listConnection reuse through keep-alive.Set DisableKeepAlives: true or close idle connections between requests.
DNS lookups leave from your serverA custom DialContext that resolves hostnames before the proxy sees them.Use the socks5:// proxy URL on the transport, which sends hostnames to the proxy.

Still stuck? Our 24/7 support team answers fast: contact us with the error and the line you used (leave the password out).

Go proxy FAQs

Yes. When the proxy URL has user info, the transport sends a Proxy-Authorization header on the CONNECT request it uses for HTTPS targets, and on plain HTTP requests.

Get CleanProxies for Go

Super clean US ISP IPs from $0.75/IP with unlimited bandwidth, rotating residential from $0.63/GB and mobile from $0.79/GB. Instant delivery, 99.9% uptime and 24/7 support.