99tools

cURL Converter

runs in your browser

Paste a cURL command and get the same request as JavaScript fetch, axios, Python requests or Go. Headers, JSON bodies and basic auth all carried across.

Output

Paste the whole command, including the word curl. Line continuations, smart quotes and a copied $ prompt are all fine.

cURL command

fetch

about this tool

Paste the command, pick a language

cURL is what API documentation gives you and what your browser's devtools hand back from "Copy as cURL". It is almost never what you are actually writing. This reads the command and prints the same request as fetch, axios, Python requests or Go.

Paste the whole thing, starting with the word curl. The line continuations, the curly quotes a documentation site left in, and the $ from a copied shell prompt are all handled — refusing those would be technically correct and no use to anybody.

One parse, four languages

The command is read once into a plain description of a request — method, URL, headers, body, credentials — and each language is printed from that same description. It is worth saying why: a quoting bug in the Go output cannot make it disagree with the Python output about what you asked for, because neither of them ever looks at your command directly.

That also means the rules cURL itself applies are applied here. A command with -d and no -X is a POST, because that is what cURL does. Repeated -d flags are joined with &. -A, -b and -e are really just headers, so that is what they become.

Bodies

A body sent with Content-Type: application/json is printed as an object rather than a string, which is what you would have written by hand. fetch gets JSON.stringify, axios gets data, and Python gets json=, which is how requests wants a JSON body.

Python's True, False and None are spelled the way Python spells them. A snippet that does not run is worse than no snippet.

Anything else is sent as text, unchanged.

-d makes cURL set a Content-Type of its own, and fetch and requests set none, so the snippet writes one out rather than letting the request go as text/plain. cURL always sends application/x-www-form-urlencoded there, and so does the snippet — except when the body is JSON, where it writes application/json instead, because a JSON body sent as a form is a command that happens to work against a lenient server rather than one you want copied into code. That is the single place the generated request differs from what cURL would have sent. A Content-Type you gave yourself is always left as you wrote it, in either case.

What it will not do

A flag it does not recognise is skipped and mentioned, rather than failing the whole command — a stray --retry 3 should not cost you your code.

Some flags have no honest equivalent. -k turns off certificate checking, and none of the generated snippets do that, because the fix is the certificate. -o, --proxy and the timeout flags belong to the shape of a command-line program rather than to the request itself. Each one produces a note saying it was left out.

-F is read and its fields are carried over, but a real upload needs a real file, so the snippet gives you the shape and leaves the file to you.

Nothing is sent

The command is parsed here and the code is written here. No request is made, which matters more on this page than on most: a cURL command copied out of devtools usually has a live session token sitting in a header.

To pull a URL apart rather than the command around it, use the URL parser. To read the token you just pasted, use the JWT decoder.

questions

Which flags does it understand?
The ones people actually paste: -X, -H, -d and its --data variants, -F, -u, -A, -b, -e, --url, and the bare switches like -L, -k and --compressed. A flag it does not know is skipped with a note rather than failing the whole command, so a stray --retry 3 still gets you your code.
Does the command leave my browser?
No. The parsing and the code generation both run in this page, and no request is ever sent. That matters here more than on most tools, because a cURL command copied from devtools usually has a live session token in it.
Why does my POST show up without -X POST in the original?
cURL sends POST automatically when you give it a body with -d, so a command with data and no method is a POST. The converter follows the same rule, which is why the method appears in the output even though it was not in the input.
What happens to -u?
It becomes the Authorization header cURL would have sent — Basic, with the credentials base64-encoded. If the command already carries its own Authorization header, that one is kept and -u is left out rather than sending two.
Will the Python snippet run as it is?
It should. A JSON body is passed with json= and anything else with data=, and the Content-Type is written into the headers dict rather than left to requests — application/json for a JSON body, application/x-www-form-urlencoded otherwise, which is what cURL sends. The booleans and nulls in the payload are spelled True, False and None — the real ones only, never the word true sitting inside a string. A method requests has no function for, like PURGE, goes through requests.request.
Can it do multipart uploads?
It reads -F and carries the fields over, but a real file upload needs a file, which a browser tool cannot invent. You get the shape of the request and a note saying to attach the file yourself.