Converting cURL to Fetch, Axios, or Python Without Losing the Headers That Matter
A cURL command is the most reliable way to reproduce an HTTP request. It is also a terrible way to ship one in code. Converting between cURL, fetch, Axios, and Python requests is mechanical, but the mechanical part is where the subtle behavior lives, in headers, body encoding, and the defaults each client applies silently.
A cURL command is the standard way to share an HTTP request. You copy it from DevTools, from a colleague, or from a vendor's documentation, and it reproduces the request exactly. The problem starts when you paste that command into source code as if it were an API call. cURL is a debugging format, not a client library, and the conversion to fetch, Axios, or Python requests is where requests quietly change behavior.
What survives the conversion
The method, the URL, the headers, and the body all survive a careful conversion. These are the parts of the request that the server actually depends on, and a good converter preserves them verbatim. The Authorization header, the Content-Type, the custom X- headers, and the request body in whatever form it takes, JSON, form-encoded, or multipart, should all appear in the output unchanged.
Cookies are the first thing to check. A cURL command captured from a browser session often carries a Cookie header with a session token. Pasting that into application code hardcodes a session that expires. The converter preserves the header, which is correct for reproduction, but you then need to replace it with your application's auth flow before shipping.
The headers each client adds silently
cURL sends a small set of default headers, including User-Agent: curl/x.y.z and Accept: */*. fetch in a browser sends a much larger set, including a browser User-Agent, Accept-Language, and Sec-Fetch-* headers that the server may use for security checks. Axios sends its own User-Agent. Python requests sends yet another.
This matters because some servers branch on these headers. A request that works in cURL may fail in fetch because the server treats browser requests differently, or because a Sec-Fetch-Site header triggers a CSRF check. When a converted request behaves differently from the original cURL, the silent headers are the first thing to compare, not the body.
Body encoding is where conversions break
A cURL command with -d '{"a":1}' sends the body as application/x-www-form-urlencoded by default, even though the content is JSON. The server may accept it because it parses JSON regardless of Content-Type, or it may reject it. When you convert to fetch, the natural translation is body: JSON.stringify({a: 1}) with a Content-Type: application/json header, which is a different request from the original.
The same issue appears with form data. A cURL command with multiple -d flags sends form-encoded data. Converting that to a JSON body because it looks like key-value pairs is a different request. A careful converter preserves the original encoding: form data stays form data, JSON stays JSON, and the Content-Type header matches the body.
Multipart is the hardest. A cURL command with -F flags uploads multipart form data, which can include files. Converting that to fetch requires FormData objects, and converting to Python requires files= and data= arguments. If the converter drops a file field or converts it to a string, the upload breaks. Always check multipart conversions against the original request before trusting them.
The Content-Type header itself is a frequent source of drift. A cURL command with -H 'Content-Type: application/json' but no body, or a body that is not valid JSON, sends an inconsistent request that some servers reject and others tolerate. When you convert to fetch and set the header manually, you also have to remember that fetch sets Content-Type automatically for some body types and not others, and a duplicate header can appear. Read the converted output and confirm there is exactly one Content-Type, with the value the server expects.
The redirects and timeout defaults
cURL follows redirects only with -L. fetch does not follow redirects by default in the same way, and the redirect: 'follow' option changes the behavior. Axios follows redirects by default in Node but not in browsers. Python requests follows redirects by default.
These defaults mean a converted request may behave differently on a 301 or 302. If the original cURL command relied on -L to follow a redirect to a login page, the converted code may stop at the redirect and return a 302 instead of the final page. Check the redirect behavior explicitly when the original command used -L.
Timeouts are similar. cURL has no default timeout, so it hangs forever if the server does not respond. fetch has no default timeout either, but a browser's network stack may impose one. Axios and Python requests have configurable timeouts but no default. If the original command hung, the converted code will hang too, unless you add a timeout.
When to convert and when to rewrite
Conversion is the right move when you need to reproduce a specific request in code, typically for a one-off script or a test. The converted code preserves the exact request, headers and all, so the server sees the same thing it saw from cURL.
Rewriting is the right move when you are building a client for an API. The converted code carries debugging artifacts, hardcoded tokens, browser-specific headers, and body encodings chosen by whoever captured the cURL. A real client needs its own auth, its own error handling, and its own retry logic. Use the converted code to understand what the API expects, then write the client from scratch.
The Request tool on this site handles the mechanical conversion, preserving headers, body, and auth, so you can compare the cURL original against the fetch, Axios, and Python outputs and see exactly what changes. The comparison is the valuable part, because it shows you the silent differences before they become a production bug.
Primary references
Standards and official documentation used to check the technical details in this guide.
Convert cURL to fetch, Axios, or Python
The Request tool on this site parses a cURL command and emits fetch, Axios, or Python requests code, preserving headers, body, and auth. Runs in the browser, so the command never leaves your machine.
Open the Request toolRelated guides
Continue with practical guides from the same topic area.
What Actually Belongs in a Production Dockerfile for Node (and What Doesn't)
Most Node Dockerfiles in the wild copy node_modules into the image, run as root, and ship a 900 MB layer. A short guide to the few decisions that matter: base image, multi-stage builds, layer caching for dependencies, the NODE_ENV trap, and why your docker-compose should not mirror production.
Catching Missing Translation Keys and Interpolation Mismatches Before Users Do
A missing translation key renders the raw key path to users, and a mismatched interpolation parameter renders an empty string or a crash. Both are easy to miss in review because the developer's locale always has every key. A guide to comparing locale JSON files, finding missing keys, and catching parameter mismatches before they ship.
Mock Data That Actually Exercises Your UI (Not Just Fills It)
Most mock data is ten copies of the same row with a different id. It fills the page and tests nothing. A guide to generating mock data that exercises layout edge cases, long names, missing fields, empty states, and the date and number formats that break formatting code, with field inference so a sample JSON becomes a realistic dataset in one step.