PLAYBOOK · FOR SEOS, CONTENT TEAMS AND DEVELOPERS

Internal Linking Opportunities: Find Them in Search Console

Search Console can’t hand you a list of your internal links through its API, but it can tell you which pages deserve more of them, which pages should carry them and which words to use. This workflow turns that data into a link plan, finds orphan pages and measures the result.

By GSC MCP Server teamUpdated 17 min read

What are internal linking opportunities?

Internal linking opportunities are places where a link from one of your pages to another would help readers, and help Google find and understand the target page, but no link exists yet. The data-led way to find them is with Google Search Console: pick target pages that already get impressions at average positions of roughly 5–20, pick source pages that earn clicks for related queries, and write anchor text from the queries the target actually ranks for. Then add the links, confirm Google has recrawled the source pages, and compare the target’s clicks after four to eight weeks.

Most internal linking tools find opportunities by text matching, which produces hundreds of possible links and no sense of which ones matter. Search Console adds demand: which pages Google is already testing near the top, which pages people land on, and the words they typed.

We make GSC MCP Server, a read-only Google Search Console MCP server that lets Claude, ChatGPT, Cursor and other AI assistants query your Search Console and Bing data, so the prompts below use its tool names. Every step also works by hand in the Search Console interface and a spreadsheet; it just takes longer.

What Google says about internal links and anchor text

Google’s link best practices page (last updated 10 December 2025) is short and specific. These are the points that shape an internal linking strategy:

  • Links must be crawlable. Google can generally only follow <a> elements with an href attribute. Links inserted with JavaScript are fine if they end up as the same markup; <span href>, <a routerLink> and links that only work through an onclick handler are not recommended.
  • Every page you care about needs at least one link from another page on your site, placed in context next to related content.
  • Anchor text should be descriptive and concise, and relevant to both the page it sits on and the page it points to. Google names “click here” and “read more” as anchors to avoid, discourages overly long ones, and suggests reading the anchor on its own to check it still makes sense.
  • No keyword stuffing. It breaks the spam policies. The words around a link count too, so don’t chain links one after another.
  • Image links use the alt text as the anchor. There is no ideal number of links per page, though a page can have too many.

Google’s SEO Starter Guide adds that Google finds most new pages through links from pages it has already crawled, and that site structure mostly matters on sites with more than a few thousand URLs. Internal links are a discovery and context signal, not a dial you can keep turning.

Step 1: pick target pages from Search Console data

A target is a page you want to perform better. The best ones are pages Google already considers relevant, so a clearer signal has something to work with. Check three groups.

Pages with impressions at positions 5–20

These pages already appear at the bottom of page one or on page two. The window is wider than the 8–20 in our striking distance keywords playbook, because positions 5–7 are still worth moving and a link is cheaper than a rewrite. Work at page-and-query level: a page averaging position 9.0 might rank third for one valuable query and fortieth for fifty others.

Try this prompt
For example.com on Google, run query_search_analytics with dimensions page and query for the last 90 days, limit 1000, and page through with startRow until you have 3,000 rows. Keep rows with an average position between 5 and 20 and at least 100 impressions. Group them by page and list the 20 pages with the most impressions in that window, with each page’s top three queries, position and CTR.

At 1,000 rows per call, that’s three tool calls. Grouping by query leaves out anonymised queries, so per-query rows won’t add up exactly to a page’s total.

Pages that lost clicks

compare_search_periods with dimension set to page and compareTo set to previous_period (or previous_year for seasonal sites) returns your biggest losing pages by clicks. A page that slid off page one usually needs a refresh as well as links; the content decay audit covers how to tell decay from seasonality.

New pages Google hasn’t indexed yet

New pages have no performance data, so check them with inspect_url. A coverage state of “URL is unknown to Google” or “Discovered – currently not indexed”, with no referring page listed, suggests Google needs better paths to the page; links from pages it already crawls provide them. If the page was crawled and still not indexed, links alone rarely fix it; see how to fix “Crawled – currently not indexed”.

Pages to leave out

  • Pages where inspect_url shows a Google-selected canonical that differs from yours. Fix the duplicate first.
  • Pages that redirect, return errors or carry a noindex rule.
  • The weaker of two pages competing for the same query. Run find_keyword_cannibalization first and settle which page should rank, using our keyword cannibalization guide.

Step 2: find source pages that rank for related queries

A source is the page that carries the new link. If a page earns clicks for queries related to the target’s topic, Google already associates it with that topic and real readers arrive on it, so the link is likely to be seen and followed. Use query_search_analytics with the page and query dimensions and a query filter: contains for one word, or includingRegex for a group of related terms (Search Console uses RE2 syntax; the Search Console regex cheat sheet has tested patterns). Add a notEquals page filter to drop the target itself. Up to 10 filters can be combined.

Try this prompt
Target page: https://example.com/templates/freelance-invoice-template/. Run query_search_analytics with dimensions page and query for the last 90 days, limit 500, with a query includingRegex filter of invoice|invoicing|billing|payment terms, a page notEquals filter for the target, and a page excludingRegex filter of /tag/|/page/. Sum clicks by page and list the 10 pages with the most clicks for those queries, with the three queries that bring each one the most clicks.

Before a candidate goes into the plan, check three things:

  • Does it already link to the target? Our server doesn’t crawl your site, so check the source file in your repo or CMS, or select the target in the Links report’s internal table to see a sample of the pages linking to it.
  • Is there a natural place for the link? If you’d have to write a new paragraph just to hold it, choose another source.
  • How many new links is it carrying? Google gives no number. We keep to two or three per source per round, so each has its own sentence of context.

Step 3: choose anchor text from the queries a page ranks for

The queries a page already earns impressions for are the vocabulary searchers and Google associate with it. Pull them, then write anchors that use that vocabulary naturally, and differently each time.

Try this prompt
For https://example.com/templates/freelance-invoice-template/, run query_search_analytics with dimension query and a page equals filter for that URL, last 90 days, limit 100. Group the queries into themes and suggest six anchor texts of two to six words each that describe the page, draw on different themes and would read naturally in a sentence. Then run find_keyword_cannibalization for the same period and flag any suggested anchor whose query also sends impressions to another of my pages.
Anchor textVerdictWhy
“click here”AvoidGeneric; Google uses it as an example of a bad anchor
“this guide”AvoidSays nothing when read out of context
“freelance invoice template”GoodThe target’s main query, and an accurate description
“an invoice template with payment terms”GoodA real longer query the page ranks for; varies the wording
“how to create invoices, templates, payment terms and reminders as a freelancer”AvoidToo long, and describes several pages rather than one
  • Vary across sources. Different sources, different real queries. The same exact phrase on thirty pages reads like a template, because it is one.
  • One phrase, one target. Don’t point the same anchor at two different pages; mixed signals from your own links feed cannibalisation.
  • Navigation is different. Short labels such as “Pricing” are normal in menus. Descriptive anchors matter most in body copy.

Find orphan pages with sitemaps and URL Inspection

An orphan page has no internal links pointing to it. Google can still find it through a sitemap or a link from another site, but Google’s sitemap documentation says a sitemap doesn’t guarantee crawling or indexing. Orphans usually come from removed navigation, retired category pages, campaign landing pages and posts published without a link from anywhere.

The three-list method

  1. URLs you want indexed: your XML sitemap, a CMS export or, for a static site, the routes in your repo. list_sitemaps confirms which sitemaps Google and Bing have, when they were last downloaded and their error counts, but it doesn’t list the URLs inside them or how many are indexed.
  2. URLs reachable by links: a crawl from your home page with a crawler such as Screaming Frog or Sitebulb, with sitemap URLs kept out of the crawl (our server doesn’t crawl sites). In a repo, an AI code editor can approximate this by collecting every internal href in your content and templates.
  3. URLs Google shows: get_search_pages or query_search_analytics with the page dimension for the last 90 days.

Pages in the first or third list but not the second are orphan candidates. Pages only in the third list are URLs Google shows that you don’t declare, such as old paths or parameter versions.

Confirm each candidate with URL Inspection

inspect_url returns Google’s verdict, coverage state, last crawl time and both canonicals. The underlying API result also lists sitemaps that include the URL and referring URLs, as far as Google knows them. Google’s URL Inspection help says the referring page list isn’t exhaustive, so an empty one is a hint, not proof. Google allows 2,000 inspections per property per day, which is plenty for an orphan check.

Try this prompt
Here are 25 URLs from my sitemap that my crawl didn’t reach. Use multicall to run inspect_url on them in batches of 10. For each one, show the verdict, coverage state, last crawl date, whether Google lists a referring page, and whether the Google-selected canonical matches the URL. Then sort them into three groups: link it, redirect it, or drop it from the sitemap.

Each inspection inside a multicall counts as one tool call, so that prompt uses 25. Then fix each orphan in one of three ways:

  • Still useful: link to it from its hub and from one or two related pages chosen with step 2.
  • Obsolete: 301 redirect it to a close equivalent, or return a 404 or 410 if there isn’t one, and remove it from the sitemap.
  • Deliberately unlinked, such as paid campaign landing pages: keep it out of the sitemap, and add a noindex rule if it shouldn’t appear in search at all.

Add the links with an AI code editor

If your site lives in a repo (Next.js, Astro, Hugo or MDX content), Claude Code, Cursor or Codex can apply the plan with Search Console data and your files in the same session. Our Claude Code SEO guide covers the setup and the wider editor workflow; for Cursor and VS Code, see technical SEO in your code editor. Three rules for the edit itself:

  • Ship real links. The rendered HTML must contain <a href>. In Next.js, the <Link> component renders one; a button that calls router.push() doesn’t.
  • Edit existing sentences. Ask for the smallest change that makes the link read naturally, and review every diff.
  • Treat template links separately. Related-post blocks, breadcrumbs and hub navigation change hundreds of pages at once, so give them their own commit and review.
Try this prompt
Here is my link plan as a table. First run inspect_url on each target and skip any row where the page isn’t indexed or Google chose a different canonical. For the rest, find the source page’s file under content/blog, locate a sentence that already discusses the target’s topic, and add one link with the planned anchor, changing no more than a few surrounding words. Don’t add a link if the file already links to the target. Show me the diff for each file before saving.

After you deploy, view the page source to confirm the links are in the HTML. If a component inserts links with JavaScript, use Test live URL in Search Console’s URL Inspection tool and check the HTML under View tested page. Our read-only inspect_url can’t run live tests or request indexing; do both in the Search Console interface.

Measure the results after 4–8 weeks

  1. Mark the date. In the Performance report, right-click the chart and add an annotation such as “Internal links round 3: 14 links, 6 targets” (120 characters at most).
  2. Confirm the recrawl. Google has to recrawl the source page before it sees the new link. Check the last crawl date of each source with inspect_url.
  3. Wait four to eight weeks, then compare an equal period before and after, clicks first, then position for the queries you used as anchors.
  4. Use a control group of similar pages you didn’t link. If they rose as much as your targets, something else, such as a core update or seasonality, probably caused the gain.
Try this prompt
For the six target pages in my link plan, run query_search_analytics with dimensions page and query and a page includingRegex filter that matches those URLs, first for 2026-09-01 to 2026-10-26 and then for the 56 days before. For each target, show clicks, impressions and average position before and after, and the position change for the queries we used as anchors. Then run compare_search_periods with dimension page, the same dates and compareTo previous_period, so I can see whether the whole site moved too.

Both of those periods fall after 27 April 2026, the end of the impressions logging error listed on Google’s Search Console data anomalies page, so impressions and position are comparable as well as clicks. Be honest about the result. If a target hasn’t moved after eight weeks, links weren’t its bottleneck: look at content, intent or competition from your own pages next.

From one-off fixes to an internal linking strategy

Hub-and-spoke topic clusters

A topic cluster is a hub page that covers a subject broadly, linked to and from spoke pages that each cover one part in depth. Search Console lets you draw clusters from data: run a query regex for the topic, list the pages that get impressions for it, and the page with the widest spread of queries is your natural hub. The hub links to every spoke; each spoke links back with a descriptive anchor, and to sibling spokes only where a reader would plausibly move between them. Keep it in proportion: on a 50-page site, a few well-placed contextual links matter more than a formal cluster diagram.

A quarterly routine

  1. Refresh the target list (step 1).
  2. Export the Links report’s internal table and file it.
  3. Run the orphan check on anything published since last time.
  4. Add 10–20 links from a new link plan.
  5. Measure the previous round against its control group.

By our count, a round for ten targets is about 35 tool calls: three to five to find targets, then one per target each for sources, anchors and an inspection. The Free plan’s 30 calls a month covers a round of seven or eight targets; regular rounds across several sites fit easily in the Pro plan’s 10,000 (see pricing). For more ready-made prompts, see our 40 Search Console prompts for Claude and ChatGPT.

Frequently asked questions

How do I find internal linking opportunities?

Start with Search Console data. Pick target pages that get impressions at average positions of roughly 5–20, find source pages that earn clicks for related queries with a page and query report filtered by topic, and choose anchor text from the queries the target already ranks for. Check that each source doesn’t already link to the target, add the link to a sentence that discusses the topic, and measure the target after four to eight weeks.

Can Google Search Console show internal links?

Yes, in the Links report under Internal links, Top linked pages, where you can select a URL to see which of your pages link to it. The data is a sample, tables stop at 1,000 rows, and the report isn’t available through the Search Console API, so you have to export it from the interface. Use a crawler when you need a complete list.

How many internal links should a page have?

Google says there is no ideal number, though a page can have too many. Add a link wherever it helps a reader move to a related page, with enough surrounding text that the link makes sense. In practice we add two or three new contextual links to a source page per round rather than dozens at once.

Should internal link anchor text be exact match?

Not every time. Google recommends anchor text that is descriptive, reasonably concise and relevant to both pages, and warns against keyword stuffing. Using the target’s main query on one or two links is natural; varying the rest with other real queries the page ranks for reads better and avoids the templated look of the same phrase on every page.

What is an orphan page in SEO?

An orphan page is a page on your site with no internal links pointing to it. Google may still find it through a sitemap or a link from another site, but a sitemap doesn’t guarantee crawling or indexing, and Google’s guidance is that every page you care about should be linked from at least one other page. Find orphans by comparing your sitemap URLs with a crawl of your site, then confirm each one with URL Inspection.

How long do internal links take to work?

Google has to recrawl the page that carries the new link before it can see it, which can take days for busy pages and weeks for quiet ones. Check the source page’s last crawl date with URL Inspection, then compare the target’s clicks and position over four to eight weeks against the same length of time before the change. If a target doesn’t move, links probably weren’t its main problem.