OpenSEO — SEO Data Plane
You connect mktg's SEO playbooks to a running OpenSEO instance (hosted at openseo.so or self-hosted Docker). You do NOT invent metrics. You do NOT call DataForSEO directly. You route measured data (KD, volume, SERP, ranked keywords, backlinks, rank tracking, GSC) into mktg artifacts like brand/keyword-plan.md.
OpenSEO is a data plane, not a playbook. The SEO methodology lives in keyword-research, seo-content, seo-audit, off-page-seo, ai-seo, and seo-machine — this skill is how those playbooks stop guessing.
North Star
- Measured data beats estimated data. When OpenSEO is configured, metrics come from OpenSEO's MCP tools. When it is not, you say so explicitly and fall back to Exa-backed qualitative research — metrics marked
unknown.
- mktg never calls DataForSEO directly. OpenSEO owns the vendor relationship; mktg talks to OpenSEO only.
- Expensive calls (bulk research,
save_keywords) follow dry-run/confirm discipline — DataForSEO credit is real money.
- OpenSEO project state syncs into
.seo/ and brand/keyword-plan.md; it never becomes a competing second source of truth.
On Activation
Run these steps before anything else. Each has a fallback that keeps the skill useful when OpenSEO is absent.
Step 1 — Verify the catalog is registered and configured
mktg catalog info openseo --json --fields configured,missing_envs,auth.credential_envs,mcp
- Exit code 1 → the openseo catalog is not registered (upgrade marketing-cli). Stop.
configured: false → env vars are missing. Build the fix string from missing_envs. Canonical envs: OPENSEO_API_KEY (required for non-interactive automation) and OPENSEO_API_BASE (REST base; self-host override). The MCP URL is mcp.default_url (https://app.openseo.so/mcp) unless OPENSEO_MCP_URL overrides it for self-host.
configured: true → proceed. If only the MCP client is connected (OAuth login in the user's agent client) but no API key exists, treat readiness as mcp_client_only: MCP tools work interactively, headless automation does not.
Step 2 — Establish the data-plane connection
Preferred: OpenSEO MCP tools via the agent's MCP client (root .mcp.json ships an openseo server entry — the user connects it once in their client). Hosted MCP uses OAuth login; for self-host, edit the url in .mcp.json (it is hardcoded) and set OPENSEO_MCP_URL so mktg catalog readiness reports the same base.
If no MCP connection and no OPENSEO_API_KEY: state the gap and downgrade to the Exa/Firecrawl path (Step 3 fallback). Do not fabricate a connection.
Step 3 — Route to the playbook with measured inputs
Hand the measured data to the SEO playbooks instead of running parallel research:
| Job |
Route |
Data you supply |
| Keyword opportunity discovery |
keyword-research |
KD, volume, intent from OpenSEO research tools |
| Programmatic SEO inputs |
seo-machine |
Validate KD/competition before page generation |
| Backlink gaps |
off-page-seo |
OpenSEO backlink overview for the domain |
| Rank drops / striking distance |
ai-seo, seo-audit |
Rank tracker + GSC snapshots |
Fallback (no OpenSEO): run the Exa-backed keyword-research path and mark every metric unknown. Say plainly: "OpenSEO is not configured — these are qualitative findings, not measured KD/volume. Set OPENSEO_API_KEY (or connect the MCP) to upgrade this run."
Cost Discipline
- Research calls in small batches are fine. Bulk pulls (hundreds of keywords) and
save_keywords writes REQUIRE user confirmation first — say the estimated call count out loud.
- Default to conservative result limits; widen only when asked.
- Log surprises (unexpected credit spend, rate limits) to
brand/learnings.md via mktg run openseo --learning '{...}'.
State Contract
| OpenSEO concept |
mktg home |
| Project id / domain |
.seo/openseo.json ({ projectId, domain, mcpUrl, updatedAt }) — create on first link |
| Saved keywords |
Merge into brand/keyword-plan.md (confirm before overwriting) |
| Rank snapshots |
.seo/rank-snapshots/<date>.json + short summary md |
| Backlink overview |
.seo/backlink-overview.json (input for off-page-seo) |
One resume protocol per long-arc SEO effort: docs/seo-machine.md stays the single tracker; OpenSEO data feeds it, it does not fork it.
Anti-Patterns
- Inventing KD/volume numbers — because agents hallucinate plausible metrics and downstream decisions (content priorities, page generation) get built on fiction. If OpenSEO is not configured, the metric is
unknown, full stop.
- Calling DataForSEO directly from mktg — because it bypasses OpenSEO's project state, caching, and cost controls, and duplicates the vendor integration mktg deliberately does not own. Always go through OpenSEO.
- Saving keywords or running bulk research without confirmation — because every call can spend DataForSEO credit; silent bulk spends are how budgets blow up. Confirm first, state the call count.
- Treating the OpenSEO web UI as required — because the MCP/API surface is the agent path; the UI is a human convenience. Never block an agent run waiting for a human to click something in a dashboard.
- Forking SEO state into a second system of record — because two keyword lists drift and agents stop trusting both. Sync INTO
.seo/ + brand/keyword-plan.md; OpenSEO stays the measurement backend, mktg stays the playbook brain.
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 --complete --writes <paths written> --result success --json
Progressive Enhancement
| Level |
Behavior |
| L0 (no envs, no MCP) |
Gap note + Exa-backed keyword-research fallback; metrics unknown |
L1 (OPENSEO_API_KEY set) |
Non-interactive research calls where REST exists; MCP still preferred |
| L2 (MCP connected) |
Full tool surface: research, SERP, ranked keywords, backlinks, GSC |
| L3 (project linked + synced) |
.seo/ snapshots feed seo-machine and off-page-seo automatically |
Integration shape follows the postiz catalog pattern: raw HTTP/MCP over the network boundary, never vendored code. OpenSEO is MIT-licensed (every-app/open-seo).
1---2name: openseo3description: Use OpenSEO (open-source Semrush/Ahrefs alternative) as the SEO data plane — keyword difficulty, search volume, SERP results, ranked keywords, measured backlink data, rank tracking, and Google Search Console. Use this skill whenever someone asks for keyword difficulty, KD, search volume, SERP positions, domain rankings, backlink data, rank tracking, or GSC performance. Owns backlink DATA (referring domains, counts, rank tracking); for link-building campaigns and outreach target lists, see /off-page-seo. ALWAYS prefer OpenSEO's measured data over estimated metrics when the catalog is configured; fall back to Exa-backed keyword-research (with an explicit gap note) when it is not. Triggers: "keyword difficulty", "search volume", "SERP results", "ranked keywords", "backlinks", "rank tracker", "GSC".4---56# OpenSEO — SEO Data Plane78You connect mktg's SEO playbooks to a running OpenSEO instance (hosted at openseo.so or self-hosted Docker). You do NOT invent metrics. You do NOT call DataForSEO directly. You route measured data (KD, volume, SERP, ranked keywords, backlinks, rank tracking, GSC) into mktg artifacts like `brand/keyword-plan.md`.910OpenSEO is a **data plane**, not a playbook. The SEO methodology lives in `keyword-research`, `seo-content`, `seo-audit`, `off-page-seo`, `ai-seo`, and `seo-machine` — this skill is how those playbooks stop guessing.1112## North Star13141. Measured data beats estimated data. When OpenSEO is configured, metrics come from OpenSEO's MCP tools. When it is not, you say so explicitly and fall back to Exa-backed qualitative research — metrics marked `unknown`.152. mktg never calls DataForSEO directly. OpenSEO owns the vendor relationship; mktg talks to OpenSEO only.163. Expensive calls (bulk research, `save_keywords`) follow dry-run/confirm discipline — DataForSEO credit is real money.174. OpenSEO project state syncs into `.seo/` and `brand/keyword-plan.md`; it never becomes a competing second source of truth.1819## On Activation2021Run these steps before anything else. Each has a fallback that keeps the skill useful when OpenSEO is absent.2223### Step 1 — Verify the catalog is registered and configured2425```bash26mktg catalog info openseo --json --fields configured,missing_envs,auth.credential_envs,mcp27```2829- Exit code 1 → the openseo catalog is not registered (upgrade marketing-cli). Stop.30- `configured: false` → env vars are missing. Build the fix string from `missing_envs`. Canonical envs: `OPENSEO_API_KEY` (required for non-interactive automation) and `OPENSEO_API_BASE` (REST base; self-host override). The MCP URL is `mcp.default_url` (`https://app.openseo.so/mcp`) unless `OPENSEO_MCP_URL` overrides it for self-host.31- `configured: true` → proceed. If only the MCP client is connected (OAuth login in the user's agent client) but no API key exists, treat readiness as `mcp_client_only`: MCP tools work interactively, headless automation does not.3233### Step 2 — Establish the data-plane connection3435Preferred: OpenSEO MCP tools via the agent's MCP client (root `.mcp.json` ships an `openseo` server entry — the user connects it once in their client). Hosted MCP uses OAuth login; for self-host, edit the `url` in `.mcp.json` (it is hardcoded) and set `OPENSEO_MCP_URL` so `mktg catalog` readiness reports the same base.3637If no MCP connection and no `OPENSEO_API_KEY`: state the gap and downgrade to the Exa/Firecrawl path (Step 3 fallback). Do not fabricate a connection.3839### Step 3 — Route to the playbook with measured inputs4041Hand the measured data to the SEO playbooks instead of running parallel research:4243| Job | Route | Data you supply |44|---|---|---|45| Keyword opportunity discovery | `keyword-research` | KD, volume, intent from OpenSEO research tools |46| Programmatic SEO inputs | `seo-machine` | Validate KD/competition before page generation |47| Backlink gaps | `off-page-seo` | OpenSEO backlink overview for the domain |48| Rank drops / striking distance | `ai-seo`, `seo-audit` | Rank tracker + GSC snapshots |4950**Fallback (no OpenSEO):** run the Exa-backed `keyword-research` path and mark every metric `unknown`. Say plainly: "OpenSEO is not configured — these are qualitative findings, not measured KD/volume. Set `OPENSEO_API_KEY` (or connect the MCP) to upgrade this run."5152## Cost Discipline5354- Research calls in small batches are fine. Bulk pulls (hundreds of keywords) and `save_keywords` writes REQUIRE user confirmation first — say the estimated call count out loud.55- Default to conservative result limits; widen only when asked.56- Log surprises (unexpected credit spend, rate limits) to `brand/learnings.md` via `mktg run openseo --learning '{...}'`.5758## State Contract5960| OpenSEO concept | mktg home |61|---|---|62| Project id / domain | `.seo/openseo.json` (`{ projectId, domain, mcpUrl, updatedAt }`) — create on first link |63| Saved keywords | Merge into `brand/keyword-plan.md` (confirm before overwriting) |64| Rank snapshots | `.seo/rank-snapshots/<date>.json` + short summary md |65| Backlink overview | `.seo/backlink-overview.json` (input for off-page-seo) |6667One resume protocol per long-arc SEO effort: `docs/seo-machine.md` stays the single tracker; OpenSEO data feeds it, it does not fork it.6869## Anti-Patterns7071- **Inventing KD/volume numbers** — because agents hallucinate plausible metrics and downstream decisions (content priorities, page generation) get built on fiction. If OpenSEO is not configured, the metric is `unknown`, full stop.72- **Calling DataForSEO directly from mktg** — because it bypasses OpenSEO's project state, caching, and cost controls, and duplicates the vendor integration mktg deliberately does not own. Always go through OpenSEO.73- **Saving keywords or running bulk research without confirmation** — because every call can spend DataForSEO credit; silent bulk spends are how budgets blow up. Confirm first, state the call count.74- **Treating the OpenSEO web UI as required** — because the MCP/API surface is the agent path; the UI is a human convenience. Never block an agent run waiting for a human to click something in a dashboard.75- **Forking SEO state into a second system of record** — because two keyword lists drift and agents stop trusting both. Sync INTO `.seo/` + `brand/keyword-plan.md`; OpenSEO stays the measurement backend, mktg stays the playbook brain.7677## Close the loop7879After writing files, log completion so `mktg plan` / `mktg status` count the work (bare `mktg run` only logs `loaded`):8081```bash82mktg run openseo --complete --writes <paths written> --result success --json83```8485## Progressive Enhancement8687| Level | Behavior |88|---|---|89| L0 (no envs, no MCP) | Gap note + Exa-backed `keyword-research` fallback; metrics `unknown` |90| L1 (`OPENSEO_API_KEY` set) | Non-interactive research calls where REST exists; MCP still preferred |91| L2 (MCP connected) | Full tool surface: research, SERP, ranked keywords, backlinks, GSC |92| L3 (project linked + synced) | `.seo/` snapshots feed `seo-machine` and `off-page-seo` automatically |9394---9596*Integration shape follows the postiz catalog pattern: raw HTTP/MCP over the network boundary, never vendored code. OpenSEO is MIT-licensed ([every-app/open-seo](https://github.com/every-app/open-seo)).*