Quick verdict: cURL defaults to GET — you do NOT need -X GET. Just curl URL sends a GET. Query strings go in the URL (URL-encode special chars). Add headers with -H. The single most common mistake: using -X GET with -d at the same time, which forces a GET-with-body (some servers reject this, others convert to POST silently).
curl https://api.example.com/usersThat is it. No flag needed — cURL's default method is GET. The response body prints to stdout.
To see the HTTP headers too:
curl -i https://api.example.com/users # -i = include response headersJust the headers, no body:
curl -I https://api.example.com/users # -I = HEAD request (headers only)Note: -I changes the method to HEAD, not GET. For a GET that only shows headers, combine -i with -o /dev/null for the body and --silent to hide progress.
Append params directly to the URL:
curl "https://api.example.com/search?q=hello&page=1&sort=date"Always quote URLs with ? or & — bash interprets & as "run in background." Single or double quotes both work; double if you need shell variable expansion.
For dynamic values with special chars, use --data-urlencode with -G:
curl -G https://api.example.com/search \
--data-urlencode "q=hello world & more" \
--data-urlencode "page=1"-G tells cURL "use -d data as query string instead of POST body." cURL URL-encodes each value safely.
curl https://api.example.com/users \
-H "Accept: application/json" \
-H "Authorization: Bearer eyJhbGc..." \
-H "User-Agent: MyApp/1.0"Multiple -H flags add multiple headers. To remove a default header, send it empty:
curl -H "User-Agent:" https://api.example.com/users # removes UACommon GET headers worth knowing:
Accept: application/json — ask for JSONAccept-Language: en-US,en;q=0.9 — language preference (some sites return different content per language)Accept-Encoding: gzip, deflate, br — compress (use --compressed shortcut)If-None-Match: "etag-value" — conditional GET; server returns 304 if unchangedSend a cookie:
curl -b "session=abc123" https://example.com/dashboardRead cookies from / write cookies to a Netscape-format cookie jar:
# Save cookies to a file (after login GET that sets cookies)
curl -c cookies.txt https://example.com/login-step1
# Reuse those cookies on a subsequent request
curl -b cookies.txt https://example.com/protected-pageFor complex flows (login + scrape), the cookie jar handles session continuity across multiple GET calls.
By default cURL does NOT follow redirects — it shows the 301/302 response and stops. Add -L:
curl -L https://example.com/short-urlSee cURL follow redirects for the full details on max redirects, redirect-method behavior, and security gotchas.
Pipe to jq for pretty-printing and querying:
curl -s -H "Accept: application/json" https://api.github.com/users/torvalds | jq .
# Just the public_repos field
curl -s -H "Accept: application/json" https://api.github.com/users/torvalds | jq .public_repos-s (silent) hides the progress meter so jq parses cleanly. Combine with -S (-sS) to still show errors.
curl --proxy http://USER:[email protected]:8000 \
https://api.example.com/dataFor geo-locked APIs or rate-limited endpoints, route GETs through residential proxies. The --proxy flag works for HTTPS targets too — cURL CONNECTs through the proxy to reach the target.
Multiple GETs with rotating IPs:
for i in {1..10}; do
SID=$((RANDOM))
curl --proxy "http://USER-session-$SID:[email protected]:8000" \
https://target.com/page/$i
doneEach iteration uses a different sticky-session IP via the session-N token.
curl -s -o /dev/null \
-w "HTTP %{http_code}\nDNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTotal: %{time_total}s\n" \
https://api.example.comUseful for measuring real-world latency from your network. The %{var} tokens are listed in man curl under --write-out.
--resolve to bypass DNS.RFC 7231 says GETs should be safe (no state changes) and idempotent (same result every time). Do not use GET for:
Related: cURL POST, cURL basic auth, cURL timeout, Mastering cURL.