ScreenshotNeo

BlogHow-to

How to Extract Curl Requests from Chrome

Copy any Chrome network request as a reusable cURL command, understand its headers and tokens, and troubleshoot replay failures safely.

By the ScreenshotNeo team29 September 20269 min read

How to Extract Curl Requests from Chrome

Short answer: open Chrome DevTools before the request happens, select the Network panel, reproduce the action, right-click the request, choose Copy → Copy as cURL, then paste the command into a terminal or editor. Chrome records network traffic while DevTools is open, so opening it afterward will not recover an earlier request. The copied command can include cookies, authorization headers and temporary tokens; treat it as a secret until you have removed or replaced those values.

What “Copy as cURL” does

Chrome converts one recorded HTTP request into a shell command that uses curl. The command normally includes the URL, method, query string, request headers and, for requests with a body, the body data. That makes it useful for reproducing an API call outside the browser, documenting an integration, importing a request into an API client or diagnosing a server response.

The command is a snapshot of the request at capture time. It is not a permanent credential or a guarantee that the same request will work later. Session state, anti-forgery tokens, signed URLs and browser-only checks can expire or change.

Step-by-step: copy one request as cURL

  1. Open DevTools first. Use Ctrl+Shift+I (Windows/Linux) or Cmd+Option+I (macOS), then select Network. You can also open DevTools with the page context menu and choose Inspect. Chrome’s Network panel records requests while DevTools remains open. See the Chrome Network panel documentation.
  2. Preserve the right recording. Click the record button if it is not active. Enable Preserve log when navigation would otherwise clear the list. Clear old entries with the trash icon if you want an unambiguous capture.
  3. Reload or repeat the action. Reload the page, submit the form, open the dialog or perform the API operation that generates the request. Start with the action only after the Network panel is recording.
  4. Filter the list. Use the filter box for a path, domain or text. Use the type chips such as Fetch/XHR, Doc, JS, Img and Other. API calls are usually Fetch/XHR, while a page navigation is usually a document request.
  5. Inspect before copying. Click the candidate request and review Headers, Payload and Response. Check the request URL, method, query parameters and whether a body is present.
  6. Copy it. Right-click the request row, hover over Copy, and select Copy as cURL. Chrome puts the generated command on your clipboard. Paste into a terminal, a text editor or an approved API client.

Chrome documents the exact menu action as “Copy as cURL. Copy the request as a cURL command.” The menu is available from the request’s context menu in the Network panel; the wording can vary slightly by Chrome release.

Chrome records the request, then converts it into a terminal-ready cURL command.
Chrome records the request, then converts it into a terminal-ready cURL command.

Run and read the generated command

Paste the command into a shell without changing it first. Add -i to show response headers, -v for connection diagnostics, or -o response.bin to write a binary response to a file. For a readable API response, pipe JSON through a formatter when one is installed.

curl 'https://api.example.com/v1/items?limit=20' \
  -H 'accept: application/json' \
  -H 'authorization: Bearer REDACTED' \
  -H 'user-agent: Mozilla/5.0' \
  --compressed

# Show status and response headers
curl -i 'https://api.example.com/v1/items?limit=20' \
  -H 'authorization: Bearer REDACTED'

# Save a binary response
curl 'https://example.com/file.pdf' -o file.pdf

Look for these parts:

Part What it represents What to check
URL Host, path and query string Environment, IDs and expiring parameters
-X HTTP method GET, POST, PATCH or DELETE matches the operation
-H Request header Authorization, content type, origin and CSRF headers
--data/--data-raw Request body JSON or form encoding and current IDs
--compressed Accept compressed responses Usually safe to retain

Choose the right copy or export variant

Right-clicking a request exposes several related options. Choose the smallest export that answers your question.

Option Best for Trade-off
Copy as cURL One request you can replay in a terminal Contains only the selected request
Copy all as cURL Capturing every request currently listed Produces a long sequence and much unrelated traffic
Copy all listed as cURL Exporting only requests that match your current filters Filter mistakes can omit required calls
Copy as fetch Reproducing the call in browser JavaScript Browser origin and CORS rules still apply
Copy as fetch (Node.js) Starting a Node.js script May need Node-specific cookie or TLS handling
Copy as PowerShell Windows PowerShell workflows Quoting differs from POSIX shells
Export HAR Sharing a richer multi-request capture Can contain sensitive data and is less convenient to run

HAR export offers sanitized and sensitive-data modes. Sanitized HAR output excludes sensitive information such as Cookie, Set-Cookie and Authorization headers by default. Export sensitive data only to a trusted recipient and storage location.

Find the request you actually need

Modern pages can create hundreds of requests. A repeatable narrowing process prevents copying an analytics beacon or a preflight request instead of the API call.

  1. Clear the log.
  2. Turn on Preserve log if the action navigates.
  3. Filter by Fetch/XHR and type a distinctive path fragment such as /checkout or graphql.
  4. Perform the action once.
  5. Compare the method, URL and payload of the new rows.
  6. Inspect the Initiator tab when several calls look similar; it shows the script or request chain that triggered the call.
  7. Copy only after confirming the response contains the data or status you expected.

If the action involves a file download, look under Other or inspect the document request. If the page uses GraphQL, the endpoint may be the same for every operation, so the request payload’s operation name is the useful discriminator.

Sanitize a copied cURL command

Assume a copied command is sensitive. Before pasting it into a ticket, chat, repository or issue tracker, remove or replace:

  • Cookie and Set-Cookie values
  • Authorization, API keys and signed query parameters
  • CSRF or anti-forgery tokens
  • Personal identifiers, account IDs and private URLs
  • Request bodies containing names, addresses, payment data or internal content

Keep the header name and use a placeholder such as REDACTED_TOKEN. If you need to share a reproducible example, create a test account and issue a short-lived test credential. Do not assume deleting the visible token is enough: cookies can identify a session, and signed URLs can grant access until they expire.

Replay the request in code

For a stable integration, translate the captured request into code and load credentials from environment variables. The following examples show the same JSON request in cURL, Python and Node.js.

cURL

curl -X POST 'https://api.example.com/v1/items' \
  -H 'accept: application/json' \
  -H 'content-type: application/json' \
  -H "authorization: Bearer $API_TOKEN" \
  --data-raw '{"name":"example","enabled":true}'

Python

import os
import requests

response = requests.post(
    "https://api.example.com/v1/items",
    headers={
        "Accept": "application/json",
        "Authorization": f"Bearer {os.environ['API_TOKEN']}",
    },
    json={"name": "example", "enabled": True},
    timeout=30,
)
response.raise_for_status()
print(response.json())

Node.js

const token = process.env.API_TOKEN;
const res = await fetch('https://api.example.com/v1/items', {
  method: 'POST',
  headers: {
    'accept': 'application/json',
    'authorization': `Bearer ${token}`,
    'content-type': 'application/json'
  },
  body: JSON.stringify({ name: 'example', enabled: true })
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log(await res.json());

Postman supports importing a single cURL request copied from Chrome DevTools. Importing is useful when you need a graphical view of headers, variables, environments and saved collections.

Why a copied cURL command fails later

Symptom Likely cause Fix
401 or 403 Expired cookie, token or signed URL Authenticate again in an authorized test environment and replace the value with a fresh credential
419, 422 or “CSRF failed” Missing or stale anti-forgery token, origin or referer Capture the token-producing request and send the current token with the expected cookies
400 with validation errors Request body changed, was truncated, or has the wrong content type Compare Payload and Headers in DevTools; preserve JSON encoding exactly
Works in Chrome but not terminal Browser state, extensions, client certificates or CORS-related assumptions Inspect every cookie and header; test against a documented API endpoint when available
Empty response Wrong request selected, asynchronous follow-up not captured, or response depends on prior calls Clear the log, repeat the action and inspect the request chain and Initiator tab
SSL or DNS error Private hostname, corporate proxy or certificate only trusted by the browser Use the correct network or proxy configuration; do not disable certificate checks in production workflows
Shell syntax error Quoting copied for another shell or multiline continuation was altered Use the Chrome export for your shell, or place the command in a script and fix quote boundaries

Use curl -v to see DNS resolution, TLS negotiation, redirects and sent headers. Use -L only when following redirects is intended. Add --fail-with-body in automation so HTTP errors produce a failing exit status while retaining the response body for diagnosis.

Reliability, performance and cost considerations

A copied command is excellent for a one-off diagnostic, but production code should define timeouts, retries and idempotency deliberately. Set a connect and total timeout, retry only transient failures such as selected 5xx responses, and avoid retrying non-idempotent POST requests unless the API provides an idempotency key. Record status codes and request IDs without logging credentials or personal data.

Filtering before copying saves investigation time, while copying all listed requests can create a large, slow-to-review script. HAR is better for analyzing a complete page load; cURL is better for a single reproducible call. Network timing in DevTools is a measurement of that browser session, not a universal performance benchmark. Run repeated measurements from the deployment environment when latency matters.

cURL itself has no per-request charge. Any cost comes from the service you call, bandwidth, proxy usage or automation platform. Check the API’s pricing and rate limits before placing a copied command in a loop.

Or skip the browser setup

If your goal is a clean image or PDF of a URL rather than reproducing an application API call, ScreenshotNeo provides a single screenshot request. It handles the browser setup and exposes options for full-page or element capture, devices and viewports, dark mode, retina scale, custom CSS and JavaScript, waits, headers, cookies, geolocation, PDF output, caching, signed links, async jobs and bulk capture. See the ScreenshotNeo API documentation for the complete parameter list.

ScreenshotNeo clears common consent banners, popups and chat widgets before capture.
ScreenshotNeo clears common consent banners, popups and chat widgets before capture.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Before capture, ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server lets Claude, Cursor and other MCP clients use take_screenshot, get_page_info and capture_pdf. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots, and every feature is available on every plan. Create a free ScreenshotNeo account.

FAQ

Can I copy a request that already happened?

Only if it is still in the Network log. If DevTools was closed and the log was not preserved elsewhere, repeat the action with DevTools open.

What is the difference between “Copy all as cURL” and “Copy all listed as cURL”?

The first includes every request in the log. The second includes only rows currently visible after your filters.

Should I share a copied command in a bug report?

Only after removing cookies, authorization, tokens, private identifiers and sensitive request bodies. Prefer a test account and a short-lived credential.

Why does my cURL command need -L?

-L tells cURL to follow HTTP redirects. Add it when the final resource is intentionally behind a redirect; omit it when you need to inspect the first response.

Can Chrome copy requests as something besides cURL?

Yes. The Network panel also offers fetch, Node.js fetch, PowerShell and HAR export variants. Select the format that matches where you will inspect or run the request.