curl converter
Paste a curl command — get fetch(), Python requests and HTTPie, live
1 curl command
A browser’s Copy as cURL paste works as is, backslash line continuations and all. Try adding -k, --retry 3 or -F 'photo=@cat.png' and watch what the three tabs say about each.
2 Converted code
Browser fetch()
-k/--insecure has no equivalent in browser fetch(). Certificate verification belongs to the browser and no option, header or trick switches it off, so nothing above ever stands in for it. Browser code is also bound by CORS, which curl is not: a request that works in your terminal can still be blocked in a tab.
Python requests
Python’s equivalents are real, so they are emitted: verify=False genuinely skips certificate and hostname checks for -k, and auth=() is genuine HTTP Basic. Needs pip install requests.
HTTPie
HTTPie’s --verify=no is a true -k. Its --compress is not curl’s --compressed — it gzips the request body you send — so it is never emitted here. Written for HTTPie 3.x, where --raw sends a body verbatim.
This page never makes the request — it converts text. The tokenizer, the parser and all three emitters run in this tab; your command, its URL, its headers and its body are never uploaded and no code is loaded from a CDN. The page does load one cookieless pageview counter from stats.dankdev.com, which records this page’s address and title and nothing you paste.
Which flags this converter honours — and which it refuses
Converted
-X,--requestthe method; overrides the POST that a body would imply-H,--headerrepeatable, order preserved;-H 'Name:'is curl’s remove form and sends nothing-d,--databody, joined with&when repeated;@fileis marked, never invented--data-rawbody with@left literal--data-urlencodepercent-encoded the way curl does it — space is%20, never+-u,--userBasic auth:btoa(),auth=(),-a-F,--formmultipart fields,@upload,<contents,;type=,;filename=--compressedall three targets already do this; you are told so instead of shown a header-L,--locationand its absence, which is why Python getsallow_redirects=False-k,--insecurereal in Python and HTTPie; impossible in browserfetch(), and said so in words-b,--cookiea real header for Python and HTTPie; a forbidden header name infetch()--url, and a bare URLplus--, clustered booleans such as-kL, and glued values such as-XPOST
Refused by name, at parse time
An option silently discarded produces a request that differs from the one you pasted — and you find out from a failure you cannot explain. So these six are listed with a reason instead, and the reason is stamped into the top of every copied snippet:
--proxy(-x)A proxy belongs to the client and its network, not to the request.fetch()cannot route through one at all, and the valuerequestsor HTTPie would need depends on your machine. Dropping it would send the call straight at the origin.--cert(-E)A client TLS certificate is a file on your disk plus, usually, a passphrase. None of the three targets can be handed one from the text of a command, and a request that quietly loses it returns a 400 or 403 you cannot explain from the code.--resolveOverrides DNS for onehost:port. A browser has no DNS layer you can reach;requestsand HTTPie need a custom adapter or an/etc/hostsentry. Code without it connects to a different machine at the same URL.--interfaceBinds the request to a named network interface or source IP — a socket option a browser cannot see. Dropping it moves the request onto whatever route the OS picks, which may not reach the host at all.--output(-o)About what curl does with the response, not about the request. Honouring it would change the shape of the emitted code, which would have to open and stream to a file.--retryA client policy.fetch()has none built in;requestsneeds anHTTPAdapteraround a urllib3Retry, and both need decisions this page cannot make for you — which status codes count, how long to back off, whether the call is safe to repeat.
Anything else the parser does not know — --data-binary, -A, --max-time, -s — is listed as unrecognised above the code, with its value consumed so it can never be mistaken for your URL.
What actually breaks when you convert a curl command
The quoting, first. A Copy as cURL paste is shell text, and a split on spaces destroys it: the body '{"note":"don'\''t split"}' is three adjacent quoted runs that a shell glues into one word containing a real apostrophe, because a single-quoted string cannot contain \' at all. This page walks the string character by character and implements the four POSIX quoting modes plus bash’s $'…', so "a\b" stays a\b (inside double quotes a backslash before an ordinary character is literal — the rule most hand-rolled splitters get backwards) while "a\$b" becomes a$b.
Then the defaults nobody writes down. -d 'a=1' makes curl send Content-Type: application/x-www-form-urlencoded that you never typed, and a converter that drops it turns a working call into a 415. Conversely curl does not follow redirects unless you pass -L, while Python requests follows them by default — so the faithful translation of a command without -L is an explicit allow_redirects=False, which is why you will see it in the Python tab on a plain GET.
And then the things a browser simply cannot do. Cookie and Accept-Encoding are forbidden header names: set them in fetch() and the browser deletes them without telling you. -k is worse than forbidden, it is absent — there is no browser API for skipping TLS verification, so the fetch tab says that in words rather than printing a plausible-looking option. A GET with a body, which curl will happily send, throws a TypeError in fetch(). Each of those is called out on the tab where it applies.
Honest limits, so you know when to stop trusting the output. Only the twelve flags listed above are converted; six more are refused by name, and everything else is reported as unrecognised rather than dropped. Only the first URL of a multi-URL command is converted, because curl makes one request per URL. Nothing on your disk can be read, so -d @body.json and -F 'photo=@cat.png' come out as markers you have to fill in. And curl sends its own User-Agent: curl/8.x and Accept: */* that none of the three targets will reproduce — if the server you are calling behaves differently per user agent, pin it with -H 'user-agent: …' before you convert.
Frequently asked
Does this page send my request anywhere? It never makes the request. The converter reads the text of your command and writes code — there is no call to the host in your URL, and what you paste stays in this tab.
Why does the fetch() output not skip certificate checks for -k/--insecure? Because browser fetch() has no way to. TLS verification is the browser’s decision, and no option, header or trick turns it off — so the fetch tab says so in words instead of emitting something that merely looks equivalent. Python and HTTPie do have real equivalents, verify=False and --verify=no, and those are emitted.
What happens to a flag this converter does not support? It is named, never dropped in silence. Six flags are refused with a stated reason — --proxy, --cert, --resolve, --interface, -o/--output and --retry — and anything else the parser does not recognise is listed as unrecognised. An option silently discarded produces a request that differs from the one you pasted, which is worse than a refusal.
Why is allow_redirects=False in the Python output when I did not ask for it? Because curl does not follow redirects unless you pass -L, while requests follows them by default. Writing allow_redirects=False keeps the Python call the same shape as your curl one; add -L and it becomes True.
Does it survive the quoting in a real Copy as cURL paste? That is the hard part, and it is why this is a character-by-character tokenizer and not a split on spaces. Single quotes, double quotes with their real escape set, trailing-backslash line continuations and $'...' ANSI-C quoting are all handled, so the '\'' idiom that puts an apostrophe inside a single-quoted JSON body comes out intact.
Can it read a file for -d @body.json or -F photo=@cat.png? No, and it says so rather than inventing content. A page in your browser cannot open a path on your disk. A -d @file body becomes a PASTE_CONTENTS_OF(...) marker, and a -F file field becomes an undefined FILE_FOR_ identifier in the fetch code — which throws a ReferenceError until you supply a real File or Blob — and a genuine open() call in the Python.