What Is a Curl Command? The Ultimate Guide

TL;DR

  • A curl command is a command line tool for transferring data to and from a remote server, and it's usually the fastest way to test an API without writing any code.
  • Learn exactly what the curl command does: the basic URL syntax, sending custom headers, posting data, and picking an HTTP method.
  • Get curl command examples for secure API requests, including bearer tokens, HTTP basic authentication, and certificate verification.
  • Learn how to turn a browser request into a curl command, and when it's worth using something beyond curl.

Introduction

You'll commonly encounter curl commands in API documentation, a Stack Overflow answer, or a terminal tutorial. It's usually a dense-looking line starting with curl, followed by a URL and a handful of flags.

Here, you'll find out what a curl command actually is, what it does under the hood, and how to build one yourself. You'll also get real, runnable examples: a basic request, sending headers and data, authenticating securely, and even turning a request you've already made in your browser into a curl command you can reuse anywhere.

What is a curl command?

Curl stands for client URL. It's a command line tool for transferring data between your machine and a remote server using URL syntax. A curl command is any instruction you give that tool: it names a URL, then tells curl what to do with it.

You run curl commands from a terminal, whether that's a shell on Linux or macOS, or Command Prompt or PowerShell on a Windows version of curl.

It ships preinstalled on almost every modern operating system, so in most cases, you can open a terminal and start sending requests without installing anything.

The command line tool itself is simple by design, with no graphical interface, request history, or save button. Instead, it has direct, scriptable access to almost every network protocol you're likely to use as a developer, which is why it appears so often in documentation.

What does the curl command do?

At its core, curl connects to a remote server, sends a request, and displays the response, or saves it to a file if you tell it to. That's the entire job: request in, response out.

The basic URL syntax looks like this:

curl [options] [url]

If you don't specify an HTTP method, curl attempts a GET request by default. Here's the simplest possible curl command, one that fetches a page and prints its HTML to your terminal:

curl https://www.browserless.io

Run that, and curl connects to the host port for that remote server, sends the request, and prints whatever comes back. No browser window opens, and nothing gets rendered. You're seeing the raw response, exactly as the HTTP server sent it.

The protocols curl supports

Curl supports far more than just HTTP and HTTPS.

The same command line tool can handle file transfer protocol (FTP) transfers, secure copies, and lesser-used protocols like DICT, for querying dictionary servers.

The protocol curl uses is dependent on the scheme in the URL. A URL starting with ftp:// triggers curl ftp mode, a URL starting with dict:// triggers dict lookups, and so on.

You don't have to learn a new tool for each protocol, just a new URL – curl handles the transfer either way.

FTP upload is a good example of how little changes between protocols. Use -T to upload a local file, and curl handles sending it to the remote site:

curl -T report.txt ftp://ftp-server.example.com/uploads/

If the target file's directory doesn't exist yet on the remote server, add --ftp-create-dirs and curl creates the missing directories on the remote server before uploading.

Config files, environment variables, and defaults

Curl reads a config file automatically if one exists. Save options you use often, such as a default file to write output to, in a curlrc file (.curlrc) in your home directory, and curl applies them to every request without you retyping them.

Curl also respects environment variables like http_proxy and https_proxy. If your network routes through a proxy at a specific IP address and host port, curl picks that up on its own, so you don't need to repeat it in the request URL of every command.

Multiple URLs and multiple transfers

Curl can also fetch multiple URLs in a single command, making it useful when you want to run multiple transfers back to back:

curl https://www.browserless.io https://docs.browserless.io

Curl handles both on the same command line, one after the other, and shows a progress meter for each transfer so you can see the transfer speed as the files download.

How to use curl commands: the basics

Once you understand the request and response model, the rest of curl is really just options layered on top of that basic pattern. Here are the core building blocks you'll use in almost every curl command example you write.

Making a simple GET request

A GET request is curl's default behavior, so you don't need any extra flags to make one:

curl -X GET https://httpbin.org/get

The -X flag lets you set the HTTP method explicitly. It's optional for a GET request since it's the default, but it's good practice to include it once your commands start mixing methods, so anyone reading the command later knows exactly what it does.

Sending custom headers and a user agent

HTTP headers carry metadata about the request, and you'll often need custom headers to tell a server what format you want back, or to identify your client. Use -H to add one:

curl -X GET https://httpbin.org/get \
  -H "Accept: application/json" \
  -H "User-Agent: my-app/1.0"

These multi-line examples use the Bash line-continuation character (\). On Windows, run curl as curl.exe from Command Prompt or PowerShell, and either put the whole command on one line or use PowerShell's backtick (`) to continue lines.

Every request also sends a user agent whether you set one or not. Curl uses its own default (something like curl/8.x), which is an obvious sign of an automated request – some servers block it automatically.

Setting your own User-Agent header, as in the example above, is a common way to work around that.

Making a POST request and sending data

You use a POST request to create or submit something on the server, rather than just retrieve it. Use -d to attach a request body:

curl -X POST https://httpbin.org/post \
  -H "Content-Type: application/json" \
  -d '{"example": "value"}'

Curl assumes the POST method automatically once you include -d, so the explicit -X POST is technically optional here too, but it's clearer to leave it in.

The Content-Type header tells the server how to parse the body you're sending, which is necessary because a server that expects URL-encoded data may reject or misinterpret a raw JSON body, and the other way around.

Saving and inspecting responses

By default, curl prints the response to your terminal. To save it to a target file instead, use -o, followed by the given file name you want to write to:

curl -o page.html https://www.browserless.io

If you want to see the response headers as well as the body, without saving anything, add -i:

curl -i https://www.browserless.io

It's often the fastest way to confirm a request worked, before you even look at the body.

Curl command examples for secure API requests

Most real API requests need some form of authentication, and getting this part wrong is the most common reason a curl command that "should work" comes back with a 401 or 403 instead.

Here are the authentication methods you'll run into most.

Authenticating with a bearer token

Token-based authentication is the most common authentication method for modern APIs. Usually, you pass the token as an Authorization header:

curl -H "Authorization: Bearer YOUR_API_TOKEN_HERE" https://api.example.com/resource

Other APIs expect the token as a URL query parameter instead of a header. Browserless's REST APIs use this approach by default: append a valid token to the request URL (some endpoints also accept it in an Authorization header), like this real example against the Scrape API:

curl -X POST "https://production-sfo.browserless.io/scrape?token=YOUR_API_TOKEN_HERE" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "elements": [{"selector": "h1"}]}'

Both approaches are common authentication methods, so check the documentation for the specific API requests you're making rather than assuming one pattern applies everywhere.

HTTP basic authentication

HTTP basic authentication sends a username and password with every request, base64-encoded rather than encrypted, which is why it should only ever be used over HTTPS. Curl has a dedicated flag for it:

curl -u user:passwd https://httpbin.org/basic-auth/user/passwd

You'll also see HTTP digest authentication in older systems. Instead of sending the password itself, it hashes the password together with a challenge the server provides, so the credential is better protected than with basic auth. Even so, digest doesn't encrypt the rest of the exchange, so you should still run it over HTTPS for confidentiality and integrity.

Curl uses -u for the credentials either way, but add --digest to request digest auth specifically, or --anyauth to let curl detect and use whichever method the server supports.

Certificate verification

When you connect over HTTPS, curl verifies the server's TLS certificate by default, confirming you're actually talking to the remote server you think you are. If you're working with a private certificate authority, you can point curl at a specific certificate file:

curl --cacert ca-certificate.pem https://internal-api.example.com

For client certificate authentication, where the server needs to verify who you are as well, you'll pass both a client certificate and a private key, usually in PEM format:

curl --cert client-certificate.pem --key private-key.pem https://internal-api.example.com

It's tempting to use -k, which disables certificate verification entirely, whenever a certificate error comes up. Avoid it outside local debugging. Skipping certificate verification means curl will accept a connection from anyone claiming to be your server, which defeats the purpose of using HTTPS in the first place.

How to use curl for REST APIs

REST APIs are where curl crops up most often in a developer's day-to-day work, since a REST API is just a defined set of endpoints that respond to standard HTTP methods over HTTPS. REST APIs typically use GET to retrieve data and POST to create or process it. Browserless's REST APIs are all POST endpoints that take a JSON body, since the body is what tells the endpoint exactly what to do:

curl -X POST "https://production-sfo.browserless.io/content?token=YOUR_API_TOKEN_HERE" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/"}'

That single call fetches the fully rendered HTML of a page, JavaScript included, in one request.

Reading the response status is a fast way to catch problems early: a 4xx points to something wrong with your request, and a 5xx means the problem is on the server's end, not yours. With Browserless, a 200 only means Browserless accepted the request – the target page's own status comes back separately in the X-Response-Code and X-Response-Status headers, so an endpoint can return 200 even when the page itself returned a 403 or 404. If you're scripting against it, add --fail-with-body so curl exits nonzero on an HTTP error while still printing the response body.

Building these requests by hand works fine for one or two endpoints, but it gets tedious once you're testing dozens of parameter combinations.

That's exactly the gap Browserless's REST API Playground is built to close. You build a request visually, choosing the browser, region, and parameters through a UI, and it generates a ready-to-copy curl command from what you configured.

You can run it straight from the playground against production infrastructure, or copy the curl command out and drop it into your own codebase or terminal. It's the same curl command you'd have written by hand, just without the trial and error of getting the flags right.

How to convert browser requests into curl commands

You don't always have to build a curl command from scratch. If you've already made the request once in a browser, you can usually export it directly.

Open your browser's developer tools, go to the Network tab, and reload the page. Right-click any request in the list and look for an option like "Copy as cURL," which turns the exact request your browser just made, including its headers, cookies, and any post data, into a curl command you can paste straight into your terminal. One caveat: a copied command can carry your session cookies, Authorization header, and CSRF tokens inline, so redact anything sensitive before you share or commit it – and think twice before replaying an authenticated write request.

It's a genuinely useful trick when you're trying to reproduce a browser-only bug from the command line, or when you want to automate a request that a site doesn't publicly document, since you're reusing the exact request the site itself is making.

Browserless takes the same idea further with BrowserQL, our GraphQL-based query language for browser automation. Once you've built an automation flow in the BrowserQL IDE, such as navigating to a page and pulling a value off it, you can export that flow with Export as Code – as a curl command or a request in the language of your choice:

curl --request POST \
  --url 'https://production-sfo.browserless.io/chromium/bql?token=YOUR_API_TOKEN_HERE' \
  --header 'Content-Type: application/json' \
  --data '{
    "query": "mutation Example { goto(url: \"https://example.com\", waitUntil: domContentLoaded) { status } text { text } }"
  }'

The above is a browser automation query, not just a plain REST call, exported as a single curl command that works from any language or tech stack. It's the same underlying idea as copying a request from your browser's network tab, just applied to a full automation flow instead of a single page load.

For sites with bot detection, swap /chromium/bql for the /stealth/bql route, which adds anti-detection capabilities.

Benefits and limitations of curl

Benefits of curl

Curl earns its place in almost every developer's toolkit for a few clear reasons.

  • Preinstalled everywhere – a curl example runs the same on a teammate's machine as on yours.
  • Scriptable – a natural fit for CI pipelines, cron jobs, and quick debugging when something breaks in production.
  • Protocol coverage – it supports many network protocols beyond HTTP and HTTPS, so one tool covers most of what you'd otherwise need several different clients for.

That reach shows up in the numbers: as libcurl, the same tool runs inside cars, TVs, routers, and mobile phones, putting it in over twenty billion installations worldwide.

Limitations of curl

Curl has real limits too.

  • No JavaScript – it doesn't render JavaScript, so it can't help when the data you need only appears after a page's own scripts run.
  • No persistent session – it doesn't hold a browser session either. Save received cookies with -c and send them back with -b, but even that isn't a substitute for a real, stateful session that keeps you logged in across a multi-step flow.
  • Readability – a command chaining several flags, headers, and a JSON body gets hard to read and maintain, especially once you're managing dozens of them across a team.

Those limits are protocol-dependent rather than a flaw in curl itself. It was built to transfer data over a network, not to run a browser, and it does the job it was built for well.

Three alternatives to curl

For a lot of day-to-day API requests, curl is genuinely the fastest option, though a few alternatives are worth knowing about for when you need more than a single command line request:

  • Postman or a similar GUI client – Better suited to saving and organizing a large collection of requests, especially across a team, and for visually inspecting response headers and bodies without reading raw terminal output.
  • A language's own HTTP library – requests in Python, fetch in JavaScript, or similar, when the request needs to be part of a larger program rather than a one-off check.
  • A real browser session – For the JavaScript-dependent pages curl can't handle, you need something that runs a real browser, whether that's your own Puppeteer or Playwright setup or a managed option like Browserless's Scrape API, which renders the page and extracts the data for you.

Conclusion

A curl command is ultimately a request-in, response-out tool: you name a URL, tell curl what to do with it, and it hands back exactly what the server sent.

If you want to see that same pattern applied to real browser automation instead of a single request, sign up for a free Browserless account and try the REST API Playground. Build a request visually, copy the curl command it generates, and you'll have a working example of your own within a couple of minutes.

Curl command FAQs

Is curl a programming language?

No. Curl is a command line tool, not a programming language. It's also available as libcurl, a library that programming languages like Python, PHP, and Java can call directly, which is why you'll sometimes see curl mentioned inside actual application code rather than just a terminal.

What's the difference between curl and wget?

Both are command line tools for transferring data over a network, but they're built for different jobs.

Wget is built around downloading files, including recursively downloading an entire site, and can resume an interrupted download automatically. Curl is built around making single requests to a server and supports a far wider range of options for headers, authentication, and HTTP methods, which makes it the better choice for testing APIs rather than just downloading files.

Can you use curl on Windows?

Yes. Curl has shipped as a built-in command in modern Windows versions since Windows 10's 1803 update, so you can run it directly from Command Prompt or PowerShell without installing anything extra.

Do you need an API key to use curl?

Not always. Curl itself doesn't require an API key. Whether a specific request does depends entirely on the API you're calling. Some public endpoints are open, while most production APIs require a key or token, usually passed as a header or a URL query parameter, so the provider can identify who's calling and enforce their own usage limits.