cURL · Code generation · Python · JavaScript

Convert cURL to Python, JavaScript and other code

Turn a cURL command into a request and then into Python, JavaScript or other code. Covers -X, -H, -d, --data-raw, -u, -F, -k, -L and --compressed, and copying cURL from browser devtools.

By · · 8 min read

To convert a cURL command to Python, JavaScript or another language, parse it into its parts (method, URL, headers, body, auth and options) and rewrite each part with the target library. In Swastik Codes you paste the cURL command into the URL bar or the import dialog, which turns it into an editable request, then open the Code snippet panel and pick one of 30 targets, including Python Requests, JavaScript fetch, Axios, Go, Java and C#. This guide shows both steps and explains what each common cURL flag means in Python requests and fetch, so you can also convert by hand.

Step 1: get a cURL command

You usually already have one: from API documentation, a teammate's message, a terminal history or a bug report. If the request comes from a website or web app, the browser can produce one for you.

Copy as cURL from browser devtools

  • Chrome and Edge: open DevTools (F12), go to the Network tab, reload or trigger the request, right-click it and choose Copy → Copy as cURL. On Windows there are two variants, Copy as cURL (cmd) and Copy as cURL (bash).
  • Firefox: in the Network tab, right-click the request and choose Copy Value → Copy as cURL. On Windows, Firefox also offers POSIX and Windows variants.
  • Safari: enable the Develop menu, open Web Inspector, go to Network, right-click the request and choose Copy as cURL.

A copied command contains every header the browser sent, including Cookie and Authorization. Treat it like a password: do not paste it into public issues or chat channels, and remove headers you do not need (sec-ch-ua, sec-fetch-*, priority and similar browser-only headers rarely matter to an API).

If you want many requests at once rather than one, save the whole Network log as a HAR file instead; Swastik Codes imports HAR files as a collection.

Step 2: import the cURL command

There are two ways in.

Paste into the URL bar. Open a new HTTP request in the app and paste the full command where the URL goes. It is recognised because it starts with curl, and the method, URL, query parameters, headers, body, auth and relevant settings are filled in. A short confirmation appears.

Use the import dialog. Open the command palette (Ctrl+K or Cmd+K) and run Import cURL / paste raw text…, or open Import and paste the text. The import dialog is the better choice for commands copied from Windows or for several commands at once:

  • It understands POSIX quoting ('…', "…" and $'…' strings) and ` line continuations, the cmd flavour with ^` escapes that browsers produce on Windows, and PowerShell backtick continuations.
  • Several commands in one paste become one collection with a request per command.
  • Anything it cannot carry over is reported as a warning instead of being dropped silently, for example a proxy (-x), client certificates (--cert, --key, --cacert) or a cookie file. Proxies and certificates are configured in the app's settings instead.

Here is a typical command to try:

Shell
curl -X POST 'https://httpbin.org/post?source=docs' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer abc123' \
  --data-raw '{"sku":"A-1","quantity":2}' \
  --compressed

After the import you have a POST request with a source=docs query parameter, two headers and a raw JSON body. Send it to check that it behaves as in your terminal. Sending from the web app needs a free account, and the target must be publicly reachable; for localhost see how to test a localhost API.

How each cURL flag is imported

cURL flagWhat it means in curlWhat the import does
-X, --requestSets the methodSets the request method
-H, --headerAdds a headerAdds a row on the Headers tab
-d, --dataSends data, implies POST; default type application/x-www-form-urlencodedBody as form fields, or raw JSON/text when the data is JSON or a content type says so
--data-rawLike -d, but @ is not treated as a file nameSame as -d, value kept as typed
--data-binarySends data exactly, no newline strippingRaw body, or a file body for @file
--data-urlencodeURL-encodes the valueForm field, encoded
--jsonJSON body plus JSON Content-Type and AcceptRaw JSON body and both headers
-F, --formmultipart/form-data field; @file attaches a fileform-data body with text and file fields
-u, --userBasic auth credentialsAuthorization tab set to Basic
--oauth2-bearerBearer tokenAuthorization tab set to Bearer
-b, --cookieSends cookiesCookie header (a cookie file is reported, not read)
-A, -eUser-Agent, RefererMatching headers
-G, --getPuts -d data in the query stringData appended to the URL
-I, --headHEAD requestMethod HEAD
-k, --insecureSkips TLS certificate verificationTurns off Enable SSL certificate verification for the request
-L, --locationFollows redirects (curl does not by default)Redirects are followed (the app's default)
-m, --max-timeOverall time limit in secondsRequest timeout
--max-redirsRedirect limitMaximum redirects setting
--compressedAsks for a compressed response and decompresses itAccepted; the engine already sends Accept-Encoding and decompresses

In the import dialog, --digest and --ntlm next to -u set the auth type to Digest or NTLM, and --http2 or --http1.1 set the request's HTTP version. Output-only flags such as -s, -v, -i, -o and -w are ignored because they only affect how curl prints.

File references need attention: the web app cannot read a path on your disk, so check file fields in the Body tab and select the file there before sending.

Step 3: generate Python, JavaScript or other code

With the request open, click the Code snippet button in the request toolbar (or run Generate code snippet from the command palette). Choose a language and copy or download the snippet. The 30 targets are:

LanguageTargets
ShellcURL, Wget, HTTPie, PowerShell (Invoke-RestMethod)
RawHTTP request text
JavaScriptFetch, Axios, jQuery, XHR
Node.jsnative http, Axios
PythonRequests, http.client
Gonet/http
JavaOkHttp, Unirest, java.net.http
C#HttpClient, RestSharp
PHPcURL, Guzzle
RubyNet::HTTP
SwiftURLSession
KotlinOkHttp
Darthttp
Rustreqwest
Clibcurl
Rhttr, RCurl
OCamlCohttp

Two options matter:

  • Resolve variables: on, {{baseUrl}} and {{token}} are replaced with their current values; off, the placeholders stay. Resolved snippets can contain real secrets.
  • Snippet settings: indent with spaces or tabs, the indent width, and whether to trim the request body.

The request's auth is applied in the snippet, including auth inherited from a folder or collection, so a Bearer token becomes an Authorization header. Generating code never sends the request. The code generation page has the details.

The round trip also works the other way: build or fix a request in the app, then pick cURL as the target to get a command for a terminal or a bug report.

Converting by hand: cURL to Python requests and fetch

If you only need one conversion, or want to understand what a generator produces, these are the equivalents for the common flags.

Method, headers and a JSON body (-X, -H, --data-raw)

Shell
curl -X POST https://api.example.com/v1/orders \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer abc123' \
  --data-raw '{"sku":"A-1","quantity":2}'
Python
import requests

resp = requests.post(
    "https://api.example.com/v1/orders",
    headers={"Authorization": "Bearer abc123"},
    json={"sku": "A-1", "quantity": 2},  # json= sets Content-Type: application/json
)
print(resp.status_code, resp.json())
JavaScript
const resp = await fetch('https://api.example.com/v1/orders', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'Bearer abc123',
  },
  body: JSON.stringify({ sku: 'A-1', quantity: 2 }),
});
console.log(resp.status, await resp.json());

Form data (-d)

curl -d 'name=Ada&role=admin' https://api.example.com/users sends application/x-www-form-urlencoded and uses POST because data is present.

Python
requests.post("https://api.example.com/users", data={"name": "Ada", "role": "admin"})
JavaScript
await fetch('https://api.example.com/users', {
  method: 'POST',
  body: new URLSearchParams({ name: 'Ada', role: 'admin' }), // sets the form content type
});

Basic auth (-u)

curl -u ada:secret https://api.example.com/me sends Authorization: Basic with ada:secret Base64-encoded.

Python
requests.get("https://api.example.com/me", auth=("ada", "secret"))
JavaScript
// Browser: btoa(); in Node.js use Buffer.from('ada:secret').toString('base64')
await fetch('https://api.example.com/me', {
  headers: { Authorization: 'Basic ' + btoa('ada:secret') },
});

File upload (-F)

curl -F 'title=Report' -F 'file=@report.pdf' https://api.example.com/upload sends multipart/form-data.

Python
with open("report.pdf", "rb") as f:
    requests.post(
        "https://api.example.com/upload",
        data={"title": "Report"},
        files={"file": ("report.pdf", f, "application/pdf")},
    )
JavaScript
const form = new FormData();
form.append('title', 'Report');
form.append('file', fileInput.files[0]); // a File or Blob
await fetch('https://api.example.com/upload', { method: 'POST', body: form });
// Do not set Content-Type yourself: the multipart boundary is added for you.

Insecure TLS (-k)

Python
requests.get("https://dev.internal/health", verify=False)  # or verify="/path/to/ca.pem"

fetch in a browser has no equivalent; the browser decides whether to trust a certificate. In Node.js you can pass a custom dispatcher from the undici package with connect: { rejectUnauthorized: false }. In every language, prefer trusting the specific CA over turning verification off.

Redirects (-L) and compression (--compressed)

curl does not follow redirects unless you pass -L. Python requests follows them by default (set allow_redirects=False to stop), and fetch follows them by default (redirect: 'manual' or 'error' to change that). Both libraries request compressed responses and decompress them automatically, so --compressed usually needs no translation.

Common conversion mistakes

  • Dropping the method change. -d or -F without -X still means POST. A converted GET with a body is a frequent bug.
  • Sending JSON as form data. -d '{"a":1}' without a Content-Type: application/json header is sent as application/x-www-form-urlencoded by curl. Many servers then reject it; add the header (or use --json) in the original command too.
  • Setting the multipart Content-Type by hand. The boundary must match the body, so let the library generate the header.
  • Quoting on Windows. Single quotes do not work in cmd. Use the browser's cmd variant or paste into the import dialog, which handles ^ escapes.
  • Leaking tokens. Generated snippets with resolved variables, and commands copied from devtools, contain live credentials. Rotate anything that ends up somewhere public.

Frequently asked questions

How do I convert a cURL command to Python requests?

Paste the command into a Swastik Codes request (URL bar or import dialog), open the Code snippet panel and choose Python - Requests. By hand: -X becomes the method function, -H the headers dict, -d the data argument (or json for JSON), -u the auth tuple, -F the files argument and -k verify=False.

How do I convert cURL to JavaScript fetch?

Import the command, then choose JavaScript - Fetch in the code snippet panel. By hand, -X maps to method, -H to headers, -d to body (a string, URLSearchParams or FormData), and Basic auth to an Authorization header you build yourself.

What is the difference between -d, --data-raw and --data-binary?

-d treats a leading @ as a file name and strips newlines from file contents. --data-raw sends the value as typed, even if it starts with @. --data-binary sends data exactly as given, including newlines, which matters for uploads.

Can I import several cURL commands at once?

Yes. Paste them together into the import dialog and each command becomes a request in one new collection.

Does Swastik Codes convert requests back to cURL?

Yes. Choose cURL in the code snippet panel. Other shell targets are Wget, HTTPie and PowerShell.

Is my cURL command sent anywhere when I convert it?

The import dialog parses the text with Swastik Codes' own importer (in the web app on the swastik.codes server, with an in-browser fallback; in the desktop app locally). The API named in the command is not called. Generating code never sends the request. Only pressing Send calls the API.

Try it on your own API

Swastik Codes runs in the browser and is free to use. Create an account to send requests, sync your workspaces and invite your team.