Quick answer
To convert cURL to Python, map the command onto the requests library: -H becomes the headers dict, the query string becomes params, -d becomes data, a JSON body becomes json, -F becomes files, -u becomes auth and -k becomes verify=False. Paste a cURL command into Playxoft's free cURL to Python converter to get runnable requests or httpx code, formatted the way Black would format it, without the command leaving your browser.
- requests or httpx
- Params, json, data and files
- Cookies as a dict
- Basic and digest auth
- Credential warnings
- Black-style formatting
How to use the cURL to Python Converter
- 1Paste a command into cURL command, or pick one from Load example.
- 2Choose requests or httpx as the library.
- 3Keep Raise on HTTP errors on to add response.raise_for_status(), and Query as params to get a params dict.
- 4Check Parsed request and the notes for anything Python handles differently, such as timeouts.
- 5Install the library with
pip install requests(orpip install httpx), then copy the code or download request.py.
cURL flags cheat sheet: what does each option become in requests and httpx?
| cURL | requests | httpx |
|---|---|---|
-X PUT | requests.put(…) | httpx.put(…) |
-H "Name: value" | headers={"Name": "value"} | Same |
?q=x in the URL | params={"q": "x"} | Same |
-d "a=1&b=2" | data={"a": "1", "b": "2"} | Same |
-d with raw text | data="…" | content="…" |
--json '{…}' or a JSON body | json={…} | Same |
-F file=@a.pdf | files={"file": ("a.pdf", open("a.pdf", "rb"))} | Same |
-u user:pass | auth=("user", "pass") | Same |
--digest -u user:pass | auth=HTTPDigestAuth(…) | auth=httpx.DigestAuth(…) |
-b "a=1" | cookies={"a": "1"} | Same |
-k | verify=False | Same |
-m 30 | timeout=30 | Same |
-L | The default (except for head()) | follow_redirects=True |
-x http://host:8080 | proxies={"http": …, "https": …} | proxy="http://host:8080" |
Two details matter. json= re-serializes your data, so the spacing changes; if a server signs the exact bytes of the body, send the original string with data= instead. And requests only builds a multipart body when files= is present, so text-only -F fields become (None, value) tuples in files.
requests vs httpx: which Python library should you use?
| requests | httpx | |
|---|---|---|
| Async support | No | Yes, with httpx.AsyncClient |
| HTTP/2 | No | Yes, with pip install "httpx[http2]" |
| Default timeout | None: it can wait forever | 5 seconds |
| Redirects | Followed by default | Only with follow_redirects=True |
| Raw body argument | data="…" | content="…" |
| Maturity | The long-standing standard | Newer, with a requests-style API |
Use requests for scripts, notebooks and synchronous services; it is everywhere and nearly every tutorial uses it. Use httpx for asyncio code such as FastAPI handlers and async workers, or when you need HTTP/2. Whichever you choose, set a timeout: a requests call without one can hang forever on a stalled server.
Why does my Python request behave differently from curl?
The converter maps every option it can, but a few behaviors differ by design:
- Timeouts.
curl -m 30caps the whole transfer. In requests,timeout=30limits the connection and each read separately, so a slow trickle of data can run longer. - Compression. curl's
--compressedneeds no code: both libraries ask for gzip and decode it. The converter drops a copiedAccept-Encodingheader because requests can only decode Brotli (br) when the brotli package is installed. - Redirects. curl stops at a 3xx unless you pass
-L. Turn on Match curl redirects to addallow_redirects=Falseand get the same response curl shows. - Default headers. Python sends its own User-Agent, such as
python-requests/2.32. Some sites block it; keep the browser's User-Agent header from the copied command if you need to look like a browser.
How do I reuse a requests.Session for cookies and retries?
Each top-level requests.get() call builds a fresh session: no connection reuse, and cookies are forgotten. Once a converted request becomes part of a script that makes several calls, switch to a Session:
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
session.headers.update({"Accept": "application/json"})
retries = Retry(total=3, backoff_factor=0.5, status_forcelist=[429, 502, 503, 504])
session.mount("https://", HTTPAdapter(max_retries=retries))
response = session.get("https://api.example.com/v1/orders", timeout=30)- Cookies. Cookies the server sets, after a login for example, go out automatically on the next call. That replaces curl's
-cand-bcookie-jar files. - Retries. The
Retrypolicy is the counterpart ofcurl --retry. By default urllib3 only retries idempotent methods such as GET, PUT and DELETE, so a POST is not repeated unless you add it toallowed_methods. - httpx. The same idea is
httpx.Client();httpx.HTTPTransport(retries=3)retries failed connections.
Copying requests from a browser? See how to copy as cURL in Chrome or Firefox DevTools. Cookies arrive in a -b flag or a Cookie header, depending on the browser, and the converter turns either one into a cookies dict.
How do I keep tokens out of a Python script?
The converter itself is private: it runs in your browser and never uploads or stores your command. The risk is the token you paste, which ends up in the generated code.
Read secrets from the environment instead. Write them as variables in the command, for example -H "Authorization: Bearer $API_TOKEN", and the converter emits:
headers = {
"Authorization": f"Bearer {os.environ['API_TOKEN']}",
}The Contains credentials badge and the amber line markers show any secret that is still hard-coded. And when verify=False makes urllib3 print an InsecureRequestWarning on every call, take it seriously: the request now accepts forged certificates, so keep it out of production.
Frequently asked questions
Last updated by the Playxoft engineering team.