Use case

Proxies for curl_cffi: the argument, and the exception you must catch

Set a proxy in curl_cffi 0.16.3: the proxy argument, proxy_auth, per-host entries, why a changed proxy gets a new connection, and which error to catch.

HProxy Team··Updated September 20, 2026·6 min read
HProxy.Use case

Free proxies won't hold up here.

Shared datacenter IPs get flagged and dropped fast. When it has to hold, gaming, streaming, accounts, you need mobile and residential IPs that read as a real device, from $0.44/GB, pay as you go.

See plans & pricing

People reach for curl_cffi because their target reads TLS fingerprints, and this library makes a Python request look like a browser handshake. Then they put a proxy underneath it, and meet a second set of rules. This page is that second set: where the proxy goes, what the library quietly does to keep two exit addresses apart, and which exception actually tells you a proxy refused you. We read release 0.16.3, published on 2 September 2026.

Where the proxy goes

import curl_cffi

r = curl_cffi.get(
    "https://example.com",
    impersonate="chrome",
    proxy="http://GATEWAY_HOST:GATEWAY_PORT",
    proxy_auth=("USER", "PASS"),
)
WhereWhat it does
proxy="..."one address for everything; preferred
proxies={...}a dictionary, for compatibility; cannot be combined with the single argument
proxies={"https://site.example": "..."}an entry for one host, which beats the general one
proxy_auth=("user", "pass")the login as its own options, not inside the address
http_proxy, https_proxyenvironment variables, read unless you turn that off

The separate login argument is worth the extra line. The library sets the username and password as their own options rather than parsing them out of a URL, so a password containing an equals sign, an at sign or a slash cannot be cut short on the way through. That failure is common enough in other tools to be worth avoiding by habit.

The https prefix mistake

The project's own documentation calls this "a very common mistake": writing https:// in front of a proxy address because the site is secure. It is not related. The prefix describes the connection to the proxy, and almost no gateway offers an encrypted one. Your address starts with http:// even when every page you fetch is secure.

The library warns at runtime if you do it, which is more than most clients offer. For a secure page through a plain proxy it also turns on tunnelling, so your own encryption runs end to end and the proxy only forwards bytes. A SOCKS address skips that step, because the protocol already carries the connection.

A changed proxy gets a new connection

This is the part worth knowing if you rotate addresses. Whenever a proxy is configured, the library turns on an option whose purpose is written in a comment next to it: a new connection is made when the proxy username changes, and the TLS session is tied to the proxy address, so that "when accessing the same site with different proxies, TLS session won't leak previous IP".

Read that twice if you rotate. TLS session resumption is a way for a site to link two visits, and by extension two exit addresses, to the same client. Reusing a session across a proxy change would undo the rotation you paid for. Here it is handled for you.

It was not always. In 2024 changing the proxy on a live session simply failed, with a TLS error out of the handshake. The fix and the privacy property are the same option.

Which exception means the proxy failed

The mapping has one special case: a receive error whose message mentions the tunnel becomes a proxy error. Everything else follows a table, and a refused connection is in it as a plain connection error.

That gap is not theoretical. In August 2026 the bundled curl changed which code it returns for a refused tunnel, from a receive error to a connect error. A library built on this one stopped rotating its sessions, because the failure no longer arrived as a proxy error. Their own words: the client "does not raise ProxyError when a proxy refuses the CONNECT tunnel, so the session is not rotated".

So catch both, or match on the message. If you rotate on failure, this is the difference between a working rotation and a scraper that hammers one dead address.

Which proxy type fits it?

Residential, and for the reason this page keeps circling: the fingerprint and the address are different problems. In our own paired test, using plain requests with no impersonation, a residential address changed 4 of 13 answers. Four sites refused both addresses. Those four are where a browser-like handshake earns its keep, and the rest is what a different address fixes. Neither replaces the other, which is exactly why this library plus a residential line is a sensible pairing.

Our lines take a plain HTTP port or a SOCKS5 port, and both work here. Keep the password in the separate argument rather than the address, or skip it entirely by allowing your machine's address on a Residential Premium plan, up to 150 per plan. The residential proxies page lists the plans and the plan API manages allowed addresses from code.

What breaks

  • Your retry never fires. The failure arrived as a connection error, not a proxy error.
  • HTTP/3 through a SOCKS5 proxy. Reported failing, and the newer proxy protocols for it are a request, not a feature.
  • A certificate error through an inspecting proxy. Pass your bundle to the verify argument: it is applied to the proxy connection as well as the site.
  • 407 Proxy Authentication Required. The login is missing or wrong. Our 407 guide covers it.
  • A cookie stops working after a rotation. A challenge cookie is tied to the address that earned it. The cookie and the exit address travel together.

What this page does not cover

We read the library as text and did not install or run it, so we did not reproduce the runtime warning, the exception behaviour or the HTTP/3 failure ourselves. The statement that a refused tunnel arrives as a connection error rests on the mapping in this release plus one dated report from a library that depends on it. Our paired address test used plain requests without impersonation, which is why it says what the address alone changes. Releases come every few weeks, and the bundled curl is what changed the error behaviour once already, so we will read this again by 20 October 2026.

Where to go from here

Proxies for yt-dlp covers the downloader whose networking code this library's error mapping is credited to. Proxies for Crawlee covers the scraper whose rotation broke when that mapping changed. Proxies for Scrapling covers a scraper that uses this library as its fast fetcher.

Sources

  • The proxy documentation and the prefix warning (docs/advanced.rst). The arguments and their exclusivity (curl_cffi/requests/session.py). What happens when a proxy is set, including the connection reuse option, the per host keys, the tunnel and the separate login (curl_cffi/requests/utils.py). The error mapping (curl_cffi/requests/exceptions.py). The fork it is built on (README.md). lexiforest/curl_cffi, release v0.16.3 of 2 September 2026, read 20 September 2026.
  • Issue 369 on changing a proxy mid-session, issue 842 on HTTP/3 over SOCKS5, issue 733 on newer proxy protocols, issue 674 on the environment variables, issue 724 on a proxy with a finance library. curl_cffi issue tracker, read 20 September 2026.
  • The report of a refused tunnel no longer arriving as a proxy error. apify/crawlee-python issue 2111, 3 August 2026.
  • Our paired address test of 19 September 2026: 16 URLs, plain requests, two runs from our server and two through a residential line of our house plan. Raw output is kept in the research folder of our OpenClaw page.
  • Plans, allowed addresses and sticky sessions. HProxy documentation, hproxy.com/docs, 20 September 2026.

Frequently asked questions

How do I set a proxy in curl_cffi?
Use the single proxy argument, for example curl_cffi.get(url, proxy='http://user:pass@host:port'). A dictionary of proxies also works for compatibility, but the project advises the single argument unless your http and https proxies differ. Passing both raises a type error.
Can I keep the password out of the URL?
Yes, and you should. Pass proxy_auth=('user', 'pass'). The library sets the username and password as their own options, so a password with awkward characters never has to survive a URL parser.
Why does https:// in front of my proxy break things?
Because that prefix means the connection to the proxy itself is encrypted, which almost no gateway offers. Your proxy address should start with http:// even for https sites. The library warns about this at runtime.
Which exception means my proxy refused me?
Not always ProxyError. A name that will not resolve raises ProxyError, and so does a receive error mentioning the tunnel, but a refused connection raises ConnectionError. Catch both if you rotate on failure.
Does HTTP/3 work through a SOCKS5 proxy?
No. That combination has been reported failing, and the newer proxy protocols built for it are a feature request rather than a feature. Keep the newest transport off behind a SOCKS line.

Proxies that don't die mid-job

Residential, ISP, datacenter and mobile, verified by the same engine that runs tens of millions of checks. They read as a real device and hold up under load. Pay as you go, and your balance never expires. $0.44/GB is the 2,000 GB+ rate; a single gigabyte is $0.50/GB, with no minimum order.

129M+ proxy checks run · 100+ countries · HTTP / HTTPS / SOCKS · re-checked every few minutes · no signup

HProxy.

Honest guides and comparisons on proxies, scraping and staying unblocked, from the team that runs the network.

RSS feed