Openseo keyword research skill
Discover keyword opportunities with MEASURED volume, keyword difficulty, CPC, and intent from OpenSEO, then write them into brand/keyword-plan.md.
by MoizIbnYousaf·MIT license·GitHub ↗
★ 31 Stars on the repo·Checked
npx degit MoizIbnYousaf/marketing-cli/skills/openseo-keyword-research#main ~/.claude/skills/openseo-keyword-researchFiles of Openseo keyword research
Files 1 file
Show the full text100 lines
OpenSEO Keyword Research
Turn seed topics into a prioritized, MEASURED keyword opportunity set and land it in brand/keyword-plan.md. mktg's keyword-research is the playbook (methodology); this skill is the measured-data engine behind it when OpenSEO is configured.
On Activation
- Readiness check:
mktg seo status --json --fields readiness,catalog.endpointError,project— if readiness isnot_configured, stop spending: state the gap and hand off to Exa-backedkeyword-researchwith metrics markedunknown. For a ready state, verify live access with the freewhoamiMCP tool before paid calls. - Project binding: read
.seo/openseo.jsonforprojectId. Missing → runopenseo-project-setupfirst (or ask the user for the project id). - Brand grounding: read
brand/positioning.md+ existingbrand/keyword-plan.md(tolerate templates). Business-fit beats volume-fit — the positioning file is the filter.
OpenSEO MCP Tools
get_search_console_performance: when GSC is connected, START here. HighrowLimit, filter average position ~5–20 client-side (the API sorts by clicks, not position). These striking-distance terms are the fastest wins — and zero extra credit cost.get_keyword_metrics: hydrate up to 700 keywords per call with volume, KD, intent, CPC, trends. Use on striking-distance terms and every candidate set.research_keywords: discovery from 1–5 seeds per call; prefer ~150 results unless exhaustive research was requested.get_ranked_keywords: when the brief includes a domain/page — exact ranking rows (near-misses, competitor-owned terms).get_serp_results: inspect SERPs for top candidates when intent is ambiguous. Keep batches small (≤10 queries).list_saved_keywords: avoid re-researching what's already saved.save_keywords: a free shared-state mutation. Use only after confirmation, with concise tags (topic:<t>,intent:<i>,page:<slug>).
Workflow
- Normalize seeds into 2–5 distinct research angles filtered by positioning.
- GSC connected? Pull striking-distance terms first and hydrate with
get_keyword_metrics. Work that list before broad discovery. research_keywordsper angle;get_keyword_metricsto hydrate;get_ranked_keywordsif a domain is in the brief.- Remove irrelevant, duplicate, branded-only, and off-intent terms.
- Prioritize by practical opportunity: business fit → clear intent → reasonable KD → volume/CPC signal → winnable SERP.
get_serp_resultsfor high-potential or ambiguous terms when SERP intent would change the call.- Write the shortlist into
brand/keyword-plan.md(preserve its required sections perbrand/SCHEMA.md; confirm before overwriting populated sections). - Present: best opportunity theme, top keywords now, keywords to save, SERP caveats. Then next actions:
openseo-keyword-clustering,seo-content, or save.
Cost Discipline
- State estimated call counts before bulk pulls (>200 keywords) and get confirmation.
- Small exploratory batches are fine without asking.
- GSC-first ordering exists precisely to avoid spending credits on data the user already owns.
Anti-Patterns
- Inventing metrics when OpenSEO returns nothing — because a hallucinated KD of "about 35" silently becomes the foundation of a content plan. If OpenSEO doesn't return a value, write
unknown. - Volume-first prioritization — because a 10k-volume term that doesn't match the product converts nobody and burns months. Positioning filters the list before metrics rank it.
save_keywordswithout explicit confirmation — saves do not burn provider credit, but they mutate shared OpenSEO account state and broad tags can disrupt other workflows. Ask, state the count and tag change, then save.- Skipping the GSC-first pass when GSC is connected — because striking-distance terms (positions 5–20) are provably the cheapest wins in SEO and they're free to read. Discovery research before first-party data is wasted spend.
- Overwriting a populated
keyword-plan.mdwithout confirmation — because that file is brand memory other skills build on (seo-content,seo-machine). Merge; confirm destructive rewrites.
Close the loop
After writing files, log completion so mktg plan / mktg status count the work (bare mktg run only logs loaded):
mktg run openseo-keyword-research --complete --writes <paths written> --result success --json
Progressive Enhancement
| Level | Behavior |
|---|---|
| L0 (no OpenSEO) | Hand off to Exa-backed keyword-research; metrics unknown |
L1 (OPENSEO_API_KEY) |
Metrics via available calls; MCP steps deferred |
| L2 (MCP connected) | Full workflow incl. SERP validation |
| L3 (GSC connected) | Striking-distance-first ordering; highest-signal path |
Adapted from every-app/open-seo .agents/skills/keyword-research (MIT). Workflow and tool guidance upstream; mktg brand-memory writes, positioning filter, and cost discipline added here.
| 1 | |
| 2 | name openseo-keyword-research |
| 3 | description >- |
| 4 | Discover keyword opportunities with MEASURED volume, keyword difficulty, |
| 5 | CPC, and intent from OpenSEO, then write them into brand/keyword-plan.md. |
| 6 | Use this skill whenever someone asks for keyword difficulty, KD, search |
| 7 | volume, keyword ideas with metrics, striking-distance opportunities from |
| 8 | Search Console, or SERP-validated keyword priorities. For qualitative |
| 9 | research without an OpenSEO connection, use mktg's keyword-research |
| 10 | instead (metrics will be unknown). Triggers: "keyword difficulty", |
| 11 | "search volume", "keyword opportunities", "striking distance keywords", |
| 12 | "measured keyword research". |
| 13 | category seo |
| 14 | tier nice-to-have |
| 15 | layer strategy |
| 16 | reads |
| 17 | - brand/keyword-plan.md |
| 18 | - brand/positioning.md |
| 19 | writes |
| 20 | - brand/keyword-plan.md |
| 21 | env_vars |
| 22 | - OPENSEO_API_KEY |
| 23 | - OPENSEO_MCP_URL |
| 24 | triggers |
| 25 | - keyword difficulty |
| 26 | - search volume |
| 27 | - keyword opportunities |
| 28 | - striking distance keywords |
| 29 | - measured keyword research |
| 30 | allowed-tools |
| 31 | - Bash(mktg catalog *) |
| 32 | - Bash(mktg run *) |
| 33 | |
| 34 | |
| 35 | # OpenSEO Keyword Research |
| 36 | |
| 37 | Turn seed topics into a prioritized, MEASURED keyword opportunity set and land it in `brand/keyword-plan.md`. mktg's `keyword-research` is the playbook (methodology); this skill is the measured-data engine behind it when OpenSEO is configured. |
| 38 | |
| 39 | ## On Activation |
| 40 | |
| 41 | **Readiness check**: `mktg seo status --json --fields readiness,catalog.endpointError,project` — if readiness is `not_configured`, stop spending: state the gap and hand off to Exa-backed `keyword-research` with metrics marked `unknown`. For a ready state, verify live access with the free `whoami` MCP tool before paid calls. |
| 42 | **Project binding**: read `.seo/openseo.json` for `projectId`. Missing → run `openseo-project-setup` first (or ask the user for the project id). |
| 43 | **Brand grounding**: read `brand/positioning.md` + existing `brand/keyword-plan.md` (tolerate templates). Business-fit beats volume-fit — the positioning file is the filter. |
| 44 | |
| 45 | ## OpenSEO MCP Tools |
| 46 | |
| 47 | `get_search_console_performance`: when GSC is connected, START here. High `rowLimit`, filter average position ~5–20 client-side (the API sorts by clicks, not position). These striking-distance terms are the fastest wins — and zero extra credit cost. |
| 48 | `get_keyword_metrics`: hydrate up to 700 keywords per call with volume, KD, intent, CPC, trends. Use on striking-distance terms and every candidate set. |
| 49 | `research_keywords`: discovery from 1–5 seeds per call; prefer ~150 results unless exhaustive research was requested. |
| 50 | `get_ranked_keywords`: when the brief includes a domain/page — exact ranking rows (near-misses, competitor-owned terms). |
| 51 | `get_serp_results`: inspect SERPs for top candidates when intent is ambiguous. Keep batches small (≤10 queries). |
| 52 | `list_saved_keywords`: avoid re-researching what's already saved. |
| 53 | `save_keywords`: a free shared-state mutation. Use only after confirmation, with concise tags (`topic:<t>`, `intent:<i>`, `page:<slug>`). |
| 54 | |
| 55 | ## Workflow |
| 56 | |
| 57 | Normalize seeds into 2–5 distinct research angles filtered by positioning. |
| 58 | GSC connected? Pull striking-distance terms first and hydrate with `get_keyword_metrics`. Work that list before broad discovery. |
| 59 | `research_keywords` per angle; `get_keyword_metrics` to hydrate; `get_ranked_keywords` if a domain is in the brief. |
| 60 | Remove irrelevant, duplicate, branded-only, and off-intent terms. |
| 61 | Prioritize by practical opportunity: business fit → clear intent → reasonable KD → volume/CPC signal → winnable SERP. |
| 62 | `get_serp_results` for high-potential or ambiguous terms when SERP intent would change the call. |
| 63 | Write the shortlist into `brand/keyword-plan.md` (preserve its required sections per `brand/SCHEMA.md`; confirm before overwriting populated sections). |
| 64 | Present: best opportunity theme, top keywords now, keywords to save, SERP caveats. Then next actions: `openseo-keyword-clustering`, `seo-content`, or save. |
| 65 | |
| 66 | ## Cost Discipline |
| 67 | |
| 68 | State estimated call counts before bulk pulls (>200 keywords) and get confirmation. |
| 69 | Small exploratory batches are fine without asking. |
| 70 | GSC-first ordering exists precisely to avoid spending credits on data the user already owns. |
| 71 | |
| 72 | ## Anti-Patterns |
| 73 | |
| 74 | **Inventing metrics when OpenSEO returns nothing** — because a hallucinated KD of "about 35" silently becomes the foundation of a content plan. If OpenSEO doesn't return a value, write `unknown`. |
| 75 | **Volume-first prioritization** — because a 10k-volume term that doesn't match the product converts nobody and burns months. Positioning filters the list before metrics rank it. |
| 76 | **`save_keywords` without explicit confirmation** — saves do not burn provider credit, but they mutate shared OpenSEO account state and broad tags can disrupt other workflows. Ask, state the count and tag change, then save. |
| 77 | **Skipping the GSC-first pass when GSC is connected** — because striking-distance terms (positions 5–20) are provably the cheapest wins in SEO and they're free to read. Discovery research before first-party data is wasted spend. |
| 78 | **Overwriting a populated `keyword-plan.md` without confirmation** — because that file is brand memory other skills build on (`seo-content`, `seo-machine`). Merge; confirm destructive rewrites. |
| 79 | |
| 80 | ## Close the loop |
| 81 | |
| 82 | After writing files, log completion so `mktg plan` / `mktg status` count the work (bare `mktg run` only logs `loaded`): |
| 83 | |
| 84 | |
| 85 | mktg run openseo-keyword-research --complete --writes <paths written> --result success --json |
| 86 | |
| 87 | |
| 88 | ## Progressive Enhancement |
| 89 | |
| 90 | | Level | Behavior | |
| 91 | |---|---| |
| 92 | | L0 (no OpenSEO) | Hand off to Exa-backed `keyword-research`; metrics `unknown` | |
| 93 | | L1 (`OPENSEO_API_KEY`) | Metrics via available calls; MCP steps deferred | |
| 94 | | L2 (MCP connected) | Full workflow incl. SERP validation | |
| 95 | | L3 (GSC connected) | Striking-distance-first ordering; highest-signal path | |
| 96 | |
| 97 | |
| 98 | |
| 99 | *Adapted from [every-app/open-seo] `.agents/skills/keyword-research` (MIT). Workflow and tool guidance upstream; mktg brand-memory writes, positioning filter, and cost discipline added here.* |
| 100 |
Discussion
Browse more free Claude skills or everything in Marketing.