How to Trace Redirects with cURL and Command Line
cURL commands for tracing redirects: follow redirect chains, view HTTP status codes, inspect response headers, and script bulk redirect checks. Copy-paste commands included.
cURL is the single best tool for tracing redirects. It shows you exactly what happens at the HTTP level — no browser cache, no cookies, no JavaScript interference. Just raw requests and responses.
Here is every cURL command you need for redirect debugging, from simple one-liners to scripted bulk checks.
The Essential Command
curl -sIL "https://example.com/old-page"
This follows the entire redirect chain and prints every response header. The flags:
-s— silent mode, suppresses the progress bar-I— HEAD request, fetches headers only (no body)-L— followLocationheaders (follow redirects)
The output shows each hop:
HTTP/2 301
location: https://www.example.com/old-page
HTTP/2 301
location: https://www.example.com/new-page
HTTP/2 200
content-type: text/html
Two redirects, then a 200. That is a redirect chain — and it should probably be flattened to one hop.
Extract Just the Status Codes and Locations
Full headers are noisy. Filter to only the status lines and Location headers:
curl -sIL "https://example.com/old-page" 2>&1 | grep -iE "^(HTTP/|location:)"
Output:
HTTP/2 301
location: https://www.example.com/new-page
HTTP/2 200
Clean, scannable, and easy to pipe into other tools.
Measure Redirect Timing
Every redirect hop costs time. Measure it:
curl -sIL -o /dev/null -w "redirects: %{num_redirects}\ntotal_time: %{time_total}s\nfinal_url: %{url_effective}\nfinal_code: %{http_code}\n" "https://example.com/old-page"
Output:
redirects: 2
total_time: 0.847s
final_url: https://www.example.com/new-page
final_code: 200
Time per redirect
For detailed per-hop timing, use --write-out with %{time_redirect} to see just the time spent on redirects, separate from the final response.
Follow Redirects with a GET Request
Some servers behave differently for HEAD (-I) vs GET requests. If you suspect this, use GET but discard the body:
curl -sL -o /dev/null -D - "https://example.com/old-page"
-D -dumps headers to stdout-o /dev/nulldiscards the response body
This sends a full GET request at each hop but still shows you all headers.
Limit the Number of Redirects
Prevent infinite loops from hanging your terminal:
curl -sIL --max-redirs 10 "https://example.com/old-page"
The default is 50 redirects. For debugging, 10 is more than enough — if a chain exceeds 10 hops, something is very wrong.
Redirect loops
If cURL exits with curl: (47) Maximum redirects followed, you have a redirect loop. Use -v (verbose) to see the loop pattern and identify which URLs are cycling.
Verbose Mode for Full Debugging
When you need everything — request headers, response headers, TLS handshake details:
curl -vL "https://example.com/old-page" 2>&1 | grep -E "^[<>*]"
Lines starting with > are sent by cURL (request). Lines starting with < are received from the server (response). Lines starting with * are connection info.
Send Custom Headers
Test how redirects behave with specific user agents or cookies:
# Test as Googlebot
curl -sIL -A "Googlebot/2.1" "https://example.com/old-page"
# Test with a specific cookie
curl -sIL -b "session=abc123" "https://example.com/old-page"
# Test with a custom header
curl -sIL -H "X-Forwarded-Proto: https" "https://example.com/old-page"
User-agent matters
Some sites redirect differently based on user agent — mobile vs desktop, bot vs human. Test with multiple user agents if you suspect this is happening.
Trace your redirect chains
Find redirect loops, broken chains, and unnecessary hops instantly.
Bulk Redirect Checking with cURL
Check a list of URLs from a file:
while IFS= read -r url; do
result=$(curl -sIL -o /dev/null -w "%{http_code} %{num_redirects} %{url_effective}" "$url")
echo "$url -> $result"
done < urls.txt
For a TSV-formatted report:
echo -e "original_url\tfinal_code\tredirects\tfinal_url"
while IFS= read -r url; do
curl -sIL -o /dev/null \
-w "$url\t%{http_code}\t%{num_redirects}\t%{url_effective}\n" \
"$url"
done < urls.txt
Speed Up Bulk Checks with xargs
Process multiple URLs in parallel:
cat urls.txt | xargs -P 10 -I {} curl -sIL -o /dev/null \
-w "{} -> %{http_code} (%{num_redirects} redirects) -> %{url_effective}\n" "{}"
-P 10 runs 10 requests concurrently. Adjust based on your connection and the target server's tolerance.
Compare Expected vs Actual Redirects
Create a CSV of expected redirects and validate them:
# expected.csv format: source_url,expected_destination
while IFS=, read -r source expected; do
actual=$(curl -sIL -o /dev/null -w "%{url_effective}" "$source")
if [ "$actual" = "$expected" ]; then
echo "PASS: $source -> $actual"
else
echo "FAIL: $source -> $actual (expected: $expected)"
fi
done < expected.csv
This is invaluable after site migrations. Export your redirect map, run this script, and catch every broken redirect before your users do.
cURL Flags Quick Reference
| Flag | Purpose | Example |
|---|---|---|
| -L | Follow redirects | curl -L url |
| -I | HEAD request (headers only) | curl -IL url |
| -s | Silent (no progress) | curl -sL url |
| -v | Verbose output | curl -vL url |
| -o /dev/null | Discard body | curl -Lo /dev/null url |
| -w FORMAT | Custom output format | curl -w '%{http_code}' url |
| -D - | Dump headers to stdout | curl -LD - url |
| --max-redirs N | Limit redirect hops | curl -L --max-redirs 5 url |
| -A AGENT | Set user-agent | curl -LA 'Googlebot' url |
Related Articles
cURL does not lie. It shows you exactly what the server sends, with no browser magic in between.
Never miss a broken redirect
Trace redirect chains and detect issues before they affect your users and SEO. Free instant tracing.