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 explains what each report checks and when its evidence is useful.
Switch sites without copying property IDs
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:
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:
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 explains how to read that result and what the export cannot prove.
Use seo start to create the first profile. The setup guide
covers multiple sites and local storage.
Find search opportunities from site data
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 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:
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:
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:
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:
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:
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 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:
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
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 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:
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:
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:
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 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:
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
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, 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:
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
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.