spyderproxy

How to Use cURL in JavaScript (2026)

A

Alex R.

|
Published date

Wed May 06 2026

Quick verdict: JavaScript has no native cURL — cURL is a system binary, not a JS library. The three alternatives in 2026 are fetch (built into browsers and Node 18+, standards-based), axios (third-party with cleaner API, interceptors, automatic JSON), and shelling out to real curl via child_process when you need exact flag compatibility. For 95% of cases, fetch is the right default.

This guide covers when to pick each, working examples for sync HTTP/POST/headers/body, plus how to add proxy support to all three patterns.

Option 1: fetch (Built-In)

Available in browsers and Node 18+. No install required.

// curl https://api.example.com/items
const r = await fetch("https://api.example.com/items");
const data = await r.json();

// curl -X POST -H "Content-Type: application/json" --data '{"a":1}' https://api.example.com/items
const r = await fetch("https://api.example.com/items", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ a: 1 }),
});

// curl -H "Authorization: Bearer xyz" https://api.example.com/profile
const r = await fetch(url, { headers: { "Authorization": "Bearer xyz" } });

For Node-specific options like custom agents (proxies, custom CA), import from undici in Node 18+:

import { fetch, ProxyAgent } from "undici";

const proxyAgent = new ProxyAgent("http://USER:[email protected]:8080");
const r = await fetch("https://api.example.com", { dispatcher: proxyAgent });

Option 2: axios (Third-Party)

npm install axios
import axios from "axios";

// GET — JSON parsed automatically
const { data } = await axios.get("https://api.example.com/items");

// POST — JSON serialized automatically, Content-Type set automatically
const r = await axios.post("https://api.example.com/items", { a: 1 });

// Through a proxy
const r = await axios.get("https://api.example.com", {
  proxy: {
    protocol: "http",
    host: "proxy.spyderproxy.com",
    port: 8080,
    auth: { username: "USER", password: "PASS" },
  },
});

// HTTPS-tunneling proxy (use https-proxy-agent for HTTPS targets)
import { HttpsProxyAgent } from "https-proxy-agent";
const agent = new HttpsProxyAgent("http://USER:[email protected]:8080");
const r = await axios.get("https://api.example.com", { httpsAgent: agent });

axios interceptors (auth refresh, retries)

axios.interceptors.response.use(
  r => r,
  async (error) => {
    if (error.response?.status === 401) {
      const newToken = await refreshAuthToken();
      error.config.headers["Authorization"] = `Bearer ${newToken}`;
      return axios.request(error.config);
    }
    throw error;
  }
);

This pattern (auth refresh on 401) is much harder to write with bare fetch — it's the main reason axios still has a large user base in 2026.

Option 3: Real curl via child_process

Use when you need exact curl-flag compatibility — porting curl-heavy bash scripts to Node, or using curl-impersonate for TLS fingerprint bypass.

import { execFile } from "node:child_process";
import { promisify } from "node:util";

const exec = promisify(execFile);

// curl -I -L -s https://example.com
const { stdout } = await exec("curl", [
  "-I", "-L", "-s",
  "-x", "http://USER:[email protected]:8080",
  "--max-time", "20",
  "https://example.com",
]);
console.log(stdout);

Pros: 100% curl flag compatibility, including HEAD requests, complex timeouts, multipart forms. Cons: slow (~50-100 ms process spawn per call), uses subprocess limits, harder to capture HTTP errors cleanly.

Which One to Pick

Use case Pick
Browser-side HTTPfetch (or axios)
Modern Node.js (18+)fetch
Need interceptors / auth refreshaxios
Need exact curl-flag compatchild_process + curl
TLS fingerprint impersonation (anti-bot)child_process + curl-impersonate
Streaming large downloadsfetch (Response.body) or axios responseType: 'stream'
High volume scraping (1000+ req/s)fetch with undici Pool