---
title: "SEO commands | SEO Skill"
description: "Audit a site, investigate lost traffic, research search opportunities and save evidence before you make a change. Scripts and CI can run the same reports as JSON."
canonical: "https://seoskill.dev/docs/cli"
language: "en"
---

# SEO commands

Audit a site, investigate lost traffic, research search opportunities and save evidence before you make a change. Scripts and CI can run the same reports as JSON.

The CLI has a short path for normal work and a report registry for agents and scripts. You do not need to learn the whole command tree before getting a useful answer.

## Get the answer without running the whole site

| Job | Start with |
| --- | --- |
| Broad review with recommended next steps | `seo report` |
| Broad technical review before connecting Google | `seo report --url <url>` |
| Rank the next search and technical actions | `seo refresh-priorities` |
| Find page-one rankings with weak CTR evidence | `seo quick-wins` |
| Turn a topic into a keyword and competitor shortlist | `competitive-opportunities` |
| Research keyword ideas and market estimates | `keyword-research`, `keyword-metrics` |
| Find recurring search competitors | `serp-competitors` |
| Compare relevant competitor keyword gaps | `competitor-keyword-gap` |
| Review referring links and linked targets | `link-evidence` |
| Review rankings averaging positions 10 to 20 | `seo second-page` |
| Check crawl and index monitoring evidence | `seo technical-watch` |
| Audit one live URL | `seo audit-page --url <url>` |
| Build a technical site baseline | `seo crawl <url> --save` |
| Notify search engines about changed URLs | `seo indexnow submit --dry-run` |

Run `seo report` first when the request is broad. Pick a focused command when the question already names the job. A one-page audit takes you straight to the live evidence when one landing page is all you need to inspect.

The [report catalog](https://seoskill.dev/docs/reports) explains what each report checks and when its evidence is useful.

## Switch sites without copying property IDs

```sh
seo projects list
seo report --project example
seo crawl --project example --max-pages 500
```

`--project` is the public selector for saved profiles. A profile can hold the Search Console property, default crawl URL, optional Google Analytics property, brand terms, and reporting preferences.

Commands can still run without a profile when you provide their required site or URL:

```sh
seo report --site sc-domain:example.com
seo report --url https://example.com
seo crawl https://example.com
seo redirect-trace --url https://example.com/old-page
```

`seo report --url` creates a limited local crawl and skips Search Console analysis on purpose. It is the right first run for a site you have not connected yet. Add `--site` or `--project` when the report should join search performance data.

A downloaded Search Console performance export can join that URL report before you connect anything:

```sh
seo report --url https://example.com --search-console-export ./performance-export
```

The report reads the query and page tables, keeps them separate from the crawl, and tells you which exported pages the crawl could not reach. The [setup guide](https://seoskill.dev/docs/getting-started) explains how to read that result and what the export cannot prove.

Use `seo start` to create the first profile. The [setup guide](https://seoskill.dev/docs/getting-started) covers multiple sites and local storage.

## Find search opportunities from site data

```sh
seo quick-wins --project example
seo second-page --project example
seo decaying --project example
seo cannibal --project example
seo ctr-underperformers --project example
seo page-opportunities --project example --url https://example.com/pricing
```

These reports use returned Search Console rows. Saved brand terms let reports exclude branded queries where that comparison matters. Read the date window, row limits, and omitted-query caveats before you call a list complete.

The [Google data guide](https://seoskill.dev/docs/google) explains why Search Console chart totals and exported query rows can differ.

## Add independent keyword and competitor research

Provider-backed reports use the same discovery and run commands as every other report:

```sh
seo providers dataforseo connect
seo providers dataforseo limits
seo reports describe serp-competitors --json
seo reports describe competitor-keyword-gap --json
```

Start with `keyword-opportunities` when Search Console demand should lead the investigation. Use `serp-competitors` to find recurring domains across an explicit keyword set. Classify the relevant domains, then compare no more than three with `competitor-keyword-gap`.

Domain research uses country and language. Use `serp-results` for a current place and device-specific result snapshot. Provider estimates, Search Console measurements and live observations stay separate.

Use `ai-mention-research` for provider-indexed mentions, cited domains, and a limited sample of related questions for one AI surface and market:

```sh
seo reports run ai-mention-research \
  --params '{"target":{"label":"Example Analytics"},"surface":"google-ai-overview","countryCode":"GB","languageCode":"en","location":{"code":2826},"domain":"example.com","site":"sc-domain:example.com"}' \
  --json
```

The default run makes one metrics request and one sample request. Set `includeSamples` to `false` for metrics only. Read provider coverage, cache, cost, task ids, observation time, and warnings before interpreting the result. Optional Search Console overlap adds Search Console context without turning an indexed mention record into a live prompt observation.

Use `ai-prompt-observations` for a small set of current answers. Pass exact current model names so later observations do not silently move to a different baseline:

```sh
seo reports run ai-prompt-observations \
  --params '{"prompts":[{"id":"analytics-tools","prompt":"Which privacy-friendly analytics tools suit a small publisher?"}],"models":[{"surface":"chatgpt","model":"current-model-name"}],"target":{"label":"Example Analytics","domains":["example.com"]},"countryCode":"GB","languageCode":"en"}' \
  --json
```

The free model-catalog check runs before paid work. An invalid model response lists current choices. The effective model is the model the provider says it actually ran, which can differ from the exact model you requested. Read it with coverage, cache state, citations, task id, exact returned cost, warnings, and comparison status before interpreting a target match or change. Each returned answer is one sample, not an assistant ranking or universal visibility score.

Use `local-search-demand` when Search Console should lead a local investigation:

```sh
seo reports run local-search-demand \
  --params '{"site":"sc-domain:example.com","locationTerms":["london","manchester"],"days":90}' \
  --json
```

The default run makes no paid request. It finds explicit place names, nearby phrases and postal codes in returned query-page rows, then groups repeated page patterns for review. Add `includeSerps`, a canonical location and a device only when up to three exact live snapshots would change the next step. Those snapshots retain limited local-pack listing rows and recurring organic domains. The domains remain unclassified search competitors until you inspect them.

Add `googleAnalyticsPropertyId` when visitor geography would change how you review the returned landing pages or repeated page templates:

```sh
seo reports run local-search-demand \
  --params '{"site":"sc-domain:example.com","locationTerms":["london","manchester"],"googleAnalyticsPropertyId":"123456789"}' \
  --json
```

The report requests sessions by landing page, country, region and city. It normalizes away the landing-page query string, then keeps only exact paths that were returned from the local Search Console evidence. It never assigns an Analytics location to a Search Console query.

The [research provider guide](https://seoskill.dev/docs/research-providers) covers credentials, local cost limits, caching, supported reports and programmatic data-source checks.

The same provider connection can add a current link summary and representative referring URLs to the existing link report:

```sh
seo links --provider dataforseo --target example.com --json
seo links --provider dataforseo --target example.com \
  --search-site sc-domain:example.com --json
```

The second form joins a matching saved crawl and returned Search Console page evidence. It can prioritize linked targets with observed technical problems, but it still requires a live page and referring-link check before action.

## Save technical evidence before you change the site

```sh
seo crawl --project example --save
seo crawl-reports --project example
seo crawl-reports --project example --compare latest --against previous
```

A saved crawl gives you a baseline for deployment checks, technical follow-ups, and agent questions. Reuse it when the page evidence is still current. Crawl again after a release or when the stored result no longer represents the live site.

The [crawler guide](https://seoskill.dev/docs/crawler) covers limits, JavaScript rendering, robots handling, exports, and severity gates.

## Reuse the same page or query group

`seo content-groups` saves a page or query pattern on your machine. Use a group when the same set needs to appear in change measurement more than once. A group id is calmer and less error-prone than copying a long URL list into every command.

Create a page group for one site:

```sh
seo content-groups add --site sc-domain:example.com --name "Blog pages" --dimension page --match contains --pattern "/blog/"
seo content-groups list --site sc-domain:example.com
seo content-groups --help
```

`--dimension` accepts `page` or `query`. `--match` accepts `equals`, `contains`, or `regex`. The command stores the site, name, dimension, match type, and pattern. It does not crawl the site or check whether every intended URL matches the pattern, so test a regex before you use it for measurement.

The add command returns a reusable group id. List output shows each saved group and its filter. Add `--json` when an agent or script needs the complete record.

Use that id as the target of a group-scoped change:

```sh
seo change-log add --site sc-domain:example.com --scope group --target <group-id> --title "Updated blog titles" --date 2026-05-12
seo change-log measure --id <change-id> --json
```

Page groups can scope compatible Search Console and Google Analytics evidence. Query groups scope Search Console evidence and do not attach unfiltered sitewide Google Analytics data. The measurement still shows correlation around a recorded change, not proof that the change caused the movement.

Delete a group only when later measurements no longer need it:

```sh
seo content-groups delete --id <group-id>
```

Deleting the local group does not change the site, Search Console, or Google Analytics. The [change measurement report](https://seoskill.dev/docs/reports/measure-change) explains finalized windows, control evidence, and confounders.

## Use JSON when nobody is watching the terminal

JSON mode never prompts. Pass every selector a command needs:

```sh
seo report --project example --json
seo crawl https://example.com --json --output crawl.json
seo crawl https://example.com --fail-on high --json
```

Structured output keeps observed evidence, derived findings, skipped sections, thresholds, source limits, and errors in fields a program can inspect. Do not scrape the human table output.

`--fail-on high` returns a non-zero exit when the crawl contains findings at that severity or above. The JSON still contains the evidence that caused the gate to fail, which makes the command useful in CI logs.

## Keep scripts current as report inputs change

```sh
seo reports list --category opportunities --json
seo reports describe quick-wins --json
seo reports run quick-wins --params '{"site":"sc-domain:example.com"}' --json
```

`list` gives you compact report ids and descriptions. `describe` returns the current input schema. `run` executes that registered report. The same registry backs the CLI and [local MCP tools](https://seoskill.dev/docs/mcp), so there is one implementation of the analysis.

## Refresh only when you need fresh provider data

Many provider requests use a local cache to avoid repeated API calls. Add `--refresh` when a command supports it and you need to bypass that cache:

```sh
seo report --project example --refresh
seo crawl --project example --refresh --save
```

Fresh does not mean final. Recent Search Console rows and Google Analytics processing can still change at the provider.

## Get focused help in the terminal

```sh
seo help
seo report --help
seo crawl --help
seo help all
```

Root help keeps the common path short. `seo help all` lists the deeper command tree when you need raw provider queries, experiments, exports, monitoring, or local data controls.
