Lee Foot

Keyword Cannibalisation Finder

Find keywords where multiple pages compete for the same query.

Launch the app → View the source

#about

Groups GSC data by query-page combinations using pandas transform("count") to detect competing pages per query.

Calculates mean position and CTR per entry.

Filters by position range, minimum impressions, minimum clicks, and minimum competing pages thresholds.

Parses percentage CTR strings automatically.

Sorts by competing page count and impressions.

Streamlit appUses Search Console data

Platform
Browser-based (no installation required)
Input
GSC export CSVCTR column optional (set to 0 when missing)Flexible column naming with auto-detection
Output
Grouped view: cannibalisation summary by query with totals. Detailed view: all query-page combinations with metrics. Summary cards in dashboard.

Use cases

  • Identifying content consolidation opportunities
  • Finding internal linking improvements
  • Prioritising page optimisation
  • Cleaning up site architecture

#features

  • Position range filter (1-100, default 1-20)
  • Minimum impressions threshold (0-100,000)
  • Minimum clicks threshold (0-10,000)
  • Minimum competing pages filter (2-10, default 2)
  • Automatic CTR percentage parsing
  • Grouped view and detailed view exports

#how-to-use

  1. Export GSC data with query and page in each row (API export; the UI export splits them)
  2. Upload CSV (columns auto-detected)
  3. Set position range (default 1-20)
  4. Configure impression, click and competing page minimums
  5. Tick Show full URLs before downloading if you need complete URLs in the grouped CSV
  6. Download grouped or detailed CSV

#faq

What input format is required?
A CSV where every row has query, page, clicks, impressions and position together. The GSC UI export splits queries and pages into separate files, so you need an API-style export with both per row. Common column name variants (Top queries, Landing Page, Avg. position and so on) are auto-mapped, and percentage CTR strings like '5.2%' are parsed.
Is a CTR column required?
No. If there is no CTR column the tool fills it with 0 rather than deriving it from clicks and impressions, so the CTR figures in the output are only meaningful if your export included them.
Why are the URLs in my grouped CSV cut short?
The 'Show full URLs' checkbox affects the grouped export as well as the on-screen table: with it off (the default), Best Page is truncated to the last path segment, capped at 50 characters, before the CSV is written. Tick 'Show full URLs' before downloading if you need complete URLs. The detailed CSV always contains full URLs.
How is cannibalisation actually decided?
Rows are filtered by position range (default 1-20) and the minimum impressions and clicks thresholds, then aggregated per query-page pair (clicks and impressions summed, position and CTR averaged). Any query left with at least the minimum number of pages (default 2) is flagged. Because the position filter runs first, a competing page averaging position 25 is not counted under the default range.

/contact

Want me to run this for you? I run this tool as a managed service, or build something custom around your data. You get the insights without touching the code.