Integration · HTTP clients
How to use a proxy with C# HttpClient
In .NET, a proxy is a WebProxy with a NetworkCredential, set on the handler behind your HttpClient: new SocketsHttpHandler { Proxy = new WebProxy("http://host:port") { Credentials = new NetworkCredential(user, pass) } }. The handler owns the connection pool, so the username, and with it the session and country, belongs to the handler.
Reviewed 30 Oct 2026
http://USERNAME _pool-arcfast _country-de:PASSWORD@ proxy.arcproxies.io:8000The short answer
- Set
ProxyonSocketsHttpHandler(orHttpClientHandler); credentials go on theWebProxy. - Microsoft's guidance: reuse clients, and use more than one instance when you need several proxies. One client per session or market.
- A refused tunnel throws
HttpRequestExceptionwithStatusCode407 andHttpRequestError.ProxyTunnelError. socks5://in theWebProxyaddress works on .NET 6 and later.
Setup
Set up C# HttpClient with a proxy, step by step
- 01
Create a client and check the exit IP
PooledConnectionLifetimestops a long-lived client from holding one connection, and one exit, for ever.ConnectTimeoutbounds connection setup;HttpClient.Timeoutbounds the whole request.Program.cs18 linesusing System.Net;static HttpClient ArcClient(string username) => new(new SocketsHttpHandler{ Proxy = new WebProxy("http://proxy.arcproxies.io:8000") { Credentials = new NetworkCredential(username, "PASSWORD"), }, UseProxy = true, ConnectTimeout = TimeSpan.FromSeconds(10), PooledConnectionLifetime = TimeSpan.FromMinutes(2),}){ Timeout = TimeSpan.FromSeconds(30),};var client = ArcClient("USERNAME_pool-arcfast_country-de");Console.WriteLine(await client.GetStringAsync("https://api.ipify.org?format=json")); - 02
Keep a client per sticky session
Mint a handle, build one client with the sticky username, and use it for every request in the task. A small dictionary keeps clients for handles you reuse.
Program.cs, continued14 linesusing System.Collections.Concurrent;using System.Security.Cryptography;var sessions = new ConcurrentDictionary<string, HttpClient>();HttpClient Session(string handle) => sessions.GetOrAdd(handle, h => ArcClient($"USERNAME_pool-arcfast_country-de_session-{h}_sesstime-10"));var handle = Convert.ToHexString(RandomNumberGenerator.GetBytes(4)).ToLowerInvariant();for (var page = 1; page <= 3; page++){ using var res = await Session(handle).GetAsync($"https://example.com/search?q=lamp&page={page}"); Console.WriteLine($"{page} {(int)res.StatusCode}");} - 03
Target a country or city
One client per market; the city is a token from the published list, lowercased without spaces. The examples use the residential pool,
_pool-arcfast.Program.cs, continued12 linesvar markets = new Dictionary<string, HttpClient>{ ["de-berlin"] = ArcClient("USERNAME_pool-arcfast_country-de_city-berlin"), ["gb-birmingham"] = ArcClient("USERNAME_pool-arcfast_country-gb_city-birmingham"), ["nl-rotterdam"] = ArcClient("USERNAME_pool-arcfast_country-nl_city-rotterdam"),};foreach (var (market, c) in markets){ using var res = await c.GetAsync("https://example.com/price/123"); Console.WriteLine($"{market} {(int)res.StatusCode}");} - 04
Separate 407s, timeouts and retryable responses
On .NET 8 and later,
HttpRequestError.ProxyTunnelErrorwith status 407 means the tunnel was refused. A timeout surfaces asTaskCanceledExceptionwith an innerTimeoutException. Retry those, and 429 or 5xx, on a fresh session; handling 429 rate limits covers the backoff.Program.cs, continued28 linesasync Task<HttpResponseMessage> FetchAsync(string url){ for (var attempt = 0; attempt < 4; attempt++) { var handle = Convert.ToHexString(RandomNumberGenerator.GetBytes(4)).ToLowerInvariant(); try { var res = await Session(handle).GetAsync(url); if (res.StatusCode == HttpStatusCode.ProxyAuthenticationRequired) throw new InvalidOperationException("proxy rejected the credentials"); if (res.StatusCode != HttpStatusCode.TooManyRequests && (int)res.StatusCode < 500) return res; res.Dispose(); } catch (HttpRequestException e) when (e.StatusCode == HttpStatusCode.ProxyAuthenticationRequired) { throw new InvalidOperationException("proxy rejected the credentials", e); } catch (TaskCanceledException e) when (e.InnerException is TimeoutException) { } catch (HttpRequestException) { } // connection reset and similar finally { if (sessions.TryRemove(handle, out var used)) used.Dispose(); // one-off session } await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt))); } throw new InvalidOperationException($"gave up on {url}");} - 05
Use SOCKS5 instead
Since .NET 6,
SocketsHttpHandleracceptssocks5://proxy addresses. The gateway takes the same credentials on the same port.Program.cs, continued8 linesvar socks = new HttpClient(new SocketsHttpHandler{ Proxy = new WebProxy("socks5://proxy.arcproxies.io:8000") { Credentials = new NetworkCredential("USERNAME_pool-arcfast_country-de", "PASSWORD"), },});Console.WriteLine(await socks.GetStringAsync("https://api.ipify.org"));
SocketsHttpHandler, HttpClientHandler and the default proxy
| Option | How the proxy is set | Note |
|---|---|---|
SocketsHttpHandler | Proxy = new WebProxy(...) | The implementation since .NET Core 2.1; exposes PooledConnectionLifetime and ConnectTimeout |
HttpClientHandler | Proxy = new WebProxy(...) | Same proxy behaviour, fewer pool settings |
HttpClient.DefaultProxy | Environment variables or system settings | Used when the handler sets no proxy; HTTPS_PROXY must be an http:// URL |
Construct WebProxy with a full URI string. Microsoft notes that the host-only constructor overload cannot be used for SOCKS.
Why one handler means one exit
HttpClient reuses pooled connections, and an HTTPS connection through the gateway is one CONNECT tunnel with one exit. In our test, two requests on one client produced a single CONNECT. With a rotating username, an exit change therefore needs a new connection: after PooledConnectionLifetime, or from a different handler.
That is why the examples key clients by session handle. Microsoft's own guidelines say several instances are needed "for scenarios with multiple proxies"; what matters is not creating and disposing one per request. The rotating vs sticky sessions guide helps decide how long a session should live.
The problem
Common pitfalls
A new HttpClient per request
Every disposed handler leaves sockets in TIME_WAIT and every new one opens a new tunnel. Reuse clients per session or market.
Assuming the first CONNECT carries credentials
.NET sends the first CONNECT without credentials and answers the 407 challenge. That extra round trip is normal; a second 407 is the real failure.
IHttpClientFactory with sticky sessions
The factory recycles handlers on its own schedule. Fine for rotation, but a named client's handler, and its proxy username, is fixed when it is configured, so build session clients yourself.
Matching on exception text
Use HttpRequestException.StatusCode and HttpRequestError rather than parsing the message, which varies by version and language.
FAQ
Questions
Something not covered? Write to contact@arcproxies.io.
How do I use a proxy with authentication in C# HttpClient?
Create the client with a handler: new HttpClient(new SocketsHttpHandler { Proxy = new WebProxy("http://host:port") { Credentials = new NetworkCredential(user, pass) } }). The handler sends Basic proxy credentials in answer to the proxy's 407 challenge.
How do I use a different proxy per request in .NET?
A handler's proxy is fixed once it has sent a request, so use one HttpClient per proxy username and pick the client per request. Keep them in a dictionary keyed by session or market.
Does HttpClient support SOCKS5 proxies?
Yes, from .NET 6: use a socks5://host:port address in the WebProxy and set Credentials for username and password authentication.
How do I detect a 407 from the proxy in C#?
For HTTPS targets, catch HttpRequestException and check StatusCode == HttpStatusCode.ProxyAuthenticationRequired; on .NET 8+ HttpRequestError is ProxyTunnelError. For plain-HTTP targets the response itself has status 407.
Sources & review
Last reviewed by the ARC Proxies team. Prices are read from the live catalog at build time.
- [1]Microsoft Learn: Make HTTP requests with the HttpClient: Configure an HTTP proxy
- [2]Microsoft Learn: HttpClient guidelines for .NET
- [3]Microsoft .NET Blog: .NET 6 Networking Improvements (SOCKS proxy support)
- [4]Microsoft Learn: SocketsHttpHandler.Proxy Property
Next
What people build with it
Integrations
Other http clients
Get started
Get credentials and paste them in.
Sign up, buy a gigabyte, generate a username in the dashboard. Code WELCOME15 takes 15% off your first purchase; bandwidth never expires.