---
name: seo-position-tracking
description: |
  Keyword position tracking for keyword ranking monitoring.
  Triggers: rank tracking, position monitoring, keyword rankings, visibility score, ranking report, 키워드 순위, 순위 추적.
---

# SEO Position Tracking

## Purpose

Monitor keyword ranking positions, detect significant changes, calculate visibility scores, and compare against competitors using our-seo-agent CLI or pre-fetched ranking data. Provides actionable alerts for ranking drops and segment-level performance breakdown.

## Core Capabilities

1. **Position Monitoring** - Retrieve current keyword ranking positions from our-seo-agent CLI or pre-fetched data
2. **Change Detection** - Detect significant position changes with configurable threshold alerts (severity: critical/high/medium/low)
3. **Visibility Scoring** - Calculate weighted visibility scores using CTR-curve model (position 1 = 30%, position 2 = 15%, etc.)
4. **Brand/Non-brand Segmentation** - Automatically classify keywords by brand relevance and search intent type
5. **Competitor Comparison** - Compare keyword overlap, position gaps, and visibility scores against competitors

## Data Source Selection

This skill can pull rank data from multiple backends. **Pick one per task** — don't fan out by default (cost + rate limits).

| Backend | Best for | Notes |
|---|---|---|
| **Ahrefs MCP** (`mcp__ahrefs__*`) | Default when an Ahrefs Rank Tracker project exists for the domain | `rank-tracker-overview`, `rank-tracker-serp-overview`, `rank-tracker-competitors-*`. Best historical view; data is what Ahrefs already polled. |
| **Semrush MCP** (`mcp__semrush__*`) | Default when no Ahrefs project; English/major market position scans | `tracking_research`, `organic_research`. `database="us"` default; `"kr"` for Korean. |
| **OurSEO CLI** (`our serp *`) | DataForSEO under the hood — full ranked-keywords pulls with volume, Korean-aware via `--location 2410` | Claude Code only (Bash). Commands: `our serp ranked-keywords`, `our serp domain-overview`, `our keywords volume`. |
| **OurSEO MCP** (`mcp__ourseo__check_serp`) | One-off rank spot-check for a single keyword/domain pair | Cheap; no historical view — pair with prior runs in MySQL / SQLite if tracking over time. |
| **DataForSEO MCP** (`mcp__dfs-mcp__*`) | Fallback when `our` CLI isn't running; historical rank overview | `dataforseo_labs_google_historical_rank_overview`, `dataforseo_labs_google_ranked_keywords`. |
| **GSC** (via `our research search-console` or Ahrefs `gsc-*`) | **First-party position data** — what Google actually rendered for the verified site | Only first-party source — use to validate or replace estimated positions. |

### How to pick

1. **User named a backend explicitly** → use it.
2. **User preference memory** — read `feedback_seo_tool_preferences.md`; honor the task-type default.
3. **Site is verified in GSC** AND task is single-site tracking → prefer **GSC** for ground truth, supplement with Semrush/Ahrefs for competitor delta.
4. **Ahrefs project exists for the domain** → prefer Ahrefs `rank-tracker-*`.
5. **Default**: Semrush MCP for new tracking jobs; **`our serp ranked-keywords`** for Korean batch.
6. **Still ambiguous + non-trivial** → ask once via `AskUserQuestion`.

### Backend call patterns

**Ahrefs MCP (when project exists):**
```
mcp__ahrefs__rank-tracker-overview(project_id="<id>")
mcp__ahrefs__rank-tracker-serp-overview(project_id="<id>")
mcp__ahrefs__rank-tracker-competitors-overview(project_id="<id>")
mcp__ahrefs__rank-tracker-competitors-stats(project_id="<id>")
```

**Semrush MCP (no Ahrefs project):**
```
mcp__semrush__tracking_research(query="<keyword>", database="us")
mcp__semrush__get_report_schema(report_id="...")
mcp__semrush__execute_report(report_id="...", params={...})
```

**OurSEO CLI (Korean batch):**
```bash
our serp ranked-keywords <domain> --location 2410 --limit 100 --format json
our serp domain-overview <domain> --location 2410 --format json
our keywords volume "<kw1>" "<kw2>" --location 2410 --language ko
our serp competitors <domain> --location 2410
```

**OurSEO MCP (spot-check):**
```
mcp__ourseo__check_serp(keyword="<keyword>", domain="<target.com>", country="kr")
```

**GSC (first-party validation):**
```bash
our research search-console queries --site sc-domain:<domain> --days 28
```

### Common parameters

| Concept | Semrush | Ahrefs | DataForSEO / `our` CLI |
|---|---|---|---|
| Korean market | `database="kr"` | `country="kr"` | `--location 2410` |
| US market | `database="us"` | `country="us"` | `--location 2840` |
| Japan | `database="jp"` | `country="jp"` | `--location 2392` |
| Language | (database-bound) | (country-bound) | `--language ko`/`en`/`ja` |

Always record the chosen data source in the report **Overview** so future tracking runs can compare like-for-like.

## Workflow

### Phase 1: Data Collection
1. Fetch current ranked keywords: `our serp ranked-keywords <domain> --location 2410 --limit 100 --format json`
2. Get domain overview: `our serp domain-overview <domain> --location 2410 --format json`
3. Get search volumes for tracked keywords: `our keywords volume "<kw1>" "<kw2>" --location 2410`
4. Fetch competitor positions: `our serp ranked-keywords <competitor> --location 2410 --limit 100`
5. For historical comparison, use MCP: `mcp__dfs-mcp__dataforseo_labs_google_historical_rank_overview`

### Phase 2: Analysis
1. Detect position changes against previous period
2. Generate alerts for changes exceeding threshold
3. Calculate visibility score weighted by search volume and CTR curve
4. Segment keywords into brand/non-brand and by intent type
5. Compare positions against each competitor

### Phase 3: Reporting
1. Compile position distribution (top3/top10/top20/top50/top100)
2. Summarize changes (improved/declined/stable/new/lost)
3. List alerts sorted by severity and search volume
4. Generate segment-level breakdown
5. Save report to Notion SEO Audit Log database

## Output Format

```json
{
  "target": "https://example.com",
  "total_keywords": 250,
  "visibility_score": 68.5,
  "positions": {
    "top3": 15,
    "top10": 48,
    "top20": 92,
    "top50": 180,
    "top100": 230
  },
  "changes": {
    "improved": 45,
    "declined": 30,
    "stable": 155,
    "new": 12,
    "lost": 8
  },
  "alerts": [
    {
      "keyword": "example keyword",
      "old_position": 5,
      "new_position": 15,
      "change": -10,
      "volume": 5400,
      "severity": "high"
    }
  ],
  "segments": {
    "brand": {"keywords": 30, "avg_position": 2.1},
    "non_brand": {"keywords": 220, "avg_position": 24.5}
  }
}
```

## Notion Output (Required)

All tracking reports MUST be saved to OurDigital SEO Audit Log:
- **Database ID**: `2c8581e5-8a1e-8035-880b-e38cefc2f3ef`
- **Properties**: Issue (title), Site (url), Category (Position Tracking), Priority, Found Date, Audit ID
- **Language**: Korean with English technical terms
- **Audit ID Format**: RANK-YYYYMMDD-NNN
