How to convert a cURL command to JavaScript fetch
By Flavio
Turn a cURL command from API docs into JavaScript fetch code with a free converter, then fix what curl does differently: content types, CORS and cookies.
Free toolThis tutorial uses the cURL to Code. It runs in your browser, so open it in another tab and follow along.
To convert a cURL command to JavaScript fetch(), paste it into the cURL to code converter, pick the fetch() or Node fetch tab, and copy the code. The converter maps -X to method, every -H to an entry in headers, and -d to body.
That’s the mechanical part. The surprises come from what curl does on its own, like picking a content type, ignoring CORS and sending cookies. Let’s convert a real command and go through them.
How curl flags map to fetch
This is what the converter does with each flag it understands:
| curl | fetch |
|---|---|
-X POST | method: "POST" |
-H 'Accept: text/html' | an entry in headers |
-d, --data, --data-raw, --data-binary | body, and a GET becomes POST |
--data-urlencode 'q=hello world' | body with the value URL-encoded (q=hello+world) |
--json '{...}' | body, plus Content-Type and Accept set to application/json |
-u user:pass | an Authorization: Basic ... header |
-F name=value | a FormData body |
-b 'session=abc123' | a Cookie header |
-L | nothing, because fetch() follows redirects by default |
Repeated -d flags are joined with &, which is what curl does too. Flags it doesn’t know, like -s or -v, are skipped.
Convert a real command
GitHub’s REST API docs show this command to render Markdown to HTML:
curl -L \
-X POST \
https://api.github.com/markdown \
-H "Accept: text/html" \
-d '{
"text": "Hello **world**"
}'
Run it in a terminal and GitHub answers with HTML:
<p>Hello <strong>world</strong></p>
Now open the converter and paste the command as it is. The backslashes at the end of the lines are fine, and so is the body that spans several lines inside the single quotes.
The fetch() tab gives you this:
const response = await fetch("https://api.github.com/markdown", {
method: "POST",
headers: {
"Accept": "text/html",
"Content-Type": "application/x-www-form-urlencoded",
},
body: "{\n \"text\": \"Hello **world**\"\n}",
});
const data = await response.json();
console.log(data);
Above the code there’s a Notes box with two lines. One says -L isn’t needed. The other one is about that Content-Type header, which isn’t in the curl command.
Check the content type
curl sends -d data with Content-Type: application/x-www-form-urlencoded unless you set a type yourself. It’s in the curl man page, and you can see it in any request log. GitHub’s command doesn’t set one, so curl sends a JSON body labeled as a form.
The converter copies that behavior, so the code sends exactly what curl sends. GitHub accepts it, but many servers look at the content type before they parse the body. An Express app using express.json() skips any request that isn’t labeled as JSON, so your data never reaches req.body. That’s why the note tells you to add -H 'Content-Type: application/json' or use --json.
Replace -d with --json and convert again:
curl -X POST https://api.github.com/markdown \
-H "Accept: text/html" \
--json '{"text": "Hello **world**"}'
Now the body becomes JSON.stringify(...) and the header is "Content-Type": "application/json".
Read the response the right way
The generated code always ends with response.json(). That’s right for most APIs, but this endpoint returns HTML. Run the Node fetch version as it is and you get this error:
SyntaxError: Unexpected token '<', "<p>Hello <"... is not valid JSON
Change one line:
const data = await response.text()
and the script prints <p>Hello <strong>world</strong></p>, the same as curl.
While you’re there, add a status check. fetch() only rejects when the request can’t be made at all. A 404 or a 500 still resolves, so test response.ok:
if (!response.ok) {
throw new Error(`GitHub answered ${response.status}`)
}
The HTTP status codes reference tells you what each status means.
Browser or Node?
The fetch() tab is for code that runs in the browser. It uses top-level await, which works in a module script or in the DevTools console.
The Node fetch tab wraps the same call in an async function main(). fetch is global in Node.js 18 and later, so you don’t need to install anything. The same tool also has Node https and Python requests tabs.
What to watch out for
CORS only exists in the browser
curl doesn’t check CORS, so a command can work in your terminal and fail in the browser with a CORS error. When your page calls another origin, the browser only lets it read the response if the API sends Access-Control-Allow-Origin for your origin. Node’s fetch doesn’t check it. If you see the error, the CORS debugger helps you find the missing header, and my post on CORS explains the rules.
Keys in browser code are public
Stripe’s docs authenticate with -u and the secret key as the username. The trailing colon stops curl from asking for a password:
curl https://api.stripe.com/v1/customers \
-u sk_test_yourKey: \
-d [email protected] \
-d name=Flavio
The converter turns -u into "Authorization": "Basic c2tfdGVzdF95b3VyS2V5Og==". That string is the key in Base64, which anyone can decode. Put it in browser code and anyone can open DevTools and copy your secret key. Code like this belongs on your server, with the key in an environment variable.
Browsers don’t send a Cookie header
If the command has -b or a Cookie header, the converter adds a note. Browsers don’t let fetch() set the Cookie header, so the browser version won’t send it. Node’s fetch does send it.
Some curl options have no fetch version
-k turns off certificate checks. The converter warns you, because browser fetch() can’t do that. --compressed isn’t needed either, since fetch handles compression for you.
Already in the browser? Copy it as fetch
If the request comes from a web page, you don’t need curl at all. In Chrome DevTools, open the Network panel, right-click a request and pick Copy > Copy as fetch. The converter is for commands you find in API docs, terminals and READMEs. If someone sends you a command made with Copy as cURL, paste it as it is: the converter decodes the $'...' quoted strings that bash-style curl commands use for bodies with special characters.
To go the other way, from an API route to a curl command, use Route to curl. For the curl side, my curl guide to HTTP requests and the free curl course lesson on sending JSON cover the flags in more detail, and The Fetch API covers fetch.
Try the cURL to Code
Paste a curl command and get fetch(), Node.js, or Python requests code — headers, auth, form data, and JSON bodies handled.
Related tools
- Route to curl: Build curl, fetch(), and httpie commands from method, URL, params, headers, and JSON body — with copy button.
- CORS Debugger: Describe a cross-origin request and see simple vs preflight, the required response headers, and fixes for classic errors.
- HTTP Status Codes: Search HTTP status codes 1xx–5xx with plain-English meanings and practical when-to-use notes.
Want me to talk about your product? You can sponsor this site.