🏆 US-Registered Digital Marketing Agency Trusted by 200+ brands · USA · UK · Canada · AUS
Advertisement
Advertisement
DEVELOPER

cURL to Fetch Converter — paste a command, get JavaScript

Turn any curl command into working fetch() code with headers, body, basic auth, and cookies handled correctly.

Before you paste: curl commands copied from a browser or an API console usually contain live API keys, session cookies, and bearer tokens. This page never sends anything anywhere — the whole conversion runs in your browser — but treat any command you paste as a credential you have just put on screen.
Backslash line continuations, single quotes, and double quotes are all handled.
Converted request
GET
 
0
Headers set
0 B
Request body size
none
Credentials found
Flags not portable
Tip: some curl flags have no browser equivalent at all. --insecure cannot be expressed in fetch, and several headers are forbidden for scripts to set — the converter flags these rather than emitting code that silently does nothing.
Advertisement

A cURL to fetch converter solves a small, extremely repetitive problem. An API's documentation gives you a curl command. Your browser's network panel gives you a curl command. Your colleague's bug report gives you a curl command. What you need is JavaScript, and translating by hand means remembering which curl flags map onto which fetch options, which ones map onto nothing, and which ones quietly change behaviour when you drop them.

This page tokenises the command properly — respecting quotes and backslash continuations rather than splitting on spaces — reads the flags it understands, and emits fetch() code you can paste straight into a console or a module. Arb Digital's developers use it when integrating third-party APIs into client applications, which is most weeks. Everything happens locally in your browser and no request is ever made to the URL in your command.

What This cURL to Fetch Converter Does

It handles the flags that carry real meaning: -X and --request for the method, -H and --header for headers, the whole -d family including --data-raw and --data-binary for the body, -u for basic authentication, -b and --cookie for cookies, -F for multipart form fields, plus -A for user agent and -e for referer. Flags that only affect curl's own behaviour — output files, timeouts, retry counts — are recognised and skipped so they do not corrupt the parse.

The method is inferred when it is not stated, using the same rule curl does: a command with data and no explicit method is a POST, everything else is a GET. Multiple -d arguments are joined with &, again matching curl. If a body is present and no Content-Type header was given, the converter adds application/x-www-form-urlencoded, because that is the type curl sends by default and omitting it is a common cause of an API rejecting an otherwise correct request. Every one of these behaviours is described in the official curl manual page, which is worth checking whenever a flag in your command is not one the converter recognises.

The four supporting figures show how many headers were set, how large the request body is in bytes, what kind of credentials were detected, and how many flags could not be represented in a browser at all.

How to Use It

  1. Paste the full curl command, including any backslash line continuations. You can leave the leading curl in place or strip it — both work.
  2. Pick a code style. Async/await produces a compact block for a module or console; the .then() chain suits older codebases and inline snippets.
  3. Choose response handling — parse as JSON, read as text, or hand back the raw Response object when you need to inspect status and headers yourself.
  4. Click Convert to fetch() and read the "flags not portable" counter before the code. A non-zero value means something in the original command has no browser equivalent.
  5. Copy the code, then replace any placeholder credential before committing it anywhere.

How the Conversion Works

The first step is tokenising, and it is the step naive converters get wrong. A curl command is a shell command line, so -d '{"a": "b c"}' is a single argument even though it contains spaces, and a trailing backslash joins the next line rather than being part of a value. The tokeniser here walks the string character by character, tracking whether it is inside single or double quotes, handling backslash escapes inside double quotes only — matching shell rules — and emitting arguments at unquoted whitespace. Splitting on spaces instead would shred any JSON body immediately.

Once tokenised, each flag maps onto a fetch option. Headers become a plain object; note that duplicate header names collapse, since an object cannot hold two identical keys — if your command genuinely sends a header twice, use the Headers constructor with append instead. Basic auth from -u user:pass becomes an Authorization header built with btoa(), since fetch has no user and password parameters. Cookies from -b become a Cookie header alongside credentials: 'include', with an important caveat covered below. The full set of options and their defaults is documented in MDN's fetch API reference.

Advertisement

The Flags That Cannot Be Converted

Some curl behaviour is simply unavailable to a script running in a browser, and pretending otherwise produces code that fails in confusing ways. --insecure disables TLS certificate verification; there is no way to do this from JavaScript, and there should not be. --proxy routes through a proxy, which a page cannot control. --cert and --key supply a client certificate, which is a browser and operating system concern rather than a page-level one. Each of these is reported in the output as a comment rather than silently dropped.

--compressed is different: it is unnecessary rather than impossible. Browsers always send an Accept-Encoding header and always decompress responses, and scripts are forbidden from setting that header themselves. -L is similar — fetch follows redirects by default, so the flag maps to the default value of the redirect option and needs no code at all.

There is a broader category worth understanding. The Fetch specification defines a list of forbidden request headers that scripts may not set, including Cookie, Host, Referer, Origin, Connection, and anything beginning with Proxy- or Sec-. The browser controls these, and an attempt to set them from JavaScript is ignored without error. So a converted command that relied on a specific Referer or a manually supplied Cookie will behave differently from the original, and that difference is invisible unless you know to look for it.

Cookies, Credentials, and Cross-Origin Reality

The cookie case deserves its own explanation because it accounts for a large share of "the curl command works but my fetch doesn't" reports. In curl, -b 'session=abc' sends that cookie header verbatim. In a browser, you cannot set the Cookie header from script. What you can do is set credentials: 'include', which tells the browser to attach whatever cookies it already holds for that origin.

That works when the cookie is already in the browser's jar for the target origin. It does not work when you were relying on the command to inject a session that the browser does not have — that request is simply unauthenticated. And for cross-origin requests, credentials: 'include' only succeeds if the server responds with Access-Control-Allow-Credentials: true and an explicit origin in Access-Control-Allow-Origin rather than a wildcard.

The same-origin policy is the deeper point. curl has no concept of origins and no CORS restrictions, so a command that works perfectly from a terminal may be blocked outright in a browser. If the converted code fails with a CORS error, the conversion is correct and the constraint is architectural: the request needs to go through your own server. Our HTTP status code lookup is useful here, because a failed preflight surfaces as a status on the OPTIONS request rather than on the request you actually wrote.

Handling the Response Properly

One behaviour of fetch surprises nearly everyone coming from curl or from older HTTP libraries: a 404 or a 500 does not reject the promise. Fetch only rejects on network-level failures — DNS resolution, connection refused, CORS blocking. An HTTP error response is a perfectly successful fetch that happens to carry a 500 status, so code that only handles the rejection path will happily parse an error page as if it were data.

For that reason the generated code checks response.ok before parsing, which is the property that is true for statuses in the 200 to 299 range. It is three lines that prevent a whole class of silent failure. If you selected raw Response handling, the check is still emitted but the body is left for you to consume, which is the right choice when you need to branch on the status code or read response headers.

Bodies: JSON, Form Data, and Multipart

A JSON body from -d is emitted as a string, not an object, because fetch requires a string, a Blob, FormData, or similar — passing an object results in the body arriving as the literal text [object Object], which is a memorable debugging session the first time. If the body is valid JSON, the converter formats it readably inside a template literal so you can edit it in place.

Form-encoded bodies from --data-raw 'a=1&b=2' pass through as-is with the matching content type. Multipart bodies from -F become a FormData object with each field appended, and the converter deliberately does not set a Content-Type header for multipart requests — the browser must generate it, because it includes a boundary token that only the browser knows. Setting that header manually is the single most common multipart mistake and produces a request the server cannot parse. If you need to build or inspect the query string side of a request instead, the query string builder and URL parser handle that end.

Integrating a third-party API into your site?

Arb Digital builds API integrations that keep credentials server-side, handle errors properly, and do not fall over the first time the upstream service returns a 429.

Web Development Services Talk To Our Team

Common Mistakes to Avoid

  • Committing the converted code with a live token still in it — a curl command copied from an API console almost always contains a real key.
  • Passing an object as the body instead of a JSON string — the request arrives containing the text [object Object] and the server rejects it.
  • Setting Content-Type manually for multipart uploads — the browser must set it, because the boundary token is generated per request.
  • Assuming a non-2xx status throws — fetch resolves on 404 and 500, so always check response.ok before parsing.
  • Expecting a working curl command to work unchanged in a browser — CORS, forbidden headers, and the cookie jar all apply to fetch and none of them apply to curl.

Related Free Tools From Arb Digital

Take apart the request URL with the URL parser, assemble parameters with the query string builder, inspect a bearer token with the JWT decoder, check what a response code means with the HTTP status code lookup, tidy a JSON body with the JSON formatter, or pull the credentials out of a config file safely with our env file parser. More in the free online tools hub.

Frequently Asked Questions

Is my curl command sent to a server?

No. Parsing and code generation run entirely in your browser, and the tool never makes a request to the URL in your command. Nothing is uploaded or logged, though you should still treat any pasted token as exposed on screen.

Why does my converted fetch fail with a CORS error?

Because curl ignores the same-origin policy and browsers do not. If the server does not send the right Access-Control headers for your origin, the request must go through your own backend instead of the browser.

Can fetch set a Cookie header like curl's -b flag?

No. Cookie is a forbidden header for scripts. The converter emits credentials include instead, which sends cookies the browser already holds for that origin, but it cannot inject a cookie the browser does not have.

What happens to the --insecure flag?

It cannot be converted. There is no way for JavaScript to disable TLS certificate verification in a browser, so the flag is reported as non-portable rather than dropped silently.

Does fetch throw an error on a 404 or 500?

No. Fetch only rejects on network-level failures, so an HTTP error status resolves normally. The generated code checks response.ok before parsing, which is why that check is included.

How is the method chosen when the command has no -X flag?

The same way curl chooses it. A command with data and no explicit method is treated as a POST, and everything else defaults to GET.

Why is no Content-Type set for multipart form uploads?

Because the browser generates that header itself, including a boundary token unique to the request. Setting it manually produces a body the server cannot parse.

Advertisement
Advertisement

Take it further

Arb Digital assistant

👋 Hey! Want to grow your business? Ask me anything — a free marketing proposal is on the table!