All fix guides
WarningLinks & Crawlability

How to Fix Redirect Chains and Loops

This audit bundles seven redirect problems: chains of multiple hops, loops that never resolve, temporary (302/307) redirects standing in for permanent moves, internal links pointing at a redirecting URL instead of the final one, JavaScript redirects many crawlers never execute, and http-to-http redirects that skip the upgrade to https. Each wastes crawl budget or user time in a different way, but the fix is the same shape for all seven: point every link straight at the final destination and use one correctly-typed server-side redirect to get there.

What this means

Your audit groups seven distinct redirect problems under one umbrella because they share a root cause: a request for a URL doesn't resolve cleanly to a final destination in a single hop. Each has its own signature.

A redirect chain is A to B to C: the browser or crawler has to follow two or more hops before landing on the real page. A redirect loop is worse, A to B back to A (or a longer cycle that eventually revisits a URL already seen), so the request never resolves at all. temporary_redirect flags a 302 or 307 used on a URL that has actually moved for good, where a 301 is the correct code. redirect_internal_link means one of your own links, in navigation, a footer, body copy, or the sitemap, points at a URL that itself redirects instead of the final address. javascript_redirect means the jump happens via window.location or a client-side router rather than an HTTP status code, so it only fires for crawlers that execute JavaScript. external_redirect flags an internal-looking link that, after following redirects, ends up on a different domain entirely. http_to_http_redirect means a redirect exists but keeps the request on plain http instead of upgrading it to https.

Severity varies a lot within this one bundle. A true redirect loop is close to a broken page: browsers give up and show a connection error, and crawlers abandon a URL that keeps redirecting without ever reaching a final page. A single 302 that should be a 301 is, by comparison, a minor cleanup item. This guide treats all seven together because the remedy looks the same in every case: find the real endpoint, point everything at it directly, and use one correctly-typed server-side hop if a redirect is still required at all.

Why it matters

Every extra hop costs something. For crawlers, each redirect is a separate HTTP request that has to be fetched and followed before the real page is reached, so chains eat into the crawl budget search engines allocate to a site, which matters most on large sites where thousands of URLs compete for the same allowance. For users, each hop adds round-trip latency; a three-hop chain on a slow mobile connection is a visibly slower click, and it directly hurts Core Web Vitals like Largest Contentful Paint, since the browser can't even start requesting the real page's resources until the chain finishes resolving.

Redirect loops are the most serious item in this group because they're a dead end, not just a slow path. A looping URL returns nothing useful to a user or a crawler. Browsers cap how many hops they'll follow and then show an error, and any traffic or link equity aimed at that URL is wasted until the loop is broken.

Using 302 or 307 for a permanent move is a smaller but real issue. Google has gotten better over the years at inferring a redirect is effectively permanent if it's left in place long enough, but that inference isn't guaranteed or instant, and other systems, analytics tools, link-sharing platforms, Bing, don't necessarily draw the same conclusion. If a move is permanent, say so with a 301 rather than relying on an algorithm to guess your intent correctly.

The JavaScript-redirect and AI-crawler angle deserves its own callout, since this tool is built around exactly that gap. Googlebot does eventually execute JavaScript, but on a second, separate rendering pass after its initial crawl, so a JS-only redirect can leave a stale or empty page representing you in search results for a period before rendering catches up. Many AI crawlers, including bots associated with ChatGPT, Perplexity, and similar answer engines, fetch raw HTML and are far less likely to execute your JavaScript at all. A redirect that only fires through a script may be functionally invisible to them: they see whatever sits on the old URL, not your destination content. If a redirect needs to be followed by every kind of bot, it has to be a real HTTP status code, not a script.

How to fix it

  1. 1

    Map every redirecting URL to its true final destination

    For each flagged URL, follow the chain by hand with curl -IL https://example.com/old-url, which prints every hop's status code and Location header until it reaches a 200. Note the final URL. If a hop's Location header points back to a URL already earlier in the list, you've found a loop rather than a chain, and that's the priority fix.

  2. 2

    Update internal links to point at the final URL directly

    Search your templates, navigation, sitemap, and body content for links to any intermediate URL in the chain, and repoint them straight at the final destination. This is the single highest-value fix here: it removes the redirect hop entirely for your own traffic and crawl requests instead of merely shortening it, and it's the direct fix for redirect_internal_link.

  3. 3

    Collapse the remaining chain to one server-side hop

    For links you don't control, old backlinks, bookmarks, external references, you still need something answering at the old URL, so replace the multi-hop chain with a single redirect straight from the old URL to the final destination. Make this change at the server or redirect-management layer (.htaccess, an Nginx block, your CMS's redirect tool, or Cloudflare), not by stacking yet another hop on top of the existing ones.

  4. 4

    Use 301 for permanent moves, 302 or 307 only for genuinely temporary ones

    If the old URL is retired for good, the redirect should return a 301. Reserve 302 or 307 for cases that really are short-lived, such as a page down for maintenance or a seasonal redirect you intend to reverse later. Getting this right matters for search engines and for any tool, analytics, a CDN, a browser, that behaves differently depending on the status code returned.

  5. 5

    Replace JS-based redirects with real HTTP redirects, and force https on every hop

    If a redirect currently runs through window.location, a router push, or a meta refresh, move it server-side so it fires as an HTTP 301 or 302 before any HTML is served; that's the only reliable way to guarantee non-JS crawlers and AI bots follow it. At the same time, confirm every http version of a URL redirects straight to the https final destination in one hop, not to an intermediate http URL. For anything flagged external_redirect, confirm the off-site destination is actually intended; if a link used to point at a resource that's since been sold, expired, or repurposed by someone else, update or remove the link rather than leaving it pointed at an unrelated domain.

Example

# Diagnose a chain: -I (headers only), -L (follow redirects), each hop printed
curl -IL https://example.com/old-page

# BAD: three hops before the real page, including a wrong 302 and a stray http hop
HTTP/1.1 301 Moved Permanently
Location: https://example.com/old-page-2

HTTP/1.1 302 Found
Location: http://example.com/final-page

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

HTTP/1.1 200 OK

# GOOD: one hop, correct type, straight to the https final URL
HTTP/1.1 301 Moved Permanently
Location: https://example.com/final-page

HTTP/1.1 200 OK

curl -IL shows every hop in a chain. The fix collapses three hops, including a wrong 302 and a stray http hop, into a single 301 straight to the final https URL.

Platform-specific steps

WordPress (Redirection plugin / Yoast / Rank Math)

Install the free Redirection plugin, or use the redirect manager built into Yoast SEO Premium or Rank Math, and search its log for any redirect whose target is itself another redirect. Edit those entries to point straight at the final URL and set the type to 301 unless the move is genuinely temporary. Also check theme and menu settings for hardcoded links to old URLs that bypass the redirect manager entirely.

Cloudflare

Open Rules > Redirect Rules (or Bulk Redirects for many URLs at once) and look for rules that chain into each other, where one rule's destination matches another rule's source. Consolidate them into a single rule per old URL pointing at the true final destination, and set the status code to 301 for permanent moves.

Nginx / Apache

Search .htaccess or your Nginx server blocks for multiple Redirect / RedirectMatch (Apache) or return 301/302 (Nginx) lines that feed into one another, and rewrite them as one direct rule per old path. Apache: Redirect 301 /old-path https://example.com/final-page. Nginx: return 301 https://example.com/final-page; inside the matching location block.

Next.js

Check next.config.js under redirects() for entries whose destination is itself a source in another entry, and collapse them into one rule with permanent: true for real moves. If a redirect currently happens client-side via router.push() or window.location, move it into redirects(), middleware, or NextResponse.redirect() in a route handler so it's a real HTTP redirect instead of a script.

Frequently asked

Should I use a 301 or 302 redirect?

Use a 301 when the move is permanent, meaning the old URL is gone for good and you want ranking signals and bookmarks to transfer to the new one. Use a 302, or 307, its stricter HTTP/1.1 equivalent, only when the redirect is genuinely temporary, such as maintenance or a short-lived test, and you plan to restore the original URL later. Search engines and browsers can treat the two differently for caching and indexing, so choose based on actual intent rather than habit.

How many redirects can a browser or crawler follow before giving up?

Browsers cap the number of hops they'll follow and then show a connection error, which is exactly what happens on a true loop. Crawlers behave similarly: they'll follow a short chain but abandon a URL that keeps redirecting without reaching a final page. Google hasn't published an exact hop limit, so the safe target is always one hop, not whatever maximum a given bot might tolerate.

Do redirects lose link equity with each hop?

Google has said following a redirect isn't a toll that shaves off value at every hop, but that doesn't make chains harmless. Longer chains take longer to crawl, are more likely to break somewhere in the middle, and add real latency for users. Treat collapsing to one hop as the goal regardless of exactly how equity transfer is modeled internally; it's the change you can actually verify and control.

Will Google eventually find my page if the redirect is done in JavaScript?

Often yes, eventually. Googlebot renders JavaScript in a second pass after its initial crawl, so it can pick up a script-based redirect, just not immediately. The bigger risk is everyone else: many AI and third-party crawlers fetch raw HTML only and may never execute the script, so they'll index or cite the old URL's content instead of your destination. Use a real HTTP redirect if every bot needs to follow it reliably.

Does your site have this issue?

Run a free, AI-powered audit and we’ll flag this and 150+ other checks in about a minute. No signup.

No signup needed. Results in under 60 seconds.

Related fixes