urllib3
urllib3 is a powerful, user-friendly HTTP client library for Python providing thread-safe connection pooling, client-side TLS/SSL verification, multipart file uploads, retry helpers, redirect handling, and support for gzip, deflate, brotli, and zstd content encoding. Current stable version is 2.6.3 (released 2025). The project follows an active release cadence with security patches, minor feature releases, and occasional major versions; the 2.x line requires Python >=3.9 and OpenSSL >=1.1.1.
Warnings
- breaking urllib3 v2.0 dropped Python 2.7 and 3.5–3.8 support and requires OpenSSL >=1.1.1. Environments compiled against older OpenSSL (e.g. AWS Lambda Python 3.9 runtime, Amazon Linux 2) will raise an ImportError or NotOpenSSLWarning on import.
- breaking VerifiedHTTPSConnection, DEFAULT_CIPHERS, and several other symbols moved or were deleted in v2.0. Importing them from their old v1.x locations (e.g. urllib3.connectionpool.VerifiedHTTPSConnection, urllib3.util.ssl_.DEFAULT_CIPHERS) raises AttributeError/ImportError.
- breaking The ssl_version parameter (used to pin a specific TLS protocol version) was deprecated in 2.0 and removed as of v2.6.0. Passing it now raises a TypeError.
- breaking v2.0 dropped commonName certificate hostname verification; only subjectAltName is now accepted. Self-signed or legacy certs that only set CN (and not SAN) will fail TLS verification.
- gotcha The module-level urllib3.request() function uses a hidden global PoolManager. In libraries or multi-threaded services, calling it shares cookies, connections, and retry state across all callers in the same process.
- gotcha Responses with preload_content=True (the default) read the entire body into memory before returning. For large or streaming responses this can exhaust memory silently.
- gotcha CVE-2026-21441 (GHSA-38jv-5279-wg99, CVSS 8.9): decompression-bomb safeguards in the streaming API were bypassed when HTTP redirects were followed. Fixed in 2.6.3.
Install
-
pip install urllib3 -
pip install urllib3[brotli] -
pip install urllib3[zstd] -
pip install urllib3[socks]
Imports
- PoolManager
import urllib3 http = urllib3.PoolManager()
- urllib3.request (top-level)
import urllib3 resp = urllib3.request('GET', 'https://example.com') - VerifiedHTTPSConnection
from urllib3.connection import VerifiedHTTPSConnection
- DEFAULT_CIPHERS
# Do not import DEFAULT_CIPHERS; urllib3 2.x uses system cipher list
- HTTPResponse
from urllib3.response import HTTPResponse
- Retry
from urllib3.util.retry import Retry
- Timeout
from urllib3.util.timeout import Timeout
Quickstart
import urllib3
from urllib3.util.retry import Retry
from urllib3.util.timeout import Timeout
# Explicit PoolManager — preferred over the module-level urllib3.request() in
# library code to avoid shared global state.
http = urllib3.PoolManager(
timeout=Timeout(connect=3.0, read=10.0),
retries=Retry(total=3, backoff_factor=0.5, status_forcelist=[500, 502, 503, 504]),
)
# Simple GET — response body is bytes; call .json() for JSON payloads
resp = http.request("GET", "https://httpbin.org/get")
print(resp.status) # 200
print(resp.json()) # parsed JSON dict
# POST with form fields
resp = http.request("POST", "https://httpbin.org/post", fields={"key": "value"})
print(resp.status)
# POST with JSON body (sets Content-Type: application/json automatically)
resp = http.request("POST", "https://httpbin.org/post", json={"key": "value"})
print(resp.json()["json"]) # echoed back by httpbin
# Streaming a large response
resp = http.request("GET", "https://httpbin.org/stream-bytes/1024", preload_content=False)
for chunk in resp.stream(32):
print(len(chunk), "bytes")
resp.release_conn()