openseo-keyword-research · git:20260816.3161ba8 · 2026-08-16 · sha256 959f9c176075c69e
openseo-keyword-research git:20260816.3161ba8A
Immutable. This exact content is served forever at /api/v1/blob/959f9c176075c69e.
--- name: openseo-keyword-research description: >- Discover keyword opportunities with MEASURED volume, keyword difficulty, CPC, and intent from OpenSEO, then write them into brand/keyword-plan.md. Use this skill whenever someone asks for keyword difficulty, KD, search volume, keyword ideas with metrics, striking-distance opportunities from Search Console, or SERP-validated keyword priorities. For qualitative research without an OpenSEO connection, use mktg's keyword-research instead (metrics will be unknown). Triggers: "keyword difficulty", "search volume", "keyword opportunities", "striking distance keywords", "measured keyword research". category: seo tier: nice-to-have layer: strategy reads: - brand/keyword-plan.md - brand/positioning.md writes: - brand/keyword-plan.md env_vars: - OPENSEO_API_KEY - OPENSEO_API_BASE triggers: - keyword difficulty - search volume - keyword opportunities - striking distance keywords - measured keyword research allowed-tools: - Bash(mktg catalog *) - Bash(mktg run *) --- # 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 1. **Catalog check**: `mktg catalog info openseo --json --fields configured` — if not configured, stop spending: state the gap and hand off to Exa-backed `keyword-research` with metrics marked `unknown`. 2. **Project binding**: read `.seo/openseo.json` for `projectId`. Missing → run `openseo-project-setup` first (or ask the user for the project id). 3. **Brand grounding**: read `brand/positioning.md` + existing `brand/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. 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. - `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`: ONLY after explicit user confirmation, with concise tags (`topic:<t>`, `intent:<i>`, `page:<slug>`). ## Workflow 1. Normalize seeds into 2–5 distinct research angles filtered by positioning. 2. GSC connected? Pull striking-distance terms first and hydrate with `get_keyword_metrics`. Work that list before broad discovery. 3. `research_keywords` per angle; `get_keyword_metrics` to hydrate; `get_ranked_keywords` if a domain is in the brief. 4. Remove irrelevant, duplicate, branded-only, and off-intent terms. 5. Prioritize by practical opportunity: business fit → clear intent → reasonable KD → volume/CPC signal → winnable SERP. 6. `get_serp_results` for high-potential or ambiguous terms when SERP intent would change the call. 7. Write the shortlist into `brand/keyword-plan.md` (preserve its required sections per `brand/SCHEMA.md`; confirm before overwriting populated sections). 8. 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_keywords` without explicit confirmation** — because saves mutate the user's OpenSEO account and bulk saves burn credit. Ask, state the count, 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.md` without 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`): ```bash 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](https://github.com/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.*