A cURL command is how most API documentation, bug reports and browser network
tabs show an HTTP request. A program needs the same request as code. This converter
reads a curl command and writes it as JavaScript fetch, Node.js axios, Python
requests, Go net/http or PHP, with the method, URL, headers, body, login and
cookies carried over.
Read as POST https://api.example.com/cats. The command is only read, never run, and nothing leaves your browser.
Python (requests)
import requests
response = requests.post(
"https://api.example.com/cats",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_TOKEN",
},
json={
"name": "Mittens",
"age": 3,
},
allow_redirects=False,
)
print(response.status_code)
print(response.text)Python 3 with the requests package (pip install requests).
The command is only read, never run. Nothing you paste is uploaded and the URL is never fetched, so it is safe to try with a request from a private API. Swap real tokens for placeholders before you share the code, though.
How to use it
- Paste a cURL command in the top box. A command that runs over several lines, with a backslash at the end of each, is fine.
- Pick the language under Convert to.
- Read the line above the code, which says how the command was understood, for
example
Read as POST https://api.example.com/cats. - Check Not converted and Ignored if they appear. Every flag the tool saw is in one of the two lists, or in the code.
- Tap Copy and paste the code into your project.
Copying a request from your browser
The quickest way to get a cURL command for a request is the browser itself.
- Open DevTools and go to the Network tab.
- Reload the page or trigger the request, then right-click it in the list.
- Choose Copy, then Copy as cURL (bash). On Windows, Copy as cURL (cmd) writes the version for the command prompt.
- Paste it here.
Both formats work. The bash one quotes a body with a newline or a non-ASCII
character as $'...', and the cmd one escapes with ^ and ends each line with
^. The tool reads both, and says Windows cmd syntax above the box when it
detects the second.
Browsers add a lot of headers (sec-ch-ua, accept-language, sec-fetch-mode).
They are all converted, because the converter cannot know which ones the server
needs. Delete the ones you do not need from the code.
What is converted
| cURL | What the code does |
|---|---|
-X, --request | Sets the method. Without it, curl sends POST when there is a body and GET otherwise |
-H, --header | Sets a header. -H 'Name:' removes one and -H 'Name;' sends it empty |
-d, --data, --data-raw, --data-binary, --data-ascii | Sends the text as the body. Several are joined with & |
--data-urlencode | Percent-encodes the value the way curl does, then sends it as the body |
--json | Sends the body and sets Content-Type and Accept to application/json |
-G, --get | Moves the -d data into the query string and sends a GET |
-F, --form, --form-string | Sends a multipart form, with text and file fields |
-u, --user | Basic authentication. The same goes for user:password@ in the URL |
--oauth2-bearer | Sets Authorization: Bearer ... |
-b, --cookie | Sets the Cookie header from name=value pairs |
-A, -e | Sets User-Agent and Referer |
-L, --location | Follows redirects. Without it the code does not follow them, as in curl |
-k, --insecure | Skips certificate checks, or says in a comment that the language cannot |
--compressed | Asks for a compressed response and decodes it, or notes that the library already does |
-I, --head | Sends a HEAD request |
--url | Takes the URL from the flag instead of an argument |
Flags can be combined (-sSL), attached to their value (-XPOST,
-H'X-Id: 7') or joined with an equals sign (--header='X-Id: 7'). The URL can
come before, between or after them. A URL with no http:// gets one, as in curl.
What is listed instead of converted
A converter that quietly drops a flag gives you code that behaves differently from the command, and nothing tells you. This one never does that.
- Ignored are flags that do not change the request:
-s,-S,-v,-i,-f,-o file,-O,-w, timeouts and retries, and the HTTP version flags. Anything after a pipe, a;, a&&or a>is ignored too, because the shell runs it after curl. - Not converted are flags that do change the request and have no equivalent
here: a proxy (
-x), client certificates (--cert), a CA bundle (--cacert), digest and NTLM authentication, DNS overrides (--resolve), a body read from a file (-d @file), a cookie file, a second URL, and any option the tool does not know. Each one is shown with its value and the reason. - Warnings cover what is not a flag, such as a
$TOKENthat the shell would have filled in and the tool keeps as text.
Each language
JavaScript fetch | Node.js axios | Python requests | Go net/http | PHP | |
|---|---|---|---|---|---|
| Runs on | Browsers and Node.js 18+ | Node.js | Python 3 | Go standard library | PHP curl extension |
-u | Authorization header | auth option | auth= | SetBasicAuth | CURLOPT_USERPWD |
-L | the default | the default | the default (not for HEAD) | the default | CURLOPT_FOLLOWLOCATION |
no -L | redirect: "manual" | maxRedirects: 0 | allow_redirects=False | CheckRedirect returns ErrUseLastResponse | the default |
-k | no option, a comment says so | https.Agent | verify=False | InsecureSkipVerify | CURLOPT_SSL_VERIFYPEER and _VERIFYHOST |
--compressed | automatic | automatic | automatic | automatic, unless you set Accept-Encoding | CURLOPT_ENCODING |
-F | FormData | FormData | files= | mime/multipart | CURLOPT_POSTFIELDS array and CURLFile |
The PHP code uses the curl extension, which most installs include and which mirrors curl option for option. Guzzle or Symfony HttpClient would do the same job, but need Composer, so the extension is the one that works everywhere.
A JSON body is written as a native object (a dictionary in Python, an object
literal in JavaScript) only when that sends the same data. Large integers,
numbers like 1.0, escaped characters and keys that would reorder do not survive
the trip through an object, so those bodies stay as the exact string curl sent.
Strings are quoted by each language's own rules, so quotes, backslashes, newlines
and non-ASCII text in a body come out as a literal that means the same thing.
Common gotchas
- Shell quoting is not part of the request.
curl -H "Authorization: Bearer $TOKEN"has the shell fill in$TOKEN. The tool cannot, so it keeps the text and warns you. Replace it with the real value, or read it from an environment variable in your code. -dis not JSON.-d '{"a":1}'sends the form content type unless aContent-Type: application/jsonheader is set, and many APIs reject that. Use--json, or add the header.-Gis not a body.curl -G -d q=catssendsGET /search?q=cats, with the data in the query string and no body. Without-G,-dmakes a POST.- Browsers will not let
fetchset every header.Cookie,Host,Origin,RefererandAccept-Encodingare ignored in a browser and sent as written in Node.js. The converted code notes it when the command has one. fetchcannot send a body with GET or HEAD. curl can. The converted code has a comment when the command does.- Redirects differ. See the table above. The converter copies what curl did,
so a command without
-Lgives code that stops at the 301. - A file path is the path on the machine that ran curl.
-F file=@photo.pngbecomes code that opensphoto.png. Change it to where the file lives. - Do not paste live secrets into any website. This one never sends them anywhere, but a pasted token also ends up in your clipboard history and your shell history. Rotate a token that has been through either.
Related
- The HTTP Status Codes reference for what
the response to your request means, from
201to429to502. - JSON Formatter to tidy the response body, and
Base64 Encoder and Decoder to read the credentials
in an
Authorization: Basicheader. - Regex Tester and Unix Timestamp Converter for the other jobs that come up while you debug an API.
- The Bash cheat sheet for the quoting and continuation rules a cURL command is written in, and the cheat sheets for JavaScript, Python, Go and PHP.
Common questions
What is a cURL converter?
A cURL converter reads a curl command and writes the same HTTP request as code in another language, so you can move a request from a terminal, an API's documentation or your browser's network tab into a program. This one writes JavaScript fetch, Node.js axios, Python requests, Go net/http and PHP code, and it keeps the method, URL, headers, body, login and cookies.
How do I convert a cURL command to Python?
Paste the command into the box above and choose Python. You get a requests call with the same method, URL, headers and body, plus the options that map to curl flags: auth for -u, verify=False for -k and allow_redirects for -L. A JSON body that survives the round trip is written as a Python dictionary passed as json=.
Does it run my cURL command or send the request?
No. The command is read as text in your browser and turned into code. Nothing is executed, the URL is never fetched and nothing you paste is uploaded. The site records that the tool was used, the language you picked and how long the command was, so we know which tools are worth building next. The command itself is never part of that.
How do I copy a request as cURL from Chrome?
Open DevTools, go to the Network tab, right-click the request, choose Copy, then Copy as cURL (bash), or Copy as cURL (cmd) on Windows. Paste the result here. Both formats are read, including the quoting Chrome uses for bodies with newlines and non-ASCII characters. Edge has the same menu, and Firefox has it under Copy Value.
Why did a -d request turn into a POST?
Because curl does the same. Any of -d, --data, --data-raw, --data-binary, --data-urlencode, --json or -F makes curl send a POST unless you also pass -X. A -d body also gets the header Content-Type: application/x-www-form-urlencoded unless you set your own, and the converter writes that header out so the code sends exactly what curl would.
What is the difference between -d, --data-raw and --data-binary?
For text on the command line they send the same bytes. The difference is the @ sign: -d and --data-binary treat @file as a file to read, while --data-raw sends the characters as they are. Chrome uses --data-raw so a body that starts with @ is not mistaken for a file. Reading a body from a file is not converted here, so the tool lists it instead.
Which cURL options does it convert?
The method (-X), URL (including --url), headers (-H), bodies (-d, --data-raw, --data-binary, --data-urlencode, --json and -G), multipart forms (-F and --form-string), basic auth (-u and credentials in the URL), bearer tokens (--oauth2-bearer), cookies (-b), -A, -e, --compressed, -L, -k and -I. Options that only change what curl prints, such as -s, -v and -o, are listed as ignored. Options that change the request and are not converted, such as proxies and client certificates, are listed as not converted.
What happens to -k and --compressed in each language?
-k becomes verify=False in Python, an https.Agent with rejectUnauthorized set to false in axios, a tls.Config with InsecureSkipVerify in Go and the CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST options in PHP. fetch has no such option, so the code carries a comment saying so. --compressed needs nothing in fetch, axios, requests or Go because they ask for gzip and decompress on their own, and it becomes CURLOPT_ENCODING in PHP.
Why does the converted code not follow redirects?
curl does not follow redirects unless you pass -L, but fetch, axios and requests do by default. So when the command has no -L, the converted code switches following off to match curl, and when it has -L the code follows them. If you would rather follow redirects, delete that option.
Does it handle file uploads with -F?
Yes. A -F name=value field becomes a text field and -F name=@path becomes a file field, with the filename and type= you gave. The code opens the file at that path, so change the path to where the file lives. Reading a field's value from a file with name=<path and sending a file from standard input are not converted.