Skip to content
Issue docs

Redirect chains and loops

Importantno_redirect_chainsIssue 10

What is this issue?

A redirect chain is a redirect that takes more than one hop to reach the page that answers:

/old-pricing  →  301  →  /pricing  →  301  →  /pricing/  →  200 OK

Every hop is another request and response before the page starts loading. Chains usually build up over time: a page moves, then moves again, and nobody updates the first redirect.

For a page to pass this check:

  • Every redirect reaches its destination in a single hop.

Example: http://example.com/blog redirects to https://example.com/blog, which redirects to https://www.example.com/blog, which redirects to https://www.example.com/blog/. Three hops where one would do.

Loops are a separate check. A redirect that comes back to an address already in its chain never arrives at all. That is reported as "Redirect loop" (#166), and a URL that loops is reported there only — not here as well. This check's title still reads "Redirect chains and loops" because check titles are kept stable; it reports chains.

Why it matters

  • Every hop costs time. Each extra redirect is a round trip — sometimes a new connection to a new host — before the reader sees anything. On mobile networks a three-hop chain can add most of a second.

  • Crawlers spend budget on hops. Each hop is a request a crawler makes instead of fetching a real page. Google follows up to ten hops and then gives up on the URL.

  • Long chains are fragile. Every hop is a rule that has to keep working. Remove one in a later clean-up and every link into the start of the chain breaks.

  • Link signals travel best in one hop. Links pointing at the start of a chain reach the destination only through every redirect along the way.

Effect on the health score

This is an important issue under the Link Integrity lens.

How to fix it

  1. Read the chain on the finding. It lists every hop from the first address to the page that answers.

  2. Point the first redirect straight at the final address.

    # Before: two hops
    location = /old-pricing { return 301 /pricing; }
    location = /pricing     { return 301 /pricing/; }
    
    # After: one hop from each old address
    location = /old-pricing { return 301 /pricing/; }
    location = /pricing     { return 301 /pricing/; }
  3. Combine host and protocol redirects. Redirect http://example.com, http://www.example.com and https://example.com straight to the one canonical origin in a single rule, rather than http → https and then non-www → www.

  4. Update internal links to the final address, so readers on your own site never take the chain at all (see "Internal links pointing at a redirect", #139).

  5. Re-scan to confirm each address now takes one hop.

Examples

Example 1: A page that moved twice

Fails (2 hops):

/old-pricing → 301 → /pricing → 301 → /pricing/ → 200 OK

Passes (1 hop):

/old-pricing → 301 → /pricing/ → 200 OK

Example 2: Protocol and host fixed in separate steps

Fails (2 hops):

http://example.com/blog → 301 → https://example.com/blog → 301 → https://www.example.com/blog → 200 OK

Passes (1 hop):

http://example.com/blog → 301 → https://www.example.com/blog → 200 OK

Example 3: A loop — reported elsewhere

/a → 301 → /b → 301 → /a → …

Not reported here. This never arrives; it is a redirect loop (#166).

Example 4: A single redirect

/old → 301 → /new → 200 OK

Passes. One hop is how a moved page should behave.

How PixyScan detects this

  1. Follows redirects during the crawl. When a page the crawler requests redirects, PixyScan records every hop (address and status code), the final address, and whether any address repeated.

  2. Counts the hops after the crawl. A recorded chain of more than one hop is reported against the address that started it, with the full chain.

  3. One redirect is fine. A single 301 from an old address to a new one is the normal, correct way to move a page. If its status code is wrong (for example a 302 for a permanent move), that is "Redirects using the wrong status code" (#7).

  4. Loops are reported elsewhere. A chain that repeats an address is a redirect loop and is reported only as #166, never also here.

  5. Respects your lens settings. Nothing is raised on a scan with the Link Integrity lens switched off.

What we store

Storage Level

Page Level


Database Table / Prisma Model

RedirectChain (redirect_chains). The finding is stored on audit_issues.details.


Fields Used

Field Type Description
redirect_chains.original_url String The address the crawler requested
redirect_chains.final_url String The address that answered
redirect_chains.chain Json Every hop, [{ url, statusCode }]
redirect_chains.chain_length Int Number of hops. More than 1 raises this check
redirect_chains.has_loop Boolean True for a loop, which is #166 instead

Stored Fields on the finding

Field Type Description
message String "Redirect chain detected (2 hops)."
originalUrl String Where the chain starts
finalUrl String Where it ends
chainLength Int Number of hops
hasLoop Boolean Always false here
chain Json The hops

Detection Dependencies

  • HTTP Response — the redirect hops the crawler followed

Further reading