๐ŸŽ‰ All Proxy Prices Reduced โ€” Save Up To36%newResidential Lite Proxies$0.50/GB
curl Follow Redirects: -L Flag, Options & Common Gotchas (2026)

curl Follow Redirects: -L Flag, Options & Common Gotchas (2026)

Last updated: 2026 ยท ~1,900 words ยท 9 min read

โšก Key Takeaways

  • By default, curl stops at the first 3xx response and prints the redirect body without following it.
  • Add -L (or --location) to follow redirects automatically โ€” this is the only flag most use cases need.
  • curl follows up to 50 redirects by default; control this with --max-redirs N.
  • POST becomes GET on 301/302/303 redirects โ€” use --post301, --post302, --post303 to preserve the method.
  • Auth headers are stripped on cross-host redirects โ€” use --location-trusted only on trusted destinations.
  • For scraping and automation, combining -L with a proxy routes the entire redirect chain through the same exit IP.

curl is deliberately conservative about redirects. When a server returns a 3xx response, curl stops, prints whatever body the redirect response contains, and exits โ€” it does not automatically follow the Location header to the new URL. For browser users this would be maddening, but for a command-line tool used in scripts, it is the safer default: scripts should explicitly declare their intent rather than silently following chains of unknown length to unknown destinations.

One flag changes that behaviour entirely. This guide covers -L in full โ€” what it does at the protocol level, every 3xx redirect code and how curl handles each one, the three documented gotchas that trip up experienced developers, and a complete reference of every redirect-related flag with practical examples for common use cases.

Default curl Behaviour Without -L

Without any redirect flags, curl fetches the response from the URL you specify and stops. If that response is a 3xx redirect, curl prints the redirect body (usually a small HTML page or an empty body) and exits with status code 0:

# Without -L: curl stops at the redirect
$ curl https://bit.ly/some-link
<html>
<head><title>301 Moved Permanently</title></head>
<body>
  <a href="https://final-destination.com">moved</a>
</body>
</html>

curl received the 301 response, printed its body, and exited. It did not request https://final-destination.com. This is not an error โ€” curl exit code 0 means the HTTP transaction completed successfully. The 3xx is a successful HTTP response; curl just is not following its instruction.

Following Redirects with -L

Add -L (long form: --location) to tell curl to follow the Location header whenever it receives a 3xx response:

# -L follows redirects to the final destination
$ curl -L https://bit.ly/some-link
<!DOCTYPE html>...  โ† content from the final destination URL

# Equivalent long form:
$ curl --location https://bit.ly/some-link

With -L, curl resends the request to whatever URL appears in the Location header, repeating this process until it reaches a non-3xx response or hits the redirect limit. As SpyderProxy's 2026 curl guide describes it: curl becomes "a redirect-following powerhouse" โ€” the -L flag is the only addition most use cases require.

3xx Redirect Codes: How curl Handles Each One

Not all redirects behave identically. The most important difference is whether curl changes the HTTP method (from POST to GET) on the redirected request:

301

Moved Permanently

Resource permanently moved to new URL. curl follows with -L.

POST โ†’ GET

302

Found (Temporary)

Temporary redirect. curl follows with -L.

POST โ†’ GET

303

See Other

Explicitly instructs client to GET the new resource. curl follows.

POST โ†’ GET (by design)

307

Temporary Redirect

Temporary redirect that preserves the original method and body.

Method preserved โœ“

308

Permanent Redirect

Permanent redirect with method preservation. The modern replacement for 301.

Method preserved โœ“

300

Multiple Choices

Server offers multiple options. curl follows if a Location header is present.

Method preserved โœ“

Method-change behaviour per ReqBin curl redirect reference; 307/308 semantics from MDN Web Docs HTTP 307.

The method-change behaviour of 301/302/303 is intentional per the HTTP specification, but it regularly surprises developers sending POST requests through redirect chains. If your API uses 301 or 302 redirects and your client is posting data, the data will be silently dropped on the redirect.

3 Gotchas Every Developer Hits With curl Redirects

โš ๏ธ Gotcha 1: POST Becomes GET

When curl follows a 301, 302, or 303, it changes the method to GET โ€” dropping the original POST body. This is standard HTTP behaviour, but it silently discards your form data or JSON payload mid-chain. Fix: use --post301, --post302, --post303 flags, or have your API use 307/308 redirects instead.

โš ๏ธ Gotcha 2: Auth Headers Stripped Cross-Host

If a redirect leads to a different hostname, curl strips Authorization headers and credentials from the follow-up request โ€” by design, to prevent credential leakage to unknown destinations. Fix: use --location-trusted only when you control and trust the entire redirect chain. Never use on user-supplied URLs.

โš ๏ธ Gotcha 3: Redirect Loops Hit the Cap

A misconfigured server that redirects Aโ†’Bโ†’A produces the error: curl: (47) Maximum (50) redirects followed. This almost always indicates a server-side loop, not a too-low limit. Fix: use -v to inspect the chain, then fix the loop rather than raising --max-redirs blindly.

Full Flag Reference: curl Redirect Options

Flag Long Form What It Does When to Use
-L --location Follow 3xx redirects automatically Almost always โ€” the base flag every redirect use case needs
--max-redirs N --max-redirs Set max redirects to follow (default: 50; -1 = unlimited) Scripts where you want a safety cap; set 5โ€“10 for most use cases
--post301 --post301 Keep POST method (don't switch to GET) on 301 redirects Submitting forms or JSON payloads through 301-redirecting endpoints
--post302 --post302 Keep POST method on 302 redirects Same as above for 302
--post303 --post303 Keep POST method on 303 redirects Rarely needed โ€” 303 explicitly asks clients to GET; only override if server is misconfigured
--location-trusted --location-trusted Send credentials to all redirect destinations, including cross-host Only on fully trusted internal redirect chains. Never on user-supplied URLs.
-v --verbose Show full request/response headers at each redirect hop Debugging redirect chains โ€” see every Location header in sequence
-I --head Fetch headers only (no body) at the final redirect destination Checking redirect target without downloading content
-w "%{url_effective}" --write-out Print the final URL after following all redirects Resolving shortened URLs or verifying redirect destinations in scripts
-c cookie.txt --cookie-jar Save cookies received across the redirect chain Authenticated redirects where session cookies are set early in the chain
-b cookie.txt --cookie Send saved cookies on each request in the redirect chain Maintaining session state across redirects that require cookies

Practical Examples: Every Common Redirect Scenario

Basic redirect following

# Follow redirects to the final destination
curl -L https://example.com/old-path

Limit redirect hops

# Follow at most 5 redirects โ€” good for production scripts
curl -L --max-redirs 5 https://example.com/redirect-chain

Inspect the full redirect chain

# See every Location header without downloading response bodies
curl -sIL https://bit.ly/some-link | grep -i "location\|http/"

# Full verbose โ€” every request and response header at each hop
curl -vL https://example.com/redirect 2>&1 | grep -E "^[<>] |HTTP/"

Find the final URL after all redirects

# Print only the final resolved URL โ€” useful for URL shortener resolution
curl -Ls -o /dev/null -w "%{url_effective}\n" https://bit.ly/some-link
https://final-destination.com/actual/path

Keep POST through 301/302 redirects

# POST data will NOT be dropped on the 301 redirect
curl -L --post301 --post302 \
  -H "Content-Type: application/json" \
  -d '{"key": "value"}' \
  https://api.example.com/old-endpoint

Download a file through a CDN redirect

# CDN endpoints almost always redirect to the actual file location
# -L is mandatory; -o saves to a file; -C - resumes partial downloads
curl -L -C - -o output.zip https://releases.example.com/latest.zip

Follow redirects with authentication

# Credentials sent only to the original host (secure default)
curl -L -u user:pass https://api.example.com/protected

# WARNING: --location-trusted forwards credentials to ALL redirect targets
# Only use on fully trusted internal redirect chains
curl -L --location-trusted -u user:pass https://internal.example.com/auth-redirect

Maintain cookie sessions across redirects

# Save cookies from the redirect chain to a file
curl -L -c cookies.txt https://example.com/login-redirect

# Send those cookies on the next request
curl -L -b cookies.txt https://example.com/dashboard

Follow redirects through a proxy

# The entire redirect chain routes through the proxy's IP
# Essential for scraping: all hops use the same exit IP
curl -L -x http://user:pass@proxy.nstproxy.io:8080 https://example.com/redirect

3 Real-World Scenarios

๐Ÿ“ฆ

Downloading Software Releases

GitHub and most CDN-hosted downloads use a two-hop redirect: the release URL redirects to a CDN-signed URL that expires after a few minutes. Without -L, curl downloads the HTML redirect page instead of the file. With -L -C -, curl follows the redirect and resumes interrupted downloads โ€” critical for large files on slow connections.

๐Ÿ”

Resolving URL Shorteners in Scripts

A monitoring script needs to resolve bit.ly or t.co URLs to verify they still point to valid destinations. Using curl -Ls -o /dev/null -w "%{url_effective}\n" resolves the full chain and prints the final URL without downloading any content โ€” a clean one-liner for batch URL resolution with no HTML noise in the output.

๐Ÿ•ท๏ธ

Web Scraping Through Redirect Chains

E-commerce product pages frequently redirect: http:// โ†’ https:// โ†’ canonical URL โ†’ localised URL. A scraper without -L only sees the first redirect body. More importantly, routing redirects through a proxy with -L -x proxy:port ensures all hops in the chain use the same residential IP โ€” preventing the target from seeing a series of requests from different IPs that would trigger bot detection.

Debugging Redirect Chains Methodically

When a redirect chain behaves unexpectedly, a structured debugging approach identifies the failure point faster than trial and error.

# Step 1: See the full chain โ€” all Location headers, no bodies
curl -sIL https://example.com/redirect | grep -i "http\|location"

# Step 2: Full verbose โ€” every request/response pair
curl -vL https://example.com/redirect 2>&1 | less

# Step 3: Confirm final destination
curl -Ls -o /dev/null -w "Status: %{http_code}\nFinal URL: %{url_effective}\nTotal redirects: %{num_redirects}\n" \
  https://example.com/redirect

# Step 4: Test without credentials to isolate auth issues
curl -vL https://example.com/redirect 2>&1 | grep -i "authorization\|location\|http/"

# Step 5: Check if proxy is affecting the chain
curl -vL -x http://proxy:port https://example.com/redirect 2>&1 | grep -i "location\|http/"

curl Redirect Flags in Python and Other HTTP Libraries

The concepts map directly to every major HTTP library โ€” understanding curl's flags helps when configuring redirect behaviour in code:

# Python requests โ€” follows redirects by default (opposite of curl)
import requests

# Disable redirect following (curl's default behaviour)
resp = requests.get("https://example.com/redirect", allow_redirects=False)

# Follow redirects with a proxy (equivalent to curl -L -x proxy:port)
proxies = {
    "http":  "http://user:pass@proxy.nstproxy.io:8080",
    "https": "http://user:pass@proxy.nstproxy.io:8080",
}
resp = requests.get("https://example.com/redirect",
                    allow_redirects=True,
                    proxies=proxies)
print(resp.url)  # Final URL after all redirects

Note the key difference: Python's requests library follows redirects by default (unlike curl). allow_redirects=False matches curl's no--L behaviour; allow_redirects=True (the default) matches curl with -L.

curl Redirect Flags for Web Scraping with Proxies

For web scraping pipelines, the proxy integration with redirect following has one non-obvious implication: with -L -x proxy:port, every hop in the redirect chain routes through the proxy. This is the correct behaviour for scraping โ€” you want all requests in the chain to appear as coming from the same residential IP, not for the final hop to originate directly from your machine.

Without a proxy, the final destination after following a cross-domain redirect sees your real IP โ€” potentially flagging the session as a bot if the originating IP was a residential proxy but the final request came from a datacenter. With -L -x proxy:port both hops go through the same exit IP, maintaining consistent session identity throughout the chain.

Nstproxy's residential proxies support this pattern natively โ€” HTTP and SOCKS5 endpoints that route all traffic including redirect chains through clean residential IPs. See the residential proxy overview and the proxy server tools guide for curl integration patterns.

Route curl Redirect Chains Through Clean Residential IPs

Nstproxy's 110M+ residential proxies integrate with curl via -x proxy:port โ€” every redirect hop routes through the same clean exit IP, maintaining session consistency across multi-hop chains.

Try Nstproxy for Free โ†’

Conclusion

curl's default behaviour of stopping at 3xx responses is a deliberate safety feature, not a limitation. Add -L to follow redirects; add --max-redirs 5 to cap the chain in production scripts; use -v to see every hop when debugging; use -w "%{url_effective}" to print the final URL without noise. The three gotchas โ€” POST-to-GET conversion, cross-host credential stripping, and redirect loops โ€” all have explicit flags that address them once you know they exist.

For scraping pipelines, the proxy integration is the most important operational detail: -L -x proxy:port routes the entire chain through the proxy's exit IP, maintaining consistent session identity across every hop. Without this, a multi-step redirect chain can expose your real IP at the final destination even when the initial request appeared to come from a residential proxy.

Frequently Asked Questions

Q1: How do I make curl follow redirects?

Add the -L flag (or its long form --location) to your curl command: curl -L https://example.com/redirect. This tells curl to follow the Location header whenever it receives a 3xx response. Without -L, curl stops at the first redirect and prints the redirect response body instead of the final content.

Q2: How many redirects does curl follow by default?

curl follows up to 50 redirects by default when using -L. You can change this limit with --max-redirs N โ€” for example, --max-redirs 5 to cap at 5 hops. Setting --max-redirs -1 allows unlimited redirects (use cautiously). If you hit the limit, you see the error: curl: (47) Maximum (50) redirects followed โ€” usually indicating a redirect loop.

Q3: Why does curl change my POST to GET when following a redirect?

When curl follows a 301, 302, or 303 redirect, it changes the method to GET and drops the request body โ€” this is standard HTTP behaviour per the specification. To preserve POST across these redirects, add the --post301, --post302, or --post303 flags. Alternatively, if you control the server, use 307 or 308 redirects instead โ€” these explicitly preserve the original method and body.

Q4: How do I see the full redirect chain with curl?

Use curl -sIL https://example.com | grep -i "http\|location" to see every redirect hop's status code and Location header without downloading bodies. For full verbose output including all request and response headers at each hop, use curl -vL https://example.com 2>&1 | less. To print only the final resolved URL after all redirects: curl -Ls -o /dev/null -w "%{url_effective}\n" https://example.com.

Q5: Does curl follow redirects when using a proxy?

Yes. When you combine -L with -x proxy:port, curl routes all redirect hops through the proxy โ€” every request in the chain uses the proxy's exit IP, not your machine's real IP. This is important for web scraping: without routing the full chain through the proxy, a multi-step redirect can expose your real IP at the final destination even if the initial request appeared to come from a residential proxy.

Nstproxy logoยฉ2026 NST LABS TECH LTD. All RIGHTS RESERVED.