Install
openclaw skills install @jerrykik/research-seo-signalsopenclaw skills install @jerrykik/research-seo-signalsTurn a natural-language SEO research goal into the smallest sufficient asynchronous SignalDig MCP request, then return an organized, evidence-linked report. Use the MCP result as evidence, not as permission to invent facts or make the user's final prioritization decision.
Efficiency stance: Prefer reuse of prior terminal results, narrow scopes, and a concise default report. Do not re-fetch the same logical research or re-dump full arrays unless the user asks for a refresh or a full export.
This Skill is a workflow spec only; it has no data of its own. Every live result comes from a connected SignalDig SEO Data MCP capability, which requires a valid SignalDig API key. Installing this Skill does not connect the MCP server — the two are separate installs.
Before starting research, inspect the current MCP tool inventory for the
required operations (e.g. submit_keyword_research_signals, submit_specific_seo_data,
get_keyword_research_signals, submit_competitor_analysis,
submit_geo_analysis, submit_backlink_analysis, submit_ranked_keywords, submit_bulk_traffic_estimation).
The server alias and any local tool namespace are client-defined. Use the exact
visible tool identifier that implements the required operation; never require,
construct, or infer a server alias or an mcp__<alias>__<tool> identifier.
If a required operation is unavailable, its source cannot be identified as the SignalDig SEO Data MCP, the API key is invalid, or an initial connection fails:
Only when the tools are available may the workflow proceed, and every substantive claim must cite a real tool result.
x_recent_search scope is a bounded keyword-level X evidence family, not a
replacement for the Social MCP's raw X-query, historical-search, or
pagination capabilities. This Skill returns evidence summaries only and does
not produce conditional recommendations.submit_specific_seo_data for one family, submit_keyword_research_signals with data_scopes for any multi-family subset, and get_keyword_research_signals to query either job. Always pass include_skills=false to retain this Skill's evidence-only boundary.submit_competitor_analysis for competitor research, submit_geo_analysis for AI-search/GEO visibility, submit_backlink_analysis for a site's backlinks and referring domains, and submit_ranked_keywords for keywords a domain or page currently ranks for, and submit_bulk_traffic_estimation for estimated search traffic of a domain or page. These tools own provider query details; do not construct low-level provider requests.search_engine="bing" is supported here. When the user explicitly requests
Bing, pass search_engine="bing" and label every SERP observation with the
engine that produced it.request_id and idempotency_key used in this conversation until the task is finished.request_id exists, call only get_keyword_research_signals. Do not create a new request for the same data.idempotency_key for a logical research request. On tool errors, client timeouts, ambiguous failures, or retries of the same logical request, reuse that exact key. Do not invent a new key for the same keyword/domain/market/language/scopes.pending or running.partial result as fully complete. State exactly which evidence is unavailable.data_scope that satisfies the user's goal.data_scopes only when the user explicitly asks for comprehensive/all-family research or when every family is demonstrably necessary to answer an already specific request. Never equate a unified MCP endpoint with permission for full retrieval.url, width, height, is_cover, and whichever source identifier is present (file_id/filename or trace_id). For video, preserve and show the returned url, width, height, duration_ms, format, and codec. Do not open, download, render, OCR, caption, classify, describe, compare, or otherwise interpret the image/video itself. Never infer visual meaning, subject matter, or material identity from a URL, filename, file ID, dimensions, cover marker, format, or codec. Do not derive a filename from the URL path; if a requested metadata field is absent, report it as unavailable.Treat two research goals as the same logical request when all of the following match after normalization:
keyword (exact seed string)domain (hostname only)market (ISO alpha-2)language (research language)data_scope / data_scopes set (order-independent)search_engine when the selected traditional scope includes serpanalysis_kind (competitor, geo, backlink, ranked_keywords, or bulk_traffic) instead of
data_scope / data_scopes for a dedicated analysis toolBuild:
idempotency_key = "seo-signals:" + keyword + "|" + target_identity + "|" + market + "|" + language + "|" + sorted_scopes + "|engine=" + search_engine
Where target_identity is domain for traditional, competitor, and GEO
research, and target for backlink analysis, ranked-keyword inventory, and traffic estimation. sorted_scopes is the selected traditional scopes joined by commas in
stable sorted order, all when the complete set is intentionally requested,
or analysis=competitor, analysis=geo, analysis=backlink, analysis=ranked_keywords, or analysis=bulk_traffic for a
dedicated analysis. Include engine= only for a traditional SERP scope. Do
not put personal or confidential data into the key.
Keep a session ledger (in agent working memory) shaped like:
logical_id -> { idempotency_key, request_id, status, terminal_at, scopes }
Update the ledger after every successful submit or get.
concise default, full only if requested), and whether they asked to refresh.market to an ISO 3166-1 alpha-2 country code such as US.language to an ISO language or supported BCP 47 code such as en or zh-TW.en.domain
for traditional, competitor, or GEO research, and target for backlink analysis, ranked-keyword inventory, or traffic estimation.submit_specific_seo_data, and two or more families to submit_keyword_research_signals with exactly those values in data_scopes. Omit data_scopes only when all supported families are required. Route a dedicated analysis directly to its matching submit tool; do not encode it as a data scope.idempotency_key from the logical research identity.request_id for this identity, call get_keyword_research_signals(request_id) only.complete or partial and the user did not ask to refresh, validate and answer from that result. Stop.pending or running, continue polling that request_id only. Do not submit again.failed and the user wants a retry, prefer resubmit with the same idempotency_key so the retry keeps the same logical identity.request_id is known, still send the stable idempotency_key on first submit so client retries collapse to one run.keyword, domain, market, research language, include_skills=false, and the same idempotency_key; pass data_scope / data_scopes only to those two tools. For a dedicated analysis, call only its matching tool with its documented inputs and omit include_skills.request_id, status, is_terminal, poll_after_seconds, and execution_deadline_at in the session ledger.is_terminal is false, wait for poll_after_seconds when provided, then call get_keyword_research_signals with the same request_id.pending or running. Do not resubmit.is_terminal is true or the client reaches a firm execution deadline.complete or partial, validate the result before interpreting it.failed, give a safe plain-English explanation and next step without exposing a machine error code. Retry only when the error is explicitly retryable or the user requests a new attempt, always reusing the prior idempotency_key for that logical identity.Use the following exact mapping:
keyword_overview: keyword metrics, properties, backlink/SERP summaries, and embedded search intent.related_keywords: related keyword discovery and their returned metrics.serp: organic results, SERP features, target-domain presence, and traceability URL.google_trends: interest timeline, geographic interest, and related top/rising queries.Use the dedicated analysis tools when the request is about competitors, AI-search visibility/LLM mentions, backlinks/referring domains, keywords a domain/page currently ranks for, or estimated search traffic for a domain/page. Keep those analysis families separate from the traditional SEO scope selection. Do not use related_keywords or serp as a substitute for submit_ranked_keywords.
Map clear requests directly:
submit_competitor_analysissubmit_geo_analysissubmit_backlink_analysissubmit_ranked_keywordssubmit_bulk_traffic_estimationThese tools are separate asynchronous jobs. Reuse and poll each job by its own
request_id; do not pretend their observations were returned by a traditional
data_scope request.
Map common user wording without another question when the intent is clear:
keyword_overviewrelated_keywordsserpgoogle_trendsIf wording spans multiple rows, select only those rows. If it matches none clearly, ask a short scope question before calling. Do not propose all families as the default or describe them as a mandatory bundle.
For SERP requests, use search_engine="bing" when the user explicitly asks for Bing/必应; otherwise omit it and keep the Google default. Do not expose or construct DataForSEO task parameters, endpoint paths, device settings, depth, or location payloads in the MCP call; the service implementation owns those details.
Use one combined submit when the answer needs two or more families; do not split one logical combination into several requests. Omit data_scopes only for a complete all-family research request.
When a prior terminal result already covers a superset of the needed scopes (for example prior all and now only serp), reuse that request_id and answer from the needed family only. Do not submit a narrower job just to re-fetch overlapping data.
When a prior result is a subset of what is now needed, submit only for the missing scopes if the tools allow a scoped request; do not re-request families already present unless the user asks to refresh.
Translate the user's request into these fields:
keyword: the exact seed query to investigate; preserve meaningful punctuation and product names.domain: the target hostname without scheme, path, query, or fragment for traditional,
competitor, and GEO research.target: for submit_backlink_analysis, submit_ranked_keywords, and submit_bulk_traffic_estimation; pass a domain or subdomain without
scheme and www., or pass a webpage as an absolute http:// or https:// URL.market: a two-letter country code. Do not send city names or free-form country names.language: the research language sent to the data service; it does not control the final answer language.data_scope / data_scopes: the smallest single family or multi-family combination needed for the goal, including x_recent_search only for bounded keyword-level X evidence.search_engine: optional SERP engine selector, google or bing; it defaults to google and does not change non-SERP data families.include_skills: always pass false; the backend default varies by submit tool and enables SignalDig analysis, which is outside this Skill's evidence-only boundary.idempotency_key: stable retry and reuse identifier for the same logical request.Use these defaults:
en when no unambiguous market-specific language can be inferred.en.poll_after_seconds.search_engine="bing"; do not fetch Bing by default.The traditional SEO function remains submit_specific_seo_data; it supports the existing SEO families and can select Google or Bing for serp. Bing fields may differ from Google, so interpret the returned result and field_semantics rather than assuming identical structure.
Do not silently replace an unsupported market-language pair with another country or language. Report the rejected pair and ask the user to choose a supported alternative.
Handle states exactly as follows:
pending: accepted but not started; wait and poll the same request_id.running: in progress; wait and poll the same request_id.complete: terminal result with all required nodes completed; reuse via get for later questions.complete: terminal usable result. Freshness-only codes signaldig_stale_data and signaldig_unknown_freshness stay on complete; treat them as quality notes, not outages.partial: terminal usable result with missing coverage such as signaldig_no_matching_data or signaldig_analysis_unavailable; report both usable evidence and missing families. Do not retry empty-result codes.failed: terminal failure; use the safe English error.message when available, but never expose error.code, and do not fabricate a result. For a service-unavailable condition, use the service-unavailable message in Hard Rule 10. Retry only with the same idempotency_key when appropriate.Trust is_terminal as the primary stop signal. Use status to explain the outcome. A missing result in a non-terminal response is normal.
Before writing the answer:
request_id returned by submit or previously reused.result.query matches the requested keyword, market, and language, plus domain or target for the selected tool.status, limitations, usage, and result.field_semantics before
interpreting any raw or normalized result field. Apply each matching entry's
unit, meaning, and caveats; do not replace the live glossary with
remembered source definitions.evidence, signals, limitations, and usage. For dedicated analysis, require its matching public section (competitor_analysis, geo_analysis, or backlink_analysis) and shared result metadata; for GEO also read analysis_coverage. For ranked keywords, require competitor_analysis["ranked-keywords"]; for traffic estimation, require competitor_analysis["bulk-traffic-estimation"]. Include shared result metadata. Do not misreport intentionally unrequested sections as missing.request_id.evidence_id values for any claim you make.evidence_refs and counter_evidence_refs item points to that set.usage.cached is true after a resubmit, treat it as reuse of an existing result and mention it only when freshness matters.language as research scope only. Never use it as the sole signal for response language.Summary: two to four evidence-grounded observations.Limitations: all limitations that affect the claim.Source job: request_id (and whether this answer reused a prior job).Provide every section relevant to the selected request:
SummaryKeyword overview (all returned overview fields)Related keywords (every item)SERP (every organic result and feature)Google Trends (every returned point/query/region)Competitor analysis (every returned subsection, only when requested)GEO / AI-search analysis (every returned subsection and coverage, only when requested)Backlink analysis (all returned samples and total counts, only when requested)Ranked keywords (competitor_analysis["ranked-keywords"], only when requested)Traffic estimation (competitor_analysis["bulk-traffic-estimation"], only when requested)Evidence and signals (every item and reference IDs)Limitations and usageNext stepsFor a comparison request, use one row per keyword or market and keep definitions consistent across rows. Reuse prior jobs per row when available. Do not compare requests with different markets or languages without labeling that difference.
When Xiaohongshu material metadata is present, add a 素材元数据 section (or the user's requested equivalent) containing one row per returned image/video. Include the exact material URL and only platform-returned metadata; keep missing fields as unavailable. Do not include a visual-content summary or any claim derived from inspecting the asset.
request_id. Do not immediately create a new request; retry get once, then resubmit only with the same idempotency_key if the user still needs the research.request_id; do not submit again automatically. Later turns must resume with get on that request_id.idempotency_key for the same logical identity. Create a new key only when the user changes keyword, domain, market, language, or scopes, or explicitly asks for a distinct new job.Reuse prior job in the same conversation:
User: Research "AI SEO tools" for example.com in US English.
(agent submits once, stores request_id)
User: Summarize the demand signals again more briefly.
(agent calls get on the same request_id only; no new submit)
Single-market research (first time):
Use $research-seo-signals to research "AI SEO tools" for example.com in the US English market.
Localized research:
Use $research-seo-signals to research "herramientas SEO con IA" for example.com in the US Spanish market and answer in Spanish.
Ranked-keyword inventory:
Use $research-seo-signals to list the keywords example.com currently ranks for in the US English market.
Evidence-focused follow-up (must reuse prior terminal job when available):
Use $research-seo-signals to summarize only the strongest supported demand and intent observations, including counter-evidence and limitations.
Single-family request:
Use $research-seo-signals to fetch only the organic SERP data for "AI SEO tools" for example.com in the US English market.
Ambiguous request (confirm before calling):
User: 帮我查一下关键词“AI SEO 工具”。
Agent: 你具体需要哪类底层数据:搜索量/CPC/竞争度与意图、相关关键词、当前 SERP,还是 Google Trends 趋势?可以选一项或多项。我会只请求你需要的数据。
Combined request:
Use $research-seo-signals to research only SERP patterns and Google Trends for "AI SEO tools" for example.com in the US English market.
Explicit refresh:
Use $research-seo-signals to refresh the SERP data for "AI SEO tools" for example.com in the US English market.
Read references/mcp-contract.md before the first live call, when interpreting terminal envelopes, or when diagnosing tool and request-state errors.