What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Short answer: use Requests for straightforward synchronous code, HTTPX when you want both synchronous and asynchronous interfaces or an HTTP/2 option, and aiohttp when its async-first session and response lifecycle suits your application. None is a proven universal speed winner. Whichever you choose, reuse its client or session for repeated requests and set timeouts explicitly.

How the three clients differ

The main distinction is not simply which package has the most features. It is how each fits into the way your program makes requests, handles concurrency, and manages connections and response bodies.

Question HTTPX Requests aiohttp
Programming model Documented synchronous and asynchronous APIs. Synchronous client in this comparison. Async-first client; requests and body reads use awaited operations.
HTTP/2 Supported, but opt-in; the server must support it as well. Not established by the sources considered here. The cited client reference documents HTTP/1.1; that is not evidence about every later release.
Persistent connections Reuse a Client or AsyncClient. Reuse a Session. Reuse a ClientSession.
Documented timeout behavior Five seconds of network inactivity by default, with connect, read, write, and pool controls. No timeout by default. The aiohttp 3.13.5 quickstart documents a 300-second total timeout and a 30-second socket-connect default.
Redirect default Does not follow redirects by default. Not comprehensively established by the pages considered here. The documented request interface allows redirects by default.

These are documented behavior differences, not benchmark scores. Defaults can vary across releases; check the documentation for the version installed in your project before depending on them. In particular, the cited aiohttp lifecycle page is labeled 4.0.0a2 development documentation, while its timeout quickstart covers 3.13.5.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose by application shape

Choose Requests for simple synchronous work

Requests is a natural fit when the calling code is synchronous and the familiar Requests API fits your application. It keeps the request model direct: make a request, inspect the response, and handle the result. For repeated calls, use a Session rather than treating each call as an entirely separate interaction.

The important operational trap is that Requests has no timeout by default. A request can wait indefinitely unless your code supplies one. Set a timeout deliberately for network operations that must not stall a worker, command, or request handler forever.

Choose HTTPX for sync/async flexibility or an HTTP/2 option

HTTPX offers both synchronous and asynchronous APIs. That can be useful when one project has ordinary synchronous code alongside async services, or when you want an HTTP/2-capable client without making every use case async. Its AsyncClient works with await and async context management, and HTTPX documents support for asyncio and Trio.

HTTP/2 support is optional and disabled by default. Enabling it does not force a server to speak HTTP/2. The remote server must support it, and you can check the negotiated protocol using response.http_version. HTTP/2 multiplexing can carry multiple concurrent streams over one TCP connection, but that capability alone does not establish that a particular workload will be faster.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

HTTPX applies a default timeout after five seconds of network inactivity. Its timeout controls distinguish connect, read, write, and pool waiting, so you can tune different phases rather than treating every delay as the same problem.

Choose aiohttp for an async-first request lifecycle

aiohttp is designed around asynchronous client work. Its recommended ClientSession holds a connection pool and shared state, including cookies, headers, and timeout configuration. A request obtains the response headers; reading the payload is a separate awaited operation. Context managers make it easier to close responses and the session reliably.

This separation is useful when the surrounding application already uses async tasks and needs to manage response bodies without blocking the event loop. It also means a reader must handle both the request operation and body consumption explicitly. Avoid creating a new session for each request in a repeated workload.

Runnable examples

These examples fetch a JSON response and print its status and body. Install only the library used by the example: python -m pip install requests, python -m pip install httpx, or python -m pip install aiohttp. They demonstrate explicit timeouts and reusable clients; adjust the endpoint and timeout values to suit your service and workload.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Requests: synchronous with a Session

import requests

url = "https://httpbin.org/get"

with requests.Session() as session:
    response = session.get(url, timeout=(5, 20))
    response.raise_for_status()
    print(response.status_code)
    print(response.json())

The tuple supplies connect and read timeout values in seconds. A timeout is not a promise that the complete operation will finish within their sum: read timeout concerns waiting for data, and a server that sends data intermittently can affect total elapsed time. Add application-level deadlines if the overall operation must have a firm limit.

HTTPX: synchronous Client

import httpx

url = "https://httpbin.org/get"

timeout = httpx.Timeout(20.0, connect=5.0)
with httpx.Client(timeout=timeout) as client:
    response = client.get(url)
    response.raise_for_status()
    print(response.status_code, response.http_version)
    print(response.json())

The configured timeout uses HTTPX’s timeout categories; the explicit connect value overrides the general value for connection establishment. To try HTTP/2, install the HTTP/2 extra as appropriate for your HTTPX release and construct the client with http2=True. Check response.http_version rather than assuming negotiation succeeded.

HTTPX: asynchronous AsyncClient

import asyncio
import httpx

async def main():
    timeout = httpx.Timeout(20.0, connect=5.0)
    async with httpx.AsyncClient(timeout=timeout) as client:
        response = await client.get("https://httpbin.org/get")
        response.raise_for_status()
        print(response.status_code, response.http_version)
        print(response.json())

asyncio.run(main())

In an async application, call main() from the application’s existing event loop rather than starting a second loop with asyncio.run(). Reuse the AsyncClient across related calls; repeatedly constructing clients in a hot loop discards the pooling benefits.

aiohttp: asynchronous ClientSession

import asyncio
import aiohttp

async def main():
    timeout = aiohttp.ClientTimeout(total=20, sock_connect=5)
    async with aiohttp.ClientSession(timeout=timeout) as session:
        async with session.get("https://httpbin.org/get") as response:
            response.raise_for_status()
            data = await response.json()
            print(response.status, data)

asyncio.run(main())

Here the session and response are both context-managed, and JSON body consumption is awaited. In an existing async service, manage the session at the application lifecycle level and share it for repeated requests rather than creating one per operation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Timeouts, redirects, pooling, and response bodies

Set timeouts for the behavior you need

Do not copy timeout numbers between libraries as if they described identical limits. HTTPX’s five-second default is based on network inactivity, while Requests has no default timeout. The aiohttp 3.13.5 quickstart gives a 300-second total default and a 30-second socket-connect default. A total timeout and an inactivity timeout measure different things.

Decide how long connection establishment may take, how long the application can wait for response data, and whether the complete operation needs an overall deadline. Then express those limits using the selected library’s semantics. Test against the version you actually deploy.

Make redirect behavior explicit

HTTPX does not follow redirects by default; enable redirect following where that is what the application expects. aiohttp’s documented request interface allows redirects by default. If migrating code or switching libraries, test both redirect responses and the final destination rather than assuming the defaults match. Do not infer a Requests redirect comparison from the sources cited here.

Reuse a client or session for repeated requests

A persistent client or session can reuse connections through a pool. Use HTTPX Client or AsyncClient, Requests Session, or aiohttp ClientSession according to the chosen API. Scope it to a sensible application or task lifecycle and close it cleanly. Creating clients repeatedly in a hot path can defeat pooling and adds avoidable connection-management overhead.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Account for async body handling

With aiohttp, receiving headers is not the same as consuming the response body. Await the body method you need, such as JSON or text, while the response is in its context manager. For large payloads or streaming, choose a streaming approach instead of loading the whole body into memory. HTTPX also documents streaming support; select the appropriate streaming API and close its response/client resources when finished.

Migrating between the clients

HTTPX describes its synchronous Client as generally equivalent in role to requests.Session(), but the APIs are not interchangeable in every detail. Before replacing Requests with HTTPX or moving code to aiohttp, check the following:

  • Timeouts: add explicit values where the old client had no default, and translate them by meaning rather than copying a number.
  • Redirects: verify whether redirects should be followed; HTTPX’s default differs from aiohttp’s documented request default.
  • Connection and shared state: preserve session-level cookies, headers, and pooling behavior using the new client’s persistent interface.
  • Proxy and transport setup: HTTPX uses mounts for routing transports; the cited compatibility guide describes Requests’ proxies convention. Recheck configuration against the installed release.
  • Async boundaries: converting a synchronous request to aiohttp or HTTPX async means awaiting the request and, where applicable, the response body. Do not block an async event loop with synchronous calls.
  • Failure handling: test status errors, connection failures, TLS configuration, cancellation, and cleanup using the exception and resource patterns of the destination library.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Performance and reliability: what can and cannot be concluded

The official documentation considered here establishes features and lifecycle behavior, not a controlled head-to-head performance result. It does not establish that aiohttp is always faster than Requests, that HTTPX is faster than either, or a universal latency or throughput ranking. Your outcome depends on workload shape, server behavior, payload size, concurrency, connection reuse, runtime, and configuration.

If speed will decide the choice, benchmark equivalent application code under representative conditions. Reuse sessions in each candidate, apply comparable timeout and redirect policies, measure both latency and throughput, and include response-body consumption rather than timing only request initiation. Record the Python and package versions and test at the concurrency and payload sizes you expect in production. Treat that result as evidence about your workload, not a general ranking.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Reliability starts with explicit timeouts, correct client/session lifetimes, and predictable cleanup. Add retries only when the operation and failure conditions make retrying safe; a timeout does not prove that the server did not process a request. For operations with side effects, use application-level idempotency protections where available.

Troubleshooting common problems

A request appears to hang

Requests has no default timeout. Add one. For HTTPX and aiohttp, inspect which timeout phase is being reached and set deliberate connect/read or total limits appropriate to the job. Also check whether the application is awaiting an async operation correctly.

HTTPX reports a redirect response instead of the destination

HTTPX does not follow redirects by default. Enable redirect following for that request or client if appropriate, then test the resulting URL and response status.

HTTP/2 was requested but not used

HTTP/2 is disabled by default in HTTPX and requires both client configuration and server support. Enable it intentionally and inspect response.http_version; configuration alone does not guarantee negotiation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Many requests create too many connections or run inefficiently

Check whether each operation constructs a fresh Session, Client, AsyncClient, or ClientSession. Reuse a persistent client within the correct lifecycle so pooling can work, and close it when that lifecycle ends.

aiohttp response data is missing or unavailable

Obtaining headers does not consume the payload. Await the response’s JSON, text, or streaming operation inside the response context manager, and keep the session alive until body handling completes.

A migration behaves differently despite similar request code

Compare timeout semantics, redirect policy, proxies or transport routing, and response-body handling. Test those behaviors explicitly against the exact library releases deployed rather than relying on API resemblance.

Or skip the browser setup

HTTPX, Requests, and aiohttp are HTTP clients for Python applications; they do not themselves provide a browser-rendered website screenshot workflow. If your task is to capture a web page as an image or PDF, ScreenshotNeo is a separate website screenshot API and MCP server. Its one-call API can return a screenshot or PDF:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, no card required.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.