tutorials
March 2, 2026
6 min

HTTPX vs Requests (2026): Speed, Async, HTTP/2, Proxies

Jason Wright
Jason Wright
Copywriting & Data Intelligence Specialist
HTTPX vs Requests (2026): Speed, Async, HTTP/2, Proxies
概要
The performance gap between httpx vs requests speaks for itself. HTTPX processes 50 synchronous GET requests in about 1.22 seconds.

Key takeaways:

  • Requests is the simplest synchronous HTTP client and the safe default for scripts and small tools. HTTPX matches its API and adds async, HTTP/2, and streaming.
  • The biggest practical difference is concurrency: an async HTTPX client handles many requests at once, while Requests sends them one at a time.
  • Watch one gotcha when you switch: HTTPX does not follow redirects by default, but Requests does.
  • For proxy work, both accept a proxy in one line. In HTTPX 0.28 the parameter is proxy=, not the old proxies=.

Requests and HTTPX cover the same job, fetching data over HTTP, with nearly the same API. The choice comes down to whether you need async and HTTP/2. This guide compares them on the differences that matter, with code tested on httpx 0.28.1 and requests 2.34.2, and shows how to route either one through a proxy.

What are HTTPX and Requests?

Requests is the long-standing Python HTTP library, known for a clean, readable API. It is synchronous, which means each call runs to completion before the next one starts. That simplicity is why it remains the default for most scripts.

HTTPX is a newer client with a Requests-compatible API. It adds an async interface, HTTP/2 support, strict timeouts, and built-in streaming helpers, while still offering a familiar synchronous mode. If you have used Requests, HTTPX will feel immediately familiar.

HTTPX vs Requests: the key differences

FeatureRequestsHTTPX
Sync APIYesYes
Async APINoYes (AsyncClient)
HTTP/2NoYes (with httpx[http2])
Follows redirects by defaultYesNo
Streaming downloadsBasicBuilt in, with num_bytes_downloaded
TimeoutsOptionalEnabled by default
Proxy parameterproxies= (dict)proxy= (single) or mounts=
MaturityVery large communityModern, actively developed

The headline difference is async. Everything else is close enough that most Requests code ports to HTTPX with small edits, as long as you account for redirects and timeouts.

Requests is sync-only; HTTPX adds async, HTTP/2, and streaming.

Installing and making your first request

Install either library with pip. For HTTP/2 or SOCKS support in HTTPX, add the extra in quotes so the shell does not expand the brackets:

pip install requests httpx

pip install "httpx[http2]"

pip install "httpx[socks]"

 

A basic GET looks almost identical in both. Requests:

import requests

 

r = requests.get("https://httpbin.org/get", timeout=15)

print(r.status_code, r.json())

 

HTTPX:

import httpx

 

r = httpx.get("https://httpbin.org/get", timeout=15)

print(r.status_code, r.json())

 

One difference to remember: Requests follows redirects automatically, while HTTPX does not. Turn it on per request or per client:

import httpx

 

r = httpx.get("https://httpbin.org/redirect/1", follow_redirects=True)

print(r.status_code)

 

Async and HTTP/2 with HTTPX

Async is the reason most teams reach for HTTPX. With AsyncClient you can issue many requests concurrently instead of waiting for each one. The same client can negotiate HTTP/2 when you enable it:

import asyncio

import httpx

 

async def main():

    async with httpx.AsyncClient(http2=True, timeout=15) as client:

        r = await client.get("https://httpbin.org/get")

        print(r.status_code, r.http_version)

 

asyncio.run(main())

 

In testing, that request negotiates HTTP/2 and returns HTTP/2 as the version. Requests has no async mode and no HTTP/2, so for concurrent or HTTP/2 work HTTPX is the only one of the two that fits.

Streaming and num_bytes_downloaded

For large responses, stream the body instead of loading it into memory. HTTPX exposes a running num_bytes_downloaded counter on the response, which is useful for progress reporting:

import httpx

 

with httpx.Client(timeout=15) as client:

    with client.stream("GET", "https://httpbin.org/bytes/100000") as r:

        for chunk in r.iter_bytes():

            pass  # write to disk, update a progress bar, etc.

        print("downloaded:", r.num_bytes_downloaded)

 

Requests streams with stream=True and iter_content, but it has no equivalent built-in byte counter, so you track progress yourself.

How to use proxies with Requests and HTTPX

Both libraries route through a proxy in one line. Use your Proxy-Cheap host, port, and credentials. With rotating residential, the gateways are proxy-us.proxy-cheap.com:5959 and proxy-eu.proxy-cheap.com:5959.

Requests takes a proxies dictionary:

import requests

 

proxies = {

    "http": "http://<proxycheap-username>:<proxycheap-password>@proxy-us.proxy-cheap.com:5959",

    "https": "http://<proxycheap-username>:<proxycheap-password>@proxy-us.proxy-cheap.com:5959",

}

r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=30)

print(r.json())

 

HTTPX 0.28 uses a single proxy argument. The older proxies= dictionary was removed, so update any code that still uses it:

import httpx

 

client = httpx.Client(

    proxy="http://<proxycheap-username>:<proxycheap-password>@proxy-us.proxy-cheap.com:5959",

    timeout=30,

)

r = client.get("https://httpbin.org/ip")

print(r.json())

client.close()

 

For a SOCKS5 proxy, install the extra (pip install "httpx[socks]" or requests[socks]) and use a socks5:// URL. Choosing between protocols is covered in our guide to SOCKS5 and HTTP proxies. For rotation patterns across many IPs, see our walkthrough on IP rotation in Python.

Performance: is HTTPX faster than Requests?

For a single synchronous request, the two are close, and network distance and the target server matter far more than the library. The real gap appears under concurrency. Sending a batch of requests one at a time with Requests is bound by the sum of each round trip. An async HTTPX client sends them together, so a hundred requests finish in roughly the time of the slowest one rather than the total.

Sequential requests add up; async requests overlap and finish together.

So the honest answer is: not meaningfully faster for one call, but dramatically faster for many concurrent calls. If your workload is high-volume web scraping or many parallel API calls, async HTTPX wins. For a handful of sequential calls, you will not notice a difference.

Thread safety is also worth noting: both requests.Session and httpx.Client are safe to share across threads for sending requests. For high concurrency in a single thread, use async AsyncClient rather than spinning up many threads.

Which should you use?

Pick by workload, then let the proxy network do the heavy lifting.

Pick by workload:

  • Choose Requests for simple synchronous scripts, quick tasks, and code where the largest community and the most examples matter.
  • Choose HTTPX when you need async, HTTP/2, strict timeouts, or built-in streaming, while keeping a Requests-like API.
  • Consider aiohttp only if you want a purely async client and do not need a sync mode or HTTP/2, since HTTPX usually covers both needs in one library.

For most data-collection projects the deciding factor is the proxy network, not the client. Pair either library with rotating residential proxiesresidential proxiesdatacenter proxies, or ISP proxies from Proxy-Cheap, and see our data scraping use cases for setup ideas or our roundup of the best proxy providers to compare options.

常见问题解答

For a single synchronous request, they are about the same. HTTPX is much faster when you send many requests concurrently with its async client, because the requests overlap instead of running one after another. For one-off calls, choose based on features, not speed.

Almost. The API is intentionally similar, so most code ports with small changes. The two differences to fix are that HTTPX does not follow redirects by default and enables timeouts by default.

It is a deliberate design choice to make behavior explicit, since silent redirects can hide what a request actually does. Pass follow_redirects=True on the request or the client to match the Requests default.

Use the proxy argument on the client, for example httpx.Client(proxy="http://user:pass@host:port"). The older proxies dictionary was removed in version 0.28, so update any code that still passes it.

Yes, when you install the extra with pip install "httpx[http2]" and create a client with http2=True. Requests does not support HTTP/2 at all.

No. Requests is synchronous only. For async you need HTTPX, aiohttp, or another async client. HTTPX is the closest async option to the Requests API.

Niquests is a community fork of Requests that adds HTTP/2, HTTP/3, and async while keeping the Requests API. It is a reasonable option if you want to stay close to Requests, though HTTPX has a larger ecosystem.

Both work, and the proxy network matters more than the client. Use async HTTPX for high-volume concurrent crawls, and Requests for simple sequential scripts. Route either through rotating residential or datacenter proxies sized to your request volume.