scalpel@labs: ~/glossary/curl-follow-redirects.mdx5 sections

Follow Redirects with curl - Replay a Chain from the Shell

`curl -L <url>` follows redirects and prints each hop. Add `-I` to send HEAD requests (headers only), and `-sSIL` bundles silent mode, show-errors, HEAD, and location-follow into one command. That single line traces the whole chain from the shell with nothing but curl.

extension: Scalpel Redirectsupdated: 2026-08-14read_time: 2 min
less curl-follow-redirects.mdx

Why it matters

A terminal command is portable. Paste it into a GitHub issue, a CI script, or a colleague's shell and it behaves the same everywhere. It's also reproducible: no browser state, no UI, just the network fact.

But curl and a browser see different chains. Curl has no cookies, runs no JavaScript, and doesn't hold HSTS state. So a cookie-gated redirect, a JS redirect that your browser took, or an HTTPS upgrade the browser cached won't appear in curl. Spot that gap and you know whether to fix the server (the curl chain is wrong) or debug the page logic (the browser took a hop curl never saw).

How it works

curl -L tells curl to follow any 3xx response by reading the Location header and requesting the new URL, and to keep going until it reaches a 2xx or 4xx response. The -I flag sends HEAD requests instead of GET, which is faster (headers only, no body). The -s flag silences progress, -S tells curl to still show errors, and -I -L together trace the chain in silence.

The result is a list of status lines, one per hop:

HTTP/1.1 301 Moved Permanently
HTTP/1.1 302 Found
HTTP/1.1 200 OK

Add the -D - flag to also dump the response headers of each hop, or use -v for a verbose transcript that shows every detail.

What does not matter

You don't need to follow every hop manually with curl. The -L flag does it for you. You don't need cookies unless your chain is guarded by login. If curl's chain is shorter than the browser's, the missing hops are almost certainly JavaScript or cookie-gated redirects that curl can't see.

Curl also doesn't honour HSTS state like a browser does. If a site has an HSTS header and a cached policy in your browser, the browser upgrades http:// to https:// before it touches the network. Curl has no cache. So a curl chain starting with an explicit 301 http→https might look different from the browser's internal 307 upgrade.

Code example

Follow a chain and print status lines and headers:

curl -sSIL https://example.com/old-page

This outputs:

HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/old-page
...

HTTP/1.1 301 Moved Permanently
Location: https://www.example.com/new-page
...

HTTP/1.1 200 OK
...

To trace one hop without following:

curl -sS -D - -o /dev/null https://example.com/old-page

The -D - dumps headers to stdout, -o /dev/null discards the body, and without -L the command stops at the first redirect.

How Scalpel Redirects shows it

Each hop card in the chain has a "Copy as curl" button next to the URL. Click it to copy a one-liner that reproduces that single hop or the entire chain. The export menu offers "Copy chain as curl" for the whole journey. Paste into a terminal and you have a record of what the tool saw, in a format that's portable and scriptable.

Sources