Skip to content

cURL to Python: Convert Any cURL Command to requests Code

Convert curl to Python requests code free — headers, JSON bodies, multipart uploads, Basic Auth and cookies mapped correctly. No sign-up.

Try it now: cURL to Python Requests Converter Turn a cURL command into idiomatic Python `requests` code — headers, JSON bodies, form data, basic auth and query strings included.

What This Actually Solves

You have a curl command — pulled out of an API's documentation, copied from a colleague's terminal history, or exported from Postman's code panel — and what you actually need isn't another way to run it from a shell. It's a working Python script. That gap between “this works when I paste it into a terminal” and “this is a function I can call from my codebase” is exactly what a curl to python conversion is for.

Typing it out by hand is slower and buggier than it looks. A JSON body's truehas to become Python's True, a form body needs data= while a JSON body needs json=, and it's easy to forget that requests has no default timeout at all. A dedicated curl to Python requests converter handles all of that in one pass — headers, JSON and form bodies, file uploads, Basic Auth, and query strings all mapped to the right keyword argument, running entirely in your browser so nothing you paste (including a bearer token or session cookie sitting in a -H flag) ever leaves your machine.

The rest of this guide is the part most curl converter online tools skip: whyeach flag maps where it does, with real before/after code for the cases you'll actually hit — the same job as the requests library itself, just applied to a curl command instead of code you're writing from scratch.

How to Actually Get a curl Command in the First Place

Before converting anything, you need the curl command itself. Three sources cover almost every case:

  • Chrome or Edge DevTools: open the Network tab, trigger the request in the page, then right-click the request in the list → CopyCopy as cURL(there's usually a bash variant and a cmd variant — pick bash unless you specifically need Windows cmd quoting).
  • Firefox DevTools: same Network tab, right-click the request → Copy Copy as cURL (POSIX) (there's a Copy as cURL (Windows)variant too). The output is functionally identical to Chrome's.
  • Postman: open a request, click Code in the right-hand panel (the </> icon), and choose cURL from the language dropdown. Postman emits a clean, single-purpose curl command with no browser-specific noise.

This is the standard copy as curl chrome devtoolsworkflow, and it's worth understanding what you're copying: DevTools reconstructs the exact request the browser sent, including every cookie and the Authorizationheader if you were logged in. That's convenient for reproducing a bug — and exactly why converting it in a tool that uploads your paste anywhere is worth thinking twice about.

The curl Flag → Python requests Parameter Map

This is the part that turns a converter into something you can actually reason about, not just trust — the actual mechanics behind any curl to requests library conversion, not just a black-box convert curl command to code button. Every common curl flag has one clear equivalent in requests:

curl flagrequests parameterNotes
-H, --headerheaders={"Name": "Value"}One dict entry per header. A header repeated with the same name collapses to the last value — a Python dict can only hold one.
-d, --data, --data-rawdata={...} or json={...}data= for a form-encoded body (curl's default with -d and no explicit Content-Type); json= when the header says application/json — requests serializes it and sets the header for you.
-F, --formfiles={...}Plain text fields use the (None, value) tuple; a file field passes an open()-ed file handle.
-u, --userauth=("user", "pass")requests builds the Authorization: Basic header for you — no manual base64 encoding.
-b, --cookiecookies={"name": "value"}A cookie string like "a=1; b=2" splits into one dict entry per pair.
-Xthe method call itselfcurl infers POST when -d is present and -X is absent. requests has no such inference — call requests.post(...) explicitly, or pass method= to requests.request().
-L, --locationallow_redirects (default True already)curl does not follow redirects unless -L is passed; requests follows them by default for most methods. See the gotcha table below.
-k, --insecureverify=FalseDisables TLS certificate verification entirely — same trade-off as -k, use only for local debugging.

Once you can read that table fluently, you can sanity-check any converter's output line by line instead of trusting it blindly — which matters, because a converted script that silently form-encodes a JSON body, or drops a query parameter, fails in ways that don't always throw an obvious error.

Real-World curl to Python Conversions, Side by Side

Five scenarios cover almost everything you'll actually paste. Each one shows the curl command first, then the idiomatic requests equivalent — not a literal, line-by-line translation, but the version an experienced Python developer would actually write.

1. GET with query parameters

curl
curl "https://api.example.com/search?q=climate+policy&limit=20&sort=recent"
python
import requests

url = "https://api.example.com/search"
params = {
    "q": "climate policy",
    "limit": 20,
    "sort": "recent",
}

response = requests.get(url, params=params, timeout=30)
response.raise_for_status()
print(response.json())

requestshandles the percent-encoding itself, so there's no need to hand-decode a pasted query string — split it into a plain params dict and let requests build the URL.

2. POST with a JSON body

curl
curl -X POST https://api.example.com/users \
  -H 'Content-Type: application/json' \
  -d '{"name": "Ada Lovelace", "role": "engineer", "active": true}'
python
import requests

url = "https://api.example.com/users"
payload = {
    "name": "Ada Lovelace",
    "role": "engineer",
    "active": True,
}

response = requests.post(url, json=payload, timeout=30)
response.raise_for_status()
print(response.json())

true becomes Python's True — capitalization that trips up hand conversion constantly. Passing the dict through json= instead of data= also means you never set Content-Type yourself; requests sets application/json and serializes the body for you.

3. Multipart file upload

curl
curl -F "description=headshot" -F "[email protected]" https://api.example.com/upload
python
import requests

url = "https://api.example.com/upload"
files = {
    "description": (None, "headshot"),
    "avatar": open("photo.png", "rb"),
}

response = requests.post(url, files=files, timeout=30)
response.raise_for_status()

The (None, value) tuple tells requests that descriptionis a plain text field, not a file part, so it's written into the multipart body correctly rather than treated as a filename. Setting Content-Type manually here would actually break the request — it needs to include the multipart boundary that requests generates itself.

4. Basic Auth

curl
curl -u demo:s3cret https://api.example.com/account
python
import requests

url = "https://api.example.com/account"
response = requests.get(url, auth=("demo", "s3cret"), timeout=30)
response.raise_for_status()
print(response.json())

Never commit credentials in a script like this. Read them from the environment instead: auth=(os.environ["API_USER"], os.environ["API_PASS"]).

5. Cookies and session reuse

curl — a single request with a cookie header
curl -b "session_id=8f14e45; theme=dark" https://api.example.com/dashboard
python — same single request
import requests

url = "https://api.example.com/dashboard"
cookies = {"session_id": "8f14e45", "theme": "dark"}

response = requests.get(url, cookies=cookies, timeout=30)
response.raise_for_status()

That covers one request. When a script needs to log in and then make follow-up calls, requests.Session()is the right tool — it persists cookies the server sets across every subsequent request made through it, which is closer to what a browser (or curl's -c/-b cookie-jar pair) does than passing cookies= by hand on every call:

python — login, then reuse the session
import requests

with requests.Session() as session:
    session.cookies.update({"theme": "dark"})

    login = session.post(
        "https://api.example.com/login",
        json={"username": "ada", "password": "s3cret"},
        timeout=30,
    )
    login.raise_for_status()

    dashboard = session.get("https://api.example.com/dashboard", timeout=30)
    dashboard.raise_for_status()
    print(dashboard.json())

requests vs. httpx: When to Reach for the Modern Alternative

requestsis still the right default for a synchronous script, and it's what this site's curl to Python requests converter targets. httpx is worth knowing about as the modern alternative, deliberately built with a requests-compatible API, plus two things requestsdoesn't have: HTTP/2 support and a native async client.

The synchronous swap is close to a drop-in replacement:

python — httpx, sync
import httpx

url = "https://api.example.com/search"
params = {"q": "climate policy", "limit": 20}

response = httpx.get(url, params=params, timeout=30)
response.raise_for_status()
print(response.json())

The case for actually switching shows up once a script lives inside asyncio — a FastAPI endpoint, a background task worker, or anything issuing several requests concurrently. requests has no async mode at all; running five requests concurrently with it means five threads or five sequential calls. httpx.AsyncClient awaits them concurrently on one thread:

python — httpx, async
import asyncio
import httpx

url = "https://api.example.com/search"

async def fetch(client, request_id):
    response = await client.get(url, params={"id": request_id}, timeout=30)
    response.raise_for_status()
    return response.json()

async def main():
    async with httpx.AsyncClient() as client:
        results = await asyncio.gather(*(fetch(client, i) for i in range(5)))
        print(results)

asyncio.run(main())

If a converted script isn't already running inside async code, there's little reason to add the extra dependency — stick with requests and reach for the curl to python httpx pattern only when concurrency or HTTP/2 is an actual requirement, not a hypothetical one.

Gotchas: Where curl and requests Quietly Disagree

A converted script that runs without error can still behave differently from the original curl command. Four places this happens in practice:

BehaviorcurlPython requests
Following redirectsOff by default — a 3xx response is shown as-is unless -L is passed.On by default for GET/POST/PUT/PATCH/DELETE. requests.head() is the one exception — it does not follow redirects unless allow_redirects=True is passed explicitly.
TLS certificate verificationOn by default; -k / --insecure disables it entirely.On by default; verify=False disables it (the same trade-off as -k). For an internal CA, verify="/path/to/ca-bundle.pem" is the safer fix.
Request timeoutNo timeout unless --max-time or --connect-timeout is set, though most terminals let you Ctrl+C a hang.No default timeout either — a stalled connection blocks the call forever. Always pass timeout= explicitly.
Header name caseSent exactly as typed on the command line.No practical difference — HTTP header names are case-insensitive per the HTTP spec, and requests' own headers dict does case-insensitive lookups and merges.

The redirect and timeout rows are the two that actually change behavior, not just wording — worth checking by eye any time a converted script needs to match the original command exactly.

GenKitLab vs. curlconverter.com vs. scrapingbee.com

curlconverter.com is the strongest pure conversion tool out there — client-side, dozens of target languages, a VS Code extension — but it's a converter and not much else, with little explanation of why a flag maps where it does. scrapingbee.com and similar scraping-vendor sites publish curl conversion pages mainly as a funnel toward a paid scraping API subscription, so the actual conversion content tends to be thin and wrapped in upsell CTAs.

GenKitLabcurlconverter.comscrapingbee.com-style pages
Where conversion runsEntirely in your browserClient-side, per their own docsVaries; the page itself is secondary to the product it promotes
Explains the flag → parameter mappingYes — the full -H/-d/-F/-u/-b/-X table earlier on this pageNot really — outputs code with little explanation of whyMinimal — content mainly supports selling a scraping API
Real annotated before/after examplesFive worked scenarios: query params, JSON POST, multipart upload, Basic Auth, cookie/session reuseSparse; example coverage is inconsistent across target languagesThin or generic, often screenshot-heavy rather than code-heavy
Sign-up or upsell required to readNoNoFrequently gated behind or steered toward a paid plan
Target languagesPython requests, plus sibling tools for JS fetch, Axios, and Node's https module50+ languages and librariesPrimarily its own scraping API's client snippets

The honest read: if you need one of the 50-plus languages curlconverter.com supports, use it — breadth is a real advantage. GenKitLab's bet is narrower and different — a handful of targets (Python, fetch, Axios, Node) covered with an actual explanation of the mapping and enough worked examples that you can spot a wrong conversion yourself, instead of trusting a black box.

Explore More Conversion Tools

A curl command and a Python target are one pairing out of several — GenKitLab runs the same conversion logic across a small family of API tools, all client-side, all free:

Frequently asked questions

How do I convert a curl command to Python requests?

Paste the full curl command — headers, body, and all — into GenKitLab's curl to Python converter and it returns idiomatic requests code: JSON bodies become a dict passed to json=, form bodies become data=, -F fields become files=, -u becomes an auth= tuple, and the method comes from -X or is inferred the way curl infers it. Everything runs client-side, so nothing you paste is uploaded anywhere.

How do I copy a curl command from Chrome DevTools?

Open DevTools, switch to the Network tab, trigger the request, then right-click it in the request list and choose Copy → Copy as cURL (bash). Firefox has the equivalent under Copy Value → Copy as cURL. Postman offers the same output from a request's Code panel by selecting cURL from the language dropdown.

How do I handle headers and cookies when converting?

Each -H flag becomes one entry in a headers={} dict, keyed by header name. A -b or --cookie flag with a string like "a=1; b=2" splits into a cookies={} dict with one entry per pair. For a single request, pass cookies= directly to requests.get() or requests.post(); for a login followed by several authenticated calls, use requests.Session() instead so cookies set by the server persist automatically across every request made through that session.

What Python library should I use instead of requests?

requests is still the right default for a synchronous script and is what this converter targets. httpx is the modern alternative worth reaching for specifically when you need HTTP/2 or an async client — httpx.AsyncClient lets a script await several requests concurrently on one thread, something requests has no built-in way to do. For a script that isn't already async, there's little reason to add the extra dependency.

How do I convert curl -F (multipart) to Python?

Each -F flag becomes one entry in a files={} dict. A plain text field is written as (None, value) so requests knows it's not a file part; a file field (curl's -F "name=@path") becomes an open()-ed file handle, for example files={"avatar": open("photo.png", "rb")}. Setting Content-Type manually on a multipart request is a mistake to avoid — requests generates the boundary and header itself.

Is there a package that automates this?

GenKitLab's curl to Python converter does exactly this conversion in your browser, with no install and no upload of the pasted command. curlconverter's own installable package is a Node/TypeScript library, not a Python one, so it's the right pick for a JS build step but not for importing directly into a Python project — for that, a small community package like uncurl (on PyPI) parses curl syntax in Python, though it's worth reviewing the output rather than trusting it blindly, same as any converter.

How do I convert curl with Basic Auth?

curl's -u user:pass (or --user user:pass) maps directly to requests' auth=("user", "pass") argument — requests builds the Authorization: Basic header for you, so there's no manual base64 encoding to write. In the generated script, replace the literal credentials with values read from environment variables, for example auth=(os.environ["API_USER"], os.environ["API_PASS"]), before committing it anywhere.

Last updated