
Key takeaways
- A redirect chain is any URL that needs two or more redirects to reach its final page. Google's crawlers follow up to 10 hops, but Google's site-move guide says to redirect straight to the final URL, or keep chains to "ideally no more than 3" if you can't.
- Chains usually come from rules stacked on top of each other: HTTP to HTTPS, www to non-www, adding a trailing slash, then an old-URL rule from a migration.
- The free redirect chain checker and practice lab follows each URL one hop at a time and flags chains, loops, temporary redirects, dead ends and wrong destinations.
- On my own site it found a 3-hop chain and old URLs that returned 404 when linked without a trailing slash. The 404s are fixed; re-testing showed the chain comes from a second layer, and the worked example below shows both.
To find and fix redirect chains, list the URLs that redirect (old URLs, HTTP and www versions, links from other sites), follow each one hop by hop, then change every rule and internal link so it points straight to the final URL with a single permanent redirect. Re-test the same list afterwards: a fix in one rule often reveals another hop behind it.
One redirect is normal. A chain means each visitor and crawler makes extra requests before seeing the page, and every extra rule is another place for a mistake, such as a loop, a temporary redirect that should be permanent, or a hop that ends in a 404.
- What Google says about redirect chains
- Chains, loops and wrong destinations
- Where redirect chains come from
- Step 1: list the URLs to test
- Step 2: run the checker
- Worked example: redirect bugs on my own site
- Step 3: fix each type of problem
- Step 4: verify the fix
- Practise with the lab
- Frequently asked questions
What Google says about redirect chains
Google's documentation on HTTP status codes says that "by default, Google's crawlers follow up to 10 redirect hops." That's a limit, not a target. In its guide to site moves, Google is clearer: avoid chaining redirects and redirect to the final destination directly. If that isn't possible, keep the chain short, "ideally no more than 3 and fewer than 5," because chains add latency for users and not every browser or user agent supports long ones.
Two more details matter when you test:
- Google's inspection tools don't follow redirects. If you paste an old URL into URL Inspection in Search Console, you'll see the redirect, not the destination. Inspect the final URL separately.
- Redirecting many old URLs to one unrelated page, such as the homepage, "might be treated as a soft 404 error," according to the same site-move guide. A redirect should go to the closest equivalent page.
Chains, loops and wrong destinations
| Problem | What it looks like | Why it matters |
|---|---|---|
| Chain | A → B → C → final page | Extra requests and more rules that can break; over 10 hops Google stops |
| Loop | A → B → A | The page never loads; browsers show "too many redirects" |
| Dead end | A → B, and B returns 404 or 500 | The old URL's visitors and links go nowhere |
| Wrong destination | A → C when your redirect map says A → B | Visitors land on the wrong page; signals go to the wrong URL |
| Homepage dump | /old-product/ → / | Unhelpful for visitors; may be treated as a soft 404 |
| Temporary hop | A 302 or 307 inside a permanent move | Sends a mixed signal about which URL should be indexed |
Where redirect chains come from
Few people create a chain on purpose. They build up as separate rules are added at different times, often in different places:
- Host and protocol rules stacked in order: HTTP to HTTPS at the CDN, then www to non-www on the server, then a trailing slash added by the framework. Each rule is correct; together they make three hops.
- Migrations on top of migrations: a 2023 redesign redirected A to B, and a 2025 redesign redirected B to C, but nobody updated A.
- Changed slugs in a CMS: WordPress and Shopify can redirect old slugs automatically, and those redirects can chain when a page is renamed twice.
- Rules that only match one URL form: a rule for
/old-page/that doesn't catch/old-pagewithout the slash. - Internal links still pointing at old URLs, so every click starts with a redirect.
If you're mid-migration, the website redesign SEO checklist includes a redirect map template that prevents most of these.
Step 1: list the URLs to test
The checker needs a CSV with a url column. Add an expected_final column if you know where each URL should end up, for example from your redirect map. Good sources of URLs:
- Every old URL in your redirect map or
.htaccess/_redirectsfile. - Your most important pages in all their variants:
http://andhttps://, with and withoutwww, with and without the trailing slash. - URLs listed under "Page with redirect" in Search Console's page indexing report.
- Old URLs that other websites link to, from a backlink tool or Search Console's Links report.
Step 2: run the checker
Download the redirect chain lab, install Python 3.9 or newer and the requests package, then run:
python redirect_chain_check.py urls.csv --out results.csv
The script requests each URL without following redirects, records the status code and Location header, and moves to the next hop itself, up to 10 hops, like Google. For every URL it reports the full path, the final URL and status, and a verdict:
- OK: no redirect, or one permanent redirect to a working page that matches your expected destination.
- CHECK: a single temporary redirect (302, 303 or 307). That can be deliberate, for example a seasonal sale page, so confirm it.
- FIX: a chain, a loop, an error at the end, a deep URL sent to the homepage, an HTTPS-to-HTTP downgrade or an unexpected destination.
Worked example: redirect bugs on my own site
On 3 November 2026 I ran the checker on 12 variants of URLs on this site. Most were fine, but three were not:
| Requested URL | What happened | Verdict |
|---|---|---|
http://www.…/blog/local-seo-nepal-guide | 301 to https://www → 301 to the apex domain → 301 to add the slash → 200 | FIX: 3-hop chain |
http://www.…/local-seo-nepal-guide | 301 → 301 → 404 | FIX: chain ending in a 404 |
https://…/blog/best-seo-experts-nepal | 404 (the redirect rule only matched the URL with a trailing slash) | FIX: old URL not redirected |
The cause was three layers that each did one job: Cloudflare upgraded HTTP to HTTPS, a redirect sent www to the apex domain, and the static-asset layer added the trailing slash. Separately, the old-URL rules in my _redirects file were written as /old-post/, so a link to /old-post without the slash never reached them and returned 404.
The fix was in the Worker. Instead of passing each redirect straight to the browser, it now asks the asset layer where a URL ends up, following its redirects internally, and sends one 301 to the final page. For a 404 without a trailing slash, it tries the slash version before giving up. The core of it, simplified:
async function resolve(env, start, method) {
let url = new URL(start);
for (let hop = 0; hop < 5; hop++) {
// redirect: 'manual' so the asset layer reports each redirect instead of following it
const res = await env.ASSETS.fetch(new Request(url, { method, redirect: 'manual' }));
const location = [301, 302, 303, 307, 308].includes(res.status) && res.headers.get('Location');
if (!location) return { url, status: res.status };
url = new URL(location, url);
}
return { url, status: 0 };
}
One detail cost me a test run: a Request follows redirects by default, so without redirect: 'manual' the asset layer quietly returned the final page and the Worker never saw the hops. I deployed the change and re-ran the checker on the live site on 4 November 2026:
| Requested URL | Result |
|---|---|
https://…/blog/best-seo-experts-nepal | Fixed: one 301 to /blog/choose-seo-expert-nepal/, instead of 404 |
http://www.…/local-seo-nepal-guide | Better: now reaches the right page instead of a 404, but still in 3 hops |
http://www.…/blog/local-seo-nepal-guide | Not fixed: still 3 hops |
The 404s were gone, but the chain wasn't. Re-testing showed why: the www to apex redirect doesn't come from my Worker at all. My Worker only runs on the apex domain, so www is redirected by a Cloudflare rule that runs first and keeps the path exactly as requested. The Worker then adds the slash as a separate hop. I had assumed my code handled www because it contains a www branch, which is exactly the kind of assumption this check exists to catch.
The remaining fix is to make one layer responsible for www: route the www host to the Worker and remove the separate Cloudflare redirect rule, so the Worker can send one 301 straight to the final URL. That leaves at most two hops for http://www, because Cloudflare's HTTPS upgrade still runs first. Your own setup will differ, but the method is the same: find every layer that redirects, re-test after each change, and don't trust a fix until the checker confirms it on the live site. The full results, before and after, are in the results file (JSON).
Step 3: fix each type of problem
Flatten chains in your redirect map
For every rule, check where its target goes. If A points to B and B now points to C, change A to point to C. Sort your map by target URL and re-run the checker; any rule whose target is also a source in the map is part of a chain.
Combine host and protocol rules
Send HTTP, www and other variants to the final HTTPS URL in one step. On Apache, one rule can handle both protocol and host:
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [L,R=301]
On Nginx, point the HTTP server block and the www HTTPS block straight at the final host:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl;
server_name www.example.com;
# ssl_certificate lines here
return 301 https://example.com$request_uri;
}
If a CDN such as Cloudflare also upgrades to HTTPS, test the combination. The CDN may add its own hop before your server runs.
Catch both URL forms
Make old-URL rules match with and without the trailing slash (and, if your old site used them, with index.html or uppercase letters), and send each straight to the final URL.
Update internal links, canonicals and sitemaps
Redirects are for visitors and links you don't control. Your own navigation, body links, canonical tags and XML sitemap should use final URLs directly. The broken internal links guide shows how to find and fix links at their source.
Fix loops, dead ends and wrong destinations
- Loops: find the two rules that send URLs back and forth, usually a slash rule fighting another slash rule, or HTTP and HTTPS rules in different layers, and remove one.
- Dead ends: point the redirect at a working replacement. If there is no equivalent page, let the old URL return 404 or 410 rather than redirecting to something unrelated.
- Homepage dumps: map each old URL to its closest equivalent, such as the category for a discontinued product.
- Temporary hops: change 302 and 307 to 301 or 308 when the move is permanent. The 301 vs 302 guide explains when each is right.
Step 4: verify the fix
- Re-run the checker on the same CSV and compare the results files. Every FIX should now be OK, or a CHECK you have a reason for.
- In Search Console, inspect a few final URLs to confirm they're indexable. Remember that URL Inspection doesn't follow redirects from old URLs.
- Watch the page indexing report over the next few weeks. Old URLs listed as "Page with redirect" are expected; new 404s or "Redirect error" entries are not.
- If you have server logs, check that Googlebot's requests to old URLs now get one redirect. The crawl budget guide covers log analysis.
If traffic fell after a migration, use the post-redesign traffic drop guide alongside this check.
Practise with the lab
The download includes lab_server.py, a small local site with every problem above built in, and a urls.csv to test it. Start the server in one terminal and run the checker in another. You should see 9 URLs checked: 6 to fix and 1 to check.
| Lab URL | Problem | Verdict |
|---|---|---|
/old-page/ | None: one 301 to the right page | OK |
/chain-a | Three hops with a 302 in the middle | FIX |
/no-slash | Slash rule, then the real rule | FIX |
/loop-a/ | Loop between two URLs | FIX |
/retired-product/ | Sent to the homepage | FIX |
/moved-to-missing/ | Redirects to a 404 | FIX |
/wrong-target/ | Works, but not where the map says | FIX |
/sale/ | Deliberate temporary 302 | CHECK |
/new-page/ | No redirect | OK |
Frequently asked questions
How many redirects is too many?
Google's crawlers follow up to 10 hops, but Google recommends redirecting straight to the final URL and, if that isn't possible, keeping chains to ideally no more than 3. Aim for one redirect from any old URL to its final page.
Is HTTP to HTTPS a redirect chain?
No, a single HTTP to HTTPS redirect is one hop. It becomes a chain when another rule follows it, such as www to non-www or adding a trailing slash. Combine those rules so the first redirect goes to the final URL.
Should I update internal links if the redirects work?
Yes. Internal links, canonical tags and sitemaps should point to final URLs. That saves every visitor a redirect and avoids sending crawlers through rules that might change later.
Does the checker work on any website?
It works on any public URL, but use it on sites you own or manage and keep the list to a sensible size. It sends one request per hop and identifies itself in the user agent.
Sources and further reading
Planning a migration or cleaning up old redirects? See my technical SEO service.
Get in touch