River
Y CombinatorBacked by Y Combinator

Marketing & GrowthFree

Internal Linking Audit and Recommendations

Content-position inlinks per page, joined to what each page could realistically win, then the source, target and anchor for every link worth adding.

Start here

River's internal linking audit reads the inlink export one link at a time and keeps the position of each link rather than the count. Navigation, footer and sidebar links get separated from links inside body copy, which usually collapses a page's inlink figure from several hundred to single digits. Those content-only counts are then joined to your performance rows, so every page carries both the authority it holds and what a link could plausibly move. The output names each link: source page, target page, anchor text.

The templates that rank for this search count internal links per URL and colour the low numbers red. That count is the thing it claims to diagnose. A page sitting in your main menu collects an inlink from every page on the site, so it reads as your best-linked asset while having never been linked from a sentence. A checklist telling you to add internal links cannot tell you which page needs one, which page should give it, or what the anchor ought to say.

Built for in-house SEOs who inherited a site nobody has mapped, agency strategists on a first technical pass, and content leads whose new posts are reachable only from the blog index. Pair it with the Search Console keyword map for the query side, the keyword cluster map for the hub structure the links ought to follow, and the content inventory and pruning pack once retirement is on the table. It runs in the marketing workspace, beside the crawl it reads.

Why the inlink count is measuring your navigation

Every crawler records where on the page a link sat, and almost every report throws it away. Screaming Frog classifies each link by its path through the document, so it can say whether a link is in the navigation, the content, the sidebar or the footer. Its own documentation gives the reason plainly: to find the inlinks that come only from body content, ignoring the main navigation. Merrivale Systems, a warehouse software vendor, has 45,054 internal links across 812 pages. 43,848 of them are the same 54 links repeated on every page.

Search Console's internal links table agrees with the raw crawl, which is what makes the number so durable. It reports one row per source and target pair, is capped at 1,000 rows and is a sample rather than a full list, and never says where on a page a link sat. So Merrivale's implementation checklist ranks third in that table with 812 links, every one of them the menu, and none from anybody's sentence. Its navigation and footer reach 54 pages. The remaining 758 receive nothing.

Counting content links is half the job. The other half is knowing which pages a link could move, and that comes from the performance rows: average position between eight and twenty, close enough that authority is plausibly the constraint. Fifteen of Merrivale's forty-one plan pages sit in that band. Ten of those have two or fewer distinct content sources, and the ten together carry 101,200 impressions a month. Google asks for anchors that are descriptive rather than click here or read more. 214 of the 1,206 existing ones fail that.

How it works

  1. Send the crawl

    The inlink export with link positions if you have them, plus your Search Console performance rows.

  2. River rebuilds the graph

    Templated links separated from content links, then each page's content inlinks counted by distinct source.

  3. Read the recommendations

    Source, target and anchor for each link, ordered by the impressions the target already earns.

  4. Add the links

    Work down the list, then send the next crawl to confirm each one landed in content.

What you get

  • Every inlink classified by where it sat, so navigation stops counting as an endorsement
  • Content-only inlink counts per page, with the distinct source pages behind each count
  • Pages ranked by what a link could move, using the position band rather than a score
  • A named source, target and anchor per recommendation, with the paragraph it belongs in
  • Orphans out of the same graph: pages with no inlink, and pages with only templated ones
  • Existing anchors flagged where they say click here, read more, or nothing much at all

Common questions

My crawl export has no link position column. Can I still run this?

Yes, and the audit tells you which findings it made without that column. Position can often be inferred from the anchor text and the pattern: a link appearing on all 812 pages with an identical anchor is a menu item, whatever the export says. Inferred classifications are labelled as inferred so nobody treats them as measured.

Why cut off at position twenty?

Because that is where a link is plausibly the binding constraint. A page at position four is already winning and a page at forty is losing for a reason no link fixes. The band is an editable input, not a rule, and every page's band is shown so you can see what was set aside. Pricing the move is the SEO forecast.

Is a page in the main navigation an orphan?

Not literally, and that is the trap. It collects one inlink per page on the site, so no report flags it. Google's guidance is that every page you care about should have a link from at least one other page, and a menu satisfies that. It is still a page nobody has ever chosen to reference.

How do you pick which page gives the link?

A source has to be topically adjacent, already have a paragraph the anchor fits inside, hold content links of its own, and not already link to the target. The output names the paragraph, because a recommendation that stops at the URL pair gets handed to a writer who then has to reread the whole page.

What about the related-posts block at the bottom of my pages?

Tell the audit in the notes field and it gets treated as templated, not editorial. Automatically generated blocks appear inside the body element, so a position classifier reads them as content links. They inflate exactly the number this audit exists to deflate, and the correction is a naming rule rather than a judgement.

Does this replace a technical SEO audit?

No. It reads one dimension of the crawl in depth and leaves the rest alone, so status codes, indexability and canonicals belong to the technical SEO audit pack, and page speed to the Core Web Vitals triage. Run those first on a site nobody has crawled, because a link pointing at a page Google will not index is wasted work.

How do I confirm the links actually landed?

Send the next crawl through the same audit. Each recommendation becomes a row that either resolves to a content-position link carrying the intended anchor, or does not. That catches the common failure, where a writer drops the link into a related-posts widget instead of a sentence, or quietly rewrites the anchor to read more.

Internal Linking Audit and Recommendations

Fill in the form and your workspace opens with the work already underway.