DevKitHub

API & Security

cURL to Code Converter — Python, JavaScript, Go and PHP

Paste a curl command, such as one from Copy as cURL in your browser's developer tools, and get code that sends the same request in Python, JavaScript, Node.js, Go or PHP.

5 lines
requests23 lines
  • The code contains credentials: the Cookie header. A request copied from browser developer tools carries your live session, so treat this code like a password — do not paste it into a gist, an issue or a chat.

Parsed request

Method
POST
URL
https://api.example.com/v1/orders
Headers
3
Body
JSON, 53 bytes
Redirects
not followed, as in curl without -L

This tool runs entirely in your browser. Your input is never uploaded, stored or logged.

How it works

A curl command is a line of shell, not a list of flags, and most converters go wrong before they reach curl's options. What curl receives is what is left after the shell has removed the quoting, joined the continuation lines and stopped at the first unquoted |, ; or &. So the command goes through a real shell word splitter: single quotes, double quotes, backslash escapes, and the $'...' strings Chrome's Copy as cURL writes whenever a value contains an apostrophe, a ! or a control character, down to \xHH, \uHHHH and octal escapes. Chrome's cmd format for Windows is read too, with cmd's ^ escapes removed before the C runtime's quoting rules are applied. PowerShell is refused with an explanation, because there curl is an alias for Invoke-WebRequest, a different program.

The options then mean what curl's manual says they mean. Repeated -d values are joined with & and --json values are not; -d @file reads a file and strips its newlines, while --data-raw gives @ no meaning; -G moves the data into the query string; -d and -F imply POST unless -X says otherwise, and -I means HEAD. Headers keep curl's order, duplicates included, and the ones curl adds because of an option — the form Content-Type that -d implies, the pair --json adds, the User-Agent from -A — are written out, because the libraries would not add them. The headers curl adds for itself, its own User-Agent and Accept: */*, are left to each library.

The code is written to send the same bytes. Strings are escaped for each language, and Python encodes a non-ASCII body to UTF-8, since requests would otherwise send it as Latin-1, or refuse it. A JSON body becomes a native object only when it survives the round trip; a duplicate key, or a number the language would rewrite, keeps it as text. Redirects are followed only with -L, because curl does not follow them and requests, fetch and Go's client do. -k becomes the library's switch where one exists, with a comment saying it disables certificate checks. What cannot be carried over — a file a browser cannot open, a shell variable, --proxy, -T, digest or NTLM authentication, a second request after --next — is named in a warning rather than dropped, and so is every credential in the code, since a copied browser request carries your session.

Common problems

Every example below is run against this tool in our test suite, so what it says here is what the tool actually does.

This is PowerShell, not curl.

Invoke-WebRequest -Uri https://api.example.com/items -Method POST
Why:
In Windows PowerShell, curl is an alias for Invoke-WebRequest, and Copy as PowerShell produces that cmdlet with its own -Uri, -Headers and -Body parameters. It is a different program, not a dialect of curl.
Fix:
Use Copy as cURL (bash) or Copy as cURL (cmd) in the developer tools instead. To run the real curl from PowerShell, call curl.exe.

A double quote is opened and never closed.

curl https://api.example.com/users -d '{"name":"O'Brien"}'
Why:
Nothing is special inside single quotes, a backslash included, so the apostrophe in O'Brien ends the quoted body early. The shell reads Brien as plain text and the next double quote as the start of a string that never closes.
Fix:
Write the apostrophe as '\'' (close, escaped quote, reopen), or use $'...' quoting, where \' is allowed. Chrome's copy uses the second.

You can only select one HTTP request method.

curl -d name=Ada -F avatar=@ada.png https://api.example.com/profile
Why:
-d sends a urlencoded body and -F a multipart one, and a request has only one body. curl refuses the combination with this message rather than choosing between them.
Fix:
Send every field with -F: name=value for text and name=@file for a file.

Only part of the query string reaches the server.

Why:
The URL was not quoted. An unquoted & ends a shell command, so curl received the URL only up to the first & and the shell ran the rest separately. The command is read here the same way, with a warning.
Fix:
Put the URL in single quotes: curl 'https://api.example.com/search?q=a&page=2'.

The server rejects a JSON body sent with -d, or reads it as a form.

Why:
-d sends Content-Type: application/x-www-form-urlencoded unless another type is given, whatever the body looks like, and the generated code sends the same header.
Fix:
Use --json, which sets Content-Type and Accept to application/json, or add -H 'Content-Type: application/json'.

Frequently asked questions

How do I copy a request as cURL from Chrome?
Open the developer tools, go to the Network panel, right-click the request and choose Copy, then Copy as cURL. On Windows Chrome offers a bash and a cmd version, and both can be pasted here. Copy as PowerShell produces Invoke-WebRequest instead, which is not curl.
Why does the Python code say allow_redirects=False?
Because curl does not follow redirects unless the command has -L, and requests does by default. Without it the code would behave differently from the command you tested. Add -L to the command if you want redirects followed.
Is it safe to paste a command with cookies or a token?
The command is converted in your browser and not sent anywhere. The code is another matter: a request copied from developer tools carries your session cookie or token, which is why each credential is listed in a warning. Remove them before the code goes into a repository, a gist or an issue.
Which Node.js version does the Node.js code need?
Node 18 or later, where fetch, FormData and Blob are built in, so there is nothing to install. It uses top-level await, so save it as an .mjs file or in a package with "type": "module".

Last updated