What each status code actually does
The number matters more than most people assume. It controls whether browsers cache the redirect, whether the HTTP method survives, and whether search engines treat the move as permanent.
| Code | Cached by browsers | Method preserved | Use it when |
|---|---|---|---|
| 301 Moved Permanently | Yes, aggressively | No — POST becomes GET | The URL has moved for good and you accept that browsers will remember it |
| 302 Found | No | No — POST becomes GET | A genuinely temporary move, e.g. maintenance |
| 303 See Other | No | Always becomes GET | After a POST, to stop resubmission on refresh |
| 307 Temporary Redirect | No | Yes | A temporary move that must keep POST bodies intact |
| 308 Permanent Redirect | Yes | Yes | A permanent move on an endpoint that accepts POST |
The chain patterns that cost you
The four-hop canonical
The classic bad chain is http://example.com → https://example.com → https://www.example.com → https://www.example.com/. Each hop is a full round trip — DNS, TCP, TLS on the first HTTPS hop — and on a mobile connection that is easily half a second of dead time before a single byte of content moves. It also compounds: every asset behind the same rule pays the cost again.
Read the full explanation of redirect checker results ↓Show less ↑
Collapse it into one rule that jumps straight to the final canonical form. In nginx that is a single return 301 https://www.example.com$request_uri; in the port-80 server block for both hostnames, not a scheme redirect followed by a host redirect.
Redirect loops
Loops produce ERR_TOO_MANY_REDIRECTS and almost always come from a mismatch between what the origin thinks the scheme is and what the edge is actually serving. The textbook case: a CDN terminates TLS and forwards to the origin over plain HTTP, the origin sees http and redirects to https, the CDN serves that redirect, and round it goes. The fix is to make the origin trust X-Forwarded-Proto instead of inspecting the connection.
HTTPS downgrades
Any hop that goes from https:// to http:// is a defect. It exposes the request, breaks under HSTS (the browser will refuse the downgrade and the chain simply dies), and in mixed environments silently drops cookies marked Secure. This tool flags every downgrade it sees.
Meta refresh and JavaScript "redirects"
A chain that ends in a 200 but still lands somewhere else in a browser is redirecting in the HTML body — <meta http-equiv="refresh"> or location.assign(). Neither is an HTTP redirect: they are slower, they are not always followed by crawlers, and they do not pass through proxies the same way. If you see a 200 here but a different final URL in your browser, that is what is happening.
Redirects and SEO
- Google follows up to roughly 10 hops before giving up; well before that it stops consolidating signals cleanly. Keep chains to one hop.
- A 301 passes ranking signals to the target. A 302 signals "the original is still canonical", so long-lived 302s leave the old URL in the index.
- Redirecting everything to the homepage instead of the equivalent page is treated as a soft 404 and throws away the signals you were trying to preserve.
- Chained redirects across domains dilute more than a single hop:
old.com/page→new.com/pagein one step is materially better than routing through an intermediate. - Keep old redirects in place. Removing them a year later re-breaks every link that was pointing at the original URL.
Tracing a chain from the command line
curl -sIL -o /dev/null -w '%{http_code} %{url_effective}\n' http://github.com
# or, to see full headers for each hop:
curl -sIL http://github.com | grep -Ei '^(HTTP/|location:|server:)'
HTTP/1.1 301 Moved Permanently
location: https://github.com/
HTTP/2 200
server: github.comcurl -so /dev/null -w 'dns %{time_namelookup}s tcp %{time_connect}s tls %{time_appconnect}s ttfb %{time_starttransfer}s total %{time_total}s\n' \
https://example.comOne caution when testing: curl -I sends a HEAD request, and a surprising number of origins, WAFs, and CDNs handle HEAD differently from GET — different status, different headers, sometimes a 405. This tool issues real GET requests for that reason. If curl and this page disagree, re-run curl with -sL -o /dev/null -D - to force GET.
Once the chain is clean, check what the final response actually sends with the HTTP headers checker, and confirm the certificate on the HTTPS hop with the SSL certificate checker — an http→https redirect into a broken certificate is worse than no redirect at all.