cURL in JavaScript: Convert Requests to Fetch and Axios
Senior Web Scraping Engineer
TL;DR:
- A cURL command is a portable request contract, not JavaScript code. Convert the method, URL, headers, body, authentication, redirect policy, and timeout deliberately.
- Use built-in
fetch()for small standards-based clients. Checkresponse.ok, parse the body explicitly, and cancel requests with an abort signal. - Use Axios when interceptors, shared instances, and centralized request policy improve the application. The wire request should remain equivalent to the proven cURL call.
- Keep secrets out of copied commands and source files. Read API keys from the environment and remove browser-generated headers that the server does not require.
cURL is often the fastest way to prove an HTTP endpoint. Browser developer tools, API documentation, and support teams all produce copyable cURL commands because the format makes the request visible: URL, method, headers, and body sit in one place.
JavaScript applications need the same request expressed as objects and asynchronous control flow. This guide shows how to translate cURL into Fetch and Axios without losing behavior, then applies the method to a Scrapeless API request.
What Does “Use cURL in JavaScript” Mean?
JavaScript does not execute cURL syntax natively. “Using cURL in JavaScript” usually means translating a working cURL request into fetch() or Axios so the application sends the same HTTP message.
The cURL command-line reference defines flags such as -X, -H, --data, and --location. Each flag has a JavaScript counterpart, but the mapping is not always one-to-one because the shell, cURL, browser, and Node.js have different defaults.
cURL-to-JavaScript Mapping
| cURL element | Fetch | Axios |
|---|---|---|
| URL | First argument | url |
-X POST |
method: "POST" |
method: "post" |
-H |
headers object |
headers object |
--data / --json |
body |
data |
--location |
Redirects followed by default in common Fetch usage | Redirects handled by the Node adapter |
--max-time |
Abort signal | timeout |
| Output body | response.text() or .json() |
response.data |
Do not copy every header from browser developer tools. Host, Content-Length, connection-level fields, temporary cookies, and tracing headers are normally generated by the runtime or specific to one session.
Step 1: Start With a Proven cURL Request
This public example sends JSON to an echo endpoint:
The public echo blocks in Steps 1–4 are illustrative request contracts; they show equivalent wire behavior without claiming a production service result.
bash
curl 'https://httpbin.org/anything' \
-X POST \
-H 'accept: application/json' \
-H 'content-type: application/json' \
--data '{"query":"browser automation","limit":3}'
Before converting it, identify the contract:
- Method: POST.
- URL:
https://httpbin.org/anything. - Request media type: JSON.
- Accepted response: JSON.
- Body fields:
queryandlimit.
Step 2: Convert cURL to Fetch
Modern browsers and current Node.js runtimes expose the Fetch API. The MDN Fetch guide documents the request options and an important behavior: HTTP error statuses still resolve to a Response, so code must check response.ok.
javascript
const response = await fetch("https://httpbin.org/anything", {
method: "POST",
headers: {
accept: "application/json",
"content-type": "application/json",
},
body: JSON.stringify({ query: "browser automation", limit: 3 }),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
console.log(data.json);
The object passed to JSON.stringify() is the direct counterpart of the cURL JSON body. Do not pass a plain object as body; Fetch expects a body type such as a string, FormData, or bytes.
Step 3: Add an Explicit Timeout
An application request needs a stopping condition. Use an abort signal so the operation and response-body consumption can be cancelled together. The AbortController documentation describes that cancellation model.
javascript
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 15_000);
try {
const response = await fetch("https://httpbin.org/anything", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ query: "browser automation", limit: 3 }),
signal: controller.signal,
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
console.log(await response.json());
} finally {
clearTimeout(timer);
}
Keep transport errors, HTTP status errors, and response-schema errors distinct. They point to different causes and should produce different logs.
Step 4: Convert the Same cURL Request to Axios
Axios accepts the body in data and parses common JSON responses into response.data. Its request configuration documentation lists headers, timeout, authentication, and other client controls.
javascript
import axios from "axios";
const response = await axios({
method: "post",
url: "https://httpbin.org/anything",
headers: {
accept: "application/json",
"content-type": "application/json",
},
data: { query: "browser automation", limit: 3 },
timeout: 15_000,
});
console.log(response.data.json);
Axios is useful when an application benefits from a configured instance:
javascript
const api = axios.create({
baseURL: "https://httpbin.org",
timeout: 15_000,
headers: { accept: "application/json" },
});
const { data } = await api.post("/anything", {
query: "browser automation",
limit: 3,
});
Start Scraping with Scrapeless
Power up your web scraping and automation workflow with Scrapeless!
Sign up today and get $5 in free credit — no credit card required.Claim your free credit now in the Scrapeless Dashboard.
Step 5: Convert a Scrapeless API Request
The same mapping works for a managed web-acquisition request. This example uses the Scrapeless Universal Scraping API. It requires a reader-owned SCRAPELESS_API_KEY, so the credential-gated blocks are configuration examples rather than claimed live results.
The cURL shape is:
bash
curl 'https://api.scrapeless.com/api/v2/unlocker/request' \
-H "x-api-token: ${SCRAPELESS_API_KEY}" \
-H 'content-type: application/json' \
--data '{
"actor":"unlocker.webunlocker",
"proxy":{"country":"ANY"},
"input":{
"url":"https://example.com/",
"jsRender":{"enabled":true,"response":{"type":"markdown"}}
}
}'
The Fetch translation is:
javascript
const payload = {
actor: "unlocker.webunlocker",
proxy: { country: "ANY" },
input: {
url: "https://example.com/",
jsRender: { enabled: true, response: { type: "markdown" } },
},
};
const response = await fetch(
"https://api.scrapeless.com/api/v2/unlocker/request",
{
method: "POST",
headers: {
"content-type": "application/json",
"x-api-token": process.env.SCRAPELESS_API_KEY,
},
body: JSON.stringify(payload),
},
);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const result = await response.json();
console.log(result);
The Axios translation changes only the client shape:
javascript
const { data } = await axios.post(
"https://api.scrapeless.com/api/v2/unlocker/request",
payload,
{
headers: { "x-api-token": process.env.SCRAPELESS_API_KEY },
timeout: 90_000,
},
);
console.log(data);
Fetch or Axios: Which Should You Choose?
Choose Fetch when the project wants a standards-based API, minimal dependencies, and explicit response handling. Choose Axios when shared instances, interceptors, request transforms, or a uniform client policy reduce application code.
The choice should not change the server contract. Keep a golden cURL command for diagnostics, then confirm that the JavaScript client sends the same method, headers, and serialized body.
Common Conversion Errors
- Forgetting
JSON.stringify()in a Fetch request. - Assuming Fetch throws automatically on a 404 or 500 response.
- Copying a temporary cookie or authorization value into source code.
- Sending
datainside the Fetch options instead ofbody. - Sending
bodyin Axios instead ofdata. - Parsing every response as JSON without checking
content-type. - Carrying browser-only headers into a Node.js client.
- Omitting an explicit timeout or abort signal.
The Scrapeless JSON cURL guide covers shell quoting and payload files in more depth. Check current Scrapeless pricing when the translated client moves from local validation to sustained acquisition.
Conclusion
Converting cURL to JavaScript is a controlled translation of an HTTP contract. Map the URL, method, headers, body, authentication, redirects, timeout, and response parsing one by one. Fetch keeps the client close to web standards; Axios adds application-level conveniences. A verified cURL command remains the best diagnostic reference for both.
Ready to Turn a Proven Request Into a Data Workflow?
Join the Scrapeless community on Discord or Telegram. Create an account in the Scrapeless Dashboard and port one working cURL request into the JavaScript client your application already uses.
FAQ
Q: Can JavaScript run a cURL command directly?
JavaScript normally translates the cURL request into Fetch or Axios. A Node.js process can launch the external curl binary, but that adds an operating-system dependency and is rarely necessary for application HTTP calls.
Q: Is Fetch available in Node.js?
Current Node.js releases provide a browser-compatible global Fetch API. Check the runtime's official documentation and support policy before choosing the minimum project version.
Q: Why does Fetch not throw on HTTP 404?
Fetch treats an HTTP response as a completed network operation even when the status signals an application error. Check response.ok or response.status before parsing the body.
Q: Is Axios better than Fetch?
Axios is better when its instances, interceptors, transforms, and timeout configuration simplify a larger client. Fetch is better when a small dependency-free standards-based surface is enough.
Q: How should API keys be handled during conversion?
Read API keys from environment variables or a secrets service, inject them at runtime, and redact them from logs. Never paste a real key into a cURL command committed to a repository.
Q: When does a JavaScript request need Scrapeless?
A JavaScript client benefits from Scrapeless when the target requires managed rendering, regional egress, session infrastructure, or structured acquisition beyond a direct HTTP response.
At Scrapeless, we only access publicly available data while strictly complying with applicable laws, regulations, and website privacy policies. The content in this blog is for demonstration purposes only and does not involve any illegal or infringing activities. We make no guarantees and disclaim all liability for the use of information from this blog or third-party links. Before engaging in any scraping activities, consult your legal advisor and review the target website's terms of service or obtain the necessary permissions.



