Links and redirects checks

Triggers and fixes for broken, redirected and nofollow links, external links, redirect chains and loops, and JavaScript redirects.

Updated 8 October 2026View as Markdown

Link issues are reported on the page that contains the link, so the fix is on that page (or the template, menu or component that renders the link). Redirect issues are reported on the redirecting URL. Only JS_REDIRECT is recheckable; the rest need a full audit, because they depend on other URLs of the site.

SEOFix reads links from <a href> elements. A link is internal when it points to the audited host, with or without www. Links under /cdn-cgi/ (Cloudflare's reserved path) are ignored.

  • Severity: error. Recheckable: no (needs a full audit).
  • Trigger: the page links to an internal URL that was crawled and answered 4xx or 5xx, or could not be fetched. Firewall-blocked targets are not counted. One issue per linking page and target.
  • Details: broken_url, status_code (null when the fetch failed).
  • Why it matters: links to missing pages waste crawl budget, leak link equity and send visitors to errors.
  • How to fix: update the link to the correct URL, or remove it. If many pages link to the same broken_url, the link is in a shared template, menu or footer; fix it there. If the target should exist, fix the target (see BROKEN_PAGE).
  • Severity: notice. Recheckable: no (needs a full audit).
  • Trigger: the page links to an internal URL that answered 3xx.
  • Details: to_url (the linked URL), redirect_to (where it redirects).
  • Why it matters: each redirect adds latency and loses a little link equity.
  • How to fix: change the link to point directly at the final URL. The most common causes are http:// links, missing or extra trailing slashes, and links to old paths.
<!-- before: /jobs redirects to /jobs/ -->
<a href="/jobs">Jobs</a>
<!-- after -->
<a href="/jobs/">Jobs</a>
  • Severity: notice. Recheckable: no (needs a full audit).
  • Trigger: the page has at least one internal link whose rel contains nofollow. One issue per linking page.
  • Details: count (distinct internal targets linked with nofollow), samples (up to 5).
  • Why it matters: rel="nofollow" on links to your own pages stops link equity flowing to them.
  • How to fix: remove rel="nofollow" from links to your own pages. If the goal was to keep a page out of search, use noindex on that page; to stop crawling, use robots.txt.

External links are probed in full audits only, after the crawl: up to 500 distinct external URLs per audit, one request at a time per host and at least 0.5 seconds apart.

  • Severity: error. Recheckable: no (needs a full audit).
  • Trigger: the page links to an external URL that answered 4xx or 5xx, or failed to connect (not a timeout). One issue per linking page.
  • Details: broken_url, plus status_code or error.
  • Why it matters: links to dead pages hurt user experience and how much search engines trust the page.
  • How to fix: update the link to a working URL (the page's new location, or an archived copy), or remove it. Some sites answer 403 or 429 to all automated requests; open the link in a browser before removing it.
  • Severity: notice. Recheckable: no (needs a full audit).
  • Trigger: the page links to an external URL that answered 3xx. At most 50 issues per external URL.
  • Details: external_url, status_code, redirect_to, linking_pages (all pages linking to it).
  • Why it matters: an extra hop for visitors, and often a sign the target moved.
  • How to fix: when the redirect stays on the same host (only http to https or a path change), change the link to redirect_to. When it goes to another host, check the destination is still what you want to link to (it may be a parked domain or a login wall) and update or remove the link.
  • Severity: notice. Recheckable: no (needs a full audit).
  • Trigger: the request to the external URL timed out. At most 50 issues per external URL.
  • Details: external_url, error, linking_pages.
  • Why it matters: the linked site may be down, slow, or throttling bots.
  • How to fix: open the link in a browser. If the site is gone or consistently slow, replace or remove the link; otherwise ignore it.

Redirects

REDIRECT_CHAIN — Redirect chain

  • Severity: warning. Recheckable: no (needs a full audit).
  • Trigger: from this URL it takes two or more redirects to reach a URL that does not redirect, following the redirects SEOFix crawled (up to 10 hops).
  • Details: chain, the list of URLs from this URL to the last one.
  • Why it matters: each hop slows the page and loses link equity; search engines may stop following long chains.
  • How to fix: redirect the first URL straight to the final destination in one hop, and update links to point at the final URL. Chains often come from stacking rules, such as http → https, then apex → www, then adding a trailing slash. Combine them into one rule.
# one hop from any http or apex URL to the canonical https://www host
server {
  listen 80;
  server_name example.com www.example.com;
  return 301 https://www.example.com$request_uri;
}

REDIRECT_LOOP — Redirect loop

  • Severity: error. Recheckable: no (needs a full audit).
  • Trigger: following the redirects from this URL comes back to a URL already in the chain.
  • Details: chain, ending with the repeated URL.
  • Why it matters: the URL never reaches a page, so neither visitors nor crawlers can open it.
  • How to fix: break the loop so the URL redirects once to a final 200 page. Loops usually come from two rules that undo each other (adding and removing a trailing slash, or a CDN forcing https while the origin forces http).

JS_REDIRECT — JavaScript / meta refresh redirect

  • Severity: warning. Recheckable: yes.
  • Trigger: a 200 HTML page redirects in the browser to another URL, by either:
    • <meta http-equiv="refresh" content="N; url=..."> with a target (a plain reload without a URL is not flagged), or
    • a small inline script (up to 1,000 characters, among the first 50 inline scripts) that assigns a literal URL to location or location.href, or calls location.replace("...") or location.assign("..."), on window, document, top, self or as a statement on its own.
  • Details: type (meta_refresh or script), target.
  • Why it matters: client-side redirects are slower, not always followed by crawlers, and pass ranking signals less reliably than a server redirect.
  • How to fix: replace it with a server-side 301 redirect from this URL to target, then remove the meta tag or script.
<!-- before -->
<meta http-equiv="refresh" content="0; url=https://example.com/new-page">
# after: the server answers the old URL with
HTTP/1.1 301 Moved Permanently
Location: https://example.com/new-page

More in Issue reference

Still stuck? Email [email protected] with your site and what you expected to see.