HomeAboutServices PortfolioSkillsToolsBlog ClientsContact

Redirect chains: find, test and fix them

Orange detour sign with an arrow beside traffic posts at a street corner
Image: MarkBuckawicki (Wikimedia Commons) · CC0 1.0. Cropped and converted to WebP.

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

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

Redirect problems the checker looks for
ProblemWhat it looks likeWhy it matters
ChainA → B → C → final pageExtra requests and more rules that can break; over 10 hops Google stops
LoopA → B → AThe page never loads; browsers show "too many redirects"
Dead endA → B, and B returns 404 or 500The old URL's visitors and links go nowhere
Wrong destinationA → C when your redirect map says A → BVisitors 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 hopA 302 or 307 inside a permanent moveSends 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-page without 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/_redirects file.
  • Your most important pages in all their variants: http:// and https://, with and without www, 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:

Before: bikeshtamang.com.np, checked 3 November 2026
Requested URLWhat happenedVerdict
http://www.…/blog/local-seo-nepal-guide301 to https://www → 301 to the apex domain → 301 to add the slash → 200FIX: 3-hop chain
http://www.…/local-seo-nepal-guide301 → 301 → 404FIX: chain ending in a 404
https://…/blog/best-seo-experts-nepal404 (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:

After: live site, checked 4 November 2026
Requested URLResult
https://…/blog/best-seo-experts-nepalFixed: one 301 to /blog/choose-seo-expert-nepal/, instead of 404
http://www.…/local-seo-nepal-guideBetter: now reaches the right page instead of a 404, but still in 3 hops
http://www.…/blog/local-seo-nepal-guideNot 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

  1. 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.
  2. In Search Console, inspect a few final URLs to confirm they're indexable. Remember that URL Inspection doesn't follow redirects from old URLs.
  3. 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.
  4. 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.

Practice URLs and expected verdicts
Lab URLProblemVerdict
/old-page/None: one 301 to the right pageOK
/chain-aThree hops with a 302 in the middleFIX
/no-slashSlash rule, then the real ruleFIX
/loop-a/Loop between two URLsFIX
/retired-product/Sent to the homepageFIX
/moved-to-missing/Redirects to a 404FIX
/wrong-target/Works, but not where the map saysFIX
/sale/Deliberate temporary 302CHECK
/new-page/No redirectOK

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
B
Bikesh Tamang
SEO specialist and front-end developer in Kathmandu, Nepal. More about me →