Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Detect keyword cannibalization across blog posts by extracting primary keywords from titles and headings, clustering semantically similar targets, and flagging posts competing for the same search intent. Supports local-only mode (grep-based) and DataForSEO API mode (Page Intersection endpoint at ~$0.01/call). Outputs severity-scored report with merge or differentiate recommendations. Use when user says "cannibalization", "keyword overlap", "competing pages", "duplicate keywords", "cannibalize".
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-13 | ✗→✓ | ▲ Improved | 58% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 81% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 107% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 45% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 129% | 0% |
Detect when multiple blog posts compete for the same search keywords. Two modes: local-only analysis (default) and DataForSEO API mode for SERP-level data.
| Mode | Flag | Cost | Data Source | |------|------|------|-------------| | Local | (default) | Free | File content analysis via Grep/Read | | API | --api | ~$0.01/call | DataForSEO Page Intersection + Ranked Keywords |
Local mode works without any API keys. API mode requires DataForSEO credentials set as environment variables: DATAFORSEO_LOGIN and DATAFORSEO_PASSWORD.
Use Glob to find all content files in the target directory:
**/*.md, **/*.mdx, **/*.htmlnode_modules/, .git/, drafts/For each file, read and extract keyword signals from:
Primary keyword extraction method:
2-gram, and 3-gram phrases.
lemmatize or stem consistently, preserve product names, and keep intent modifiers such as "best", "pricing", "vs", "review", "template", and year.
first paragraph supporting.
secondary keywords from H2 headings.
Group posts into clusters using these matching rules (in priority order):
commercial, transactional, comparison, or troubleshooting. Include confidence and a one-sentence rationale, or use an embeddings workflow with a documented threshold.
vs "email marketing for startups")
For each cluster with 2+ posts, assess severity and generate a recommendation.
Display the results table and per-cluster recommendations.
Requires the --api flag and a dedicated local CLI wrapper that reads DATAFORSEO_LOGIN and DATAFORSEO_PASSWORD from the environment and emits JSON. Do not use WebFetch for DataForSEO POST calls and never expose Basic auth headers, login, password, or encoded credentials in prompts or reports. If no wrapper exists in the project, report SKIPPED: DataForSEO wrapper unavailable and run local mode.
Page Intersection - find keywords where multiple URLs rank:
POST https://api.dataforseo.com/v3/dataforseo_labs/google/page_intersection/live
{
"pages": {
"1": "https://example.com/post-a",
"2": "https://example.com/post-b"
},
"language_code": "en",
"location_code": 2840
}Cost: ~$0.01 per call. Returns overlapping keywords with position, volume, CPC.
Ranked Keywords - get all keywords a single URL ranks for:
POST https://api.dataforseo.com/v3/dataforseo_labs/google/ranked_keywords/live
{
"target": "https://example.com/post-a",
"language_code": "en",
"location_code": 2840
}The wrapper sends DataForSEO auth headers from environment variables and never prints them.
Four severity levels based on overlap signals:
| Level | Criteria | Action Urgency | |-------|----------|----------------| | Critical | Same exact keyword, both pages in top 20 | Immediate | | High | Same keyword cluster, one page outranks the other | This week | | Medium | Related keywords with partial SERP overlap | This month | | Low | Semantic similarity but different confirmed intents | Monitor |
severity_score = overlap_count x avg_search_volume x (1 / position_gap)Where:
overlap_count = number of shared ranking keywordsavg_search_volume = mean monthly volume of shared keywordsposition_gap = absolute difference in average ranking position (min 1)Higher score = more urgent cannibalization problem.
Without SERP data, use a simplified scoring:
| Post A | Post B | Shared Keywords | Severity | Recommendation |
|--------|--------|-----------------|----------|----------------|
| /best-crm-tools | /top-crm-software | best crm, crm tools, crm software | Critical | MERGE |
| /email-tips | /email-marketing-guide | email marketing | High | DIFFERENTIATE |
| /seo-basics | /seo-for-beginners | seo basics, beginner seo | Critical | CANONICAL |
| /react-hooks | /react-state-mgmt | react, state | Low | NO ACTION |For each flagged cluster, provide:
Four possible actions for each cannibalization cluster:
When both pages are thin or cover the same intent with similar depth.
When pages serve different intents but keyword targeting overlaps.
When one post is clearly the authority and the other is a lesser duplicate.
rel="canonical" on the weaker page pointing to the authorityfrom search is intended
When a page should be removed from search results but still exist for users.
When intent is genuinely different despite surface-level keyword similarity.
rate limits. If it still fails, switch to local mode for remaining URLs and report the failed endpoint without credentials
Other measured skills in the registry, with their headline benchmark lift.