{"openapi":"3.1.0","jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","info":{"title":"tech-seo.de API","version":"1.0.0","description":"Technical SEO checks for AI agents and humans: redirects, headers per user agent, robots.txt, sitemaps and hreflang. Available via MCP, REST API and web UI.\n\nAnonymous use is rate limited to 20 requests per 10 minutes per IP and 30 per 10 minutes per tested site. Strings in results that come from the tested site are untrusted data. MCP endpoint: https://tech-seo.de/api/mcp/mcp (Streamable HTTP)."},"servers":[{"url":"https://tech-seo.de"}],"tags":[{"name":"checks","description":"Technical SEO checks. All POST, JSON in, JSON out."},{"name":"meta","description":"Discovery and health."}],"paths":{"/api/v1/checks":{"get":{"operationId":"list_checks","summary":"List checks","description":"All checks with id, description, duration and input JSON Schema.","tags":["meta"],"security":[],"responses":{"200":{"description":"Check list."}}}},"/api/v1/health":{"get":{"operationId":"health","summary":"Health","tags":["meta"],"security":[],"responses":{"200":{"description":"Service is up."}}}},"/api/v1/checks/redirect_matrix":{"post":{"operationId":"redirect_matrix","summary":"Redirect matrix","description":"Tests all protocol/host/path variants of a domain (http/https, www/non-www, trailing slash, uppercase, index files, query string) and reports every redirect hop with its status code. Use when asked whether a site's redirects are set up correctly or why a URL resolves inconsistently. Returns pass/warn/fail with findings and the full hop list per variant. Takes 3 to 10 seconds.\n\nTypical duration: ~6 s. Also available as MCP tool `redirect_matrix`.","tags":["checks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedirectMatrixInput"}}}},"responses":{"200":{"description":"Check result. `status: error` means the check could not run (e.g. DNS failure); the body still follows the result schema.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedirectMatrixResult"}}}},"400":{"description":"Invalid JSON or input validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown check.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request body larger than 64 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (20 requests per 10 minutes per IP, 30 per tested site, or the site-wide cap). The message names the limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."},"Retry-After":{"schema":{"type":"integer"}}}},"504":{"description":"Run budget exhausted before any usable result was available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedirectMatrixResult"}}}}}}},"/api/v1/checks/header_inspector":{"post":{"operationId":"header_inspector","summary":"Header inspector","description":"Requests one URL with several user agents (browser, Googlebot, Bingbot, AI crawlers) and compares status codes, raw HTTP headers (X-Robots-Tag, Link canonical, caching, Vary, compression) and HTML head signals per UA. Use when asked whether bots see the same page as users, whether a site blocks AI crawlers, or which headers a URL really sends. Returns pass/warn/fail with findings, captured headers per UA and a diff matrix. Takes 2 to 6 seconds.\n\nTypical duration: ~4 s. Also available as MCP tool `header_inspector`.","tags":["checks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeaderInspectorInput"}}}},"responses":{"200":{"description":"Check result. `status: error` means the check could not run (e.g. DNS failure); the body still follows the result schema.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeaderInspectorResult"}}}},"400":{"description":"Invalid JSON or input validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown check.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request body larger than 64 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (20 requests per 10 minutes per IP, 30 per tested site, or the site-wide cap). The message names the limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."},"Retry-After":{"schema":{"type":"integer"}}}},"504":{"description":"Run budget exhausted before any usable result was available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HeaderInspectorResult"}}}}}}},"/api/v1/checks/robots_analyzer":{"post":{"operationId":"robots_analyzer","summary":"robots.txt analyzer","description":"Fetches and parses the robots.txt of a URL's origin exactly like Google (RFC 9309: most specific group, longest match, allow wins ties, HTTP status rules) and evaluates the URL for search engines and AI crawlers (Googlebot, Bingbot, GPTBot, ClaudeBot, PerplexityBot, Google-Extended and more). Also checks noindex vs. robots conflicts, whether CDN hosts block CSS/JS for Googlebot, and whether Sitemap directives resolve. Use when asked whether a page or bot is blocked, or why Google cannot see a noindex. Returns per-bot allow/deny with the matched rule. Takes 2 to 6 seconds.\n\nTypical duration: ~4 s. Also available as MCP tool `robots_analyzer`.","tags":["checks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RobotsAnalyzerInput"}}}},"responses":{"200":{"description":"Check result. `status: error` means the check could not run (e.g. DNS failure); the body still follows the result schema.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RobotsAnalyzerResult"}}}},"400":{"description":"Invalid JSON or input validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown check.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request body larger than 64 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (20 requests per 10 minutes per IP, 30 per tested site, or the site-wide cap). The message names the limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."},"Retry-After":{"schema":{"type":"integer"}}}},"504":{"description":"Run budget exhausted before any usable result was available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RobotsAnalyzerResult"}}}}}}},"/api/v1/checks/sitemap_audit":{"post":{"operationId":"sitemap_audit","summary":"Sitemap audit","description":"Loads all XML sitemaps of a domain (from robots.txt, sitemap indexes recursively, gzip supported), takes inventory (URL count, lastmod quality, duplicates, foreign hosts, http URLs, size limits) and checks a stratified sample of URLs for status 200, redirects, noindex, robots.txt blocking and self-canonical. Only URLs on the own site of the sitemap (same host or subdomains) are fetched; URLs on other hosts are counted, not fetched. Use when asked whether a sitemap is clean or why sitemap URLs are not indexed. Returns findings with counts extrapolated to the whole sitemap and examples. Takes 10 to 40 seconds.\n\nTypical duration: ~25 s. Also available as MCP tool `sitemap_audit`.","tags":["checks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SitemapAuditInput"}}}},"responses":{"200":{"description":"Check result. `status: error` means the check could not run (e.g. DNS failure); the body still follows the result schema.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SitemapAuditResult"}}}},"400":{"description":"Invalid JSON or input validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown check.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request body larger than 64 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (20 requests per 10 minutes per IP, 30 per tested site, or the site-wide cap). The message names the limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."},"Retry-After":{"schema":{"type":"integer"}}}},"504":{"description":"Run budget exhausted before any usable result was available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SitemapAuditResult"}}}}}}},"/api/v1/checks/hreflang_validator":{"post":{"operationId":"hreflang_validator","summary":"hreflang validator","description":"Builds the hreflang graph of a language cluster starting from one URL (HTML link tags, HTTP Link headers and optionally XML sitemaps), fetches every alternate URL and checks return links, self-references, ISO language/region codes, x-default, status 200, self-canonical and noindex on targets. Use when asked whether hreflang is implemented correctly or why the wrong language version ranks. Returns findings, the URL × language matrix and all edges with their source. Takes 3 to 20 seconds.\n\nTypical duration: ~8 s. Also available as MCP tool `hreflang_validator`.","tags":["checks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HreflangValidatorInput"}}}},"responses":{"200":{"description":"Check result. `status: error` means the check could not run (e.g. DNS failure); the body still follows the result schema.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HreflangValidatorResult"}}}},"400":{"description":"Invalid JSON or input validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown check.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request body larger than 64 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (20 requests per 10 minutes per IP, 30 per tested site, or the site-wide cap). The message names the limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."},"Retry-After":{"schema":{"type":"integer"}}}},"504":{"description":"Run budget exhausted before any usable result was available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HreflangValidatorResult"}}}}}}},"/api/v1/checks/bot_verifier":{"post":{"operationId":"bot_verifier","summary":"Bot verifier","description":"Verifies whether IP addresses really belong to the crawler their user agent claims (Googlebot, Bingbot, GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, PerplexityBot, Applebot and others) using the operators' published IP ranges and forward-confirmed reverse DNS. Accepts IPs, IP plus user agent pairs, or raw access log lines. Use when asked whether bot traffic in logs is real, how much of it is spoofed, or before allowlisting or blocking a crawler. Returns pass/warn/fail with findings, a verdict per IP and totals per bot. Takes 1 to 15 seconds.\n\nTypical duration: ~8 s. Also available as MCP tool `bot_verifier`.","tags":["checks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BotVerifierInput"}}}},"responses":{"200":{"description":"Check result. `status: error` means the check could not run (e.g. DNS failure); the body still follows the result schema.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BotVerifierResult"}}}},"400":{"description":"Invalid JSON or input validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown check.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request body larger than 64 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (20 requests per 10 minutes per IP, 30 per tested site, or the site-wide cap). The message names the limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."},"Retry-After":{"schema":{"type":"integer"}}}},"504":{"description":"Run budget exhausted before any usable result was available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BotVerifierResult"}}}}}}},"/api/v1/checks/render_diff":{"post":{"operationId":"render_diff","summary":"Render diff","description":"Fetches one URL twice, as raw HTML and rendered in headless Chromium, and compares SEO signals: title, meta robots, canonical, hreflang, headings, main text, links, structured data and images. Use when asked whether content or links depend on JavaScript, whether search engines or AI crawlers that do not render see the page, or why JavaScript changes indexing signals. Returns pass/warn/fail with findings, both snapshots and a diff. Takes 8 to 30 seconds.\n\nTypical duration: ~18 s. Also available as MCP tool `render_diff`.","tags":["checks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderDiffInput"}}}},"responses":{"200":{"description":"Check result. `status: error` means the check could not run (e.g. DNS failure); the body still follows the result schema.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderDiffResult"}}}},"400":{"description":"Invalid JSON or input validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown check.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request body larger than 64 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (20 requests per 10 minutes per IP, 30 per tested site, or the site-wide cap). The message names the limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}},"headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix time (s)."},"Retry-After":{"schema":{"type":"integer"}}}},"504":{"description":"Run budget exhausted before any usable result was available.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderDiffResult"}}}}}}}},"components":{"schemas":{"Error":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string","description":"Machine-readable error code."},"message":{"type":"string"},"issues":{"type":"array","items":{"type":"object"},"description":"Zod validation issues."}}},"RedirectMatrixInput":{"type":"object","properties":{"domain":{"type":"string","minLength":3,"maxLength":2048,"description":"Hostname without protocol, e.g. \"example.com\". A www. prefix is stripped and both variants are tested. A full URL is accepted; only its host is used."},"path":{"default":"/","description":"Path to test variants for, e.g. \"/blog/\". Default \"/\".","type":"string","maxLength":2048},"includePathVariants":{"default":true,"description":"Also test trailing slash, uppercase, /index.html, /index.php and query string variants on the canonical host.","type":"boolean"},"userAgent":{"default":"googlebot_smartphone","description":"UA preset id (e.g. \"googlebot_smartphone\", \"chrome_desktop\") or a raw UA string.","type":"string","minLength":1,"maxLength":512,"pattern":"^[\\x20-\\x7e]+$"}},"required":["domain"]},"RedirectMatrixResult":{"type":"object","properties":{"check":{"type":"string"},"version":{"type":"string"},"input":{},"startedAt":{"type":"string","description":"ISO timestamp."},"durationMs":{"type":"number"},"requestCount":{"type":"number"},"status":{"type":"string","enum":["pass","warn","fail","error"],"description":"fail if any fail finding, else warn if any warn finding, else pass. error if the check could not run."},"summary":{"type":"string","description":"1-2 sentences with numbers, written for LLMs."},"findings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable finding id, e.g. \"redirect.302_in_chain\"."},"severity":{"type":"string","enum":["info","warn","fail"]},"message":{"type":"string","description":"One concrete sentence with URLs and values."},"evidence":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"recommendation":{"description":"One sentence: what to do.","type":"string"}},"required":["id","severity","message"],"additionalProperties":false},"description":"Sorted by severity (fail first), then id."},"data":{"description":"Structured facts for verification.","type":"object","properties":{"canonicalHost":{"type":"string","description":"Host most variants resolve to."},"userAgent":{"type":"string"},"variants":{"type":"array","items":{"type":"object","properties":{"variant":{"type":"string","description":"Variant id, e.g. \"host:http-www\" or \"path:uppercase\"."},"label":{"type":"string"},"kind":{"type":"string","enum":["host","path"]},"startUrl":{"type":"string"},"hops":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"status":{"type":"number"},"location":{"type":"string"},"ttfbMs":{"type":"number"}},"required":["url","status","ttfbMs"],"additionalProperties":false}},"hopCount":{"type":"number","description":"Number of redirects before the final response."},"final":{"anyOf":[{"type":"object","properties":{"url":{"type":"string"},"status":{"type":"number"},"hsts":{"type":["string","null"]},"canonicalHtml":{"type":["string","null"]},"canonicalHeader":{"type":["string","null"]}},"required":["url","status","hsts","canonicalHtml","canonicalHeader"],"additionalProperties":false},{"type":"null"}]},"loop":{"type":"boolean"},"tooManyHops":{"type":"boolean"},"error":{"anyOf":[{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"url":{"type":"string"}},"required":["code","message","url"],"additionalProperties":false},{"type":"null"}]}},"required":["variant","label","kind","startUrl","hops","hopCount","final","loop","tooManyHops","error"],"additionalProperties":false}}},"required":["canonicalHost","userAgent","variants"],"additionalProperties":false},"truncated":{"description":"True if the run budget was hit.","type":"boolean"}},"required":["check","version","input","startedAt","durationMs","requestCount","status","summary","findings"],"additionalProperties":false},"HeaderInspectorInput":{"type":"object","properties":{"url":{"type":"string","maxLength":2048,"format":"uri","description":"Absolute http(s) URL to inspect."},"userAgents":{"default":["chrome_desktop","googlebot_smartphone","gptbot","claudebot"],"description":"UA preset ids (chrome_desktop, chrome_mobile, googlebot_desktop, googlebot_smartphone, bingbot, gptbot, oai_searchbot, chatgpt_user, claudebot, claude_user, perplexitybot, perplexity_user, techseobot, none) or raw UA strings. Max 8. The first browser UA (or the first entry) is the reference.","minItems":1,"maxItems":8,"type":"array","items":{"type":"string","minLength":1,"maxLength":512,"pattern":"^[\\x20-\\x7e]+$"}},"followRedirects":{"default":true,"description":"Follow redirects (max 5 hops) and compare the final responses.","type":"boolean"},"includeBodySignals":{"default":true,"description":"Also parse title, canonical, meta robots and h1 from the HTML to detect UA-dependent differences.","type":"boolean"}},"required":["url"]},"HeaderInspectorResult":{"type":"object","properties":{"check":{"type":"string"},"version":{"type":"string"},"input":{},"startedAt":{"type":"string","description":"ISO timestamp."},"durationMs":{"type":"number"},"requestCount":{"type":"number"},"status":{"type":"string","enum":["pass","warn","fail","error"],"description":"fail if any fail finding, else warn if any warn finding, else pass. error if the check could not run."},"summary":{"type":"string","description":"1-2 sentences with numbers, written for LLMs."},"findings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable finding id, e.g. \"redirect.302_in_chain\"."},"severity":{"type":"string","enum":["info","warn","fail"]},"message":{"type":"string","description":"One concrete sentence with URLs and values."},"evidence":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"recommendation":{"description":"One sentence: what to do.","type":"string"}},"required":["id","severity","message"],"additionalProperties":false},"description":"Sorted by severity (fail first), then id."},"data":{"description":"Structured facts for verification.","type":"object","properties":{"reference":{"type":"string","description":"Key of the reference UA."},"perUserAgent":{"type":"array","items":{"type":"object","properties":{"ua":{"type":"object","properties":{"key":{"type":"string","description":"Unique key used in diff values."},"id":{"type":"string"},"label":{"type":"string"},"category":{"type":"string"},"uaString":{"type":["string","null"]}},"required":["key","id","label","category","uaString"],"additionalProperties":false},"hops":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"status":{"type":"number"},"location":{"type":"string"},"ttfbMs":{"type":"number"}},"required":["url","status","ttfbMs"],"additionalProperties":false}},"final":{"anyOf":[{"type":"object","properties":{"url":{"type":"string"},"status":{"type":"number"},"headers":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"bodySignals":{"anyOf":[{"type":"object","properties":{"title":{"type":["string","null"]},"canonical":{"type":["string","null"]},"metaRobots":{"type":["string","null"]},"botMetaRobots":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"}},"h1":{"type":["string","null"]},"internalLinkCount":{"type":"number"}},"required":["title","canonical","metaRobots","botMetaRobots","h1","internalLinkCount"],"additionalProperties":false},{"type":"null"}]},"ttfbMs":{"type":"number"}},"required":["url","status","headers","bodySignals","ttfbMs"],"additionalProperties":false},{"type":"null"}]},"error":{"anyOf":[{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false},{"type":"null"}]}},"required":["ua","hops","final","error"],"additionalProperties":false}},"diff":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"differs":{"type":"boolean"},"values":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":["string","null"]}}},"required":["differs","values"],"additionalProperties":false}}},"required":["reference","perUserAgent","diff"],"additionalProperties":false},"truncated":{"description":"True if the run budget was hit.","type":"boolean"}},"required":["check","version","input","startedAt","durationMs","requestCount","status","summary","findings"],"additionalProperties":false},"RobotsAnalyzerInput":{"type":"object","properties":{"url":{"type":"string","maxLength":2048,"format":"uri","description":"Page URL to evaluate. The robots.txt of its origin is fetched automatically."},"checkAssetHosts":{"default":true,"description":"Also fetch robots.txt of CDN/asset hosts referenced in the HTML (max 5) and check whether Googlebot may load the page CSS/JS.","type":"boolean"},"bots":{"description":"Bot tokens to evaluate, e.g. [\"Googlebot\", \"GPTBot\"]. Default: full catalog (search engines, AI training and AI retrieval crawlers).","maxItems":40,"type":"array","items":{"type":"string","minLength":1,"maxLength":64}}},"required":["url"]},"RobotsAnalyzerResult":{"type":"object","properties":{"check":{"type":"string"},"version":{"type":"string"},"input":{},"startedAt":{"type":"string","description":"ISO timestamp."},"durationMs":{"type":"number"},"requestCount":{"type":"number"},"status":{"type":"string","enum":["pass","warn","fail","error"],"description":"fail if any fail finding, else warn if any warn finding, else pass. error if the check could not run."},"summary":{"type":"string","description":"1-2 sentences with numbers, written for LLMs."},"findings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable finding id, e.g. \"redirect.302_in_chain\"."},"severity":{"type":"string","enum":["info","warn","fail"]},"message":{"type":"string","description":"One concrete sentence with URLs and values."},"evidence":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"recommendation":{"description":"One sentence: what to do.","type":"string"}},"required":["id","severity","message"],"additionalProperties":false},"description":"Sorted by severity (fail first), then id."},"data":{"description":"Structured facts for verification.","type":"object","properties":{"robotsTxt":{"type":"object","properties":{"url":{"type":"string"},"finalUrl":{"type":["string","null"]},"status":{"type":["number","null"]},"bytes":{"type":"number"},"policy":{"type":"string","enum":["parsed","allow_all","disallow_all"],"description":"How Google treats the file given its HTTP status."},"groups":{"type":"array","items":{"type":"object","properties":{"agents":{"type":"array","items":{"type":"string"}},"rules":{"type":"number"},"line":{"type":"number"}},"required":["agents","rules","line"],"additionalProperties":false},"description":"First 200 groups; groupCount has the total."},"groupCount":{"type":"number"},"sitemaps":{"type":"array","items":{"type":"string"},"description":"First 50 Sitemap lines."},"syntaxErrors":{"type":"array","items":{"type":"object","properties":{"line":{"type":"number"},"text":{"type":"string"},"reason":{"type":"string"}},"required":["line","text","reason"],"additionalProperties":false},"description":"First 100 ignored lines (text cut at 200 characters); syntaxErrorCount has the total."},"syntaxErrorCount":{"type":"number"}},"required":["url","finalUrl","status","bytes","policy","groups","groupCount","sitemaps","syntaxErrors","syntaxErrorCount"],"additionalProperties":false},"evaluation":{"type":"array","items":{"type":"object","properties":{"bot":{"type":"string"},"vendor":{"type":"string"},"category":{"type":"string"},"allowed":{"type":"boolean"},"matchedRule":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["allow","disallow"]},"path":{"type":"string"},"line":{"type":"number"}},"required":["type","path","line"],"additionalProperties":false},{"type":"null"}]},"group":{"type":"array","items":{"type":"string"},"description":"User-agent tokens of the applied group (first 20); [] = no group applies."}},"required":["bot","vendor","category","allowed","matchedRule","group"],"additionalProperties":false}},"page":{"type":"object","properties":{"url":{"type":"string"},"finalUrl":{"type":["string","null"]},"status":{"type":["number","null"]}},"required":["url","finalUrl","status"],"additionalProperties":false},"pageDirectives":{"type":"object","properties":{"metaRobots":{"type":["string","null"]},"googlebotMeta":{"type":["string","null"]},"xRobotsTag":{"type":["string","null"]},"noindex":{"type":"boolean"}},"required":["metaRobots","googlebotMeta","xRobotsTag","noindex"],"additionalProperties":false},"pageResources":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"allowed":{"type":"boolean"}},"required":["url","allowed"],"additionalProperties":false}},"assetHosts":{"type":"array","items":{"type":"object","properties":{"host":{"type":"string"},"robotsStatus":{"type":["number","null"]},"policy":{"type":"string"},"checkedResources":{"type":"number"},"blockedResources":{"type":"array","items":{"type":"string"}}},"required":["host","robotsStatus","policy","checkedResources","blockedResources"],"additionalProperties":false}},"sitemaps":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"status":{"type":["number","null"]},"error":{"type":["string","null"]}},"required":["url","status","error"],"additionalProperties":false}},"catalogVersion":{"type":"string"}},"required":["robotsTxt","evaluation","page","pageDirectives","pageResources","assetHosts","sitemaps","catalogVersion"],"additionalProperties":false},"truncated":{"description":"True if the run budget was hit.","type":"boolean"}},"required":["check","version","input","startedAt","durationMs","requestCount","status","summary","findings"],"additionalProperties":false},"SitemapAuditInput":{"type":"object","properties":{"source":{"type":"string","minLength":3,"maxLength":2048,"description":"Domain (e.g. \"example.com\"; sitemaps are taken from robots.txt, fallback /sitemap.xml) or the absolute URL of a sitemap or sitemap index."},"mode":{"default":"sample","description":"\"sample\" checks a stratified sample of URLs synchronously. \"full\" (every URL as a background job) is not available yet.","type":"string","enum":["sample","full"]},"sampleSize":{"default":100,"description":"Number of sitemap URLs to fetch and check in sample mode (10-300).","type":"integer","minimum":10,"maximum":300},"userAgent":{"default":"googlebot_smartphone","description":"UA preset id or raw UA string used for all requests.","type":"string","minLength":1,"maxLength":512,"pattern":"^[\\x20-\\x7e]+$"}},"required":["source"]},"SitemapAuditResult":{"type":"object","properties":{"check":{"type":"string"},"version":{"type":"string"},"input":{},"startedAt":{"type":"string","description":"ISO timestamp."},"durationMs":{"type":"number"},"requestCount":{"type":"number"},"status":{"type":"string","enum":["pass","warn","fail","error"],"description":"fail if any fail finding, else warn if any warn finding, else pass. error if the check could not run."},"summary":{"type":"string","description":"1-2 sentences with numbers, written for LLMs."},"findings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable finding id, e.g. \"redirect.302_in_chain\"."},"severity":{"type":"string","enum":["info","warn","fail"]},"message":{"type":"string","description":"One concrete sentence with URLs and values."},"evidence":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"recommendation":{"description":"One sentence: what to do.","type":"string"}},"required":["id","severity","message"],"additionalProperties":false},"description":"Sorted by severity (fail first), then id."},"data":{"description":"Structured facts for verification.","type":"object","properties":{"origin":{"type":"string"},"sources":{"type":"array","items":{"type":"string"}},"sourcesFromRobots":{"type":"boolean"},"inventory":{"type":"object","properties":{"sitemaps":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"type":{"type":"string","enum":["urlset","index","error"]},"status":{"type":["number","null"]},"urlCount":{"type":"number"},"bytes":{"type":"number"},"gzip":{"type":"boolean"},"truncated":{"type":"boolean"},"error":{"type":["string","null"]}},"required":["url","type","status","urlCount","bytes","gzip","truncated","error"],"additionalProperties":false}},"totalUrls":{"type":"number"},"uniqueUrls":{"type":"number"},"lastmodCoverage":{"type":"number","description":"Share of URLs with a lastmod (0-1)."},"lastmodValidShare":{"type":"number","description":"Share of present lastmod values in W3C format (0-1)."},"duplicates":{"type":"number"},"foreignHost":{"type":"number"},"httpUrls":{"type":"number"},"incomplete":{"type":"boolean","description":"True if not all child sitemaps could be loaded."}},"required":["sitemaps","totalUrls","uniqueUrls","lastmodCoverage","lastmodValidShare","duplicates","foreignHost","httpUrls","incomplete"],"additionalProperties":false},"sample":{"type":"object","properties":{"size":{"type":"number"},"results":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"sitemap":{"type":"string"},"status":{"type":["number","null"]},"finalUrl":{"type":["string","null"]},"redirects":{"type":"number"},"indexable":{"type":"boolean"},"robotsAllowed":{"type":["boolean","null"]},"noindex":{"type":"boolean"},"canonical":{"type":["string","null"]},"selfCanonical":{"type":["boolean","null"]},"error":{"type":["string","null"]}},"required":["url","sitemap","status","finalUrl","redirects","indexable","robotsAllowed","noindex","canonical","selfCanonical","error"],"additionalProperties":false}}},"required":["size","results"],"additionalProperties":false},"estimates":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"count":{"type":"number"},"share":{"type":"number"},"estimatedTotal":{"type":"number"},"examples":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"detail":{"type":"string"}},"required":["url"],"additionalProperties":false}}},"required":["count","share","estimatedTotal","examples"],"additionalProperties":false}}},"required":["origin","sources","sourcesFromRobots","inventory","sample","estimates"],"additionalProperties":false},"truncated":{"description":"True if the run budget was hit.","type":"boolean"}},"required":["check","version","input","startedAt","durationMs","requestCount","status","summary","findings"],"additionalProperties":false},"HreflangValidatorInput":{"type":"object","properties":{"url":{"type":"string","maxLength":2048,"format":"uri","description":"Any URL of the language cluster to start from."},"includeSitemap":{"default":false,"description":"Also read xhtml:link hreflang annotations from the XML sitemaps of the origin.","type":"boolean"},"maxUrls":{"default":40,"description":"Maximum number of cluster URLs to fetch (2-100).","type":"integer","minimum":2,"maximum":100}},"required":["url"]},"HreflangValidatorResult":{"type":"object","properties":{"check":{"type":"string"},"version":{"type":"string"},"input":{},"startedAt":{"type":"string","description":"ISO timestamp."},"durationMs":{"type":"number"},"requestCount":{"type":"number"},"status":{"type":"string","enum":["pass","warn","fail","error"],"description":"fail if any fail finding, else warn if any warn finding, else pass. error if the check could not run."},"summary":{"type":"string","description":"1-2 sentences with numbers, written for LLMs."},"findings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable finding id, e.g. \"redirect.302_in_chain\"."},"severity":{"type":"string","enum":["info","warn","fail"]},"message":{"type":"string","description":"One concrete sentence with URLs and values."},"evidence":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"recommendation":{"description":"One sentence: what to do.","type":"string"}},"required":["id","severity","message"],"additionalProperties":false},"description":"Sorted by severity (fail first), then id."},"data":{"description":"Structured facts for verification.","type":"object","properties":{"cluster":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"status":{"type":["number","null"]},"canonical":{"type":["string","null"]},"noindex":{"type":"boolean"},"hreflangCount":{"type":"number"},"fetched":{"type":"boolean"},"error":{"type":["string","null"]}},"required":["url","status","canonical","noindex","hreflangCount","fetched","error"],"additionalProperties":false}},"edges":{"type":"array","items":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"hreflang":{"type":"string"},"source":{"type":"string","enum":["html","header","sitemap"]}},"required":["from","to","hreflang","source"],"additionalProperties":false}},"matrix":{"type":"object","properties":{"codes":{"type":"array","items":{"type":"string"}},"rows":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"links":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":["string","null"]}}},"required":["url","links"],"additionalProperties":false}}},"required":["codes","rows"],"additionalProperties":false},"invalidCodes":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"reason":{"type":"string"},"suggestion":{"type":["string","null"]},"pages":{"type":"array","items":{"type":"string"}}},"required":["code","reason","suggestion","pages"],"additionalProperties":false}},"clusterTruncated":{"type":"boolean","description":"True if maxUrls was reached or annotations were cut (300 per page, 3,000 in total)."}},"required":["cluster","edges","matrix","invalidCodes","clusterTruncated"],"additionalProperties":false},"truncated":{"description":"True if the run budget was hit.","type":"boolean"}},"required":["check","version","input","startedAt","durationMs","requestCount","status","summary","findings"],"additionalProperties":false},"BotVerifierInput":{"type":"object","properties":{"entries":{"description":"IP with optional user agent. The user agent decides which bot is claimed.","minItems":1,"maxItems":500,"type":"array","items":{"type":"object","properties":{"ip":{"type":"string","maxLength":45,"description":"IPv4 or IPv6 address."},"userAgent":{"description":"User agent that decides which bot is claimed.","type":"string","maxLength":512},"hits":{"description":"How many requests this pair represents.","type":"integer","minimum":1,"maximum":9007199254740991}},"required":["ip"],"additionalProperties":false}},"ips":{"description":"IPs without user agent: the check reports which known crawler operator, if any, they belong to.","minItems":1,"maxItems":500,"type":"array","items":{"type":"string","maxLength":45}},"log":{"description":"Raw access log lines (max 1 MB, 5000 lines). Only IP, user agent and optionally path are read.","type":"string","maxLength":1048576},"logFormat":{"default":"auto","type":"string","enum":["auto","combined","common","jsonl"]},"bots":{"description":"Limit to bot ids from the registry (see list_bots). Default: all.","maxItems":40,"type":"array","items":{"type":"string"}},"onlyClaimedBots":{"default":true,"description":"Log mode: only verify lines whose user agent claims a known bot.","type":"boolean"},"methods":{"default":["ip_ranges","rdns"],"minItems":1,"maxItems":2,"type":"array","items":{"type":"string","enum":["ip_ranges","rdns"]}},"includePaths":{"default":false,"description":"Log mode: include the top 5 requested paths per spoofed IP.","type":"boolean"},"maxListItems":{"default":200,"type":"integer","minimum":10,"maximum":500}},"additionalProperties":false},"BotVerifierResult":{"type":"object","properties":{"check":{"type":"string"},"version":{"type":"string"},"input":{},"startedAt":{"type":"string","description":"ISO timestamp."},"durationMs":{"type":"number"},"requestCount":{"type":"number"},"status":{"type":"string","enum":["pass","warn","fail","error"],"description":"fail if any fail finding, else warn if any warn finding, else pass. error if the check could not run."},"summary":{"type":"string","description":"1-2 sentences with numbers, written for LLMs."},"findings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable finding id, e.g. \"redirect.302_in_chain\"."},"severity":{"type":"string","enum":["info","warn","fail"]},"message":{"type":"string","description":"One concrete sentence with URLs and values."},"evidence":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"recommendation":{"description":"One sentence: what to do.","type":"string"}},"required":["id","severity","message"],"additionalProperties":false},"description":"Sorted by severity (fail first), then id."},"data":{"description":"Structured facts for verification.","type":"object","properties":{"input":{"type":"object","properties":{"mode":{"type":"string","enum":["entries","ips","log"]},"logFormat":{"type":"string"},"lines":{"type":"number"},"unparsedLines":{"type":"number"},"uniquePairs":{"type":"number"},"invalid":{"type":"array","items":{"type":"string"}}},"required":["mode","uniquePairs","invalid"],"additionalProperties":false},"results":{"type":"array","items":{"type":"object","properties":{"ip":{"type":"string"},"version":{"anyOf":[{"type":"number","const":4},{"type":"number","const":6}]},"hits":{"type":"number"},"claimed":{"anyOf":[{"type":"object","properties":{"botId":{"type":"string"},"name":{"type":"string"},"operator":{"type":"string"},"purpose":{"type":"string"}},"required":["botId","name","operator","purpose"],"additionalProperties":false},{"type":"null"}]},"userAgent":{"type":["string","null"]},"verdict":{"type":"string","enum":["verified","wrong_bot","spoofed","inconclusive","unverifiable","operator_match","no_match","private"]},"actualBot":{"anyOf":[{"type":"object","properties":{"botId":{"type":"string"},"operator":{"type":"string"}},"required":["botId","operator"],"additionalProperties":false},{"type":"null"}]},"granularity":{"anyOf":[{"type":"string","enum":["bot","operator"]},{"type":"null"}]},"methodConflict":{"anyOf":[{"type":"string","enum":["rdns_mismatch","range_gap"]},{"type":"null"}]},"ipRanges":{"type":"object","properties":{"checked":{"type":"boolean"},"matches":{"type":"array","items":{"type":"object","properties":{"sourceId":{"type":"string"},"operator":{"type":"string"},"prefix":{"type":"string"}},"required":["sourceId","operator","prefix"],"additionalProperties":false}}},"required":["checked","matches"],"additionalProperties":false},"rdns":{"type":"object","properties":{"checked":{"type":"boolean"},"ptr":{"type":"array","items":{"type":"string"}},"matchedSuffix":{"type":["string","null"]},"forwardConfirmed":{"type":["boolean","null"]},"error":{"type":["string","null"]},"cached":{"type":"boolean"},"via":{"anyOf":[{"type":"string","enum":["dns","doh"]},{"type":"null"}]}},"required":["checked","ptr","matchedSuffix","forwardConfirmed","error","cached","via"],"additionalProperties":false},"cdn":{"type":["string","null"]},"topPaths":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"hits":{"type":"number"}},"required":["path","hits"],"additionalProperties":false}}},"required":["ip","version","hits","claimed","userAgent","verdict","actualBot","granularity","methodConflict","ipRanges","rdns","cdn"],"additionalProperties":false}},"totals":{"type":"object","properties":{"byBot":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"object","properties":{"verified":{"type":"number"},"wrongBot":{"type":"number"},"spoofed":{"type":"number"},"inconclusive":{"type":"number"},"hitsVerified":{"type":"number"},"hitsSpoofed":{"type":"number"}},"required":["verified","wrongBot","spoofed","inconclusive","hitsVerified","hitsSpoofed"],"additionalProperties":false}},"claimedPairs":{"type":"number"},"spoofedShare":{"type":"number"}},"required":["byBot","claimedPairs","spoofedShare"],"additionalProperties":false},"sources":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"operator":{"type":"string"},"fetchedAt":{"type":"string"},"creationTime":{"type":["string","null"]},"prefixCount":{"type":"number"},"ageHours":{"type":"number"},"status":{"type":"string","enum":["ok","stale","error","snapshot"]}},"required":["id","operator","fetchedAt","creationTime","prefixCount","ageHours","status"],"additionalProperties":false}},"dns":{"type":"object","properties":{"lookups":{"type":"number"},"cacheHits":{"type":"number"},"dohFallbacks":{"type":"number"},"timeouts":{"type":"number"}},"required":["lookups","cacheHits","dohFallbacks","timeouts"],"additionalProperties":false}},"required":["input","results","totals","sources","dns"],"additionalProperties":false},"truncated":{"description":"True if the run budget was hit.","type":"boolean"}},"required":["check","version","input","startedAt","durationMs","requestCount","status","summary","findings"],"additionalProperties":false},"RenderDiffInput":{"type":"object","properties":{"url":{"type":"string","maxLength":2048,"format":"uri","description":"Absolute http(s) URL to fetch raw and rendered."},"userAgent":{"default":"googlebot_smartphone","description":"UA preset id or a raw user-agent string. Default googlebot_smartphone.","type":"string","minLength":1,"maxLength":512,"pattern":"^[\\x20-\\x7e]+$"},"viewport":{"default":"auto","description":"auto follows the user agent.","type":"string","enum":["auto","mobile","desktop"]},"emulateRobotsTxt":{"default":"auto","description":"auto is on for search, AI-training and AI-retrieval user agents.","type":"string","enum":["auto","on","off"]},"waitFor":{"default":"networkidle","type":"string","enum":["networkidle","load","domcontentloaded"]},"renderTimeoutMs":{"default":15000,"type":"integer","minimum":3000,"maximum":25000},"settleMs":{"default":1000,"type":"integer","minimum":0,"maximum":5000},"expandViewport":{"default":true,"description":"Grow the viewport to the page height, capped at 20000px.","type":"boolean"},"blockResourceTypes":{"default":["image","media","font"],"maxItems":10,"type":"array","items":{"type":"string","maxLength":40}},"sections":{"default":["head","content","links","structuredData","images","network","console"],"maxItems":7,"type":"array","items":{"type":"string","enum":["head","content","links","structuredData","images","network","console"]}},"maxListItems":{"default":300,"type":"integer","minimum":10,"maximum":2000},"noCache":{"default":false,"description":"Bypass the 10 minute cache. Counts twice against render limits.","type":"boolean"}},"required":["url"]},"RenderDiffResult":{"type":"object","properties":{"check":{"type":"string"},"version":{"type":"string"},"input":{},"startedAt":{"type":"string","description":"ISO timestamp."},"durationMs":{"type":"number"},"requestCount":{"type":"number"},"status":{"type":"string","enum":["pass","warn","fail","error"],"description":"fail if any fail finding, else warn if any warn finding, else pass. error if the check could not run."},"summary":{"type":"string","description":"1-2 sentences with numbers, written for LLMs."},"findings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Stable finding id, e.g. \"redirect.302_in_chain\"."},"severity":{"type":"string","enum":["info","warn","fail"]},"message":{"type":"string","description":"One concrete sentence with URLs and values."},"evidence":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"recommendation":{"description":"One sentence: what to do.","type":"string"}},"required":["id","severity","message"],"additionalProperties":false},"description":"Sorted by severity (fail first), then id."},"data":{"description":"Structured facts for verification.","type":"object","properties":{"userAgent":{"type":"object","properties":{"preset":{"type":["string","null"]},"value":{"type":"string"}},"required":["preset","value"],"additionalProperties":false},"viewport":{"type":"object","properties":{"width":{"type":"number"},"height":{"type":"number"},"deviceScaleFactor":{"type":"number"},"isMobile":{"type":"boolean"},"hasTouch":{"type":"boolean"}},"required":["width","height","deviceScaleFactor","isMobile","hasTouch"],"additionalProperties":false},"raw":{"type":"object","properties":{"status":{"type":"number"},"finalUrl":{"type":"string"},"contentType":{"type":["string","null"]},"wordCount":{"type":"number"}},"required":["status","finalUrl","contentType","wordCount"],"additionalProperties":false},"rendered":{"anyOf":[{"type":"object","properties":{"status":{"type":"number"},"finalUrl":{"type":"string"},"wordCount":{"type":"number"},"timedOut":{"type":"boolean"},"renderMs":{"type":"number"},"coldStart":{"type":"boolean"},"jsNavigation":{"type":"boolean"}},"required":["status","finalUrl","wordCount","timedOut","renderMs","coldStart","jsNavigation"],"additionalProperties":false},{"type":"null"}]},"head":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"raw":{},"rendered":{},"change":{"type":"string","enum":["same","added","removed","changed"]}},"required":["field","raw","rendered","change"],"additionalProperties":false}},"content":{"type":"object","properties":{"wordsRaw":{"type":"number"},"wordsRendered":{"type":"number"},"rawCoverage":{"type":"number"},"renderedOnlySample":{"type":"string"},"headings":{"type":"object","properties":{"raw":{"type":"array","items":{"type":"string"}},"rendered":{"type":"array","items":{"type":"string"}},"added":{"type":"array","items":{"type":"string"}},"removed":{"type":"array","items":{"type":"string"}},"changed":{"type":"boolean"}},"required":["raw","rendered","added","removed","changed"],"additionalProperties":false},"canonicalInBody":{"type":"boolean"}},"required":["wordsRaw","wordsRendered","rawCoverage","renderedOnlySample","headings","canonicalInBody"],"additionalProperties":false},"links":{"type":"object","properties":{"internalOnlyRendered":{"type":"array","items":{"type":"object","properties":{"href":{"type":["string","null"]},"resolved":{"type":["string","null"]},"internal":{"type":"boolean"},"rel":{"type":"array","items":{"type":"string"}},"text":{"type":"string"},"kind":{"type":"string","enum":["crawlable","fragment_only","javascript_href","no_href","form_post"]}},"required":["href","resolved","internal","rel","text","kind"],"additionalProperties":false}},"internalOnlyRaw":{"type":"array","items":{"type":"object","properties":{"href":{"type":["string","null"]},"resolved":{"type":["string","null"]},"internal":{"type":"boolean"},"rel":{"type":"array","items":{"type":"string"}},"text":{"type":"string"},"kind":{"type":"string","enum":["crawlable","fragment_only","javascript_href","no_href","form_post"]}},"required":["href","resolved","internal","rel","text","kind"],"additionalProperties":false}},"changedClassOrRel":{"type":"array","items":{"type":"object","properties":{"resolved":{"type":"string"},"raw":{"type":"string"},"rendered":{"type":"string"}},"required":["resolved","raw","rendered"],"additionalProperties":false}},"nonCrawlableRendered":{"type":"object","properties":{"fragment_only":{"type":"number"},"javascript_href":{"type":"number"},"no_href":{"type":"number"},"form_post":{"type":"number"}},"required":["fragment_only","javascript_href","no_href","form_post"],"additionalProperties":false},"counts":{"type":"object","properties":{"raw":{"type":"number"},"rendered":{"type":"number"},"internalRendered":{"type":"number"}},"required":["raw","rendered","internalRendered"],"additionalProperties":false}},"required":["internalOnlyRendered","internalOnlyRaw","changedClassOrRel","nonCrawlableRendered","counts"],"additionalProperties":false},"structuredData":{"type":"object","properties":{"typesRaw":{"type":"array","items":{"type":"string"}},"typesRendered":{"type":"array","items":{"type":"string"}},"onlyRendered":{"type":"array","items":{"type":"string"}},"onlyRaw":{"type":"array","items":{"type":"string"}},"changedBlocks":{"type":"number"},"parseErrors":{"type":"object","properties":{"raw":{"type":"number"},"rendered":{"type":"number"}},"required":["raw","rendered"],"additionalProperties":false}},"required":["typesRaw","typesRendered","onlyRendered","onlyRaw","changedBlocks","parseErrors"],"additionalProperties":false},"images":{"type":"object","properties":{"lazyResolvedByJs":{"type":"number"},"missingAltRendered":{"type":"number"},"renderedCount":{"type":"number"},"samples":{"type":"array","items":{"type":"object","properties":{"src":{"type":["string","null"]},"lazy":{"type":["string","null"]},"alt":{"type":"string","enum":["present","empty","missing"]}},"required":["src","lazy","alt"],"additionalProperties":false}}},"required":["lazyResolvedByJs","missingAltRendered","renderedCount","samples"],"additionalProperties":false},"network":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"type":{"type":"string"},"status":{"type":["number","null"]},"blocked":{"anyOf":[{"type":"string","enum":["blocked_by_guard","robots","type","limit"]},{"type":"null"}]},"bytes":{"type":"number"},"error":{"type":["string","null"]}},"required":["url","type","status","blocked","bytes","error"],"additionalProperties":false}},"console":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["error","pageerror"]},"text":{"type":"string"}},"required":["kind","text"],"additionalProperties":false}},"cache":{"type":"object","properties":{"hit":{"type":"boolean"},"ageSeconds":{"type":["number","null"]}},"required":["hit","ageSeconds"],"additionalProperties":false}},"required":["userAgent","viewport","raw","rendered","head","content","links","structuredData","images","network","console","cache"],"additionalProperties":false},"truncated":{"description":"True if the run budget was hit.","type":"boolean"}},"required":["check","version","input","startedAt","durationMs","requestCount","status","summary","findings"],"additionalProperties":false}},"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Optional internal key; lifts the rate limit."}}},"security":[{},{"bearer":[]}]}