To use a SOCKS5 proxy with a username and password, give your HTTP client a socks5h://USER:PASS@HOST:PORT URL. Most clients need one extra package for SOCKS. Below is a short, working snippet for curl, Python, Node and Go. Each one prints the IP that an echo service sees.
Replace HOST, PORT, USER and PASS with the values from your dashboard. Elusive shows them as HOST:PORT:USER:PASS.
Key takeaways
- Use
socks5h://so the proxy resolves domain names. Here is what the h changes. - Python needs an extra package:
requests[socks],httpx[socks]oraiohttp-socks. - Go supports SOCKS5 proxy URLs in
net/httpwith no extra package. - Node's built-in
fetchdoes not take asocks-proxy-agent. Usehttps.get, or undici's own SOCKS5 agent. - Keep credentials in env variables, and percent-encode special characters in the password.
Before you start
Env variables. Don't paste the login into source files. Set it in your shell:
export PROXY_HOST=HOST
export PROXY_PORT=PORT
export PROXY_USER=USER
export PROXY_PASS='PASS'
The Python and Node snippets below read these four variables. Single quotes keep the shell from touching characters like $ or ! in the password.
Special characters. Inside a proxy URL, characters like @, :, /, # and ? break parsing. They must be percent-encoded: p@ss:word becomes p%40ss%3Aword. The snippets do this for you with quote() in Python and encodeURIComponent() in Node. Go's url.UserPassword encodes it as well. In the curl example, encode it by hand.
The echo service. We use https://api.ipify.org. It returns your IP as plain text. The sample outputs use 203.0.113.45, a documentation address. Yours will show the proxy's exit IP.
curl
curl -x "socks5h://USER:PASS@HOST:PORT" https://api.ipify.org
Output:
203.0.113.45
-x is short for --proxy. The curl manual says the socks5h:// prefix makes the proxy resolve the hostname. The older flag --socks5-hostname HOST:PORT does the same, with -U USER:PASS for the login.
Python: requests
Install: pip install "requests[socks]"
import os
from urllib.parse import quote
import requests
user = quote(os.environ["PROXY_USER"], safe="")
pw = quote(os.environ["PROXY_PASS"], safe="")
proxy = f"socks5h://{user}:{pw}@{os.environ['PROXY_HOST']}:{os.environ['PROXY_PORT']}"
r = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=20)
print(r.text)
Output:
203.0.113.45
The Requests docs explain the schemes: socks5 resolves DNS on the client, socks5h on the proxy. The timeout matters, because Requests has no default timeout and can hang for a long time.
Python: httpx
Install: pip install "httpx[socks]"
import os
from urllib.parse import quote
import httpx
user = quote(os.environ["PROXY_USER"], safe="")
pw = quote(os.environ["PROXY_PASS"], safe="")
proxy = f"socks5h://{user}:{pw}@{os.environ['PROXY_HOST']}:{os.environ['PROXY_PORT']}"
with httpx.Client(proxy=proxy, timeout=20) as client:
print(client.get("https://api.ipify.org").text)
Output:
203.0.113.45
The argument is proxy= (singular). Older tutorials show proxies=, which newer httpx versions removed. If you see an error about an unexpected keyword, check which one your version expects. Without the extra package, httpx raises an error saying the socksio package is not installed.
Python: aiohttp
Install: pip install aiohttp aiohttp-socks
import asyncio
import os
from urllib.parse import quote
import aiohttp
from aiohttp_socks import ProxyConnector
user = quote(os.environ["PROXY_USER"], safe="")
pw = quote(os.environ["PROXY_PASS"], safe="")
proxy = f"socks5://{user}:{pw}@{os.environ['PROXY_HOST']}:{os.environ['PROXY_PORT']}"
async def main():
connector = ProxyConnector.from_url(proxy, rdns=True)
async with aiohttp.ClientSession(connector=connector) as session:
async with session.get("https://api.ipify.org") as resp:
print(await resp.text())
asyncio.run(main())
Output:
203.0.113.45
aiohttp has no SOCKS support of its own, so the aiohttp-socks connector adds it. It takes the socks5:// scheme, and rdns=True makes the proxy resolve the domain, the same as socks5h elsewhere.
Node: https.get with socks-proxy-agent
Install: npm install socks-proxy-agent
import https from "node:https";
import { SocksProxyAgent } from "socks-proxy-agent";
const user = encodeURIComponent(process.env.PROXY_USER);
const pass = encodeURIComponent(process.env.PROXY_PASS);
const { PROXY_HOST, PROXY_PORT } = process.env;
const agent = new SocksProxyAgent(`socks5h://${user}:${pass}@${PROXY_HOST}:${PROXY_PORT}`);
https.get("https://api.ipify.org", { agent }, (res) => {
let body = "";
res.on("data", (chunk) => (body += chunk));
res.on("end", () => console.log(body));
});
Output:
203.0.113.45
This is an ES module, so save it as .mjs. The agent plugs into https.get, https.request and libraries built on Node's http and https modules. It decodes percent-encoded credentials in the URL. In its source, the socks5 scheme resolves DNS locally and socks5h leaves it to the proxy.
Node: fetch
Node's built-in fetch runs on undici. It does not accept an agent option, so socks-proxy-agent does not work with it.
The right route is undici's own SOCKS5 dispatcher. It is marked experimental in undici's docs and needs undici 7.23 or newer. Install: npm install undici
import { fetch, Socks5ProxyAgent } from "undici";
const user = encodeURIComponent(process.env.PROXY_USER);
const pass = encodeURIComponent(process.env.PROXY_PASS);
const { PROXY_HOST, PROXY_PORT } = process.env;
const dispatcher = new Socks5ProxyAgent(`socks5://${user}:${pass}@${PROXY_HOST}:${PROXY_PORT}`);
const res = await fetch("https://api.ipify.org", { dispatcher });
console.log(await res.text());
Output:
203.0.113.45
Import fetch from the undici package, as shown, so the dispatcher and the fetch come from the same version. Per the docs, hostnames are sent to the proxy for resolution, and HTTPS is negotiated end to end. If you want to avoid an experimental feature, use the https.get version above.
Go: net/http with a proxy URL
Go's http.Transport supports SOCKS5 proxy URLs on its own. Its docs list socks5 and socks5h and say "socks5" is treated the same as "socks5h". If the URL has a username and password, Go uses them for the SOCKS login.
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
)
func main() {
u := &url.URL{
Scheme: "socks5h",
User: url.UserPassword(os.Getenv("PROXY_USER"), os.Getenv("PROXY_PASS")),
Host: os.Getenv("PROXY_HOST") + ":" + os.Getenv("PROXY_PORT"),
}
client := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(u)}}
resp, err := client.Get("https://api.ipify.org")
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Output:
203.0.113.45
Building the URL with url.UserPassword encodes special characters for you. You can also set HTTPS_PROXY to a socks5h:// URL and use http.ProxyFromEnvironment, which the default transport uses.
Go: golang.org/x/net/proxy
Use this when you need a plain dialer, for example for raw TCP, not just HTTP. Install: go get golang.org/x/net/proxy
package main
import (
"context"
"fmt"
"io"
"net"
"net/http"
"os"
"golang.org/x/net/proxy"
)
func main() {
auth := &proxy.Auth{User: os.Getenv("PROXY_USER"), Password: os.Getenv("PROXY_PASS")}
dialer, err := proxy.SOCKS5("tcp", os.Getenv("PROXY_HOST")+":"+os.Getenv("PROXY_PORT"), auth, proxy.Direct)
if err != nil {
panic(err)
}
transport := &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return dialer.(proxy.ContextDialer).DialContext(ctx, network, addr)
},
}
client := &http.Client{Transport: transport}
resp, err := client.Get("https://api.ipify.org")
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Output:
203.0.113.45
The dialer sends the target as a domain name when it is not an IP address (we checked this in the package's SOCKS client source), so the proxy does the lookup. The Auth struct carries the username and password.
Common errors
**Missing dependencies for SOCKS support or the 'socksio' package is not installed.** Install the extra: requests[socks] or httpx[socks].
**Authentication failed or general SOCKS server failure.** Check the login for typos, then check that special characters in the password are encoded.
Connection refused or timeout. Check HOST and PORT. A sticky proxy keeps its IP up to 24 hours and runs on a real device, so it can go offline earlier. Test a fresh one.
Node fetch ignores the agent. Built-in fetch has no agent option. Use undici's SOCKS5 dispatcher or https.get.
The IP is your own. The proxy is not applied. In Requests, set both the http and https keys. In Go, check that the transport is the one your client uses.
HTTP/3 or other UDP traffic. These snippets are TCP only. See HTTP/3 and QUIC over SOCKS5.
For more error messages and fixes, see proxy works but the site blocks me.
Next steps
Once the exit IP prints correctly, check the IP before you use it and run a DNS leak check. For Scrapy, there is a separate guide. To pick a proxy, open the catalog.
FAQ
How do I use a SOCKS5 proxy with Python requests?
Install requests[socks] and pass socks5h://USER:PASS@HOST:PORT for both the http and https keys of proxies.
Does Node fetch support SOCKS5 proxies?
Not on its own. Built-in fetch has no agent option. Use Socks5ProxyAgent from undici as the dispatcher (experimental, undici 7.23 or newer), or use https.get with socks-proxy-agent.
Does Go support SOCKS5 proxies?
Yes. http.Transport accepts socks5 and socks5h proxy URLs, and golang.org/x/net/proxy gives you a SOCKS5 dialer.
How do I put a special character in the proxy password?
Percent-encode it. @ becomes %40, : becomes %3A, / becomes %2F. Most languages have a helper, like quote() in Python.
Does SOCKS5 in these examples support UDP?
No. These use TCP. UDP needs a proxy with UDP ASSOCIATE; read does SOCKS5 support UDP.