Skip to content
Issue docs

Internal links pointing at a redirect

Standardinternal_link_to_redirectIssue 139

What is this issue?

This check reports a page that links to one of your own addresses that redirects, when it could link straight to the address the redirect leads to.

The redirect itself is working. Nobody sees an error, and a link checker that follows the hop reports success. What is wrong is the link: it names an address that is no longer the real one, and every visit through it costs an extra request before anything is shown.

For a page to pass this check:

  • Every internal link it carries points at an address that answers directly, rather than at one that forwards somewhere else.

Example: the site moved /blog/seo-basics to /guides/seo-basics and put a 301 in place. Two years later the navigation, the footer and forty articles all still link to /blog/seo-basics. The redirect is holding the site together instead of doing the one-off job it was added for.

This is a finding about the linking page, not about the redirect. "Redirects using the wrong status code", "Redirect chains and loops" and "Redirect resolving to a 4xx error page" are all reported against the redirecting address and are fixed in the redirect rule. This one is fixed by editing an anchor.

Links to an address that returns 404 or 500 are not reported here. That is "Broken internal links and pages", a more serious finding with a different fix.

Why it matters

  • Every visit pays for the hop. A redirect is an extra round trip before the browser has a single byte of the page. On a mobile connection that is a visible pause, repeated on every internal navigation that goes through it.
  • Crawl budget is spent on nothing. A crawler following the link fetches the redirect, reads where it points, then fetches the destination. On a large site with a stale navigation that is thousands of requests producing no content.
  • The redirect becomes load-bearing. A rule added for the handful of external links pointing at an old address turns into infrastructure the site cannot run without, and anybody tidying the redirect map later breaks live navigation.
  • Signals take a longer route. Search engines do pass ranking signals through a 301, but they have to discover and follow it first — and a stale internal navigation is the shape that eventually grows into a redirect chain.

It is graded standard rather than important on purpose. The page is indexable, the link works, and the reader arrives where they were going. What is lost is a round trip and some tidiness, and the fix is usually a find-and-replace. That is precisely the standard definition: a real but indirect cost, cheap to correct.

Clearing it lifts the Link Integrity part of the health score, and on a site with a stale navigation it is one of the cheapest gains available — a single template edit can remove the finding from every page at once.

How to fix it

  1. Point the link at the final address. Take the destination the redirect resolves to and use it in the anchor. This is usually a find-and-replace in a template, a navigation config or a content database.

  2. Start with the templates. A header, footer or sidebar link is repeated on every page of the site, so one edit there usually removes most of the report.

  3. Then the body content. Older articles accumulate links to addresses that have since moved. A bulk update against the redirect map fixes them together.

  4. Keep the redirect. It still has a job: external links, bookmarks and old search results point at the original address and always will. The point is that your own pages should not need it.

  5. Re-check after a migration. These appear in bulk the day a site changes its URL structure, and they are easiest to clear immediately, while the mapping from old address to new is still in front of you.

  6. Follow the whole route. If the destination is itself a redirect, fix the route in one go rather than moving the link one hop along it.

Examples

Scenario: The navigation links to the current address.

Passes because: the target answers directly, with no hop.

<a href="/guides/seo-basics">SEO basics</a>
<!-- GET /guides/seo-basics -> 200 -->

Example 2: A navigation left pointing at the old address

Scenario: The blog moved to /guides a year ago and the header was never updated.

Fails because: every page on the site sends readers through a redirect.

<a href="/blog/seo-basics">SEO basics</a>
<!-- GET /blog/seo-basics   -> 301 -> /guides/seo-basics -->
<!-- GET /guides/seo-basics -> 200                       -->

Corrected version:

<a href="/guides/seo-basics">SEO basics</a>

Scenario: The server canonicalises to a trailing slash and the templates link without one.

Fails because: it is the same hop, on every link, site-wide. The most common form of this finding and the cheapest to clear.

<a href="/pricing">Pricing</a>
<!-- GET /pricing -> 301 -> /pricing/ -->

Corrected version: link in whichever form the server serves directly.

<a href="/pricing/">Pricing</a>

How PixyScan detects this

  1. Records every internal link with its anchor. As each page is crawled, PixyScan stores the links it carries to other pages on the same site.

  2. Checks what each link target actually answers. After the crawl, every distinct internal link target is requested and the status it returned is recorded once, in one place.

  3. Reports a page whose links point at a 3xx. Any status from 300 to 399 counts. A permanent redirect is no more the final address than a temporary one, and both cost the same extra request.

  4. Leaves broken targets alone. A target answering 4xx or 5xx is reported by "Broken internal links and pages" instead, so one dead link is never counted twice under two codes with two different fixes.

  5. Leaves unmeasured targets alone. Where a target was never successfully probed, no claim is made about it. "We did not check this" and "this is fine" are different answers.

  6. Raises one finding per linking page, listing the addresses it points at and the status each returned, so the anchors that need editing are on the row rather than something to reproduce by hand.

What we store

Storage Level

Page Level


Database Table / Prisma Model

PageInternalLink, joined to Url. The finding itself is stored on audit_issues.details.


Fields Used

Field Type Description
page_internal_links.url_id String The page that carries the link, and the page this finding is raised against
page_internal_links.target_url_id String The page being linked to
page_internal_links.anchor_text String The visible text of the link, so the anchor to edit can be named
urls.status_code Int What the target answered when it was probed; 300-399 is what this check reads

Stored Fields on the finding

Field Type Description
redirectLinkCount Int How many of this page's links point at a redirect
targets Object[] Up to 25 of them: target URL, the status it returned, and the anchor text
truncated Boolean Whether more targets exist than the finding lists
url String The page carrying the links

Detection Dependencies

  • Internal Links
  • HTTP Response — the post-crawl status probe over every distinct link target

Further reading