Keyword cannibalization happens when two or more pages on your site target the same search intent and Google can’t settle on which one to rank. The fix is to choose one primary URL per intent, then merge, re-target, de-optimize or canonicalize the others and back the winner with internal links. Confirm it first, though: plenty of multi-URL rankings are harmless.
What cannibalization is, and what it isn’t
Real cannibalization has three ingredients:
- Same intent. Both pages answer the same question for the same searcher. Sharing a word isn’t enough.
- Swapping. The URL Google shows for the query changes from week to week, and the position moves with it.
- A weaker result than one page would earn. Backlinks, internal anchors and content depth are split across two URLs, so neither reaches the position a single strong page could hold.
What it isn’t:
- Two of your URLs showing together for one query. Google chose to show both, and you own more of the page.
- Pages sharing a keyword but not an intent. “Email marketing software” (a product page) and “email marketing examples” (a post) overlap in words, not in what the searcher wants.
- A trickle of impressions for a loosely related query. Almost every page picks those up for long-tail variants.
- Technical duplicates from parameters, trailing slashes or http/https versions. That’s a canonicalization problem for technical SEO, not a content decision.
Finding it in Search Console
The Performance report has everything you need, though the interface makes you work one query at a time.
- Build a candidate list. Open Performance > Search results, set the last three months and export the queries. Keep the ones with commercial value or meaningful impressions. Nobody needs to fix cannibalization on a query with a handful of impressions.
- Check which pages rank for each query. Click a query to filter the report to it, then open the Pages tab. More than one URL with real impressions makes it a candidate.
- Look for swapping. Keep the query filter, add a page filter for each URL in turn and switch on Average position in the chart. Or use the date comparison to put this month next to last month. If URL A earned the impressions last month and URL B earns them now, with position dropping at each handover, that’s the pattern.
- Scale it past the interface. On a site with hundreds of pages, pull query and page together through the Search Console API, the Looker Studio connector’s URL impression table, or the bulk data export to BigQuery. Then filter for queries where two or more URLs each carry a real share of impressions. I start with a threshold of around 10 to 20% per URL and adjust from there; it’s a working filter, not a rule.
A quick site:yourdomain.com keyword search shows which pages Google associates with a term, but it doesn’t reflect real rankings. Use it to spot candidates, never to confirm them.
When two ranking pages are fine
Before changing anything, ask one question: if one of the two pages disappeared tomorrow, would someone searching this query lose anything? If not, you have cannibalization. If yes, you probably have two pages doing different jobs.
| What you see | Verdict |
|---|---|
| Two URLs, both stable on page one | Fine. Leave them alone |
| Primary URL stable, second URL appears deep in results with few impressions | Noise. Ignore it |
| Branded query showing homepage, pricing and product pages | Normal for branded terms |
| Ranking URL alternates week to week, position drifts down | Cannibalization |
| Wrong page type ranks, such as a post for a commercial query | Cannibalization of intent. Fix it |
| Two near-identical pages, neither in the top 10 | Cannibalization. Usually a merge |
Mixed-intent queries deserve care. If the results page shows service pages and how-to guides side by side, Google hasn’t decided what the searcher wants, and ranking with one page of each type can be the best outcome available.
Fix options: merge, re-target, de-optimize or canonicalize
Start by choosing the primary URL. Intent comes first: a commercial query belongs to a commercial page, even if a blog post currently ranks higher. Among pages that match the intent, prefer the one with more referring domains, the better conversion rate and the stronger history in Search Console.
| Situation | Fix | Key step |
|---|---|---|
| Same topic and intent, secondary adds little | Merge | Move unique content, then 301 to the primary |
| Secondary has value and an open adjacent keyword | Re-target | New title, H1 and angle for a different query |
| Secondary must stay indexed for another reason | De-optimize | Remove the term from title, H1 and anchors |
| Near-duplicate needed for users or campaigns | Canonicalize or noindex | Canonical tag pointing to the primary |
Merge
This is the most common fix and usually the strongest. Move anything useful from the secondary page into the primary: a better example, a section the primary lacks, a table. Then 301 the secondary to the primary, update internal links so they point straight to the final URL instead of through the redirect, and remove the old URL from your XML sitemap. Don’t redirect to a loosely related page just to keep link equity somewhere; redirect to the page that actually answers the same query.
Re-target
When the secondary page is worth keeping, give it its own job. Pick an adjacent query nobody on the site owns yet, then rewrite the title tag, H1, intro and section headings around it. Say two posts both chase “SaaS onboarding.” One becomes the onboarding email sequence post, the other the onboarding checklist. Each now has a distinct intent, and both can rank.
De-optimize
Some pages have to stay for other reasons. A post might attract links, or a feature page might support sales. If one of them pulls a commercial term away from the page that should own it, remove the term from the title tag and H1, cut exact-match repetitions in the body and change any internal anchors that use it. Then add a contextual link to the primary page using that term. Keep the URL as it is; changing it creates a redirect you don’t need.
Canonicalize or noindex
Use a canonical when near-duplicates must stay live for users: product variants, the same article published under two sections, or a campaign page cloned from an organic one. Add rel="canonical" on the duplicate pointing to the primary. Google treats it as a hint and can ignore it when the pages differ substantially, so it only works on genuine near-duplicates. For paid landing pages that should never rank, noindex is cleaner. Don’t combine noindex with a canonical to another URL on the same page; the signals conflict.
Two mistakes I see in cleanup projects: deleting the secondary page and letting it 404 when it has backlinks, and changing a dozen pages in one week so nobody can tell which fix worked. Work in small batches and log what changed and when.
Using internal links to signal the primary page
Internal links are the cheapest signal you control, and inconsistent ones often keep cannibalization going. If half your posts link to one page with the keyword as anchor text and half link to another, you’ve told Google two pages own that term.
- Crawl the site with Screaming Frog or a similar crawler and export all internal links with their anchor text.
- Filter anchors containing the target keyword or its close variants.
- Repoint every matching link to the primary URL. Links that still point to the secondary page should use anchors that describe its new focus.
- Link from the secondary to the primary near the top of the body, with a descriptive anchor.
- Raise the primary’s prominence through navigation, hub pages or breadcrumbs if it’s a key commercial page.
Internal links rarely fix true duplicates on their own. They’re the follow-through after a re-target or de-optimize, and they keep a merge from drifting back. The wider system for planning links between related pages is in internal linking strategy.
Preventing it with a keyword-to-URL map
Most cannibalization comes from the content calendar: someone briefs a new post for a term an older page already owns. A keyword-to-URL map stops that. It’s a spreadsheet with one row per intent, and every keyword on the site has exactly one owner.
Here’s what a few rows might look like for a hypothetical SaaS company:
| Primary keyword | Variants on the same row | Intent | Owner URL | Anchor to use |
|---|---|---|---|---|
| customer onboarding software | onboarding platform, onboarding tool | Commercial | /product/onboarding/ | customer onboarding software |
| customer onboarding checklist | onboarding checklist template | Informational | /resources/onboarding-checklist/ | onboarding checklist |
| onboarding email sequence | welcome email series | Informational | /resources/onboarding-emails/ | onboarding email sequence |
The rules that keep it working:
- Check the map before approving any brief. If the keyword or a close variant has an owner, update that page instead of publishing a new one.
- One intent, one owner URL. Variants with the same intent go on the same row, not new rows.
- Record the anchor text other pages should use when linking to each owner.
- Update the map the day you merge, redirect or re-target a page.
- Once a month, re-run the query-and-page check on your top queries and review any query that picked up a second URL.
The map is only as good as the research behind it. If you’re building one from scratch, keyword research for B2B SaaS covers how to group terms by intent before you assign owners. In my SEO engagements, the map sits next to the content calendar, and no brief gets written without an owner URL on it.
Get it built
If rankings keep swapping between your pages, or your blog is outranking the pages that should convert, I’ll find the conflicts, fix them and set up the map that keeps them fixed. Start with a Growth Audit, $1,500 fixed and credited if we continue. See pricing or get in touch.