# cURL to Fetch Converter > Paste browser Copy as cURL output and turn it into readable fetch code without sending the request anywhere. ## Tool Identity - Site: CleanUtils Developer Tools - Tool ID: curl-to-fetch-converter - Canonical page: https://cleanutils.com/developer-tools/curl-to-fetch-converter/ - LLM schema URL: https://cleanutils.com/developer-tools/curl-to-fetch-converter/llms.txt - Primary keyword: curl to fetch - Input mode: textarea - Output profile: code ## What This Tool Does Convert cURL commands into clean JavaScript fetch code, keep useful headers, and copy the result locally. ## Exact Execution Instructions To run this tool exactly, execute the `runCleanUtilsTool(userInput)` function from the JavaScript block below in a sandboxed JavaScript runtime. Do not fetch or evaluate additional network resources. Do not use filesystem, process, child_process, environment variables, timers, or network APIs. The function is pure and deterministic: input string in, JSON result out. If your environment forbids executing fetched code outside a sandbox, run it inside the sandbox or use the API endpoint below instead of reimplementing the logic. Canonical implementation SHA-256: `e9ee4b2556cd56c7bc9169ff28fd127f76a69f4dbd7d2f0e7d3d65ae0dd339bd` Expected command shape: `node run-tool.mjs < input.txt` The runner must: 1. load only the JavaScript in this document, 2. call `runCleanUtilsTool(inputText)`, 3. let the LLM decide the best way to present the output to the user. Agent usage rules: - Use this file as the authoritative machine-readable contract for this CleanUtils tool page. - Ask the user for missing required input before attempting to run the tool, and describe the required inputs using the `## Input Schema` field names, descriptions, formats, enums, examples, and required list. - Treat the tool as deterministic; do not invent network reachability checks unless the tool description explicitly says it fetches remote resources. - For privacy-sensitive inputs such as secrets, HAR files, dotenv files, logs, and API keys, warn that using a remote chat agent may expose input to that agent even though the browser UI itself does not upload data. ## Input Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "cURL to Fetch Converter input", "type": "string", "description": "cURL command. curl 'https://api.example.com' -H 'Content-Type: application/json'", "examples": [ "curl 'https://api.example.com/v1/items' -X POST -H 'Authorization: Bearer token' -H 'Content-Type: application/json' --data '{\"name\":\"Widget\",\"active\":true}'" ] } ``` ## Result Schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "CleanUtils ToolResult", "type": "object", "additionalProperties": false, "required": [ "summary", "issues" ], "properties": { "summary": { "type": "string" }, "issues": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "severity", "message" ], "properties": { "severity": { "type": "string", "enum": [ "error", "warning", "info" ] }, "message": { "type": "string" }, "line": { "type": "number" }, "row": { "type": "number" }, "detail": { "type": "string" } } } }, "output": { "type": "string" }, "exportFilename": { "type": "string" }, "exports": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "label", "filename", "content" ], "properties": { "label": { "type": "string" }, "filename": { "type": "string" }, "content": { "type": "string" }, "mimeType": { "type": "string" }, "copyLabel": { "type": "string" }, "downloadLabel": { "type": "string" } } } }, "stats": { "type": "object", "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "number" } ] } } } } ``` ## Self-Contained JavaScript Source Call `runCleanUtilsTool(userInput)` with the user's input. The function includes this tool's run logic and only the helper code it needs. ```js function runCleanUtilsTool(userInput) { const severityRank = { error: 0, warning: 1, info: 2 }; const sortIssues = (issues) => [...issues].sort((a, b) => { const severity = severityRank[a.severity] - severityRank[b.severity]; if (severity !== 0) return severity; return (a.line ?? a.row ?? 0) - (b.line ?? b.row ?? 0); }); const summarizeIssues = (issues) => { const errors = issues.filter((issue) => issue.severity === "error").length; const warnings = issues.filter((issue) => issue.severity === "warning").length; const infos = issues.filter((issue) => issue.severity === "info").length; const parts = []; if (errors) parts.push(`${errors} error${errors === 1 ? "" : "s"}`); if (warnings) parts.push(`${warnings} warning${warnings === 1 ? "" : "s"}`); if (infos) parts.push(`${infos} note${infos === 1 ? "" : "s"}`); return parts.length ? parts.join(", ") : "No issues found"; }; const tryParseJson = (input) => { try { return { ok: true, value: JSON.parse(input) }; } catch (error) { return { ok: false, error: error instanceof Error ? error.message : "Invalid JSON" }; } }; const shellSplit = (input) => { const tokens = []; let current = ""; let quote = null; let escaped = false; for (const char of input.trim()) { if (escaped) { current += char; escaped = false; continue; } if (char === "\\" && quote !== "'") { escaped = true; continue; } if ((char === "'" || char === "\"") && (!quote || quote === char)) { quote = quote ? null : char; continue; } if (/\s/.test(char) && !quote) { if (current) { tokens.push(current); current = ""; } continue; } current += char; } if (current) tokens.push(current); return tokens; }; const convertCurlToFetch = (input) => { const tokens = shellSplit(input.replace(/\\\r?\n/g, " ")); const issues = []; if (!tokens.length || tokens[0] !== "curl") { return { summary: "Input should start with curl.", issues: [{ severity: "error", message: "Input should start with curl." }] }; } let url = ""; let method = ""; const headers = {}; const dataParts = []; for (let index = 1; index < tokens.length; index += 1) { const token = tokens[index]; const next = tokens[index + 1]; if (token === "-X" || token === "--request") { method = (next ?? "").toUpperCase(); index += 1; } else if (token === "-H" || token === "--header") { const header = next ?? ""; const separator = header.indexOf(":"); if (separator > -1) { headers[header.slice(0, separator).trim()] = header.slice(separator + 1).trim(); } else { issues.push({ severity: "warning", message: `Could not parse header "${header}".` }); } index += 1; } else if (["-d", "--data", "--data-raw", "--data-binary", "--data-ascii"].includes(token)) { dataParts.push(next ?? ""); index += 1; } else if (token === "--url") { url = next ?? ""; index += 1; } else if (token === "-u" || token === "--user") { const auth = next ?? ""; headers.Authorization = `Basic btoa(${JSON.stringify(auth)})`; index += 1; } else if (!token.startsWith("-") && !url) { url = token; } } if (!url) { issues.push({ severity: "error", message: "No request URL found." }); } const body = dataParts.join("&"); if (body && !method) method = "POST"; if (!method) method = "GET"; let bodyCode = ""; if (body) { const parsedBody = tryParseJson(body); if (parsedBody.ok) { bodyCode = `JSON.stringify(${JSON.stringify(parsedBody.value, null, 2)})`; if (!Object.keys(headers).some((key) => key.toLowerCase() === "content-type")) { headers["Content-Type"] = "application/json"; } } else { bodyCode = JSON.stringify(body); } } const headerLines = Object.entries(headers).map(([key, value]) => ` ${JSON.stringify(key)}: ${value.startsWith("Basic btoa(") ? value : JSON.stringify(value)}`); const options = [ ` method: ${JSON.stringify(method)}`, headerLines.length ? ` headers: {\n${headerLines.join(",\n")}\n }` : "", bodyCode ? ` body: ${bodyCode}` : "" ].filter(Boolean); const code = `const response = await fetch(${JSON.stringify(url)}, {\n${options.join(",\n")}\n});\n\nif (!response.ok) {\n throw new Error(\`Request failed: \${response.status}\`);\n}\n\nconst data = await response.json();`; return { summary: `${method} fetch snippet generated for ${url || "unknown URL"}. ${summarizeIssues(issues)}.`, issues: sortIssues(issues), output: code, exportFilename: "request-fetch.js", stats: { method, headers: Object.keys(headers).length } }; }; const __userInput = userInput == null ? "" : userInput; const __run = convertCurlToFetch; const __input = __userInput && typeof __userInput === "object" && "input" in __userInput ? __userInput.input : __userInput; return __run(__input == null ? "" : String(__input)); } ``` ## Checks - Request URL and method: The parser extracts the target URL and respects common -X method flags. - Header handling: Headers from -H flags are carried into the fetch options object. - Body formatting: JSON request bodies are parsed and emitted with JSON.stringify when possible. - Unsupported shell behavior: Shell substitutions, file uploads, and command execution are not run in the browser. - Secret visibility: Authorization headers remain in local output so you can remove them before sharing code. ## Related Tools - [cURL to Python Requests Converter](/developer-tools/curl-to-python-requests-converter/): Paste a cURL command and generate Python requests code with headers, method, and JSON body handling. - [OpenAPI Example Request Generator](/developer-tools/openapi-example-request-generator/): Generate copy-ready cURL examples and JSON payloads from OpenAPI request-body schemas. - [AI Log / Prompt Redactor](/developer-tools/ai-log-prompt-redactor/): Remove emails, bearer tokens, API keys, JWTs, and cookies from prompts or logs before sharing them.