The SOCKS5 protocol lets a client ask the proxy to connect either to an IP address or to a hostname. Which one it sends is the client's decision, and the URL scheme is how you tell many clients:

  • socks5:// resolves the hostname on your machine and sends the proxy an IP address.
  • socks5h:// sends the hostname and lets the proxy resolve it. The h stands for hostname.

The protocol is the same in both cases; only the lookup moves.

Why it matters

Resolving locally has three costs:

  1. A DNS leak. Your own resolver sees every hostname you visit.
  2. The wrong server. CDNs answer DNS with an edge node near the resolver asking. Resolve in London, exit in Tokyo, and you reach a London node through a Japanese IP, which can change the content and looks odd to the site.
  3. Names the proxy knows but you do not fail to resolve locally.

For scraping through a proxy, socks5h is almost always what you want.

Using it

curl and Python requests (with requests[socks] installed) both accept the scheme:

curl -x socks5h://USERNAME:PASSWORD@HOST:PORT "https://api.ipify.org?format=json"
proxy = "socks5h://USERNAME:PASSWORD@HOST:PORT"
requests.get(url, proxies={"http": proxy, "https": proxy})

curl also has the flag form --socks5-hostname HOST:PORT. Other tools use a setting instead of a scheme: Firefox calls it "Proxy DNS when using SOCKS v5", as the Firefox guide shows. Check your library's documentation, because some treat socks5:// as remote resolution already and some do not accept socks5h at all.

Common confusion

socks5h is not a separate protocol or a separate port. It is the same SOCKS5 proxy, asked to do the DNS lookup.