calendar Last updated: 7 September 2026
How I Catch Keyword Cannibalization with Search Console and Claude
Data integration

How I Catch Keyword Cannibalization with Search Console and Claude

Try It Free

Connect your data in 1 min. Free forever plan

Got insights from this post? Give it a boost by sharing with others!

Keyword cannibalization, or content cannibalization, is two of our own pages ranking for the same queries and splitting the impressions between them. I find it in Search Console by pulling query and page together, then measuring, for each page in a pair, what share of its own impressions comes from the queries it shares with the other page. That percentage and the position gap on those shared queries decide whether one page gets redirected into the other. Search Console calculates neither, so this is a check I run on the data itself, and these days a question I ask Claude.

Search Console, GA4, and your CMS (WordPress here, since that’s what we run) are usually three separate places to check: three logins, three exports, three URL formats that don’t match by default. Joined into one table, keyed on the same URL, they stop being three exports and become a single queryable dataset, a real dashboard you can ask questions of.

Two examples of what that makes visible: keyword cannibalization, and updates whose results get judged before Google has even had a chance to see them.

Both patterns show up on any site that’s had more than one person touching content over time. Strategy shifts, priorities change, different people make different calls without a shared view of what’s already live, that’s what causes them, not a one-off mistake.

I check for both with the cannibalization module in an internal dashboard built around a process I ran by hand for years before it existed: pulling Search Console, GA4, and WordPress data separately and merging it myself in spreadsheets. The dashboard covers a lot more than these two problems, editorial priorities, opportunity scoring, page-level performance, but here’s how I use it for these two specifically. Making a call between two competing pages takes three sources, each doing a different job:

  • Search Console shows which one Google already prefers, and when it last crawled either.
  • WordPress shows when each was last edited, so you know whether a before/after read is even trustworthy yet.
  • GA4 shows the engagement rate for each, telling me whether the page I’m keeping needs anything from the one I’m redirecting.

How I find keyword cannibalization in Search Console

The pull is query and page together, with impressions and average position for each row, over the last 30 days. Non-branded queries only, and each query needs at least 30 impressions in that window, so a handful of stray impressions doesn’t create a pair.

For every query where two of our pages both show, I work out two numbers per page: the share of its own impressions that comes from the queries it shares with the other page, and its average position on those shared queries only. A page drawing 80% or more of its impressions from queries the other page outranks it on is a merge and redirect candidate. An 80% concentration over 3 shared queries is the same signal as 80% over 30.

Search Console’s Performance report shows one page’s queries at a time and exports 1,000 rows. It has no view that puts two pages next to each other and it doesn’t calculate the share, which is why I ran this in a spreadsheet for years after exporting, and why the cannibalization module in the dashboard exists.

Here’s a pair that came up when I ran this check.

The pair I found

Eight shared queries. One page pulling 38% of its own impressions from that shared set, the other 100%.

URLs and queries below are relabeled, real pages, real numbers, just not ones I’m naming publicly:

  • 38.0% of Page A’s impressions come from these 8 queries
  • 100.0% of Page B’s impressions come from these 8 queries
Query Page A impr. Page A pos. Page B impr. Page B pos.
Query 1 668 3.0 44 3.0
Query 2 26 26.0 46 6.2
Query 3 69 7.9 1 13.0
Query 4 35 6.7 33 9.6
Query 5 17 8.0 2 9.5
Query 6 11 7.2 7 10.7
Query 7 8 9.0 1 7.0
Query 8 4 77.8 3 88.3

Keep Page A. It averages position 4.8 on the shared queries versus 8.1 for Page B, Google already prefers it. Page B should be merged into Page A and redirected, it draws no impressions from outside this overlap.

Unique to Page A: 1,367 impressions outside the shared set. Unique to Page B: none of significant volume.

Page B has no traffic outside the shared queries, and Page A outranks it on every one of them. That’s not visible from either page’s Search Console numbers alone, only when you check what percentage of each page’s traffic comes from the shared set, a percentage Search Console doesn’t calculate for you.

Contrast this with a pair where the overlap is real but partial, say 40% for one page and 20% for the other. Redirecting there is riskier: both pages draw meaningful traffic the other doesn’t touch, so consolidating would throw away real, unique impressions. Same range of shared queries, a different correct action, and you can’t tell which situation you’re in without the percentage.

Before I redirect anything, I check GA4

Search Console only measures visibility, not what happens after the click. If the losing page has better engagement metrics, the fix is updating the winner’s format to match it, not just redirecting.

So before I acted on the recommendation above, I pulled GA4 engagement data for both pages over the same window:

Metric (last 3 months) Page A Page B
Sessions 53 10
Engagement rate 47.2% 50.0%
Avg. engagement time 31s 22s

Nothing here changes how Page A ends up looking. Page B’s engagement rate edges out Page A’s by under 3 points, but that’s on a sample of 10 sessions, too small to treat as a real difference. Its average engagement time is actually shorter, not longer. If Page B had real volume behind that engagement rate, or if its engagement time were ahead too, that’s the pattern that would send me back into Page A’s content to borrow whatever Page B was doing right, before touching the redirect. Here, there’s nothing worth carrying over.

That’s the typical outcome: most of the time, GA4 doesn’t turn up anything worth changing about the page I’m keeping. I run the check every time regardless, because the times it does are exactly the times I’d want to update that page’s format before redirecting, not just after.

Why I don’t trust a before/after check without a crawl date

The common way to measure a content update: change the page, note the date, come back in a couple weeks, compare Search Console numbers before and after. It’s also an easy way to reach the wrong conclusion.

Search Console’s Performance data doesn’t record when Google recrawled a page, only when clicks and impressions were logged. You can get a page’s last crawl date from the URL Inspection tool in the GSC UI, but only one URL at a time, and there’s no way to export it, you’d have to check and note down each URL by hand. Confirming it at any scale means the URL Inspection API instead.

So before trusting a before/after comparison, I check whether Google has recrawled the page since I edited it. If not, I stop. The dashboard also flags this automatically: any edit inside the last 14 days is too fresh to read, on top of Search Console’s 2-3 day reporting delay and GA4 dropping the current day as partial.

New content needs the same check, in reverse. The data point is when the new page’s URL first shows impressions in Search Console, not the publish date. Zero impressions for the first couple of weeks may just mean it’s not indexed yet, not that it’s underperforming.

What I check, every time

On every page pair, whether or not anything looks off:

  • Any pair where one page draws 80%+ of its own impressions from queries the other page already outranks it on gets flagged for a merge or redirect decision.
  • Position gap gets checked on the shared queries specifically, not each page’s overall average position, which is diluted by every unrelated query it also ranks for.
  • Before acting on that flag, I pull GA4 engagement rate and average engagement time for both pages. If the “losing” page is ahead on both, with real session volume behind it, I update the winner’s format to match it before redirecting.
  • Pairs with real, meaningful traffic unique to both pages get a closer look, not a redirect: I check whether the overlapping queries are actually important to each page on its own terms, and how much of each page’s unique impressions they’re pulling in, before deciding whether the two need to be differentiated or can stay as they are.

How I ask for it instead of exporting it

Once this is one connected dataset, I ask directly instead of exporting three things and eyeballing them. The first prompt is the keyword cannibalization check itself, the same calculation described above, run on connected data:

Which of our page pairs have one page drawing 80%+ of its own impressions from non-branded queries it shares with another page, each query with a minimum of 30 impressions over the last 30 days? Doesn't matter if that's over 3 shared queries or 30.
Pull GA4 engagement rate, average engagement time, and sessions for [url] and [url]. Flag it if either is ahead on both engagement metrics.
Has Google recrawled [url] since I last edited it? If not, don't compare before/after numbers yet, tell me when it's safe to check.
Give me our top 10 cannibalized page pairs, ranked by overlap percentage. For each, show how much traffic each page gets, last crawl date, publish date, and engagement metrics for both.

These are ordinary questions to ask once the sources are connected. What made them hard before was three separate logins and three incompatible URL formats to reconcile before the analysis could even start.

🚀 See what your own Search Console, GA4, and WordPress data looks like connected in one place. Free forever plan, no credit card. Try Windsor.ai.

What I’m doing about this pair

Before redirecting, I check whether Page B has any content Page A doesn’t, something worth merging in rather than losing. Here it doesn’t: everything Page B ranks for, Page A already ranks for too, and outranks it on average. Page A keeps 1,367 impressions from outside the overlap. Page B’s contribution outside the overlap rounds to nothing, nothing meaningful to lose by redirecting it in.

Conclusion

Keyword cannibalization and measuring too early are both common problems. Both stay hidden unless you’re looking at Search Console, GA4, and WordPress together.

I’ve built this kind of dashboard before, more than once, at previous jobs. Every time, step one was authenticating each source myself, a few minutes per connector, and it doesn’t always go smoothly. What’s different about doing it through a connector is what happens after that: I can share the dashboard, or a Claude skill built on top of it, with a teammate without handing them an API key, or with anyone who already has the same connectors set up on their own end.

The tools behind this

I pull this from our own Google Search Console, Google Analytics 4, and WordPress connectors. If you also want this queryable from Claude, here’s the Windsor MCP setup guide.

FAQs

What is keyword cannibalization?

Two or more of your own pages ranking for the same queries and splitting the impressions between them, so neither performs as well as one consolidated page would. The number to look at is the share of a page’s own impressions that comes from queries another page already outranks it on. A page at 80% or more is a merge and redirect candidate, whether that concentration sits over 3 shared queries or 30.

Tired of juggling fragmented data? Get started with Windsor.ai today to create a single source of truth

Let us help you automate data integration and AI-driven insights, so you can focus on what matters, growth strategy.
g logo
fb logo
big query data
youtube logo
power logo
looker logo