curlpro
An HTTP client with a browser's network fingerprint: the TLS ClientHello, the HTTP/2 and HTTP/3 frames, header order and header case.
pip install curlpro
import curlpro
with curlpro.Session("chrome-151-windows") as s:
r = s.get("https://example.com")
print(r.status, r.text[:200])
Neither Go nor a compiler is needed: the native library and all 47 profiles are already inside the wheel, and the profiles load themselves.
Why another one
The existing clients keep their browser profiles in compiled code: a new Chrome comes out every four weeks, and each time that means editing C or Go, rebuilding and releasing. Here a profile is data, and it can be registered at runtime:
curlpro.register_profile({
"name": "chrome-152-windows",
"based_on": "chrome-151-windows",
"headers": {"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Chrome/152.0.0.0 ..."},
})
Your own fingerprint, without a request
What a server would see is computed locally, from the same ClientHello bytes that would go on the wire. No network, no oracle:
with curlpro.Session("chrome-151-windows") as s:
fp = s.fingerprint()
print(fp.ja4) # t13d1516h2_8daaf6152771_806a8c22fdea
print(fp.akamai) # 1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p
Checked against 47 captures: JA4 47/47, JA3N 47/47, Akamai 47/47.
audit() answers the second question — the one people actually lose days to.
Not "does my fingerprint look right" but "does anything here disagree with
anything else", because that is what gives a client away:
for finding in s.audit():
print(finding)
Personas
Profile, proxy, device, headers and cookies — one identity, one file:
p = curlpro.Persona.new("chrome-151-windows", proxy="http://user:pass@host:8080")
p.save("accounts/user42.json")
p = curlpro.Persona.load("accounts/user42.json")
with p.session() as s:
s.get("https://example.com/")
p.save() # the cookies moved on; the identity did not
requests compatibility
import curlpro.requests as requests
r = requests.get("https://example.com/", timeout=10)
Existing code changes one import. It is a subset, and it says so: an argument the shim cannot honour is refused with a reason rather than ignored.
What is inside
A thin ctypes wrapper over a native library written in Go: the handshake is driven by uTLS, HTTP/2 by fhttp, QUIC by uquic.
The fingerprint is checked against tls.browserleaks.com: Chrome 151 gives
t13d1516h2_8daaf6152771_806a8c22fdea — the same JA4 as the live browser.
Boundaries
The library covers the network layer. It does not forge the JS fingerprint (canvas, WebGL, navigator) — that is the browser's level, and the answer there is Playwright. Matching the network fingerprint is necessary but not sufficient: modern systems score JA4 together with JA4H, JA3S/JARM and behaviour.
HTTP/1.1, HTTP/2, HTTP/3 and WebSocket are supported, along with cookies, redirects, proxies (HTTP CONNECT and SOCKS5), multipart, streaming reads and uploads, and an asynchronous API.
# WebSocket: the handshake follows the profile's template, permessage-deflate works
with curlpro.Session() as s:
with s.websocket("wss://echo.websocket.org/", max_message_size=1 << 20) as ws:
ws.send("hello") # str -> a text frame
ws.send(b"\x00\xff") # bytes -> a binary one
for message in ws: # until the server closes: curlpro.WebSocketClosed;
print(message) # a silence timeout is CurlProError with .code == "timeout"
# A large file goes as a stream rather than through memory
with curlpro.Session() as s:
s.post("https://example.com/upload", body_file="archive.zip")
# The connection is reused between requests, as a browser's is. keep_alive=False
# gives every request its own — needed when a balancer pins a client to one node.
with curlpro.Session(keep_alive=False) as s:
s.get("https://example.com/")
The HTTP/3 fingerprint is checked against Chrome 144 on quic.browserleaks.com:
with curlpro.Session("chrome-151-windows", http3=True) as s:
print(s.get("https://quic.browserleaks.com/fp").json()["h3_text"])
# 1:65536;6:262144;7:100;51:1;GREASE|GREASE|984832|m,a,s,p
The QPACK dynamic table is supported by a decoder of our own: the profile advertises a capacity as Chrome does, and a server that uses it gets parsed.
Install
Wheels are built for Linux (x86-64 and ARM64, glibc 2.28+), macOS 13+ (Intel and Apple Silicon) and Windows x64. The macOS 13 floor is not ours to choose: that is what Go 1.27 requires, and the native part is built with it.
Platforms outside that list — Alpine and other musl distributions, Windows on ARM, older glibc or macOS — install from the source archive, and there Go and a C compiler are required:
pip download curlpro --no-binary :all: --no-deps
tar -xzf curlpro-*.tar.gz && cd curlpro-*/go
CGO_ENABLED=1 go build -buildmode=c-shared -o ../curlpro/lib/libcurlpro.so ./lib
The library is looked up through CURLPRO_LIBRARY, then in curlpro/lib/, then
in dist/.
Full documentation and sources — github.com/int3re/curlpro.
Release files for curlpro 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| curlpro-0.4.0.tar.gz | 311.3 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| curlpro-0.4.0-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| curlpro-0.4.0-py3-none-manylinux_2_28_x86_64.whl | Python 3 | none | Linux glibc 2.28+ x86-64 | Details |
| curlpro-0.4.0-py3-none-manylinux_2_28_aarch64.whl | Python 3 | none | Linux glibc 2.28+ ARM64 | Details |
| curlpro-0.4.0-py3-none-macosx_13_0_x86_64.whl | Python 3 | none | macOS 13.0+ x86-64 | Details |
| curlpro-0.4.0-py3-none-macosx_13_0_arm64.whl | Python 3 | none | macOS 13.0+ ARM64 | Details |
Total release size: 39.2 MB
Release files / curlpro-0.4.0.tar.gz
| Download URL | curlpro-0.4.0.tar.gz |
|---|---|
| Size | 311.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
112c5631b0d72d6cc10642f24ffb82d97564d61fdc001ed151224879325a7f34
|
|
BLAKE2b-256 checksum How to use checksums |
65e0a32f9cfe308f16938c096689c48878ebfab9186dfda41783382318e32de0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency logRelease files / curlpro-0.4.0-py3-none-win_amd64.whl
| Download URL | curlpro-0.4.0-py3-none-win_amd64.whl |
|---|---|
| Size | 9.6 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
62d6d44593594be3a0f29f77606d75197f7d459e544e92fdd578f93e2b315a28
|
|
BLAKE2b-256 checksum How to use checksums |
ef6ac4d0ddbb34ff1289fb5e901202bf21bbbc997a0bdb5bbbb90ec8d0356cda
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency logRelease files / curlpro-0.4.0-py3-none-manylinux_2_28_x86_64.whl
| Download URL | curlpro-0.4.0-py3-none-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 9.8 MB |
| Tags | Linux glibc 2.28+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
61aa1132c3d18809ab8672b63ef6835f0f52b8ac6da3522da02a89e5a708c474
|
|
BLAKE2b-256 checksum How to use checksums |
b2c2659ba4c34993a59a27b0dfd3671d532e3ceb4b690f9b1cc6ffa29a89231d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency logRelease files / curlpro-0.4.0-py3-none-manylinux_2_28_aarch64.whl
| Download URL | curlpro-0.4.0-py3-none-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 9.0 MB |
| Tags | Linux glibc 2.28+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
46b00c5303450f8cc844543c3b9d1eccbf0bd5f444361d482b975819640beaeb
|
|
BLAKE2b-256 checksum How to use checksums |
25c092ebedceb5b140ad00537a25c37133bf8dee8671c6829658de580200a247
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency logRelease files / curlpro-0.4.0-py3-none-macosx_13_0_x86_64.whl
| Download URL | curlpro-0.4.0-py3-none-macosx_13_0_x86_64.whl |
|---|---|
| Size | 5.4 MB |
| Tags | Python 3 macOS 13.0+ x86-64 |
|
SHA-256 checksum How to use checksums |
db9912d49b947edd18e92088db53a2b4c23896a928417ea5d21fb0b7c909f2df
|
|
BLAKE2b-256 checksum How to use checksums |
f0efc14b3d80557d2a9ef809ec948286543bbeb50da055268900c8e3b24fcdca
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency logRelease files / curlpro-0.4.0-py3-none-macosx_13_0_arm64.whl
| Download URL | curlpro-0.4.0-py3-none-macosx_13_0_arm64.whl |
|---|---|
| Size | 5.0 MB |
| Tags | Python 3 macOS 13.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
bc289cb3beb98d559c08406cca07e192149b25af3163e986d5e664a0f9ee0d28
|
|
BLAKE2b-256 checksum How to use checksums |
faca8758e97c6a9cbb867ac88a3b80791daeebe54f48e9aa6151789b8e9ccae3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency log