Most articles about keyword cannibalization start from the assumption that any two pages ranking for the same search are a problem, and end by telling you to merge them. That advice fixes some sites and quietly damages others. A better starting point is to ask what the two pages are each for, and what the numbers say is actually happening.
This guide is about telling those cases apart on a WordPress site: the habits that create competing pages, a step-by-step way to find them in Google Search Console, and a decision table for which ones to leave alone. The detailed fixes have their own guide on merging, redirecting and re-targeting competing posts, which this one refers to as “the fixes guide” from here on.
What keyword cannibalization is
Keyword cannibalization (also spelled “cannibalisation”) is when two or more pages on your site go after the same search, with the same purpose, so they compete with each other instead of one of them being the clear answer. The word is borrowed from retail, where a new product “cannibalises” sales of an old one. Here, what gets split is clicks, links and Google’s confidence about which of your pages to show.
Two things have to be true for it to be cannibalization rather than coverage:
- The same query. Both pages get impressions for the same search, in the same period, not just for vaguely related ones.
- The same intent. A reader typing that search would be equally happy with either page, because they answer the same need. This is the part most audits skip. Search intent is what the person wants, not the words they used.
A recipe blog with “Easy banana bread” and “Banana bread with oil instead of butter” has two pages that will both show for banana bread recipe. A reader who wants the classic version does not want the oil version, and the reverse. That is two answers to two needs that happen to share words. A travel site with “Lisbon in three days” and “Three-day Lisbon itinerary (updated)” has two answers to one need. Only the second is a problem.
Nobody is penalised for this; Google has never described a penalty for it, and its own staff talk about it as a question of focus, not of rules (more on that below). The cost is indirect: links and attention are split, the URL Google shows can keep changing, and neither page settles as high as one clear page might. That last part is the common industry view rather than something Google has documented, so treat it as a hypothesis to test against your own numbers.
What it isn’t: when two results are fine
Google’s own people have been openly sceptical of the term. In September 2025 John Mueller replied on Bluesky to a question about tracking cannibalization in Search Console. He pointed out that Search Console only reports pages that were actually shown, said “it’s not really ‘cannibalization’ if it’s theoretical”, and added that three of your pages in the same results is not a problem just because it is more than one. His advice was to cut unnecessary duplication and put the energy into one excellent page, while remembering that pages are not duplicates simply because they appear for the same search.
Parts of the SEO industry say the same. Ahrefs’ own guide to keyword cannibalization argues it is a problem only when overlapping pages demonstrably cost traffic, and quotes Patrick Stox dismissing the idea that several pages simply “confuse” Google. One reason to be careful: pages rank for far more than one keyword. In Ahrefs’ 2017 study of three million queries, the average number-one page also ranked in the top ten for nearly 1,000 other relevant keywords (the median was around 400). Merge two pages to win one query and you can lose some of the hundreds of others the weaker page was quietly earning.
That gives you three situations that look like cannibalization and usually are not:
- Two of your pages on page one, together. Google can show more than one result from a site. In 2019 it announced a site diversity change that generally limits a site to two listings in the top results, which tells you two is a normal, allowed outcome. If a hobby site on fountain pens has its buying guide at position 3 and its nib-size explainer at position 6, it has two shots at the click.
- Different intents behind one phrase. A WooCommerce outdoor-gear shop’s category page for trail running shoes (wants to browse and buy) and its blog post “How to choose trail running shoes” (wants to learn first) serve different moments. If the results for that search mix shops and buying guides, there is room for both.
- A page that ranks for thousands of queries. Any decent post will pick up impressions for long-tail searches that a neighbouring post owns. A handful of impressions at position 60 for someone else’s keyword is noise.
Ask whether the two pages are taking turns, or working together. Taking turns is a problem. Working together is coverage. The rest of this guide is mostly about telling those apart with data.
Symptoms worth taking seriously
These are the patterns that are worth your time, roughly from most to least telling.
- The ranking URL flips. For one query, Google shows post A for a week or two, then post B, then A again. In the illustrative chart below, the query’s total impressions hardly change; what changes is which page gets them.
- Impressions are split, and both pages sit lower than one used to. Say a personal-finance blog’s guide ranked around position 6 for sinking funds before a second post went up, and now the two share the impressions at positions 14 and 18. The before-and-after is what makes the case; a split on its own does not.
- The wrong page ranks. A local plumber wants the “Boiler repair in Leeds” service page to show for boiler repair leeds, but Google keeps choosing a 2021 blog post about a boiler repair job, which has no booking form.
- A low click-through rate on a decent position. If the URL Google picks has a title that does not match the search, people skip it. This is often the wrong-page symptom seen from another angle.
How WordPress creates competing pages
WordPress makes it easy to publish the same thing twice without meaning to. These are the usual sources, and most sites have at least three of them.
| Source | What happens | Usual fix |
|---|---|---|
| A tag and a category with the same name | /category/sourdough/ and /tag/sourdough/ list almost the same posts, and both can rank for the topic | Keep one taxonomy per topic; set tag archives to noindex in your SEO plugin |
| Date and author archives | On a one-author blog, /author/name/ is a copy of the home page; /2023/05/ pages repeat post excerpts | Disable them in your SEO plugin (paths below) |
| Yearly “update” posts | “Best budgeting apps 2023”, “…2024”, “…2025” all live at once and all target the same search | One evergreen URL, updated each year; redirect the old ones to it |
| Attachment pages | Every uploaded image gets its own thin page that can be indexed | Turn them off; WordPress 6.4 does this by default on new sites only |
| Pagination | /blog/page/2/ and later pages pick up impressions for broad topic queries | Leave each page’s canonical tag pointing at itself; strengthen the hub instead |
| WooCommerce products and categories | A product called “Waterproof hiking jacket” competes with the category of the same name | Distinct titles and copy; link products up to the category |
| Imported or migrated content | A move from another platform leaves old and new slugs live, or creates “-2” duplicates | Redirect the duplicates; check for posts ending in -2 |
Where the switches are in Yoast and Rank Math
Most of the archive problems above are one setting each. The menu paths below are from each plugin’s current documentation; labels move between versions, so if yours differ, look for the same words nearby.
| Archive | Yoast SEO | Rank Math |
|---|---|---|
| Tag archives | Yoast SEO → Settings → Categories & tags → Tags: turn off showing them in search results | Rank Math SEO → Titles & Meta → Tags: enable Tag Archives Robots Meta, choose No Index |
| Author archives | Yoast SEO → Settings → Advanced → Author archives (switch off on a one-author site) | Rank Math SEO → Titles & Meta → Authors → Author Archives: Disabled |
| Date archives | Yoast SEO → Settings → Advanced → Date archives | Rank Math SEO → Titles & Meta → Misc Pages → Date Archives |
| Attachment pages | Yoast SEO → Settings → Advanced → Media pages (redirect attachment URLs to the file) | Rank Math SEO → General Settings → Links → Redirect Attachments |
Sources for those paths: Yoast’s help pages for its Advanced settings and its Categories & tags settings, and Rank Math’s knowledge-base articles on Titles & Meta, noindexing URLs and its General Settings. Noindexing a tag archive is the right tool here rather than a redirect: the archive still exists for readers who click a tag, it just stops competing in search.
Three of the causes deserve a closer look.
Attachment pages
Older WordPress sites give every uploaded image its own page. In version 6.4, core disabled attachment pages for new installations, but sites that existed before the upgrade keep them switched on. If your site is older than late 2023, check: open any image in the media library and click through to its attachment URL. If it shows a page, turn them off with your SEO plugin’s setting or the wp_attachment_pages_enabled option.
Pagination
It is tempting to point the canonical of /page/2/ at page one. Google specifically says not to: its pagination guidance says don’t use the first page of a paginated sequence as the canonical, and to give each page its own. If archive pages are outranking your posts, the archive is not the problem; the post is not clearly the best answer yet, and probably needs more internal links from related posts.
The yearly update post
This is a very common cause on review and how-to sites. Each January somebody publishes “Best X for 2025” at a new URL instead of updating last year’s. After three years you have three posts on one search, the oldest with the most links and the newest with the freshest content. Keep one URL with no year in the slug, update it each year, and put the year in the title only.
Finding it in Google Search Console
Search Console is the only place that tells you which of your URLs Google actually showed for a query. Start here, with one query you care about.
- Open Performance → Search results and set the date range to the last three months. Shorter ranges are too noisy for this.
- Filter to one query. Click + Add filter → Query, then choose “Exact query” to see one search, or “Queries containing” to catch variations like sinking funds list and what are sinking funds.
- Switch to the Pages tab. It now lists every one of your URLs that appeared for that query, with clicks, impressions and average position for each. Google notes in its Performance report documentation that tables grouped by page are aggregated by page, so each URL gets its own count even when two appeared in the same search.
- Look for a second URL with a real share. One page with 95% of the impressions and another with 5% is normal. Two pages with 60% and 40% is worth a closer look.
- Check for flipping. Click one URL in the table to filter to it, switch the chart to show impressions, and look at the line. Then do the same for the other. If one rises as the other falls, Google is taking turns.
- Compare pages directly. Remove the page filter, add a Page filter with Compare, and put the two URLs side by side, still filtered to the query. The table then gives you a difference column for each metric. Google’s help page on advanced filtering and comparison covers the options, including regex query filters.
Here is what a real-looking result for the personal-finance example looks like:
| Page | Clicks | Impressions | Avg. position |
|---|---|---|---|
| /what-are-sinking-funds/ | 212 | 6,240 | 14.3 |
| /sinking-funds-2024/ | 131 | 4,910 | 17.8 |
| /category/saving/ | 4 | 380 | 41.0 |
Two posts with a 56/44 split of impressions, both outside the top ten, for the same informational search: that is the pattern worth fixing. The category page at position 41 is noise.
Google says filtering by query or page can change report totals because of data truncation and anonymised queries, so filtered numbers will not add up to the unfiltered ones. And average position is an average over every time the page was shown, so a page that sat at 8 for a month and at 30 for two months will show as roughly 23. Use the chart, not just the table.
Checking a whole site with a spreadsheet
Checking one query at a time is fine for your top twenty searches. For a whole site you need every query and page pair in one table, and the export from the Performance report will not give you that: its Queries and Pages tabs are separate lists. There are two ways to get the pairs.
- Looker Studio. Add the Search Console connector and choose the URL Impression table (the Site Impression table counts by property, so it cannot tell your pages apart). Build a table with Query and Landing Page as dimensions and Impressions, Clicks and Average Position as metrics, then export it to Google Sheets.
- The Search Console API. Its searchanalytics.query method takes
queryandpageas dimensions and returns up to 25,000 rows per request, paged withstartRow. The script below exports a quarter. The service account’s email address has to be added as a user on the property first.
# pip install google-api-python-client google-auth
# Read-only. Exports every query + page pair for one quarter to query-page.csv.
from google.oauth2 import service_account
from googleapiclient.discovery import build
import csv
SITE = "sc-domain:example.com" # or "https://www.example.com/"
creds = service_account.Credentials.from_service_account_file(
"key.json", scopes=["https://www.googleapis.com/auth/webmasters.readonly"])
gsc = build("searchconsole", "v1", credentials=creds)
rows, start = [], 0
while True:
resp = gsc.searchanalytics().query(siteUrl=SITE, body={
"startDate": "2026-07-01", "endDate": "2026-09-30",
"dimensions": ["query", "page"],
"rowLimit": 25000, "startRow": start,
}).execute()
batch = resp.get("rows", [])
rows += batch
if len(batch) < 25000:
break
start += 25000
with open("query-page.csv", "w", newline="") as f:
out = csv.writer(f)
out.writerow(["query", "page", "clicks", "impressions", "position"])
for r in rows:
out.writerow([*r["keys"], r["clicks"], r["impressions"], round(r["position"], 1)])Open the file in Google Sheets or Excel with the columns in this order: query (A), page (B), clicks (C), impressions (D), position (E). Then add two helper columns.
F2 pages with 10+ impressions for this query:
=COUNTIFS(A:A, A2, D:D, ">=10")
G2 this page's share of the query's impressions:
=D2 / SUMIF(A:A, A2, D:D)
Then filter: F >= 2, G between 0.15 and 0.85, D >= 100.
Sort by query, then by impressions (largest first).What you are left with is every query where two or more of your pages each take a real share of the impressions. The thresholds (10 impressions, a 15–85% share, 100 impressions per query) are working rules, not anything Google publishes; loosen or tighten them until the list is short enough to read. Then group the rows by the pair of URLs involved, because the same two posts tend to compete on a cluster of related searches, and you fix the pair once.
For example, a SaaS help centre might find 31 queries with a split that come down to only nine pairs of articles, most of them an old article and the rewrite that replaced it, both still published. Nine decisions is an afternoon’s work; 31 looks like a project.
Quick checks: site: searches and free tools
Search Console only knows about searches where you already get impressions. Two quicker checks catch the rest, including competing pages that are too new or too weak to show up yet.
- A site: search. Type
site:yourdomain.com sinking fundsinto Google. Google’s documentation for the site: operator says it does not necessarily return every indexed URL, so it is not a complete list or a ranking report. It is still a fast way to see which of your pages match the phrase. If five posts come back with near-identical titles, you have a cluster to look at. - Your own titles. In WordPress, go to Posts → All Posts, click the Title column to sort alphabetically, and scan for repeats; use the search box for “best”, “guide” and each recent year. Ten minutes of reading catches most yearly-update duplicates.
- A free checker. Our keyword cannibalization checker gives you a first shortlist of pages that may be competing, so you know which pairs to open in Search Console first.
Deciding whether it’s a real problem
Now the important part. For each pair you found, decide whether there is anything to fix. Intent is the deciding question; the numbers tell you how urgent it is.
| What you see | Same intent? | Verdict | Example |
|---|---|---|---|
| Two pages, both on page one, combined clicks up | Either | Leave it. This is coverage. | Pen buying guide at 3, nib-size explainer at 6 |
| A category or product page and a how-to post | No | Leave it; make titles and copy distinct, link post to category | “Trail running shoes” category and “How to choose trail running shoes” |
| Two posts taking turns, both below position 10 | Yes | Fix: merge into one URL and redirect the other | “Sinking funds” and “Sinking funds 2024” |
| The wrong page ranks for a money search | Partly | Fix: re-target the blog post and repoint internal links | Plumber’s case-study post outranking the service page |
| An archive page competes with a post | Yes | Fix: noindex thin tag archives; add links to the post | /tag/kyoto/ outranking “Kyoto in two days” |
| A few impressions at position 50 or worse | Either | Ignore. It is noise. | Any page picking up long-tail stragglers |
If you cannot tell whether the intent is the same, search the phrase yourself and look at what Google shows. If the top ten are all one kind of page (all recipes, all product listings, all step-by-step guides), Google has decided the intent, and only one of your pages fits it. If the results are mixed, there is room for both of yours.
The fixes, in brief
Once you know a pair is a real problem, there are six things you can do with it. Here they are in brief; each one has a full walkthrough, with WordPress steps and server examples, in the fixes guide linked at the top of this page.
| Fix | When it fits |
|---|---|
| Merge and 301 | Same intent, both pages have something worth keeping. Fold the best of one into the other and add a 301 redirect. |
| Re-target | The pages overlap but could each own a different, real search. Rewrite one for its own angle. |
| Canonical | Both URLs must stay live for readers (a printable version, a filtered list). Point a canonical tag at the main one. |
| Noindex | Pages that should exist but never rank, such as thin tag archives. Use noindex, not a redirect. |
| De-optimise | The weaker page is right to exist but uses the stronger one’s title and headings. Change its wording. |
| Leave it | Different intents, or both pages already doing well together. |
Deleting the weaker post outright, which leaves broken links and throws away its history; or adding a canonical between two pages that say different things. Google treats a canonical as a signal, not a command, in its guidance on consolidating duplicate URLs, and it is meant for duplicates.
Choosing one winner, giving it the best content from both, redirecting the other, and pointing every internal link straight at the winner.
The internal-link side of the problem
Internal links are where many competing-post problems are made worse, and the cheapest place to fix them. Google says in its link best practices that it uses links as a signal when judging the relevance of pages, and that good anchor text describes the page it points to. Your own links are the part of that signal you fully control. If half your posts link to one sinking-funds post and half to the other, you are describing both as the answer.
Three things to check for every pair you decide to fix:
- Which page do your links point at? Count the inbound internal links to each URL. A crawler will give you exact numbers; Search Console’s Links report (Links → Internal links → Top linked pages) gives a rough count, though Google describes it as a sample. The winner should have clearly more.
- Which words do they use? If links with the anchor text “sinking funds” go to both posts, pick one destination for that phrase. The guide to anchor text for internal links explains why one phrase should mean one page, and the one on exact-match links covers how much repetition is too much.
- Do any links go through a redirect? After a merge, every link to the old URL still works but takes an extra hop. Update them to point straight at the winner.
For the wrong-page problem, repointing links is the cheapest thing to try first, before anything you cannot easily undo. Picture a travel site whose tag archive for Kyoto keeps outranking its Kyoto itinerary. A crawl shows only two posts link to the itinerary in their text, while every Kyoto post links to the tag through the theme. Adding contextual links to the itinerary from six related posts costs half an hour and changes nothing else, so if the itinerary takes over in the following weeks, you know why. There is no published study that says how often this alone is enough; it is a low-risk first step, not a guaranteed fix.
Competing pages also tend to turn up during a broader audit; the internal link audit checklist includes them as one step, and the internal linking strategy pillar explains, more broadly, how to decide which pages your links should favour.
What to do on Monday
- Pick your ten most valuable queries
The ones that bring traffic or sign-ups. Run the six-step Search Console check on each.
- Look for flipping and real splits
Two URLs with at least 15% of the impressions each, or a ranking URL that changes from week to week.
- Decide by intent
Use the table above. Write down the verdict for each pair, including “leave it”.
- Repoint internal links first
For every pair you are fixing, point links and the matching anchor text at the winner.
- Then merge, redirect or re-target
Following the step-by-step guide, one pair at a time, with the date noted so you can measure it.
Where Silotree fits
Silotree detects competing posts from your Search Console queries, suggests which one should be the winner, and repoints your internal links to it in one click. Links that go through redirects after a merge can be fixed in one click too, on every plan. The merging and redirecting itself stays your decision, made in WordPress. If you want to see the rest of your link problems first, the free internal link checker needs no account. If you already use Rank Math, the comparison of Silotree and Rank Math covers what each one does with internal links, and the pricing page lists what each plan includes.
- John Mueller on cannibalization and Search Console data (Bluesky, September 2025) — John Mueller, Google
- Announcement of the site diversity change (June 2019) — Google Search Liaison
- Performance report (Search results) — Search Console Help
- Performance report: advanced filtering and comparison — Search Console Help
- Search Analytics: query — Google Search Console API
- Pagination, incremental page loading, and their impact on Google Search — Google Search Central
- Changes to attachment pages — Make WordPress Core
- Keyword cannibalization: what it (really) is and how to fix it — Ahrefs
- “Also rank for” study (3 million queries, 2017) — Ahrefs
- Link best practices for Google — Google Search Central
- How to specify a canonical URL with rel="canonical" and other methods — Google Search Central
- Google Search site: operator — Google Search Central
- Links report — Search Console Help
- Connect to Search Console — Looker Studio Help
- Yoast SEO settings: Advanced — Yoast
- Yoast SEO settings: Categories & tags — Yoast
- Titles & Meta settings — Rank Math
- How to noindex URLs with Rank Math — Rank Math
- General Settings — Rank Math
Questions people ask
Does Google penalise keyword cannibalization?
No. There is no penalty for having two pages that rank for the same query. The cost is indirect: links, clicks and attention are split between two pages, and Google may keep swapping which one it shows, so neither settles as high as one clear page might.
Is it a problem if two of my pages rank together on page one?
Usually not. If both results are useful and the pair together earns more clicks than either did alone, that is a good outcome. It becomes a problem when the two pages take turns, when the wrong one shows, or when both sit lower than a single page used to.
How many impressions do I need before I trust the data?
There is no official threshold. As a working rule, ignore queries with fewer than a hundred or so impressions over three months, because the averages swing too much to read. Spend your time on queries that bring real traffic or that matter to your business.
Should I delete one of the competing posts?
Rarely on its own. Deleting a post without a redirect throws away whatever links and history it had and leaves broken internal links behind. If a post has nothing worth keeping, redirect it to the closest match instead of deleting it outright.
Can category and tag pages cannibalise my posts?
Yes, especially when a tag and a category share a name, or when an archive page has more text than the posts in it. The usual fix is to stop creating duplicate taxonomies and set thin tag archives to noindex in your SEO plugin, rather than redirecting them.
How long after a fix should I check the results?
Give it at least four weeks, and compare equal periods before and after. Google has to recrawl both pages and the links pointing at them. Some fixes settle within a fortnight; others take a couple of months, and a single week of data tells you very little.
