Seo Audit Console

io.github.houtini-ai由 GitHub 帳號 houtini-ai 發布v1.0.1更新於 Nov 5, 2026

Technical SEO in Claude: GSC + crawl + DataForSEO - audit, portfolio, market sizing, content recon.

發布方自己的服務:audit.domains - Domain Valuation

概覽

AI 產生的概覽

在本機執行的 SEO 稽核伺服器,把 Google Search Console 資料與網站爬取合併,在助理內給出評分後的技術 SEO 問題與修正方案。

可以做什麼
  • 以背景工作同步 Search Console 歷史、爬取網站、檢查 URL 索引與排名,並輪詢工作狀態
  • 執行評分式技術 SEO 稽核、依單項檢查查詢證據,並以彙總查詢讀取原始資料表
  • 產生可直接貼上的修正(JSON-LD、301 規則、內部連結),把 404 整理成重新導向對照表,並比對最近兩次爬取
  • 依範本分群頁面、找出語意近似重複頁、為段落打相關性分數並產出有依據的寫作簡報
  • 呼叫付費 DataForSEO 資料:關鍵字量、搜尋意圖、趨勢、SERP 特性、競爭對手、反向連結與 Lighthouse
  • 產出內容機會報告、多網域組合檢視,以及儀表板或可分享的 HTML 報告
適用情境
當你擁有 Search Console 資源,希望助理稽核它、依可挽回點擊量解釋問題並起草修正時使用。適合持續的技術與內容 SEO 工作、競爭對手與市場研究,以及多網域組合監控。
執行需求
透過 npx 在本機執行,需要 Node.js 22 或更新版本(僅桌面端)。需要 GOOGLE_APPLICATION_CREDENTIALS 指向 Google 服務帳戶 JSON 金鑰,且該帳戶電子郵件須在 Search Console 資源中加為使用者。選用:DATAFORSEO_USERNAME 與 DATAFORSEO_PASSWORD、MAJESTIC_API_KEY、CRUX_API_KEY、SAC_DATA_DIR。轉譯頁面檢查需選用安裝 Playwright。
安裝前請注意
服務帳戶金鑰檔可存取你的 Search Console 資料,請勿放入共用設定。DataForSEO 與 Majestic 為按次付費服務,部分工具會依關鍵字或 URL 計費。資料僅透過你觸發的呼叫外送:Google、DataForSEO、Majestic、Wikidata、Hugging Face 模型下載,以及對外部連結的 HEAD 請求。修正為試執行產物,但清理與儲存工具會更動本機資料庫。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Seo Audit Console,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

[SEO Audit Console]

SEO Console - the technical/content/research/opportunity SEO audit MCP server for Claude

A technical SEO audit you can hold a conversation with - built from your own Search Console data and a live crawl of your site, run inside Claude.

[npm version] [License: Apache 2.0] [MCP] [Node] [Socket Badge]

Almost every technical SEO audit I've been handed in twenty years is a crawler's opinion, and a crawler only ever sees half the picture. It tells you what your site says. It has nothing to say about what Google did about it: which queries you rank for, which pages earn the impressions, where the clicks land.

This one brings the other half. SEO Audit Console runs inside Claude, pulls your Google Search Console history, crawls your site properly, and joins the two so every finding carries the traffic at stake. A hundred and forty-three checks, ranked by the clicks the fix could recover rather than how alarming the check sounds, and it writes the fix for you: the 301 rule, the JSON-LD, the internal links. The core audit needs nothing but your own Search Console; DataForSEO and Majestic slot in later, when your questions grow into competitors and link building. Your data stays on your machine.

Built by Houtini. We build automation for the grunt work of digital marketing - the data collection, the crawling, the merging, the checking - so your team's time goes on the thinking, the strategy and the client work that needs a human. This plugin is that idea applied to the technical SEO audit.

New to MCPs, or not sure where to start? The Getting started guide takes you from a completely fresh machine (no Node, no Git, never heard of a service account) to your first audit - every step screenshotted, including the one everyone misses. Ten minutes, honestly.

console
you  › run an SEO audit on mysite.com
     ⣾ search console  1.8M rows synced (19s - incremental)     ⣾ crawl           868 pages · HTTP/2 · robots-polite · 8 parallel     ⣾ link graph      internal PageRank · click depth · in-degree     ✓ 143 checks · 220 findings · ranked by expected clicks per dev-hour
     #1  CTR far below position-expected     /pricing                   XL     #2  Page losing clicks (trend)          site-wide                  XL     #3  Keyword cannibalisation             "project management app"   L     #4  Robots-blocked page earning traffic /category/guides           L
you  › generate the fix for #1 ▍

[The Summary tab - data freshness, a one-line verdict, the headline tiles, 16 months of clicks, health per audit, what's broken and what to fix first, what changed since the last crawl, AI search and data coverage]

[The Network tab - the site-network map of your internal link skeleton, equity vs traffic by template, and the folder-to-folder equity flow]

Quick start

It's on npm, so there's nothing to clone or build. You need Node.js 22 or newer (Node 20 is end-of-life) and a Search Console property you own.

The quickest start, on Windows, is one-click. Download seo-audit-console.mcpb from the latest release and open it in Claude Desktop (Settings → Extensions). It installs itself, dependencies and runtime included, and asks for your Google key in a form instead of any JSON editing. The bundle carries native modules built for Windows; on macOS or Linux (or if you'd rather wire it up yourself, or you're on Claude Code) use the config routes below, which fetch the right binaries for your system. Either way you still need the Search Console service account - see getting started.

Claude Desktop - add this to claude_desktop_config.json, then restart Claude:

json
{  "mcpServers": {    "seo-audit-console": {      "command": "npx",      "args": ["-y", "@houtini/seo-audit-console"],      "env": {        "GOOGLE_APPLICATION_CREDENTIALS": "C:/path/to/service-account.json",        "DATAFORSEO_USERNAME": "",        "DATAFORSEO_PASSWORD": "",        "MAJESTIC_API_KEY": "",        "CRUX_API_KEY": ""      }    }  }}

The first line is required. The others are optional: paste your key between the quotes, or leave them empty to switch the tier off. DataForSEO and Majestic are paid tiers; CRUX_API_KEY is field Core Web Vitals from a free Google API key restricted to the Chrome UX Report API. Empty means off. Template text such as your-key-here, <your key> or changeme is treated as empty too, and the server's log says so in one line (e.g. MAJESTIC_API_KEY looks like a placeholder; Majestic tier disabled.), so a tier you expected that stays off is worth a look at the log.

Claude Code - one command (add --env DATAFORSEO_USERNAME=… and the others the same way if you use them):

bash
claude mcp add seo-audit-console --env GOOGLE_APPLICATION_CREDENTIALS=C:/path/to/service-account.json -- npx -y @houtini/seo-audit-console

GOOGLE_APPLICATION_CREDENTIALS alone is the whole core audit. The step everyone misses: the JSON key belongs to a Google Cloud service account, and that account's email has to be added as a user on your property in Search Console, or the tool can't see any of your data. Getting started walks through it with screenshots, plus the one-click Claude Desktop extension and the build-from-source route.

Then ask Claude: "list properties", "refresh mysite.com", "run an SEO audit".

Opening the dashboard

Once a property has been refreshed or audited, there are three ways to see it:

You wantAsk ClaudeWhat you get
A quick look in the chat"show me the dashboard for mysite.com"The dashboard drawn inside the conversation (get_dashboard)
The full dashboard in your browser"open the dashboard for mysite.com"A link such as http://127.0.0.1:53817/dashboard?siteUrl=… (open_dashboard). Click it. It reads the local database live, so reload after each refresh
Something to send a client"export the report for mysite.com"One self-contained HTML file (export_report)

You often don't need to ask: when a refresh, crawl, sync or audit finishes, the reply says the dashboard is updated and includes the browser link. The link is local to your machine (it only answers on 127.0.0.1), and the port changes each time the server starts, so use the link from the latest reply. Want one stable address? Run seo-audit-dashboard with SAC_DASHBOARD_PORT=8788 as a standing process and give the MCP the same port and data dir: it then hands out that dashboard's link (it checks the process on that port really is this dashboard, serving the same data, before it does). Add &theme=dark for dark mode, or &redact=1 to blur the numbers for a screenshot.

Running it under Docker or the Docker MCP gateway? The browser link points at a port inside the container, which your browser can't reach. Run the dashboard as its own small container on a fixed port instead, on the same data volume:

bash
docker run -d --init --name seo-audit-dashboard --restart unless-stopped -p 127.0.0.1:8788:8788 -e SAC_DATA_DIR=/data -e SAC_DASHBOARD_BIND=0.0.0.0 -e SAC_DASHBOARD_PORT=8788 -v <your-data-volume>:/data node:22-slim npx -y -p @houtini/seo-audit-console@<your-version> seo-audit-dashboard

Then open http://127.0.0.1:8788/dashboard?siteUrl=sc-domain:mysite.com. Replace <your-data-volume> with the volume your MCP server writes to, and <your-version> with the version it runs, so the two match (the server prints this command with its own version filled in). The volume must be writable: the dashboard's actions start jobs. In Git Bash on Windows, put MSYS_NO_PATHCONV=1 in front of the command so /data isn't rewritten as a Windows path. More in dashboard.md.

The manual

This README is the story and the quick start. The detail lives in the manual:

PageWhat's in it
Getting startedInstall, the GSC service-account setup (and the step everyone misses), Claude Desktop and Claude Code config, your first audit, troubleshooting
Tool referenceEvery tool: what it does, inputs, joins, an example prompt
The check registryAll 143 checks with what each catches, its D/N label, and the fix
CompositionThe join keys, the grains, and fourteen recipes for asking your own questions across the data
Competitive analysisThe competitive workflows, DataForSEO setup, link intersect with the Majestic Trust Flow tier, and the real costs
ArchitectureFor contributors and reviewers: how the code fits together (storage, the join key, collection, the audit engine, jobs, the dashboard) and the conventions it follows
SEO ReconWhy a page is losing: the live SERP + AI-Overview citation verdict, the competitor diff, and the trackable to-do ledger
DataForSEO functionsEvery DataForSEO-backed tool grouped by API module - Keywords, SERP, Labs, Backlinks, OnPage - each with its endpoint and cost
Majestic functionsThe optional Trust Flow tier - what it adds, and how link_intersect and pull_backlinks use it
The portfolioEvery domain you look after on one page (owned + watched): measured vs estimated, Domain Rank, AI mentions, needs-attention, the domain overview, and quoted, budget-capped refreshes
Dashboard & reportsThe ten tabs, what each chart shows, the browser dashboard (and its standalone version for Docker), and the shareable export

Surprisingly little has changed in twenty years

The technical audit I was writing for clients in 2006 is, structurally, the audit most agencies still sell today. A crawler runs, a template fills, a 60-page PDF lands. Everything a crawler could find, in severity order, with no idea which findings are worth money and which are cosmetic.

What has changed is what's possible. Google gives every site owner a complete record of its search reality - which queries, which pages, how many impressions, where you ranked. Your crawl tells you what your site says. Search Console tells you what Google did about it. And in my experience, the gap between those two datasets is where nearly all of the recoverable traffic hides.

So that's what I built. SEO Audit Console is a Model Context Protocol server that merges your Search Console history with a first-party crawl of your site (and, when you want it, DataForSEO) into one thing: a prioritised, evidence-backed audit you can interrogate inside Claude Desktop. It hands you paste-ready fixes. Every finding traces back to a real datapoint.

One idea underneath all of it:

Your crawl is intent. Search Console is reality. The money is where they diverge.

A flat crawler tells you a page 404s. Useful, but only just. This tells you the 404 is draining 15% of your homepage's internal PageRank, that the page used to earn 10,000 clicks a month, and it writes the 301 rule to fix it. It finds the page at position #3 on 150,000 impressions with a 0.2% click-through rate - a title rewrite probably worth thousands of clicks - and ranks that above the cosmetic findings. Severity is what crawlers sell you. Yield is what moves the numbers.

Who is this for?

The SEO consultant who wants the collection and checking automated so the thinking time survives. The in-house marketer who's been quoted four figures for a commodity audit. And anyone newer to this who wants to learn what a good audit looks at - because every finding shows its evidence, the tool doubles as a teacher.

A note on where to run it. Claude Desktop is the easy start, but in my view Claude Code is the best home for this tool - because it closes the loop. In a chat client the audit hands you a 301 rule to paste somewhere. In Claude Code, the same session has your site's repo, a terminal and git: the audit finds the issue, writes the fix, applies it to the codebase, commits it, and re-crawls to verify. Finding to deployed fix, one conversation.

You don't need to learn an interface. You type "run an SEO audit on mysite.com" into Claude and it happens. Forget what's possible? Ask "run seo_audit_help" and you get the full menu with example prompts.

Does the approach work?

Yes. The crawl-plus-GSC merge is not a novelty; it's the method. On one property, seeding the crawl from Search Console URLs took coverage of GSC-known pages from 29% to 70% - every one of those extra pages is a page a conventional crawl silently missed, and several were earning traffic with no internal links pointing at them at all. On the same property the incremental sync turned a 33-minute data refresh into 19 seconds, which is the difference between "audit quarterly" and "audit whenever you're curious".


What the audit checks

run_audit executes 143 checks over the joined data and returns a ranked list - not a wall of everything, a priority order with the traffic at stake attached to each finding. The families, briefly:

FamilyWhat it catches
Crawlability & indexationBroken links, redirect hygiene (chains, loops, temporary redirects carrying equity, redirects onto non-indexable pages or the homepage, live pages removed without a redirect), URLs that don't exist answering 200 (soft-404 setup) and http/https or www/apex twins not redirected in one 301, orphans, index bloat, spider-traps, robots-blocked pages still earning traffic, canonicals that hand indexing to another host, hreflang that Google would ignore (invalid codes, no self-reference, duplicate locales, canonical conflicts), and the reason every URL isn't indexable
On-page & structured dataTitles, metas, H1s, alt text - plus a local validator covering ~30 rich-result types, required fields only, so it never nags about properties Google ignores. For stores: product pages that went from 200 to 404, and Product markup missing what merchant listings need
Page weight & assetsWhat every page loads, from the crawl: CSS, JavaScript and font files that return errors, render-blocking scripts and stylesheets in <head>, static files with no cache lifetime, broken images, images over 300 KB and JPEG/PNG where WebP would be smaller (measured as a browser is served them). Real-user Core Web Vitals come from CrUX
Trends (GSC over time)Pages losing clicks, rankings slipping, vanished queries, rising pages worth doubling down on, stale content decaying year-on-year
The merged questionsCannibalisation, striking distance, ghost pages, traffic to dead URLs, internal authority wasted on no-click pages, titles missing the query you already rank for
AI-search readinessPhrases you rank for but never say, queries your copy never answers in one passage, content that doesn't chunk cleanly for retrieval
AccessibilityA deterministic subset of the axe-core rules read straight from the HTML - links and buttons with no accessible name, unlabelled form fields, pinch-zoom disabled, positive tabindex, duplicate ids - alongside alt text, heading order and missing lang
JavaScript rendering & duplicationOn demand: Response vs Render (render_pages) crawls each page in headless Chromium and flags content and links that exist only after JavaScript, and what JavaScript changes (canonical, title, noindex in either direction, server-rendered copy it removes), and semantic near-duplicate detection (find_duplicates) finds pages that say the same thing - both run locally, no API cost

Every check is labelled D (deterministic - here are the bytes) or N (judgement - off by default, ask for "the judgement findings" to see them). In my view a wrong finding is worse than no finding at all, so the heuristic checks have to ask permission. The full registry, check by check, is in the manual.

And if you grew up on the classic desktop SEO crawlers, the dashboard's Crawl health tab will feel like home - response codes, indexability reasons, crawl depth, the heaviest images, server errors and slow pages, all as clean stat bars. Same diagnostics, except each one is sitting next to the Search Console numbers for the same URL. The tab-by-tab tour is in dashboard.md.


The crawl, properly explained

The crawl is where audits usually go wrong, so it's worth understanding what this one does differently. I've spent enough of my career cleaning up after crawlers that fooled themselves. This one is a proper SEO crawler - it just happens to have your Search Console history sitting next to it.

It discovers pages three ways. Following links, reading your XML sitemaps, and - the important one - starting from every URL Google is already sending traffic to, straight out of your GSC data. Coverage stops depending on your sitemap being honest. It's also exactly how ghost pages get caught: if Google ranks a URL your own site structure can't reach, that URL still gets crawled, and the mismatch becomes a finding.

It records why, not just what. For every URL that isn't indexable it stores the reason - 404, noindex, X-Robots header, canonicalised elsewhere, robots-blocked, non-HTML. "This page won't rank" is a fact; "this page won't rank because a plugin set an X-Robots header nobody remembers" is a fix.

It refuses to be fooled. A redirect that leaves your site (Shopify OAuth flows, I'm looking at you) is recorded as a redirect-out, never stored as a page. It always uses GET rather than HEAD, because a HEAD request can return a different status than the real request would - but it abandons the body for images, PDFs and assets, so it records status and size without downloading the bytes.

It's quick without being rude. HTTP/2 where your origin supports it, gzip and brotli negotiated, keep-alive connections reused. The speed comes from efficiency, not from hammering your server. It respects robots.txt properly, per RFC 9309: a bot-specific group replaces * (plenty of commercial crawlers get that wrong), * and $ wildcards and query strings match, a redirect into a disallowed path is never followed, and a robots.txt that errors stops the crawl rather than being read as "allow everything". It skips the junk: internal search, faceted filter combinations, login flows. This is a crawler for sites you own. Being a good guest is the point.

It slows down when your host asks it to. A 429 (or a 503 with Retry-After) halves the crawl's concurrency, waits out the Retry-After, and puts the URL at the back of the queue for two more tries; clean responses add workers back. Shopify stores are spotted from their headers and start gently. A URL still rate limited at the end is stored as rate limited with no status, never as a broken page, and the crawl status tells you how many.

It tests what a crawl can't find on its own. Each crawl ends with up to five site probes: two URLs that can't exist (does the site answer 404, or 200 and a soft-404?) and the http/https and www/apex twins of the homepage and a deep page (one 301 to the canonical host, or a split?). It also records what every page loads - stylesheets, scripts, fonts, images, first or third party, in the head or the body - without downloading any of it; headResources:true adds a header-only pass for their status, size and caching.

It says what it didn't measure. A check whose data was never collected - the asset checks before a headResources crawl, the render checks before render_pages, field Core Web Vitals before sync_crux - is listed in the audit as not collected, with the step that collects it. An empty table never reads as a clean bill of health.

After the crawl it computes a real link graph: internal PageRank with nav and footer links down-weighted, click depth from the homepage counting body links only, in-degree per page. That graph powers the orphan, equity-leak and underlinked-page checks - and the donor rankings when the tool suggests internal links.

[The Crawl health tab - the canonical, redirect and not-found breakdown, then classic crawl diagnostics as stat bars]


The workflows, briefly

Each of these is a real procedure I use, and each is one prompt. The expanded versions, with what happens underneath, live in the manual pages linked.

  1. Your first audit. "Refresh sc-domain:mysite.com", then "Run an SEO audit on mysite.com". Twenty minutes on a mid-size site, and the top five findings are usually worth more than the other eighty-five combined. Then "generate the fix for #1". → getting-started.md
  2. Sitewide keyword optimisation. The question isn't "what keywords should I target?" - it's "where does my copy fail to say what I already rank for?" "Score the passages on mysite.com" runs a small local relevance model over every ranking page; "draft the missing content for /page" writes the fix in your site's own voice, grounded so it invents nothing. → tools.md
  3. Cannibalisation. "Show me the cannibalisation findings with evidence" - thresholds tuned so incidental long-tail overlap doesn't count, so the consolidate-or-differentiate call is made on numbers. → checks.md
  4. The content plan. "Suggest new pages for mysite.com" mines demand Google already shows you; "what topics should mysite.com cover?" maps the demand it doesn't. Together: a quarter's plan. → competitive.md
  5. The template play. "List the page templates" - big sites aren't 50,000 pages, they're a dozen templates repeated, and one template fix corrects the whole cluster. → tools.md
  6. Monitoring and migrations. "Detect changes on mysite.com" diffs your two most recent crawls by severity. During a migration this is the difference between catching a stray noindex on Tuesday and explaining a traffic graph in a board meeting three weeks later. I've been on the wrong end of that one. → tools.md
  7. AI-search readiness. "Check agent readiness for mysite.com" - the web is quietly growing a second audience, and almost no SEO tool checks any of it. → tools.md
  8. Your own questions. The four datasets share three join keys, and the most valuable analyses are the ones you compose yourself - "which pages lost clicks after being cited in AI Overviews?" is one prompt here and a feature nowhere else. → composition.md
  9. Reporting. "Show me the dashboard" in the chat, "serve the dashboard" for the live version in your browser, or "export the report" as one self-contained HTML file you can send a client. → dashboard.md
  10. The content opportunity report. If you write for a living, this is your page one: "Content opportunities for mysite.com" returns what to WRITE next (demand you already earn impressions for with no winning page), what to REFRESH (pages bleeding clicks), which SNIPPETS to rewrite (ranking well, under-clicked), and which clusters to STRENGTHEN (position 4-20, one push from the money). Every row traces to your own Search Console data - no invented keyword ideas - and "draft the brief for row 1" turns any of them into a grounded outline. → competitive.md
  11. Market Sizing and Prioritisation. "Size the market: mysite.com vs rival1.com and rival2.com" - the keyword universe, total monthly demand, and share of voice per topic cluster, from one cached call per domain. The engagement-opening read that used to need a paid SEO suite. → competitive.md
  12. Content recon - why is this page losing? "Run content recon on mysite.com" takes your highest-impression pages sitting at positions 3-15 (the ones a push could move), pulls the live Google SERP for each, and reads whether the AI Overview cites you. The verdict is the honest bit: rank but not cited is a data-accuracy or freshness problem, not a rewrite. It reads the reachable competitors with a free browser-profile fetch (Reddit through its own JSON), lists the ranking videos for you to watch, and writes the gaps into a tracked to-do board you can annotate and re-measure. → recon.md
  13. Link prospecting, sorted by authority that's real. "Link intersect for mysite.com vs rival1.com, rival2.com" returns the domains linking to your rivals and not to you - the outreach list, followed-first and spam-filtered. Add a Majestic key and it re-sorts on Trust Flow and shows each prospect's Topical Trust Flow, so the directories drop out and what's left is authority that's on your topic. → Majestic, below

[The Search performance tab - branded vs non-branded, ranking distribution over time (impressions by position bucket) and search visibility over time]

[Content architecture - your search demand grouped into topic clusters, each with a coverage score, striking-distance members and gaps]


What DataForSEO adds (and what it costs)

Everything above works with just your Search Console data. But GSC can only describe searches where you already appear. The moment your question is "how big is this market?" or "what do competitors rank for that I don't?", you need third-party data - and that's DataForSEO: a pay-as-you-go API for volumes, live rankings, competitor data and Lighthouse runs. No subscription; calls cost fractions of a cent to a few cents, cached for 20 days, and only ever run when you ask. My own usage runs to a few dollars a month.

It unlocks the competitive layer: the organic visibility overview for any domain, any site's top pages and ranked keywords (including which of them show an AI Overview), the content gap, topic gaps, search intent, lab Core Web Vitals and backlinks. It also drives content recon - recon_targets pulls the live Google SERP for a losing page, reads whether the AI Overview cites you, and tells you why you're behind. The full workflows and setup: competitive.md.

It also powers the portfolio: one table across your owned properties and any domains you watch. Organic keywords and traffic, referring domains, Domain Rank and AI mentions (Google AI Overviews + ChatGPT) sit next to your measured Search Console clicks and audit health, with a "needs attention" tab and a per-domain overview. Every figure says whether it was measured or estimated, and refreshes quote their cost before anything is spent (8 domains on the weekly tier cost $0.22 on a live run). The detail: portfolio.md.

One more thing DataForSEO unlocks gets a section of its own, because the link work has a second, optional service behind it.


Link intersect, and the Majestic Trust Flow tier

Link building is the one discipline where the prospect list is the strategy, so link_intersect builds it from evidence rather than a hunch. One DataForSEO domain_intersection call over your competitor set - yours excluded - returns every domain that links to them and not to you, aggregated per prospect: how many of your rivals it links to, whether the link is followed, its worst spam score, the anchor mix. Point it at a single company instead of a set and it answers the other classic, what links does company X have that we don't?

That gets you a list. It doesn't get you a priority order, and this is where link prospecting has always gone wrong. DataForSEO sorts on domain rank, which is a link-volume metric, so directories, aggregators and syndicated-press domains float straight to the top - technically authoritative, worthless to pitch. Every link builder I know has lost a week to that list.

Set MAJESTIC_API_KEY and the order changes to one you can defend. Majestic has been crawling and scoring the web's link graph since before most of today's SEO tools existed, and its two flagship metrics are exactly the ones that fix this:

  • Trust Flow (0-100) - editorial authority, propagated from a seed set of trusted sites. It measures who vouches for a domain rather than how many links it has managed to accumulate. That's the directory killer: in testing, a domain DataForSEO ranked 227 came back Trust Flow 0. A volume metric simply cannot see that.
  • Topical Trust Flow - what that authority is about, as ranked topics. A Trust Flow 45 domain is a brilliant link when its top topic is Recreation/Autos and you sell car parts, and a wasted pitch when it's Health/Nutrition. It's the difference between a strong link and a relevant one, and it's the column that makes an outreach list survive contact with a client.

With the key set, every qualifying prospect is enriched, the table gains a Trust Flow column and each domain's leading topic, and the whole list is re-sorted by Trust Flow:

console
you  › link intersect for mysite.com vs rival1.com, rival2.com
     Prospect domain     Links to  Trust Flow  Link    Spam  Backlinks  Top topic     enthusiast-mag.com  2/2       54          follow  2     31         Recreation/Autos     club-forum.org      2/2       41          follow  0     12         Recreation/Autos     free-link-list.net  2/2       0           follow  28    904        –

(Shape of the output, names invented.) Same three prospects, same DataForSEO data underneath - and note which one has the most backlinks. Sorted DataForSEO's way, the directory is the one you'd have emailed first.

link_intersect needs DataForSEO's Backlinks subscription, which is separate from their SERP/Keywords/Labs APIs; if it isn't activated the tool says so in plain English rather than throwing a code at you.

The tier is careful with your allowance: enrichment is batched 100 domains per call (about one unit each), capped by enrichLimit (default 100 - and when more prospects qualify than get enriched, the response says so and tells you to raise it, rather than handing you a half-scored list), requests are serialised, and every response is cached for 30 days via MAJESTIC_CACHE_DAYS. Ask the same question twice in a fortnight and the second answer costs nothing.

Optional, and I mean optional: with no key, link_intersect still runs and still sorts followed-first by domain trust. Majestic is what turns "here are 100 domains" into "here are the 20 worth an email, and here's why". Grab a key on their plans and pricing page; the full workflow is in competitive.md.

Trust Flow and Topical Trust Flow are trademarks of Majestic (Majestic-12 Ltd). This tier calls the Majestic API with your own key, only when you run link_intersect or pull_backlinks (which adds Trust Flow to your own backlinked pages for the dashboard's Trapped authority report), and nothing else in the tool touches it.


Installation, in brief

Three steps - the quick start above is the short version, and the full walkthrough with the gotchas is getting-started.md:

  1. Get it: the quick route is npx - point your MCP config at npx -y @houtini/seo-audit-console and there's nothing to build. Or clone this repo, npm install, npm run build if you want the source. Either way, Node ≥ 22.
  2. Connect Search Console: create a Google Cloud service account, download its JSON key, and - the step everyone misses - add the service account's email as a user on your property in Search Console. Prefer a walkthrough with pictures? Setting it up from scratch covers the whole flow.
  3. Point your MCP client at it with GOOGLE_APPLICATION_CREDENTIALS set: npx -y @houtini/seo-audit-console for the published package, or node /path/to/seo-audit-console/dist/index.js if you built from source. Works in Claude Desktop and Claude Code; only the one env var is required.

The environment variables an MCP client config usually sets, in one block (the dashboard, job-runner and tuning ones are in the getting-started table). The first is required and everything below it is optional: fill in the ones you use and leave the rest as empty strings (or delete them). An empty value switches that service off, and so does leftover template text such as your-key-here (with one line in the server's log saying so).

json
{  "mcpServers": {    "seo-audit-console": {      "command": "npx",      "args": ["-y", "@houtini/seo-audit-console"],      "env": {        "GOOGLE_APPLICATION_CREDENTIALS": "C:/path/to/service-account.json",        "SAC_DATA_DIR": "",        "DATAFORSEO_USERNAME": "",        "DATAFORSEO_PASSWORD": "",        "DATAFORSEO_CACHE_DAYS": "20",        "MAJESTIC_API_KEY": "",        "MAJESTIC_CACHE_DAYS": "30",        "CRUX_API_KEY": ""      }    }  }}

Built from source instead? Swap the two launch lines for "command": "node" and "args": ["C:/path/to/seo-audit-console/dist/index.js"]; the env block is identical.

GOOGLE_APPLICATION_CREDENTIALS gets you the whole core audit. DataForSEO adds the market layer, MAJESTIC_API_KEY adds the Trust Flow re-sort to link_intersect, and CRUX_API_KEY (optional: field Core Web Vitals, a free Google API key restricted to the Chrome UX Report API) adds real-user LCP, INP and CLS. Line-by-line, including the advanced ones you'll probably never need (the reranker device, the Majestic sandbox host, and the dashboard server's bind, port and auto-start): getting-started.md.

Then: "list properties" to check it's connected, "refresh", "run an SEO audit".

Upgrading to 0.16.0

0.16.0 changes how Search Console rows are stored. The device and country rows a segments:true sync pulls now live in their own table (search_analytics_segments), and search_analytics holds only the all-country totals, so no total can count a day twice. Nothing to do by hand, but know what the first sync after upgrading does to a database that held both shapes:

  • It backs the database up first, to <database>.bak-<date-time> beside it. The backup is a full copy, so a 5 GB database leaves a 5 GB .bak file.
  • It checks free disk before it starts: room for the backup, plus half the database again, plus 256 MB. Without that room the migration waits: the sync still runs in the old layout (totals stay correct, because the views count each day once), the reply says "storage migration deferred: needs N GB free", nothing is moved, and it migrates on a later sync once there's space.
  • Then it moves the rows, a batch of days at a time. On a 5.5 GB database that took under three and a half minutes, backup included. If it's interrupted it carries on from where it stopped on the next sync, and the numbers read correctly throughout.
  • Afterwards, reclaim the space. The database file keeps its size until it's compacted: ask "vacuum the mysite.com database" (data_storage, prune with vacuum). On the 5.5 GB test database that took it to 4.4 GB. Once you're happy with the numbers, delete the .bak file yourself; nothing deletes it for you.

A database that only ever held one shape (most do: a sync without segments) is marked as migrated on first open, with no backup and no move. The changelog has the rest of the release.

Docker and the Docker MCP gateway

Crawls, syncs and refreshes run as background jobs: the tool returns a job id at once and the work carries on while you poll check_crawl_status. Run normally (npx, or node dist/index.js from Claude Desktop), the server process is long-lived and does that work itself. Nothing below applies.

The Docker MCP gateway is different, in two ways.

  • Start-up. The gateway runs the server in a worker container. Without longLived: true on the catalog entry it starts a fresh worker for every tool call; with it, one worker per client connection. A worker started from node:22-slim with npx installs the package before it can answer, which takes 60-90 seconds and is longer than Claude Code waits for a tool call. So every call times out, even seo_audit_help. The fix is an image with the package preinstalled, plus longLived: true (step 1 below).
  • Jobs. The gateway replaces workers freely: on disconnect, on a router recreate, when it reaps idle ones. A job running inside a worker dies with it. The fix is to move the work out of the worker into one long-running job runner container that the gateway never touches (steps 2 and 3).

Measured on a gateway in October 2026 (0.16.2):

Catalog entryFirst call on a new connectionLater calls
node:22-slim + npx, no longLived88-108 s88-108 s (every call)
node:22-slim + npx, longLived: true75-80 sinstant
Prebuilt image, no longLived2 s2 s
Prebuilt image, longLived: true2 sinstant

1. Build the image and point the catalog entry at it. Pin the version, so the image and the runner stay on the same release:

dockerfile
FROM node:22-slimRUN npm install -g @houtini/[email protected]ENTRYPOINT ["seo-audit-console"]

docker build -t seo-audit-console:0.17.0 . in the folder holding that file. Then, in the catalog entry, set image: seo-audit-console:0.17.0, delete the command: line (the image's entrypoint starts the server), and add longLived: true. The gateway runs local images with --pull never, so it finds the one you built. Rebuild the image for each release and change the tag in the catalog entry.

The runner takes the other two steps:

  • the MCP server, started with SAC_JOB_RUNNER=external, only queues each job in _jobs.db in the data directory and reads its status;
  • the runner (seo-audit-runner, in the same npm package) claims queued jobs, runs them and writes progress back to the same database.

The workers become disposable: recreate the router mid-crawl and the crawl carries on in the runner.

2. Start the runner on the same data volume, with the same credentials as the gateway's catalog entry, from the image you built in step 1:

bash
docker run -d --init --name seo-audit-runner --restart unless-stopped \  -v mcp-sac-data:/data -v mcp-sac-creds:/creds:ro \  -e SAC_DATA_DIR=/data -e GOOGLE_APPLICATION_CREDENTIALS=/creds/gsc.json \  -e DATAFORSEO_USERNAME -e DATAFORSEO_PASSWORD -e MAJESTIC_API_KEY -e CRUX_API_KEY \  --entrypoint seo-audit-runner seo-audit-console:0.17.0

The four -e NAME flags with no value pass those variables through from your shell, so the keys stay out of the command line; leave out any you don't use. On Windows in Git Bash, prefix the command with MSYS_NO_PATHCONV=1, otherwise MSYS rewrites /data and /creds into Windows paths (PowerShell doesn't need it). --init makes docker stop reach the runner as a clean SIGTERM. docker logs seo-audit-runner shows it start and every job it claims. (Without the image, node:22-slim npx -y -p @houtini/[email protected] seo-audit-runner works too: the runner is one long-running container, so npx installs only once, on its first start.)

3. Switch the gateway to queueing. Add SAC_JOB_RUNNER=external to the env of this server's catalog entry. Keep longLived: true. The runner makes jobs survive a worker being replaced; longLived keeps the worker warm between calls. They solve different problems, and they work together (tested: a sync queued through a longLived worker was claimed and finished by the runner).

What you'll see. A job reads queued: waiting for the job runner until the runner picks it up, then running as before. If a job stays queued for over a minute and no runner has checked in, the status says so and prints the docker run line above. After about two minutes with no runner heartbeat it reads queued (no runner) and no longer blocks data_storage prune or repair; it stays listed until the usual one-day prune. One runner runs one job at a time by default; set SAC_RUNNER_CONCURRENCY to run more, though two jobs for the same property never run at once. To update: build the image for the new release (step 1, new tag), change the tag in the catalog entry, restart the gateway, and recreate the runner from the new image (docker rm -f seo-audit-runner, then the docker run line again). Keep the runner and the gateway on the same release. A job running when the runner stops is recorded as interrupted, so re-run it.

If you stay on npx in the gateway, every new worker installs the package first, so expect the first call of each client connection to time out (later calls are fast with longLived: true). The server notices this case: started by npx inside a container, it logs a warning pointing here, visible in docker logs for the gateway.

After upgrading, restart the MCP client. Clients read the tool list once, when they connect, and keep it. Until Claude Desktop or Claude Code is restarted (fully, from the tray on Windows), tools added in the new release, such as sync_crux, stay invisible even though the server has them.

Without the runner, the older options still work: longLived: true on the catalog entry (or --long-lived on the gateway), or plain docker run -i --rm with the volumes mounted, which is one long-lived stdio process for the session. Either way, mount named volumes for the data directory and the credentials (for example -v seo-audit-data:/data -e SAC_DATA_DIR=/data and -v seo-audit-creds:/creds:ro -e GOOGLE_APPLICATION_CREDENTIALS=/creds/service-account.json) so audits and the job list survive a restart.

There's no published image for the server itself. Step 1's image installs the published npm package; to run your own build of this repo instead, use its Dockerfile (docker build -t seo-audit-console .), whose entrypoint is node dist/index.js, the stdio server.

Every job is recorded in _jobs.db in the data directory. If the process running a job exits before it finishes, the job reads as interrupted with the reason rather than disappearing, and a finished job's result can still be read after a restart.

The gateway doesn't publish the server container's ports, so the browser dashboard the server starts after a job isn't reachable from your machine. The server notices it is in a container without a published dashboard port (no SAC_DASHBOARD_BIND=0.0.0.0 with SAC_DASHBOARD_PORT), and says so in place of the link, with the command to start the standalone dashboard. get_dashboard still renders it in chat, and for a browser tab you can run the standalone dashboard, seo-audit-dashboard, as a second container on the same data volume with a published port. The command is in dashboard.md.


The tools, at a glance

The one-line version - full descriptions, inputs and example prompts for every tool are in the tool reference.

ToolWhat it does
refresh_propertySync GSC + crawl + inspect + rank history + CrUX field data, one job
sync_gsc · start_crawl · inspect_urls · track_ranks · sync_cruxRun a single part on its own (sync_crux: real-user Core Web Vitals from the Chrome UX Report, free with a CRUX_API_KEY)
check_sync_status · check_crawl_statusWatch a long job's progress
run_audit · query_audit · list_checksThe scored audit · one check with evidence · the catalogue
query_dataRead-only queries over the raw tables - aggregates in the database, answers not rows
open_dashboardThe property's live browser dashboard link; finished syncs and crawls offer it themselves
probe_urls · triage_404sTest any URL live (redirects, canonical, cache, case/slash/host variants) · the 404 list as a redirect map
fix_findingPaste-ready remediation (JSON-LD / 301 / internal links)
detect_changesWhat changed between the two most recent crawls
check_agent_readiness0-100 AI-agent readiness score with copy-paste fixes
list_templates · suggest_pagesTemplate clusters · new-page ideas from real demand
score_passages · draft_contentLocal relevance scoring · grounded writing briefs
find_duplicates · render_pagesSemantic near-duplicate pages (local model) · Response vs Render in headless Chromium (optional Playwright)
resolve_entitiesWikidata entities and the link gaps between them
keyword_volume · related_terms · search_intentDataForSEO keyword data
youtube_discovery · news_discovery · topic_trend · trend_categoriesContent research: the videos ranking for a topic (pair with a transcript tool) · recent news coverage / freshness · Google Trends interest-over-time for keywords, a whole category, or a term inside one (rising / falling / seasonal, plus breakout topics and queries) · free lookup of the Trends category codes
competitors_domain · page_intersection · topic_gapsCompetitors · content gap · topic gaps
domain_visibility · top_pages · ranked_keywordsOrganic overview, top pages and ranked keywords for any domain (+ aioOnly for the keywords that show an AI Overview)
page_lighthouse · pull_backlinksLab CWV · backlink profile with live status
link_intersectThe links your competitors have that you don't - a prioritised outreach list (followed-first, sorted by domain trust; optional Majestic Trust Flow re-sort kills directory noise)
market_sizing · serp_featuresShare of voice vs named competitors · AI-Overview / snippet / video exposure by volume
keyword_list · content_opportunitiesCluster a keyword list (own / weak / absent) · the content marketer's report
recon_targets · save_recon_todo · recon_todosContent recon: why a page is losing (live SERP + AI Overview) → a tracked, annotatable to-do board
portfolio · refresh_portfolio · schedule_portfolio_refresh · get_portfolioThe portfolio: every domain you look after (owned + watched) in one table, measured vs estimated · refresh it (quotes first) · schedule it under a monthly budget cap · see it in chat
get_dashboard · serve_dashboard · export_reportIn-chat dashboard · the same in a local browser tab · shareable HTML
get_dashboard_data · list_findings · get_portfolio_data · get_domain_overviewInternal: the dashboard widgets fetch their data through these; not for direct use
composition_cookbookThe data-surface map and recipes for bespoke analyses
data_storagePer-property disk usage and row counts, confirm-gated pruning, and an integrity check with index repair
normalize_url · data_location · list_properties · seo_audit_helpUtilities and the help menu

How it works under the hood

  • The join key (url_key). GSC page and crawl url both normalise down to the same key - force HTTPS, unify www and apex, strip tracking params, and so on. Everything joins on that. It's the whole trick, really.
  • One SQLite database per property (WAL, prepared statements). Your data stays on your machine.
  • Scored once, sorted by yield. (expected clicks × yield × certainty) / effort. Covering-indexed, so the audit stays fast even when the GSC table runs to millions of rows.
  • Careful with your history. Crawls and syncs never destroy the previous snapshot until new data has started arriving - a site outage mid-crawl doesn't cost you your data.
  • Owned-site only, dry-run fixes. It crawls sites you control, and the generators return artifacts. They never write to your site. That's a line I won't cross.

Privacy and data

Your Search Console data and the crawl live in local SQLite files under SAC_DATA_DIR. The passage-scoring model runs locally too. Nothing leaves your machine except the API calls you trigger - Google (your own GSC, and the Chrome UX Report if you've set CRUX_API_KEY: it's sent your origin and top page URLs) and, if you've set them up, DataForSEO and Majestic (link_intersect sends prospect domain names; pull_backlinks sends your own backlinked page URLs). Every one of those is keyed by you, called on demand, and cached locally so it isn't called twice. Content recon's competitor fetch requests those public pages directly, with no service in between. The crawl also reaches beyond your own site in one way: after each crawl it checks the outbound links your pages carry (a HEAD request, or a ranged GET, to each linked URL; checkExternal:false turns that off). And the free extras fetch from public sources: the local models download once from Hugging Face, resolve_entities queries Wikidata, and news_discovery reads the Google News feed. No telemetry. None.


What's coming

A few things I'm building next, in rough order:

  • Structured-data opportunities, by template. Not "you have no schema" (most modern stores have plenty), but "this template could earn review stars or an FAQ rich result and doesn't."
  • A per-page content scorecard. A dedicated table of every ranking phrase your copy misses, not just the top query.
  • More agent readiness. A WebMCP advisory (which tool actions your site could expose to agents) and the agent-commerce protocols.
  • A printable report. A proper A4 document you can hand a client, not a slide deck.
  • Source-level parser checks. The layer most tools never touch: elements that silently break <head> parsing, and directives hoisted into the body and ignored. (Raw-vs-rendered divergence now ships - see JavaScript rendering above.)

Got a weird edge case you wish a tool caught? Tell me - that's exactly how the merged GSC×crawl checks got built.

About Houtini

Houtini exists for one reason: the hours your team loses to grunt work. Pulling Search Console exports, running crawls, cross-referencing spreadsheets, re-checking what changed since last month - none of it needs a person, and all of it eats the time your people should be spending on strategy, on clients, on the work that moves numbers. So we automate exactly that layer. SEO Audit Console is one of a family of tools built on the same principle - if a machine can collect it, merge it and check it, a machine should.

Questions, licensing, or something you'd like automated: [email protected]

Credits

SEO Audit Console stands on a few third-party services - all optional except your own Search Console access, and each called only with a key you provide:

  • Google Search Console - your own search-performance history (the one required credential).
  • DataForSEO - SERP, keyword, Labs and backlink data: keyword volumes, competitor footprints, rank history, and the link_intersect domain intersection. Pay-as-you-go, optional.
  • Majestic - Trust Flow and Topical Trust Flow for the link_intersect enrichment tier, which re-sorts link prospects by real editorial authority. Trust Flow and Topical Trust Flow are trademarks of Majestic (Majestic-12 Ltd). Optional; get a key on their plans page.

Built with better-sqlite3, cheerio, Apache ECharts, and a local ms-marco cross-encoder (via Transformers.js) for on-device passage scoring - no data leaves your machine for that.

Contributing

Issues and PRs welcome. The check registry (src/audit/checks.ts) is built to be extended - each check is a pure read over the joined data that returns findings with evidence, so adding one is fairly self-contained. There's an end-to-end smoke test (npm run smoke) and per-feature probes (npm run probe:*) to keep you honest. By submitting a PR you agree your contribution is licensed under the project's LICENSE (Apache-2.0).

License

Apache License 2.0. Free to use, modify, and redistribute, including commercially - full terms in LICENSE.

來源:README.md,提交 7503c8a

工具

65

seo_audit_help

Help — setup status and what this audit can do

Start here on first use, or after a "not set" / credentials / permission error: what is configured on this machine (Search Console key, DataForSEO, Majestic, CrUX, local data) and how to fix the rest, then every feature with an example prompt. Free, local, no API calls.

無需輸入參數。

composition_cookbook

Composition cookbook (data-surface map + recipes)

The full data-surface map (every source: grain, dimensions, join keys, freshness, cost) plus worked multi-source recipes and novel combinations, in this server's actual tool and table names. Static — no API calls, no cost. Call this BEFORE planning any complex question that spans more than one data source.

無需輸入參數。

list_checks

List audit checks

The live check registry (every check: id, category, severity, D/G/N labels, certainty, the fix). Free, local. Use it to pick a check for query_audit, or to explain what run_audit covers.

輸入參數category

list_templates

Detect page templates

Cluster the crawled pages into templates (by URL morphology + JSON-LD @type) and return each template with its page count and a representative exemplar URL. A single template-level fix corrects every page in the cluster — this is the map for per-template analysis. Needs a crawl (run refresh_property / start_crawl first).

輸入參數siteUrl必填minMembers

data_location

Get or set where audit data is stored

No args: report the folder where per-property crawl/audit databases are saved. With `path`: set it (persisted to ~/.seo-audit-console.json) — restart Claude Desktop to apply. Default is your Documents folder; the SAC_DATA_DIR env var overrides everything.

輸入參數path

data_storage

Data storage summary + pruning

Data hygiene. No args: list every per-property database in the data dir — size (incl. WAL), key row counts (search_analytics, pages, links, page_snapshots, findings), last sync and last crawl, and any link_intersect prospect set with its capture date (flagged when it is going stale) — plus the DataForSEO/Majestic caches and reports folder sizes. Optional siteUrl narrows to one property. Pruning via `prune:{siteUrl, action}`: "vacuum" (compact the DB, reports bytes reclaimed), "clear-crawl-history" (delete page_snapshots + audit runs/findings older than the 5 most recent, then vacuum), "delete-property" (remove the DB files entirely). Destructive actions (clear-crawl-history, delete-property) REQUIRE confirm:true and refuse loudly without it, naming what would be deleted. Refuses to prune while any job is running. Integrity: `check:true` (with siteUrl) starts an async job running SQLite's full integrity_check (minutes on a multi-GB DB; check:"quick" is faster but misses missing-index-row damage) and reports damaged indexes. `prune:{siteUrl, action:"repair"}` with confirm:true backs up the DB file, REINDEXes the damaged indexes and re-checks (async job) — the fix for a sync failing with "database disk image is malformed".

輸入參數hidecheckpruneconfirmsiteUrl

run_audit

Run SEO audit

Run the technical-SEO checks against synced data and return scored findings, ranked by expected clicks per dev-hour — Priority = (T × Y × C) / E (T = clicks at stake from real GSC data, Y = expected yield, C = certainty, E = effort hours). Crawl + GSC + URL-inspection checks. Set includeJudgement=true to include heuristic (N) checks. Returns the counts (byCheck, bySeverity, byCategory, notCollected) and the top findings (topLimit, default 10, max 50) with trimmed evidence; each check's title and fix appear once in `checks`. query_audit is the drill-down: every finding of one check, full evidence.

輸入參數scopesiteUrl必填topLimitcategoriesincludeJudgement

query_audit

Run one audit check

Run a single named check (see list_checks) and return its affected URLs + evidence. Token discipline: `columns` narrows evidence to the named keys, string evidence values are truncated at 120 chars (trailing …), `offset` + `limit` page through large result sets (the footer states showing X–Y of TOTAL). Grain: finding per URL with evidence JSON. Joins: url_key across all sources.

輸入參數check必填limitoffsetcolumnssiteUrl必填

query_data

Query the raw data (aggregate first)

Direct read-only access to the property database — the composition layer's escape hatch. AGGREGATE IN THE DATABASE and return answers, not rows: default mode groups by the columns you name and returns counts, percentages and sum/avg/min/max metrics (classic crawler-style distributions in one call — "status codes by folder", "clicks by page_key"). mode:rows returns raw rows with strict token discipline (curated default columns, 120-char cells, loud paging footer). Filters are exact/range/like/in/match and always parameterised; op:"match" is full-text search via FTS5 (words, "phrases", prefix*, AND/OR/NOT, NEAR(a b, 5)) on search_analytics.query, pages.title / h1 / body_chunks and links.anchor_text — use it instead of like for text on big tables; column names are validated against the live table schema. Grain: per table — search_analytics = date × query × page; pages/links = latest crawl per url_key; url_inspection / sitemap_urls / page_backlinks = one row per URL; findings = check × URL per audit run. Joins: url_key across pages/links/search_analytics.page_key/url_inspection/sitemap_urls/page_backlinks; query → keyword tools; run_id → audit runs.

輸入參數modelimittable必填offsetcolumnsfiltersgroupBymetricsorderBysiteUrl必填orderDir

score_passages

Score passage relevance (AI-search readiness)

Run a local cross-encoder reranker (ms-marco-MiniLM-L-6-v2, downloaded once to a cache, no Python) over each ranking page's heading chunks against its top Search Console query, and persist the single best-passage relevance score. It SCORES relevance (a classifier — it cannot hallucinate). Powers the `weak-passage-answer` check — the "RAG snippetability" test: does any passage confidently answer the query, the way AI/passage search re-ranks? Returns the score for EVERY page it scored (not just the failures) with the flag threshold, the band convention and the run's own distribution, so a passing page's score is readable without a second query_data hop. On-demand + ML-heavy (~0.6s/page), bounded to pages that already rank. `limit` caps pages (highest-impression first); `minImpressions` sets the floor (default 50). First run downloads ~25MB. Re-run after a re-crawl.

輸入參數urlslimitsiteUrl必填minImpressions

render_pages

Response vs Render (JavaScript rendering tier)

[Opt-in: needs the optional `playwright` package + `npx playwright install chromium`] Render a BOUNDED, sampled set of indexable pages in headless Chromium and diff the rendered DOM against the raw HTML the crawler fetched — the "Response vs Render" check the classic desktop crawlers are known for. Surfaces content and internal links that exist ONLY after JavaScript runs (what a first-pass crawl, and Google before it renders, can miss). Persists to render_audit (raw vs rendered canonical, title, robots meta, X-Robots-Tag, noindex and main-content words); run_audit then reports `content-only-in-rendered-dom`, `canonical-changed-by-js`, `title-changed-by-js`, `noindex-changed-by-js` and `hydration-content-loss`. Slow (a real browser), so it is a separate async job and never part of the normal crawl — poll check_crawl_status. `limit` caps pages (default 10, lowest raw word-count first — the likeliest JS-dependent pages); pass `urls` to render specific pages. Degrades with a clear message if the browser isn’t installed; the HTTP audit is unaffected either way.

輸入參數urlslimitsiteUrl必填

find_duplicates

Find near-duplicate content (semantic embeddings)

Embed each indexable HTML page's title+body with a local sentence model (all-MiniLM-L6-v2, downloaded once to a cache, no Python, no API cost) and flag pairs whose cosine similarity clears a threshold — the semantic near-duplicate / cannibalisation signal. Persists pairs to near_duplicates; run_audit then reports them as `near-duplicate-content` (judgement — needs includeJudgement:true). On-demand + ML-ish; `limit` caps pages compared (default 500, highest word-count first), `threshold` the cosine bar (default 0.9). The model reads ~the first 200 words, so it catches templated/boilerplate duplicates and thin variants — verify a pair before consolidating. First run downloads ~25MB. Re-run after a re-crawl.

輸入參數limitsiteUrl必填threshold

draft_content

Draft a grounded fix in the author's own voice

Assemble a GROUNDED writing brief for a page so YOU (the assistant) can draft the fix — no bundled LLM. Returns the ranking-query gap, the page's OWN passages as voice exemplars (match tone/pace/lexicon), and the most query-relevant existing passages (selected by the reranker) as facts to ground in. Use it on a weak-passage-answer / not-front-loaded page to write a self-contained answer passage in the site's voice, inventing nothing. Omit urlKey to target the weakest-scoring page. Needs body_chunks (+ score_passages for the gap).

輸入參數urlKeysiteUrl必填

detect_changes

Detect changes since the last crawl

Compare the two most recent crawls and report what changed per URL — status code, indexability, canonical, robots/noindex, title, meta, H1, schema, large content swings — each classified by severity (critical → info). This is the monitor: run refresh_property on different days to build history, then this surfaces regressions (a page that went noindex, a canonical that flipped, a 200 that became a 404). Needs at least two crawls.

輸入參數limitsiteUrl必填

check_agent_readiness

Check agent readiness (AI-agent / GEO signals)

Probe a site for AI-agent readiness — the signals agents use to discover and use it: robots.txt AI-bot rules + Content Signals, sitemap, Link headers, llms.txt, agents.md, Markdown content negotiation, Web Bot Auth, MCP server card, Agent Skills, API Catalog, OAuth discovery. Returns a 0–100 score, a level (Basic web presence → Agent-native), and a per-check checklist with copy-paste fixes. Live HTTP probes of the property origin (no crawl/GSC needed). Modelled on Cloudflare's isitagentready.com.

輸入參數siteUrl必填

fix_finding

Generate a fix for a finding

Turn an audit finding into a concrete, paste-ready remediation: JSON-LD for missing structured data, a 301 rule for broken / redirecting internal links, or internal-link suggestions for orphan / striking-distance pages. Other checks return their deterministic fix guidance. Dry-run — returns artifacts, never writes to your site. Identify the finding by findingId (from run_audit) or by check + url.

輸入參數urlchecksiteUrl必填findingIdredirectFormat

normalize_url

Normalise a URL to its join key

Return the canonical url_key used to join GSC data to crawl data.

輸入參數url必填siteUrl

list_properties

List GSC properties

List Google Search Console properties accessible to the service account.

無需輸入參數。

refresh_property

Refresh a property (sync + crawl + inspect)

[Free, except one paid DataForSEO Labs rank call when DataForSEO is set (cached 20 days; ranks:false skips it)] Full refresh for a property in one async job: GSC sync → site crawl → URL inspection → DataForSEO rank history → CrUX field data (when CRUX_API_KEY is set; each target at most once per 7 days). Opens a live progress widget (phases + counts). Set gsc/crawl/inspect/ranks/crux=false to run just part. GSC sync is "lite" (date×query×page) by default — set segments=true to also pull device/country breakdowns (much heavier on large sites). GSC sync is INCREMENTAL: the first sync pulls the window (default last 90 days; pass startDate to go deeper), later syncs only fetch new days — set full=true to force a full re-pull. Use this for "sync everything"; use the single-purpose tools to update just one thing.

輸入參數gsccruxfullcrawlranksendDateinspectsiteUrl必填locationmaxPagessegmentsstartDate另有 1 個

sync_gsc

Sync Search Console data (just GSC)

Update just the GSC search-analytics history (async job — poll with check_sync_status). Incremental: the first sync pulls the range (default last 90 days; pass startDate to go deeper), later syncs only fetch new days — set full=true to force a full re-pull. Lite by default (date×query×page); set segments=true (or pass dimensions) to also pull device/country. For a full refresh use refresh_property. Grain: date × query × page. Joins: page_key (url_key) → crawl/inspection/backlinks; query → DataForSEO keyword tools.

輸入參數fullendDatesiteUrl必填segmentsstartDatedimensionssearchType

check_sync_status

Check sync status

Poll any async job (sync, crawl, refresh, inspect, render, recon, backlinks, …) by id, or omit jobId to list recent jobs (structuredContent: counts by state, live = running + queued, and jobs[] with id, type, state, scope; read state from there, not from the text). check_sync_status and check_crawl_status are the same tool under two names. A running crawl reports its stage (fetching, writing-links, image-weights, resource-headers, link-graph, revalidation-probe, snapshot, site-probes, external-links), pages crawled vs the cap, pages/sec and an ETA for the fetch stage, so a long crawl is never mistaken for a stalled one; poll every 60-120 s. A failed job's reason is in the text reply as well as in structuredContent.error. A job whose server process exited before it finished reads as "interrupted" (see README, Docker).

輸入參數jobId

inspect_urls

Inspect URLs (just URL inspection)

Update just the GSC URL Inspection data (coverage, indexing, Google-vs-declared canonical, last crawl) for top URLs into url_inspection. Quota-limited — samples top pages by clicks. Async job. For a full refresh use refresh_property. Grain: one row per inspected URL. Joins: url_key → pages/GSC.

輸入參數limitsiteUrl必填

start_crawl

Crawl a site (just the crawl)

Update just the crawl: fetch the site into the local database (async job — poll with check_crawl_status every 60-120 s; it reports the stage, pages crawled vs maxPages, pages/sec and an ETA). Large sites: maxPages up to 50000 (default 4000); a 10k-page crawl is typically 20-40 minutes and streams pages/links to SQLite as it goes, then runs the post-crawl stages (link graph, snapshot, outbound-link check). Rate limits are adapted to (#54): a 429 (or 503 with Retry-After) halves the effective concurrency and honours Retry-After, 20 clean responses add one back up to maxConcurrency, and rate-limited URLs are re-queued at the end (2 more attempts); a URL still limited is stored with fetch_state "rate_limited" and no status, never as a 429 error. Shopify hosts are detected from their headers and start at concurrency 3 unless maxConcurrency is set. HTTP crawl; respects robots.txt; asset file-types are fetched with GET and the body is aborted unread (no download; HEAD can lie about status); internal-search / cart / wp-json / builder junk URLs are skipped by default. For a full refresh use refresh_property. excludePatterns adds extra URL regexes to skip (e.g. ["/author/","/tag/","/page/"]) to keep big crawls light. Every crawl also records each page's subresources (CSS, JS, fonts, images: type, first/third party, head/body, async/defer/preload) into page_resources without downloading them; headResources:true adds a header-only pass over the CSS/JS/font ones. After the crawl, every distinct outbound link target is checked (HEAD, ranged-GET fallback, host-throttled, cached 7 days in external_link_status; bot walls are "unverifiable", not broken) and run_audit reports external-broken / external-redirected — checkExternal:false skips it. Grain: one row per url_key, latest crawl. Joins: url_key → GSC/inspection/backlinks.

輸入參數delayMssiteUrl必填maxDepthmaxPagesuserAgentsiteProbescheckExternalheadResourceschromeFallbackmaxConcurrencyexcludePatternsexternalCacheDays

probe_urls

Probe URLs (test a URL hypothesis live)

Fetch arbitrary URLs on the property's own host (apex or www) — including ones you generate to test a hypothesis — and report per URL: status, the full redirect chain and final URL, canonical, meta robots and X-Robots-Tag, title, a content fingerprint (equal contentHash = same page), and cache headers (cf-cache-status, x-cache, age, cache-control). The crawler only fetches what it discovers; use this to test case, trailing-slash, parameter, scheme, host or typo variants, redirect rules, or whether a 404 in the data still 404s. `variantsOf` (up to 6 URLs) is a preset: it generates uppercase, title-case, slash, index.php, unknown-param, http and www/apex variants of each URL and says per variant whether the site normalises it (one 301 to the baseline), contains it (200 with canonical to the baseline: indexing is safe but each variant is crawled and usually bypasses the page cache), or serves a duplicate. Max 50 URLs per call, 4 at a time, 45-second budget (unfinished URLs are marked, not dropped). persist:true stores results in the probes table for query_data. Free (your own server).

輸入參數urlspersistsiteUrl必填variantsOfchromeFallbackfollowRedirects

triage_404s

Triage 404s into a redirect map

Turn the crawl's 404/410 list into a short redirect map. A GSC-seeded crawl reports every URL Google has seen, so real lost pages (traffic, backlinks) sit among many mangled variants of real slugs from scraped or AI-rewritten links. Each 404 gets its discovery sources (internal link / sitemap / GSC / backlink), clicks, impressions and last-seen date from search_analytics, backlinks and referring domains, and the closest live indexable URL by slug similarity (token overlap or edit distance, 0-1). Buckets: redirect (has clicks, ≥minImpressions impressions or referring domains, AND a match ≥minScore), ignore (no clicks, <10 impressions, no internal links, not in sitemap, no backlinks), review (everything else, e.g. internal links pointing at it: fix those at source). Before bucketing, the redirect and review candidates are probed live (verify:true, default; up to 50 URLs, 30s): a URL that already 3xx's to a live page is reported as already-redirected with its live destination (so a suggestion never replaces a correct redirect), and one that answers 200 now as live-now. Slug scores weight rare tokens (a brand or model) over ones shared across the site (buyers-guide, review), and archive targets (/tag/, /category/, /author/, /page/N) are discounted and flagged. Needs a crawl; GSC and pull_backlinks data sharpen it. Free: local data plus requests to your own host.

輸入參數limitverifysiteUrl必填minScoreminImpressions

check_crawl_status

Check crawl status

The same tool as check_sync_status (same arguments, same reply), under the name a crawl result points to. Free.

輸入參數jobId

keyword_volume

Keyword search volume (DataForSEO)

[Paid: Keywords API, cheap, cached 20d | Use for: demand sizing] True monthly search volume + CPC + competition for keywords (DataForSEO KEYWORDS_DATA). Served from a 20-day cache; live calls are serialised. Default location: United States (2840).

輸入參數keywords必填locationlanguageCode

youtube_discovery

YouTube video discovery (DataForSEO SERP)

[Paid: SERP call PER KEYWORD, cached 20d | Use for: finding the videos that rank for a topic — content research, competitor video scan, freshness] The ranking YouTube videos for a keyword (DataForSEO YouTube organic SERP). Returns title, URL, channel, view count, publish date, duration and shorts/live flags, in rank order. Watch the top few to see what the winning videos actually cover. SERP scope, 20-day cache. Default location: United States (2840).

輸入參數keyword必填locationblockDepthlanguageCode

news_discovery

News discovery (Google News RSS + DataForSEO)

[Google News is FREE (no key); DataForSEO adds a paid, richer Google News SERP | Use for: what has been PUBLISHED on a topic — freshness, "what changed since {date}", competitor coverage] Recent news for a keyword from Google News (the free RSS search feed — Google's old News API is retired) and/or the DataForSEO Google News SERP. Returns title, source, publish time, URL. Default source "both" merges + dedupes; pass source:"google" for a free keyless lookup, "dataforseo" for the paid SERP only. Default location: United States.

輸入參數depthsourcekeyword必填locationlanguageCode

topic_trend

Google Trends interest over time (DataForSEO)

[Paid: Keywords API, cheap, cached 20d | Use for: seasonality + "is this rising or fading" — should we update now, when to publish; category monitoring — is a whole market growing] Google Trends relative interest (0–100) over time (DataForSEO KEYWORDS_DATA / google_trends). Give up to 5 keywords, a categoryCode (find it with trend_categories), or both: keywords alone search all categories; keywords + categoryCode narrow a term to one industry (e.g. "jaguar" in Autos); categoryCode alone returns interest in the WHOLE category, no keyword needed. related:true adds the top + rising related topics and queries (at most 1 keyword) — the category-only form surfaces what is breaking out across a market. Returns the time series plus a rising/falling/flat read. timeRange: past_7_days | past_30_days | past_90_days | past_12_months (default) | past_5_years | 2004_present. type: web (default) | news | youtube | images | froogle. Default location: United States.

輸入參數typerelatedkeywordslocationtimeRangecategoryCodelanguageCode

trend_categories

Google Trends category codes (DataForSEO)

[Free endpoint; needs DataForSEO credentials | Use before topic_trend with categoryCode] Search the Google Trends category tree (~1,400 categories) by name and get the codes topic_trend takes, with each match's parent so you can pick the right level. Omit query to list the top-level categories.

輸入參數limitquery

suggest_pages

Suggest new pages from real demand (gaps)

Propose NEW pages grounded in real Search Console demand: queries you already get impressions for but rank 11+ (no winning page), after subtracting demand you already satisfy (you rank ≤10, or a page already covers the query, or one URL owns it). Survivors are clustered into one proposed page per intent and scored by impressions × intent. Returns evidence + the nearest existing page to link the new page from. Computable from synced GSC + crawl — no paid calls (run search_intent siteUrl:<property> first to weight by intent).

輸入參數siteUrl必填maxProposalsminImpressions

content_opportunities

Content opportunity report (write / refresh / rewrite)

The content marketer's report, composed entirely from stored data - NO paid calls. Four sections: WRITE NEXT (new pages proposed from queries you already earn impressions for but have no winning page - suggest_pages), REFRESH NOW (pages that lost 20%+ of their clicks vs the prior period - content decay), REWRITE SNIPPETS (page-1 rankings earning far below expected CTR - title/meta rewrites, the fastest wins), and STRENGTHEN (keyword clusters where you rank 4-20 - one push from the money positions). Every line traces to real Search Console data. Chain into draft_content for a brief, or keyword_volume to size a cluster against the market.

輸入參數limitsiteUrl必填

recon_targets

Content recon: why a page is losing, and what to do about it

[Paid: DataForSEO SERP per page (~$0.004 each, plus a small refundable surcharge for loading async AI Overviews), bounded to the batch | Use for: the deep "why are we behind and what to add" recon] For each of your striking-distance pages (auto-selected: the page's top query at positions 3-15, highest impressions first; or pass explicit urls), this fetches OUR live page with the crawler, pulls the live Google SERP (DataForSEO SERP-advanced, depth 20 organic), and classifies WHY we are behind using the organic-rank x AI-Overview-citation matrix: defend-and-deepen (cited + strong), accuracy-or-freshness (rank but the AIO will not quote us - the sharpest, most actionable class), consolidate-weak-page, competitive-gap, or page-cannot-rank (the crawl says the URL is noindex/canonicalised away, so its GSC history is legacy and the SERP read belongs to another page). Honesty rules baked in: every GSC figure carries its 28-day window; organicRank:null means "absent from the top 20 ORGANIC results", never a position; and an AI Overview whose citations could not be resolved reports aioCitesUs:null (UNKNOWN) rather than "not cited". To-dos are prioritised by OPPORTUNITY (impressions x the CTR gap between where you rank and a realistic target, damped by the verdict), not by raw impressions, and cannibalisation is counted across the whole query cluster. Set scrapeCompetitors:true to also pull the top competitors as content, free and with no API key, routed by host: Reddit → its .json, other pages → a browser-profile HTTP fetch, and ranking videos are listed rather than fetched (a video page has no readable text over HTTP); competitorLimit (default 5) caps how many are fetched and everything above the cap is listed as skipped. Cloudflare-challenge sites (e.g. PCMag) still can't be fetched from a server and come back as a per-URL error — the SERP still tells you they rank; if one matters, ask the user to paste its copy or supply a text file and diff that in. Watch the ranking vide

輸入參數urlslimitcrawlAssiteUrl必填locationminImpressionscompetitorLimitscrapeCompetitors

save_recon_todo

Save content-recon to-dos (research writeback)

Write content-recon findings back into the trackable ledger for a page — the gaps and originality the research session found by diffing the competitor pages and ranking videos against our content. Each to-do is an action with a type (content-gap / originality / schema / freshness / format), rationale and evidence. Snapshots the page baseline so the fix's effect on rank/AIO-citation is measurable later. Run recon_targets first (it classifies the page and seeds the deterministic to-dos); this adds the judgement ones. Track everything with recon_todos.

輸入參數todos必填urlKey必填siteUrl必填

recon_todos

List, track and annotate content-recon to-dos

The content-recon to-do board. With no id: list to-dos (optionally filter by page or status), grouped by page with each page's verdict — the pick-a-page-to-work-on surface, and the hand-off to content-machine. With id: update one to-do — set status (open → researching → drafted → shipped → dismissed) and/or append a dated annotation note (your own observations, the history). On status:shipped with remeasure:true it re-fetches the SERP and records the outcome, so you can see whether the fix moved you from AIO-uncited to cited, or up the organic ranks.

輸入參數idnotestatusurlKeysiteUrl必填locationremeasure

keyword_list

Cluster a keyword list into topics with own/weak/absent verdicts

Demand-first keyword clustering from stored data - NO paid calls. Give it a keyword list (or omit keywords to use your top 500 GSC queries) and it clusters them by the page Google ALREADY answers them with (two keywords that rank via the same URL belong together - the strongest clustering signal, free from your own GSC data), then groups non-ranking keywords lexically. Each cluster gets a deterministic verdict: OWN (best position <=3), WEAK (4-20), ABSENT (no ranking page), plus the ranking URL, summed 90-day impressions and clicks. The keyword-research workhorse: paste a client keyword list, get the topic map and where you stand. Chain with keyword_volume for market volumes on the interesting clusters, or draft_content for the absent ones.

輸入參數limitsiteUrl必填keywords

search_intent

Search intent classification (DataForSEO Labs)

[Paid: Labs, cheap, cached 20d, up to 1000 kw/call | Use for: intent mapping before content planning] Classify the search intent (informational / navigational / commercial / transactional) of keywords — primary label + probability + secondary intents. Use it to spot intent mismatch: e.g. a transactional product page ranking for an informational query (a common cause of high impressions / low CTR). Pass siteUrl to persist the intents so run_audit can surface intent-vs-pagetype-mismatch. Labs call, cached 20 days, up to 1000 keywords. Language-only (no location).

輸入參數siteUrlkeywords必填languageCode

page_lighthouse

Page Lighthouse — lab Core Web Vitals (DataForSEO On-Page)

[Paid: On-Page, ONE URL per call | Use for: CWV evidence on a page that earns clicks] Run a live Lighthouse audit for ONE url: lab Core Web Vitals (LCP, CLS, TBT, FCP, Speed Index), category scores (performance/SEO/best-practices/accessibility), and the top time-saving opportunities. Complements GSC/CrUX field data (aggregate + delayed) with on-demand lab data. Pass siteUrl to persist the CWV so run_audit can surface high-yield-cwv-fail. Paid On-Page call (~2000 credits), slow (~20–120s), cached 20 days.

輸入參數url必填siteUrlforMobile

competitors_domain

Competitor domains (DataForSEO Labs)

[Paid: Labs, cheap, cached 20d | Use for: naming the real competitor set - the opening move of competitive work] Discover the domains competing with a target for the same organic keywords (ranked by keyword overlap), with intersection counts and organic traffic estimates. The seed list for content-gap analysis (feed these into page_intersection). Labs call, cached 20 days. Pass location + language for the right market.

輸入參數limittarget必填locationlanguageCode

page_intersection

Content gap — page intersection (DataForSEO Labs)

[Paid: Labs, cheap, cached 20d | Use for: page-level content gap vs named rival URLs] Find keywords that competitor pages rank for but your page does NOT (the content gap). Pass competitor URLs as `competitorUrls` (max 20; wildcards like https://site.com/blog/* allowed) and your own URL(s) in `excludePages` (max 10) to subtract. Returns gap keywords sorted by search volume, with each competitor’s rank. Labs call, cached 20 days. Pass location + language.

輸入參數limitlocationexcludePageslanguageCodecompetitorUrls必填

domain_visibility

Domain visibility over time (DataForSEO Labs)

[Paid: Labs, cheap, cached 20d | Use for: visibility-over-time trend, any domain, no GSC needed] Monthly organic visibility for ANY domain or subdomain — no Search Console access needed: ranking-keyword totals, position distribution (1–3 / 4–10 / 11–20 / 21–100) and estimated traffic volume (ETV) per month, plus a trend verdict. The "organic overview / visibility over time" for you or a competitor. Labs call, cached 20 days. Pass location (name or code) for the right market. Grain: month × domain. Joins: domain → Labs/backlinks tools; period → rank_history.

輸入參數monthstarget必填locationlanguageName

top_pages

Top ranking pages on a domain (DataForSEO Labs)

[Paid: Labs, cheap, cached 20d | Use for: where rival traffic actually lands] The top organic pages of ANY domain or subdomain, ranked by estimated traffic volume (ETV): page, ranking-keyword count, ETV and top-3 / top-10 keyword counts. The "top pages" view — works on competitors, no crawl or GSC needed. Labs call, cached 20 days. Pass location for the right market. Grain: page × domain. Joins: domain → Labs tools; URL → pages.url_key on your own property.

輸入參數limittarget必填locationlanguageCode

ranked_keywords

Ranked keywords for a domain / URL / folder (DataForSEO Labs)

[Paid: Labs, cheap, cached 20d - ONE call replaces any keyword loop | Use for: full keyword footprint of a domain/page/folder] Every keyword a target ranks for in Google organic — scope it to a whole domain, a subdomain, ONE page (scope:url with the full URL), or a subfolder (scope:folder + folder:"/blog/"). Returns keyword, position, search volume, ETV, the ranking URL, plus keyword difficulty, search intent and SERP features where the response carries them. Set aioOnly:true to list only keywords whose SERP shows a Google AI Overview (your AIO exposure list; per-keyword CITATION checking uses the SERP tools — see the cookbook). The "keywords a page or site ranks for" view — works on any site. Labs call, cached 20 days. Pass location for the right market. Grain: keyword × target. Joins: keyword → GSC search_analytics.query; URL → pages.url_key.

輸入參數limitscopefoldertarget必填aioOnlyorderBylocationlanguageCode

serp_features

SERP-feature footprint (AI Overviews, snippets, PAA)

[Paid: Labs, ONE cached call | Use for: AI-Overview / zero-click exposure with real numbers] How much of your keyword universe carries each SERP feature - AI Overviews, featured snippets, People Also Ask, shopping, video - weighted by search volume, and how much of that volume you already rank page 1 for. ONE DataForSEO Labs ranked_keywords pull (top-volume sample, cached 20 days, never per-keyword SERP loops). Answers "how exposed are we to AI Overviews / zero-click?" with real numbers. Deterministic: feature PRESENCE (from the Labs index). Judgement proxy: page-1 rank stands in for feature ownership - true ownership needs per-keyword SERP calls (see ranked_keywords aioOnly + the cookbook). Persists to the property DB so the dashboard charts it.

輸入參數limittargetsiteUrl必填locationlanguageCode

market_sizing

Market Sizing and Prioritisation (share of voice vs competitors)

[Paid: Labs, one cached call per domain (<=5) | Use for: sizing the organic market and who owns it] Build the organic market map: your domain plus up to 4 named competitors, ONE cached Labs ranked_keywords pull each, unioned into a keyword universe. Returns total monthly demand (deduplicated search volume), each domain's share of voice (ETV share) overall and per topic cluster, and the leader per cluster - the "here is the market, here is who owns it, here is where to attack" table that opens an engagement. Deterministic: the competitor set and ranked keywords (Labs index). Judgement: ETV is DataForSEO's CTR-curve traffic estimate - the SoV percentages inherit that. Persists to the property DB for the dashboard chart. Get the competitor set from competitors_domain first if unsure.

輸入參數siteUrl必填locationcompetitors必填languageCodelimitPerDomain

topic_gaps

Topic gaps — what to cover to be expert in your space (Labs + GSC)

[Paid: Labs, <=4 cached calls | Use for: topic-level gap plan vs competitors] What related topics should this site cover to be seen as expert in its space? Pulls competitor keyword footprints (DataForSEO Labs ranked_keywords, ≤4 bounded + 20-day-cached calls), subtracts everything YOU already surface for (every GSC query with impressions) or already have a page about (title/H1/slug near-match), clusters the surviving gap keywords lexically, and scores each topic by summed search volume × how many competitors rank there. Each topic names the owning competitor with an example URL, your nearest existing page to build from, and (when resolve_entities has run) whether it sits beside entities you already cover. Pass competitors explicitly (max 3) or let it derive the top 2 from ranking overlap. Needs synced GSC data + DataForSEO credentials.

輸入參數limitsiteUrl必填locationcompetitors

portfolio

Portfolio: list and edit the monitored domains (free)

The domains table (owned properties + watched domains such as competitors). Free: reads and edits only, never calls DataForSEO. action "list" (default) shows every domain with organic keywords and traffic (DataForSEO estimates), referring domains, Domain Rank (the DataForSEO rank), AI mentions (AI Overviews + ChatGPT) and, for owned sites, Search Console clicks (measured) and audit health, plus "needs attention" reasons. Changes compare the last COMPLETE month with the month before. "add" watches a domain (location = DataForSEO location code or country name, default United States; group e.g. "competitors"). "remove" stops watching. "group" sets a group label. "location" changes a watched domain's country, or an owned property's saved DataForSEO location. Owned domains come from the local property databases automatically. To fetch data use refresh_portfolio (paid, quotes first).

輸入參數groupactiondomainlocation

refresh_portfolio

Refresh the portfolio from DataForSEO (paid: quotes first)

[Paid: DataForSEO Labs + Backlinks + LLM Mentions. Default is a QUOTE only, nothing spent] Fetch the portfolio data. tier "weekly" = current traffic estimates, Domain Rank, referring domains, backlinks, new/lost, search-results mix (bulk calls, cents for the whole portfolio); "monthly" = monthly history (keywords, traffic, positions, referring domains, AI mentions per platform), countries, top pages by traffic and by links, AI-cited pages and co-cited sources (per domain); "all" = both (default). Without confirm:true it returns the call count and estimated cost per family and spends nothing: show the user the quote and ask before confirming. With confirm:true it runs as an async job (poll check_sync_status) and records actual spend; cached responses cost nothing. If a refresh schedule with a monthly budget exists, a manual run counts toward it and is refused over the cap unless overBudget:true (only when the user explicitly agrees). An API family that is not enabled on the DataForSEO account fails on its own and the rest continues.

輸入參數tierconfirmdomainsoverBudget

schedule_portfolio_refresh

Schedule portfolio refreshes with a monthly budget (two-step)

Set up automatic portfolio refreshes: the weekly tier on a weekday plus the monthly tier on a day of the month, never exceeding a monthly USD budget (portfolio refreshes only). Two-step consent: without confirm:true it previews the cadence, the per-run quotes and the projected monthly cost and saves nothing; show that to the user and ask. With confirm:true it saves the schedule, which is the user's consent to spend up to the cap. A run whose cost has risen more than 25% since consent (domains added) is skipped until the schedule is re-confirmed. enabled:false with confirm:true turns scheduling off. The schedule runs in the job runner (SAC_JOB_RUNNER=external) or in this MCP process while it is running; a missed run happens once on the next start.

輸入參數confirmenabledbudgetUsdweeklyDowmonthlyDom

get_portfolio

Portfolio dashboard (domains table + domain overview)

Interactive portfolio dashboard in chat: the domains table (owned + watched; Search Console measured vs DataForSEO estimated, Domain Rank, AI mentions, needs-attention), and, with domain, that domain's overview: traffic trend, keyword positions, AI search (mentions, cited pages, sources cited alongside, rank vs citation), countries, backlinks and top pages. Free: reads stored data only.

輸入參數domain

get_portfolio_data

Portfolio data (internal)

Portfolio dataset for the UI widget. App-only.

無需輸入參數。

get_domain_overview

Domain overview data (internal)

One portfolio domain's overview for the UI widget. App-only.

輸入參數domain必填locationCode

get_dashboard

SEO dashboard

Interactive dashboard for a property: summary metrics, rank & clicks over time, and top-keyword performance (click a keyword for related terms). Needs synced GSC data — run refresh_property first.

輸入參數siteUrl必填

get_dashboard_data

Dashboard data (internal)

Full dashboard dataset for the UI widget. App-only — not for direct use.

輸入參數dayssiteUrl必填

list_findings

Findings page (internal)

A page of the latest audit findings for the dashboard Issues list, filtered by severity / category / check. App-only.

輸入參數limitoffsetcheckIdsiteUrl必填categoryseverity

export_report

Export a shareable dashboard report (HTML)

Write a self-contained, interactive dashboard HTML for a property (all data + charts inlined) to the reports folder, and return the file path. Open it in any browser or send it to a client — no server, no MCP-App host support needed. Run refresh_property (+ run_audit for findings) first.

輸入參數themesiteUrl必填

serve_dashboard

Serve the dashboard on a local webserver

Start a localhost-only webserver and return a URL that opens the full interactive dashboard in your browser — live data straight from the local database (always current, unlike export_report snapshots), a domain dropdown (All domains, your properties, watched domains), free actions (crawl, Search Console sync, URL inspection, audit, agent readiness), working CSV downloads, and no host widget limits. The server stays up while the MCP server runs; call again with stop=true to shut it down. Localhost only — nothing is exposed to the network.

輸入參數portstopsiteUrl

open_dashboard

Open the dashboard for a property

Return a link that opens the property's interactive dashboard in the browser, starting the localhost dashboard server if it isn't running. Offer this after a sync, crawl, refresh or audit finishes. Where no local port can be served (e.g. the Docker MCP gateway), it says to use get_dashboard, which renders the dashboard in chat.

輸入參數siteUrl必填

resolve_entities

Resolve page entities (Wikidata)

Heuristically resolve each top page’s primary entity (by H1, fallback title) to a Wikidata QID, and store subclass-of / part-of relationships between them. Unlocks the entity-internal-link-gap finding (suggests internal links a topical mesh implies). Heuristic — those findings are judgement (N), shown only with includeJudgement. Free (public Wikidata API), cached ~45 days, on-demand. Async job — poll check_sync_status.

輸入參數limitsiteUrl必填language

track_ranks

Track ranks over time (DataForSEO)

Ingest the DataForSEO over-time sequence (monthly rank distribution + ETV) into rank_history, so rank charts have a real time axis reconciled with GSC. DataForSEO Labs call — cached 20 days. Pass location once (e.g. "Australia", "United Kingdom") — it is saved per property. Async job.

輸入參數siteUrl必填location

sync_crux

Sync CrUX field data (Core Web Vitals)

[Free: Google API key in CRUX_API_KEY | Use for: real-user Core Web Vitals, incl. INP, which lab tools cannot measure] Pull Chrome UX Report field data (p75 + good/needs-improvement/poor shares for LCP, INP, CLS, plus FCP, TTFB, RTT, the LCP sub-parts, LCP resource type and navigation types) for the property's origin and its top URLs by GSC clicks (default 50), each on PHONE and DESKTOP, into crux_metrics / crux_fractions / crux_targets. A target's first pull backfills ~25 weekly 28-day windows of history; later pulls add the newest window, at most once per 7 days per target (force:true overrides). A URL without enough Chrome traffic is recorded as insufficient_data (not an error) and re-asked after 28 days. Throttled under the API's 150 queries/min. Async job - poll check_sync_status, then run_audit for crux-field-lcp / -inp / -cls and crux-regression. refresh_property runs this too when the key is set. Grain: target x form factor x metric x 28-day window (windows overlap - a trend, never a sum). Joins: target = url_key -> pages/GSC.

輸入參數urlsforcelimitsiteUrl必填

版本歷史

13
  1. v1.0.1最新Nov 4, 2026
  2. v1.0.0Oct 31, 2026
  3. v0.17.0Oct 25, 2026
  4. v0.16.2Oct 18, 2026
  5. v0.16.1Oct 17, 2026
  6. v0.15.0Oct 17, 2026
  7. v0.13.0Oct 14, 2026
  8. v0.12.1Oct 6, 2026
  9. v0.12.0Oct 6, 2026
  10. v0.11.1Oct 6, 2026
  11. v0.10.0Sep 29, 2026
  12. v0.9.1Sep 23, 2026
  13. v0.8.0Sep 16, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分
  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分

其他 Audit 整合