Skip to main content

Internal link platform

How to use it

  1. Run an analysis. It reads your crawl and your content to find pages that should link to each other.
  2. Review the suggestions. Each row shows the source page, the target, the proposed anchor text, and the target's value.
  3. Apply the ones you want — individually, or in bulk as a background job.
  4. Set a policy if you are going to work in bulk. The defaults are sensible; the point is that a batch cannot quietly breach them.
  5. Come back for the impact panel once the links have had time to be crawled.

⏱ ~10 min per pass · 💳 Starter+ · 🎯 Move link equity to the pages that earn

What gets linked, and where

SurfaceWritten intoNotes
ProductDescription HTMLThe most common case
CollectionDescription HTML
Blog postArticle body
PagePage body

The source type is determined from the URL rather than from a stored label, because older suggestion rows can carry a stale classification — a /blogs/… URL is a blog article regardless of what the row says it is.

Links are always root-relative — and this is not cosmetic

An internal link is written as /products/winter-throw, never https://…/products/winter-throw.

The reason is concrete. Suggestion targets come from crawled page URLs. If a crawl ran against the .myshopify.com mirror, every absolute URL written into a product description would point customers and Google at the mirror — permanently, inside your live product HTML, long after the crawl that caused it was forgotten. Root-relative links resolve correctly on whatever domain the page is served from, so a wrong-host crawl becomes merely unhelpful instead of destructive.

Off-domain targets are refused. When the platform cannot confirm which host is yours — a failed lookup, a throttled API call — it declines the write as retryable and records nothing, rather than guessing.

Suggestions are ranked by the value of the target page, not by keyword similarity alone. The value model blends:

  • Search Console clicks, impressions and position for the target
  • Attributed revenue where available
  • Click depth — how many clicks from the home page the target sits at
  • Whether the target is actually indexable

Depth is read as a real number, so depth 0 is the home page, not "unknown". Target quality is read from the crawl: robots directives, canonical status, status code. A target that is missing from the crawl is marked unknown, never "not indexable" — the difference matters when you are deciding whether to link to it.

Orphans and depth distribution

An orphan is a page nothing links to. The orphan panel lists them alongside the distribution of click depth across your site, which is usually the more actionable of the two: a store where 60% of products sit at depth 5 has a structural problem that fixing twelve orphans will not solve.

Policy guardrails

Guardrails exist because bulk application is where internal linking goes wrong. Each is set per store:

GuardrailDefaultWhat it prevents
Inbound per target per week10A single "money page" absorbing hundreds of links in one run
Outbound per source8A product description turning into a link farm
Repeated anchor cap30%The same anchor phrase used over and over across the site
Block off-domainOnAny target outside your domain
Block non-indexableOnLinking to pages Google will not index
Max depthLinking to pages buried too deep to be worth it
Minimum target valueSpending link equity on pages that earn nothing

The important property is that a batch cannot breach a budget that each row respected individually. When 40 suggestions each point at the same target, all 40 individually pass a limit of 10 — so bulk evaluation carries a running tally and stops at the tenth.

The same rules are evaluated in three places — the list you are looking at, a single apply, and the background worker — so what the tab greys out is what the worker will actually refuse.

If the guardrail data cannot be read, the run stops

When the platform cannot load your current link tallies, empty tallies would read as "no links yet" and wave every guardrail through. Bulk runs and single applies both fail closed in that case, and the scheduler skips the cycle rather than proposing against unknown budgets.

Applying in bulk

Bulk application is a tracked background job, not something that happens inside your browser request. Kinds:

KindWhat it does
PreviewDry run — evaluates everything, writes nothing
ProposeMoves suggestions to proposed for review
ApproveApproves proposed suggestions
ApplyWrites the links into live content

Writes are spaced out, one run at a time per store. The tab polls the job and shows progress; if a run is already going, a second request is refused rather than queued behind it.

Undo

Undo re-reads the live page and removes the exact anchor that was applied. Only if that fails does it fall back to matching on href and text, then to "already absent", and only as a last resort to the stored whole-body snapshot — and that final fallback runs only when the current body still hashes to what was recorded at apply time. If the page has changed since, undo reports that and offers an explicit "restore anyway".

This sequence exists because the naive version — restore the snapshot — destroys every edit made after the apply, and undoing the first of two links silently reverts the second while its row still says applied.

Multi-locale

Writes reach your primary locale only. If you publish translated content, the translated bodies of your published locales are checked and reported — the platform tells you which locales are missing the link. It never rewrites a translation automatically, because a machine-inserted anchor in a language you have had professionally translated is not a fix.

The impact panel does not simply compare clicks before and after. It snapshots a control cohort of about 25 Search Console-covered pages that are not link targets, on the same clock, and measures them first each run. The median change across that cohort is subtracted from the change on your linked pages, producing an adjusted figure.

If fewer than five comparable pages exist, the panel reports "no control" — it does not fabricate one. A number with no control group during a seasonal upswing is a story, not a measurement.

Scheduled analysis

Analysis can run on a per-store cadence. It generates suggestions and, if you enable it, proposes them.

Scheduled analysis can never apply a link. Application is always a human action. Scheduling is off by default, and a cycle where guardrail data cannot be read is skipped rather than run blind.

Governance and audit

ActionWho can do it
Run an analysisSEO audit permission
Apply a link, bulk apply, bulk proposeSEO autofix permission
Approve in bulk, edit policy, clear suggestionsSEO governance permission

Clearing suggestions only deletes pending, rejected and expired rows. Applied rows are kept, because they hold the undo record for every live link — deleting them would strand real links in your content with no way to remove them. The result of a clear tells you how many were deleted and how many kept.

Rejecting a suggestion takes a reason, and every action writes to the audit history, viewable from the tab.

Plan tiers

CapabilityFreeStarterProAgencyEnterprise
Suggestions + value ranking
Apply into products and collections
Apply into blog posts and pages
Orphan + click-depth report
Surgical undo
Policy guardrails
Background bulk apply
Control-group impact measurement
Multi-locale gap report
Scheduled analysis

Best practices

  • Fix the crawl host before applying anything. Suggestion targets come from the crawl. Root-relative writes make a wrong-host crawl survivable, not correct.
  • Preview before you apply in bulk. The dry run costs nothing and shows you exactly which rows the guardrails will block.
  • Lower the repeated-anchor cap if your catalogue is narrow. Thirty percent of a hundred links is thirty identical anchors.
  • Link to earners, not to everything. Set a minimum target value and let the ranking do the work.
  • Do not enable auto-propose on day one. Run two manual passes first, so the policy is tuned before the scheduler starts using it.

See also