The standard advice about redirect chains is built on a claim Google has repeatedly denied: that each hop "leaks link equity." That framing survives because it's easy to say and impossible for anyone outside Google to disprove. Meanwhile the costs that are observable — extra fetches, delayed discovery, hard hop limits, and canonicalization ambiguity — get less attention than they deserve.
If you fix chains for the wrong reason, you'll prioritize the wrong ones. A two-hop chain on a page nobody links to is noise. A four-hop chain sitting in front of every product URL in your sitemap is a crawl tax you pay on every recrawl, forever.
Where multi-hop chains come from
Nobody designs a five-hop redirect. Chains accumulate because redirect rules live in different layers that each run independently, and each layer only knows its own job.
A realistic stack:
- CDN edge rule upgrades
http://tohttps:// - CDN edge rule adds or strips
www - Application normalizes casing or strips a tracking parameter
- Framework router enforces a trailing slash
- A 2019 migration rule maps
/old-category/itemto/shop/item - A 2023 migration rule maps
/shop/itemto/products/item
Each rule is one 301. Request http://example.com/Old-Category/Item?utm_source=x and you get six. Nothing is broken — every hop returns a valid Location header — which is exactly why nobody notices. Browsers follow all of it in a few hundred milliseconds and users never see a problem.
Migration layering is the worst offender. Each migration adds a rule that points at the current URL rather than resolving against the final one, so chains grow by one hop per redesign and never shrink.
What Googlebot does when it hits a chain
Google's documentation on redirects describes a limit of 10 redirect hops. If Googlebot doesn't receive content within that limit, Search Console reports a redirect error, and the crawler resumes the chain on a later crawl rather than giving up permanently.
The practical mechanics matter more than the limit:
- Every hop is a separate HTTP request. A four-hop chain means Googlebot spends five fetches to retrieve one document. In Search Console's Crawl stats report, those show up in the "by response" breakdown as 301s — they are counted as crawl requests.
- Hops serialize. Each one costs a full round trip, so a chain inflates the time to first byte of the useful response. That feeds directly into the host-load side of crawl scheduling.
- Redirects are a canonicalization signal, not a directive. Google treats a redirect as a strong hint that the target is the canonical URL, but it still reconciles that against internal links, sitemaps, and
rel=canonical. A chain whose intermediate steps contradict your declared canonicals gives the system conflicting evidence. - JavaScript redirects wait for rendering. An HTTP redirect is resolved at fetch time. A
window.locationredirect isn't visible until the page is rendered, which can be minutes or days later.
Does a chain actually lose PageRank?
Google representatives, including Gary Illyes, have stated publicly that no PageRank is lost through 30x redirects, and John Mueller has repeated versions of that since. That's a statement from the vendor, not something anyone can independently verify, so treat it as a strong prior rather than proof.
Here's the decision rule that works regardless of who's right. If a redirect resolves cleanly and quickly to a relevant target, the signal question is almost certainly moot and your effort is better spent elsewhere. Worry when one of these is true instead:
- The chain has an intermediate hop that returns a 302 into a 301, or crosses hostnames more than once — canonical selection gets noisier.
- The final target isn't a close equivalent of the original. Google has documented that redirecting an irrelevant page to a generic destination (say, every retired product to the homepage) can be treated as a soft 404.
- The chain terminates in a loop or a 4xx. That's not a signal problem, it's a dead URL.
Not all redirect types behave the same
| Mechanism | Resolved at | Method preserved | Notes |
|---|---|---|---|
| 301 / 308 | Fetch time | 308 only | Permanent; strongest canonical hint |
| 302 / 307 | Fetch time | 307 only | Google may still consolidate if it persists |
meta refresh (0s) | Parse time | n/a | Google supports it; slower and weaker than HTTP |
JS location change | Render time | n/a | Requires rendering; worst for discovery latency |
rel=canonical | Indexing | n/a | Not a redirect; users still land on the old URL |
If you control the server, HTTP redirects are the only option worth defaulting to. The others exist for cases where you don't.
How to inventory your chains
The fastest single-URL check:
curl -sIL -o /dev/null \
-w '%{num_redirects} hops | %{time_total}s | %{url_effective}\n' \
'http://example.com/Old-Category/Item'
For full chain visibility, print every hop:
curl -sIL 'http://example.com/old' | grep -Ei '^(HTTP/|location:)'
At scale, run your crawler with redirect-following disabled so every hop is recorded as its own row, then join url → location repeatedly until you reach a non-3xx. That gives you chain length, terminal status, and loop detection in one pass. Following redirects silently is what hides the problem.
Then check the two places chains actually hurt:
- Log files. Count Googlebot requests by status per day. The ratio of 3xx to 200 responses is your crawl tax. Group the 3xx URLs by path pattern — chains are almost always template-wide, not per-URL.
- XML sitemaps. Any URL in a sitemap that returns a 3xx is a self-inflicted wound. Sitemaps should contain only final, canonical, 200-returning URLs.
What to fix, in order
- Flatten chains that sit in front of indexable templates. Rewrite old migration rules to point at the current final URL, not at the next rule in line. This is a config change, not a redesign.
- Remove 3xx URLs from sitemaps and internal links. Internal links to redirecting URLs are the largest avoidable source of 3xx crawl requests on most sites, and they're entirely under your control.
- Collapse normalization rules into one layer. Protocol, host, case, and trailing slash should be decided in a single rule that emits one
Location, not four chained ones. - Convert render-time redirects to HTTP redirects wherever a server or edge worker can make the decision.
- Re-measure with logs, not a crawler. A crawl tells you the chain exists; logs tell you how many times Googlebot paid for it last week.
Fix the chains that run across templates and sitemaps. Leave the orphaned two-hop ones alone — the measurable cost there is close to zero, and so is the payoff.