{
  "data": {
    "a": {
      "slug": "nexscope",
      "name": "Nexscope",
      "vendor": "ECOCREATE TECHNOLOGY PTE. LTD.",
      "vendorUrl": "https://www.nexscope.ai",
      "kind": "platform",
      "category": "web-scrapers",
      "summary": "Nexscope is a hosted platform for ecommerce sellers with marketplace product, keyword and competitor data for Amazon, TikTok Shop, Walmart, Temu, 1688 and others, plus AI product images and video, through a web app, REST API and remote MCP server.",
      "url": "https://www.anchorterminal.com/tools/nexscope",
      "markdownUrl": "https://www.anchorterminal.com/tools/nexscope.md",
      "slimMarkdownUrl": "https://www.anchorterminal.com/tools/nexscope.min.md",
      "jsonUrl": "https://www.anchorterminal.com/api/v1/tools/nexscope.json",
      "dns": "nexscope.grade.anchorterminal.com",
      "repo": "https://github.com/nexscope-ai/nexscope-ecommerce-api",
      "license": "Proprietary hosted service under the Nexscope terms (last updated 8 October 2026), whose contracting party is ECOCREATE TECHNOLOGY PTE. LTD. of Singapore. The OpenAPI file's licence is 'Proprietary API; use subject to Nexscope Terms'. In github.com/nexscope-ai/nexscope-ecommerce-api only the example clients, validation scripts, tests and workflow are MIT. The API documentation, catalogue, definitions and sample data stay copyright Nexscope",
      "transports": [
        "streamable-http",
        "http"
      ],
      "remoteUrl": "https://api.nexscope.ai/mcp",
      "packages": [],
      "auth": "mixed",
      "authNotes": "The remote MCP server takes OAuth 2.1 (authorisation code with PKCE, scope `mcp:tools`) in clients that support it, or a Nexscope API key as `Authorization: Bearer nk-...`, which the tool pages call a compatibility option. The REST API takes the same key as a Bearer header. A person signs in and creates the key under API Access, API Keys. The full key is shown once, and keys can be expired, disabled or deleted, per the help page's troubleshooting. No key scopes, rotation rule or key-management API were found. Creative API key access needs an active subscription. Trial credits don't enable it. The OAuth metadata on api.nexscope.ai was not read (https://www.nexscope.ai/mcp-map/amazon-search, https://www.nexscope.ai/help/skills-external-access, https://github.com/nexscope-ai/nexscope-ecommerce-api, checked 2026-11-10).",
      "pricing": "paid",
      "pricingNotes": "Credits on a monthly subscription. A Free Trial gives 1,000 credits for 3 days with no card, at 1 API and 1 MCP request a second and 1 concurrent each, with no video API. Starter is $29 a month for 30,000 credits (3 requests a second, 2 concurrent), Growth $55 for 75,000 (5 and 4) and Pro $129 for 150,000 (10 and 8), each half price for the first period, with yearly billing and credits that reset monthly and don't roll over. Pay-as-you-go top-ups buy Data credits only, with no subscription. Each tool has its own credit cost, at least 10 for a Data API call. Amazon Search shows 'from 21 credits per call' and a recent average of 30. Refunds within 7 days if unused, per the terms. The home page listed Growth at $69 on the same day (https://www.nexscope.ai/pricing, https://www.nexscope.ai/mcp-map, https://www.nexscope.ai/terms, checked 2026-11-10).",
      "priceSummary": "$0.001 / credit",
      "where": "hosted",
      "x402": {
        "level": "no",
        "evidence": "No x402, MPP or L402 on the pricing page, the API quickstart, the MCP map, llms.txt, the visible part of the OpenAPI file or the GitHub repository on 2026-11-10. Credits come from a subscription or a Data top-up after a browser sign-in (https://www.nexscope.ai/pricing).",
        "endpoints": []
      },
      "toolCount": 382,
      "popularity": {
        "githubStars": null,
        "npmWeekly": null,
        "pypiWeekly": null,
        "asOf": "2026-11-10"
      },
      "docsUrl": "https://www.nexscope.ai/api-docs",
      "llmsTxt": "https://www.nexscope.ai/llms.txt",
      "openapi": "https://api.nexscope.ai/openapi.json",
      "registryName": "io.github.nexscope/ecommerce",
      "capabilities": [
        "web.extract",
        "shopping.search",
        "shopping.prices",
        "seo.keywords",
        "seo.backlinks",
        "search.serp",
        "image.generate",
        "image.edit",
        "video.generate",
        "video.image-to-video"
      ],
      "tags": [
        "hosted",
        "official",
        "closed-source",
        "mcp",
        "remote-mcp",
        "oauth",
        "api-key",
        "openapi",
        "llms-txt",
        "marketplace",
        "shopping",
        "images",
        "video",
        "credits",
        "subscription",
        "free-trial",
        "no-card",
        "new"
      ],
      "lastRelease": "2026-11-09",
      "graded": true,
      "anchor": {
        "graded": true,
        "score": 46.2,
        "grade": "D",
        "agentReady": false,
        "rank": 1191,
        "ranked": true,
        "rankOf": 1520,
        "categoryRank": 28,
        "methodology": "0.7",
        "run": "2026-10-01",
        "scores": {
          "ergonomics": 44,
          "maintenance": 65,
          "payments": 35,
          "reliability": 39,
          "schema": 64,
          "security": 41,
          "transparency": 41
        },
        "pending": [
          "performance",
          "tasks"
        ],
        "assessment": {
          "confidence": "medium",
          "date": "2026-11-10"
        },
        "negative": 0,
        "verdict": "An agent can reach Amazon, TikTok Shop, Temu, 1688 and other marketplace data, plus image and video models, on one credit balance through a remote MCP server with OAuth or a REST API with a public OpenAPI file. The connection loads 382 tools at once, and there is no status page, changelog or idempotency key.",
        "bestFor": "Agents that research ecommerce products, competitors, keywords, sourcing and patents across Amazon, TikTok Shop, Walmart, Temu, 1688 and other marketplaces, and that also make listing images and video, on one credit balance.",
        "strengths": [
          "Marketplace product, keyword, competitor and sourcing data across more than ten marketplaces behind one key and one MCP endpoint",
          "OAuth 2.1 with PKCE and a `mcp:tools` scope on the MCP server, or a Bearer key shown once",
          "A public OpenAPI 3.1 file and a GitHub repository with request and response definitions, samples and standard-library clients for every documented API",
          "Per-plan API and MCP request limits published, and a 3-day trial of 1,000 credits with no card",
          "1688 order, payment-link, receipt and cancel calls each need an explicit JSON `true` confirmation field"
        ],
        "weaknesses": [
          "The MCP connection advertises the full catalogue of 382 tools, with no toolsets or read-only subset",
          "No status page, SLA, public changelog or security.txt found",
          "No idempotency keys, and business errors answer HTTP 200 unless a header asks otherwise",
          "The privacy policy states no retention periods and names no hosting, AI or data suppliers",
          "Many Data definitions are field descriptors rather than JSON Schema, and the Amazon Search tool page omits the `keyword` argument its own examples pass"
        ],
        "agentNotes": [
          "Check the outer `code` is 0 before reading `data`, or send `X-Nexscope-Http-Status: semantic` to get HTTP error statuses.",
          "Call an image or video tool once, keep the `taskId`, and poll `nexscope_media_task_result`. A second call bills a second job.",
          "Read the tool's credit cost before a call. Each tool costs at least 10 credits and some cost over 300.",
          "Before you set a 1688 confirmation field to `true`, show the user the preview and get approval.",
          "If the server returns 429 or 503, wait for `Retry-After` when present and back off."
        ],
        "metrics": {
          "kind": "remote",
          "measured": false
        },
        "reviewCount": 0,
        "avgRating": 0,
        "history": [
          {
            "basis": "public evidence",
            "confidence": "medium",
            "grade": "D",
            "methodology": "0.7",
            "pending": [
              "performance",
              "tasks"
            ],
            "run": "2026-10-01",
            "runLabel": "October 2026 research run",
            "score": 46.2
          }
        ],
        "editorialScores": {
          "ergonomics": 44,
          "maintenance": 65,
          "payments": 35,
          "reliability": 39,
          "schema": 64,
          "security": 41,
          "transparency": 33
        },
        "provenanceScore": 48,
        "checked": {
          "categories": {
            "ergonomics": "2026-11-10",
            "maintenance": "2026-11-10",
            "payments": "2026-11-10",
            "reliability": "2026-11-10",
            "schema": "2026-11-10",
            "security": "2026-11-10",
            "transparency": "2026-11-10"
          },
          "last": "2026-11-10",
          "oldest": "2026-11-10",
          "stale": false,
          "staleAfterDays": 90
        }
      },
      "connect": {
        "http": "curl --fail-with-body -X POST 'https://api.nexscope.ai/api/skill-api/v1/skills/amazon-search/run' \\\n  -H \"Authorization: Bearer $NEXSCOPE_API_KEY\" \\\n  -H 'Content-Type: application/json' \\\n  -H 'X-Nexscope-Http-Status: semantic' \\\n  -d '{\"keyword\":\"phone case\",\"page\":1}'",
        "config": {
          "mcpServers": {
            "nexscope": {
              "headers": {
                "Authorization": "Bearer YOUR_NEXSCOPE_API_KEY"
              },
              "type": "streamableHttp",
              "url": "https://api.nexscope.ai/mcp"
            }
          }
        }
      },
      "letme": {
        "capability": "https://letme.dev/web.extract",
        "tool": "https://letme.dev/nexscope"
      },
      "area": "web-data",
      "unitPrices": [
        {
          "item": "Nexscope credit (Starter)",
          "unit": "credit",
          "usd": 0.00097,
          "note": "$29 a month for 30,000 credits, half price in the first month. Credits reset monthly"
        },
        {
          "item": "Nexscope credit (Pro)",
          "unit": "credit",
          "usd": 0.00086,
          "note": "$129 a month for 150,000 credits"
        },
        {
          "item": "Amazon Search tool call (Starter)",
          "unit": "call",
          "usd": 0.029,
          "note": "A recent average of 30 credits, range 16 to 94, per the MCP tool page on 10 November 2026. About 20 results a page"
        },
        {
          "item": "Starter plan",
          "unit": "month",
          "usd": 29,
          "note": "30,000 credits, 3 API and 3 MCP requests a second, 2 concurrent each"
        }
      ],
      "provenance": {
        "legalEntity": "ECOCREATE TECHNOLOGY PTE. LTD.",
        "domain": "nexscope.ai",
        "domainRegistered": "2026-03-04",
        "domainNote": "RDAP (Identity Digital) gives nexscope.ai a registration date of 4 March 2026 through GoDaddy, with the registrant behind Domains By Proxy. The terms and privacy policy name ECOCREATE TECHNOLOGY PTE. LTD., 'a company incorporated in Singapore', with no registration number or street address.",
        "endpointOnVendorDomain": true,
        "terms": "https://www.nexscope.ai/terms",
        "privacy": "https://www.nexscope.ai/privacy",
        "statusPage": "",
        "changelog": "",
        "securityTxt": "none",
        "checked": "2026-11-10",
        "notes": [
          "The terms (last updated 8 October 2026) name ECOCREATE TECHNOLOGY PTE. LTD. under the laws of Singapore with SIAC arbitration seated in Singapore, cap liability at the amount paid in the six months before a claim, promise no availability, permit the official APIs and MCP integrations within plan limits, forbid bots and scrapers outside them, and give notice of material changes through the service or by email.",
          "The privacy policy (last updated 8 October 2026) names the same company, says uploaded materials are not used to train AI models, names Google Analytics, Microsoft Clarity, Ahrefs Analytics, Google Ads, X advertising and FirstPromoter, lists hosting, storage, AI processing, payment, email, support and authentication providers only by type, gives no retention periods ('this policy does not specify a single deletion deadline for all data') and mentions no DPA.",
          "https://www.nexscope.ai/.well-known/security.txt answered a client error. No status page or changelog is linked from the home page, llms.txt, the API quickstart or the MCP map.",
          "robots.txt on www.nexscope.ai gives `*` and twelve named crawlers, ClaudeBot among them, the same rules and disallows /api/ and /share/. Nothing there was fetched. api.nexscope.ai publishes no robots.txt (/robots.txt answers a JSON login error). Only /openapi.json and one GET to /mcp were sent there, per the batch. The MCP registry's /robots.txt answered a client error.",
          "firstReleased is 2026-08-07, the date on Nexscope's launch post ('Updated Aug 07, 2026', no earlier publication date shown), which names API, MCP and Skills as the ways to connect an agent and 1,000 free starting credits. The API repository dates its snapshot of an already public directory of 225 APIs to 10 September 2026, and the OpenAPI version label is 2026-08-28-public-catalog-v1. The domain dates from 4 March 2026 and the npm `nexscope` skills CLI from 20 March 2026, but neither reaches the API. lastRelease is 2026-11-09, when the 1688 procurement API contracts were synced as released."
        ],
        "score": 48
      },
      "pageJsonUrl": "https://www.anchorterminal.com/tools/nexscope.json",
      "live": {
        "slug": "nexscope",
        "probe": {
          "target": "https://api.nexscope.ai/mcp",
          "method": "get",
          "lastAt": "2026-11-11T06:59:50.048088824Z",
          "lastOk": true,
          "lastStatus": 405,
          "lastMs": 305,
          "authRequired": false,
          "uptime24h": 100,
          "uptime30d": 100,
          "p50ms24h": 271,
          "p95ms24h": 358,
          "samples24h": 43,
          "samples30d": 43,
          "days": [
            {
              "date": "2026-11-11",
              "probes": 43,
              "ok": 43
            }
          ],
          "since": "2026-11-11T02:53:20.057234625Z"
        },
        "githubStars": 18,
        "updatedAt": "2026-11-11T06:59:50.048088824Z"
      },
      "streak": {
        "days": 0,
        "from": "2026-11-11",
        "sinceWatching": true,
        "best": 0
      }
    },
    "answer": "ZenRows scores 75.9 (BB) on agent readiness against Nexscope's 46.2 (D), and leads in every scored category.",
    "b": {
      "slug": "zenrows",
      "name": "ZenRows",
      "vendor": "ZenRows",
      "vendorUrl": "https://www.zenrows.com",
      "kind": "http-api",
      "category": "web-scrapers",
      "summary": "Scraping API (Fetch, formerly Universal Scraper API) with JavaScript rendering, residential proxies and anti-bot bypass, plus Extract for structured JSON, Crawl for following a site's links, Batch for bulk URL jobs and hosted Browser Sessions.",
      "url": "https://www.anchorterminal.com/tools/zenrows",
      "markdownUrl": "https://www.anchorterminal.com/tools/zenrows.md",
      "slimMarkdownUrl": "https://www.anchorterminal.com/tools/zenrows.min.md",
      "jsonUrl": "https://www.anchorterminal.com/api/v1/tools/zenrows.json",
      "dns": "zenrows.grade.anchorterminal.com",
      "transports": [
        "http",
        "streamable-http",
        "stdio"
      ],
      "remoteUrl": "https://api.zenrows.com/v1/",
      "packages": [
        {
          "registry": "npm",
          "name": "@zenrows/mcp"
        },
        {
          "registry": "npm",
          "name": "zenrows"
        },
        {
          "registry": "pypi",
          "name": "zenrows"
        }
      ],
      "auth": "mixed",
      "authNotes": "The Fetch API takes the key as the apikey query parameter, so it ends up in the request URL. Batch takes it in an X-API-Key header, Crawl and Extract take either, and the hosted MCP at mcp.zenrows.com takes a Bearer header, or OAuth in clients that support it. An account can hold up to 10 keys, each with optional credit caps. The local stdio server reads ZENROWS_API_KEY, and with none set it provisions a Free account through POST https://app.zenrows.com/api/agent/signup, stores the key under ~/.zenrows/ and prints a claim URL, unless ZENROWS_AUTO_SIGNUP=false.",
      "pricing": "freemium",
      "pricingNotes": "Free 5,000 credits a month, no card, 5 concurrent requests. Build from $19 a month (45,000 credits), Launch from $69 (250,000), Growth from $199 (1.2 million), Scale from $549 (5 million), about 17 per cent less billed yearly. A standard request costs 1 credit, JavaScript rendering 5, premium proxies 10, both 25. Browser Sessions and residential proxies cost 25,000 credits a GB plus 5 credits a session-minute. Only successful requests are billed (https://www.zenrows.com/pricing).",
      "priceSummary": "$19 / mo",
      "where": "both",
      "x402": {
        "level": "partial",
        "evidence": "An agent storefront at agents.zenrows.com sells plans and prepaid credit ($5 minimum) settled over x402 (USDC on Base), MPP or card. It runs on ZeroClick's platform with its own buyer terms and proxies calls through a per-session storefront path. There's no per-call x402 price on api.zenrows.com (https://agents.zenrows.com/llms.txt, checked 2026-09-30).",
        "endpoints": []
      },
      "toolCount": 63,
      "popularity": {
        "githubStars": 21,
        "npmWeekly": 34642,
        "pypiWeekly": null,
        "asOf": "2026-09-30"
      },
      "docsUrl": "https://docs.zenrows.com",
      "llmsTxt": "https://docs.zenrows.com/llms.txt",
      "openapi": "https://www.zenrows.com/openapi.json",
      "registryName": "io.github.ZenRows/zenrows-mcp",
      "capabilities": [
        "web.scrape",
        "web.extract",
        "browser.hosted",
        "scraping.proxies",
        "scraping.js-render",
        "scraping.anti-bot",
        "scraping.screenshot"
      ],
      "tags": [
        "hosted",
        "freemium",
        "free-tier",
        "no-card",
        "mcp",
        "llms-txt",
        "proxies",
        "x402",
        "python",
        "typescript"
      ],
      "lastRelease": "2026-10-30",
      "graded": true,
      "anchor": {
        "graded": true,
        "score": 75.9,
        "grade": "BB",
        "agentReady": true,
        "rank": 53,
        "ranked": true,
        "rankOf": 1520,
        "categoryRank": 2,
        "methodology": "0.7",
        "run": "2026-10-01",
        "scores": {
          "ergonomics": 79,
          "maintenance": 90,
          "payments": 80,
          "reliability": 87,
          "schema": 93,
          "security": 50,
          "transparency": 79
        },
        "pending": [
          "performance",
          "tasks"
        ],
        "assessment": {
          "confidence": "medium",
          "date": "2026-11-01"
        },
        "negative": -3,
        "negativeNotes": [
          "2026-10-20. MCP v2.15.0, a minor release after v2.14.0, removed extract's automatic fallback to autoparse, so a call on a domain not yet prepared that returned autoparse JSON now returns REQS007, and `fallback_autoparse`, documented with a default of true, is now ignored. The same release stopped returning the page HTML unless `include_html` is set. The commit is a plain `feat`, not marked breaking, the repository keeps no changelog, and the README described the fallback as current until that release, so no advance notice was found. The API's autoparse parameter still works and the new error names the next step, so 3 points, the floor, by the 1 November 2026 rule and as shotstack was read for an unmarked break. https://github.com/ZenRows/zenrows-mcp/commit/c71f9a6d0e16d447f8e4df507bf7e7a485351709"
        ],
        "verdict": "No incidents in the 90 days to 1 November 2026 on a six-component Better Stack status page, and an OpenAPI 3.1 file with coded errors. The Fetch API only takes the key in the query string.",
        "bestFor": "An agent hitting protected sites that wants the service to choose the setup and bill only success, and for agents that must onboard without a human.",
        "strengths": [
          "No incidents in the 90 days to 1 November 2026 on a six-component Better Stack status page",
          "OpenAPI 3.1 file, 35 coded errors with fixes, and a twelve-month deprecation policy with Sunset headers",
          "5,000 free credits a month with no card, and a stdio MCP that can provision a free account by itself",
          "Up to 10 keys per account, each with its own credit cap",
          "Every MCP tool carries readOnlyHint and destructiveHint, and the scrape tool says when to use extract instead"
        ],
        "weaknesses": [
          "The Fetch API only takes the key in the query string",
          "A protected request costs 25 credits, so real costs sit well above the headline rate",
          "63 MCP tools load at once, 38 of them for the browser",
          "No prompt-injection guidance for the pages it returns",
          "x402 runs only through a third-party storefront, and the 2026 product renames aren't in the changelog"
        ],
        "agentNotes": [
          "Start with mode=auto and let it escalate. Force js_render or premium_proxy only when you know the site needs it",
          "Prefer the extract tool over scrape when you need fields, since it returns far fewer tokens than a full page",
          "On REQS007 from extract, read `reason`. Call prepare_domain for domain_not_prepared, or fall back to css_extractor; extract no longer falls back to autoparse",
          "Read the Concurrency-Remaining response header before fanning out, as extra requests get 429",
          "On a 402 with AUTH014, only this key hit its cap. Read X-Key-Credits-Remaining and don't tell the user to buy credits",
          "Set ZENROWS_AUTO_SIGNUP=false in stdio configs so a missing key fails loudly instead of creating an account",
          "Pass `idempotency_key` to `crawl_create` and `batch_create` so a retried call returns the same job instead of starting and billing a second one"
        ],
        "metrics": {
          "kind": "remote",
          "measured": false
        },
        "reviewCount": 8,
        "avgRating": 3.8,
        "history": [
          {
            "basis": "public evidence",
            "confidence": "medium",
            "grade": "BB",
            "methodology": "0.7",
            "pending": [
              "performance",
              "tasks"
            ],
            "run": "2026-10-01",
            "runLabel": "October 2026 research run",
            "score": 75.9
          }
        ],
        "editorialScores": {
          "ergonomics": 79,
          "maintenance": 90,
          "payments": 80,
          "reliability": 87,
          "schema": 93,
          "security": 50,
          "transparency": 65
        },
        "provenanceScore": 92,
        "checked": {
          "categories": {
            "ergonomics": "2026-11-01",
            "maintenance": "2026-11-01",
            "payments": "2026-11-01",
            "reliability": "2026-11-01",
            "schema": "2026-11-01",
            "security": "2026-11-01",
            "transparency": "2026-11-01"
          },
          "last": "2026-11-01",
          "lastMoved": "2026-11-01",
          "oldest": "2026-11-01",
          "stale": false,
          "staleAfterDays": 90
        }
      },
      "connect": {
        "http": "curl \"https://api.zenrows.com/v1/?apikey=$ZENROWS_API_KEY\u0026url=https%3A%2F%2Fexample.com\u0026mode=auto\"",
        "claudeCode": "claude mcp add --transport http zenrows https://mcp.zenrows.com/mcp --header \"Authorization: Bearer $ZENROWS_API_KEY\"",
        "config": {
          "mcpServers": {
            "zenrows": {
              "args": [
                "-y",
                "@zenrows/mcp"
              ],
              "command": "npx",
              "env": {
                "ZENROWS_API_KEY": "${ZENROWS_API_KEY}",
                "ZENROWS_AUTO_SIGNUP": "false"
              }
            }
          }
        }
      },
      "letme": {
        "capability": "https://letme.dev/web.scrape",
        "tool": "https://letme.dev/zenrows"
      },
      "area": "web-data",
      "unitPrices": [
        {
          "item": "Build plan (B1)",
          "unit": "month",
          "usd": 19,
          "note": "45,000 credits, 20 concurrent. $16 a month billed yearly"
        },
        {
          "item": "Launch plan (L1)",
          "unit": "month",
          "usd": 69,
          "note": "250,000 credits, 50 concurrent. $57 a month billed yearly"
        },
        {
          "item": "Growth plan (G1)",
          "unit": "month",
          "usd": 199,
          "note": "1.2 million credits, 100 concurrent"
        },
        {
          "item": "Standard request on Build B1",
          "unit": "1k-requests",
          "usd": 0.42,
          "note": "1 credit each, successful requests only"
        },
        {
          "item": "Protected request on Build B1",
          "unit": "1k-requests",
          "usd": 10.56,
          "note": "JavaScript rendering plus premium proxies, 25 credits each"
        }
      ],
      "provenance": {
        "legalEntity": "ZENROWS, S.L.",
        "domain": "zenrows.com",
        "domainRegistered": "2020-08-05",
        "endpointOnVendorDomain": true,
        "terms": "https://www.zenrows.com/legal/terms",
        "privacy": "https://www.zenrows.com/legal/privacy",
        "statusPage": "https://status.zenrows.com",
        "changelog": "https://www.zenrows.com/changelog",
        "securityTxt": "valid",
        "checked": "2026-11-01",
        "notes": [
          "The privacy policy gives a registered address in Getxo, Bizkaia, Spain, and tax ID B10660298, and the DPA names Zenrows SL with the same number.",
          "www.zenrows.com/.well-known/security.txt served a file on 1 November 2026 expiring 2027-11-01, with Contact security@zenrows.com and a Policy link to the information security policy. app.zenrows.com's robots.txt now allows /.well-known/.",
          "The dated changelog is at www.zenrows.com/changelog. The Intercom news page at eu.intercom.news/zenrows stops at 14 July 2026.",
          "The website returns 403 to plain curl without a browser user agent."
        ],
        "score": 92
      },
      "requirements": {
        "setupChecked": true,
        "complianceChecked": true,
        "agentAlone": true,
        "card": "no",
        "freeTier": true,
        "credential": "api-key",
        "euResidency": "unknown",
        "trainsOnData": "unknown",
        "zeroRetention": "unknown",
        "certifications": [
          "SOC 2 Type II",
          "ISO 27001",
          "GDPR"
        ],
        "dpa": true,
        "selfHost": "no"
      },
      "pageJsonUrl": "https://www.anchorterminal.com/tools/zenrows.json",
      "live": {
        "slug": "zenrows",
        "probe": {
          "target": "https://api.zenrows.com/v1/",
          "method": "get",
          "lastAt": "2026-11-11T07:00:13.412116543Z",
          "lastOk": true,
          "lastStatus": 400,
          "lastMs": 371,
          "authRequired": false,
          "uptime24h": 100,
          "uptime30d": 100,
          "p50ms24h": 373,
          "p95ms24h": 858,
          "samples24h": 244,
          "samples30d": 7731,
          "days": [
            {
              "date": "2026-10-11",
              "probes": 247,
              "ok": 247
            },
            {
              "date": "2026-10-12",
              "probes": 247,
              "ok": 247
            },
            {
              "date": "2026-10-13",
              "probes": 248,
              "ok": 248
            },
            {
              "date": "2026-10-14",
              "probes": 249,
              "ok": 249
            },
            {
              "date": "2026-10-15",
              "probes": 253,
              "ok": 253
            },
            {
              "date": "2026-10-16",
              "probes": 252,
              "ok": 252
            },
            {
              "date": "2026-10-17",
              "probes": 253,
              "ok": 253
            },
            {
              "date": "2026-10-18",
              "probes": 256,
              "ok": 256
            },
            {
              "date": "2026-10-19",
              "probes": 255,
              "ok": 255
            },
            {
              "date": "2026-10-20",
              "probes": 252,
              "ok": 252
            },
            {
              "date": "2026-10-21",
              "probes": 253,
              "ok": 253
            },
            {
              "date": "2026-10-22",
              "probes": 253,
              "ok": 253
            },
            {
              "date": "2026-10-23",
              "probes": 248,
              "ok": 248
            },
            {
              "date": "2026-10-24",
              "probes": 251,
              "ok": 251
            },
            {
              "date": "2026-10-25",
              "probes": 250,
              "ok": 250
            },
            {
              "date": "2026-10-26",
              "probes": 252,
              "ok": 252
            },
            {
              "date": "2026-10-27",
              "probes": 249,
              "ok": 249
            },
            {
              "date": "2026-10-28",
              "probes": 250,
              "ok": 250
            },
            {
              "date": "2026-10-29",
              "probes": 249,
              "ok": 249
            },
            {
              "date": "2026-10-30",
              "probes": 249,
              "ok": 249
            },
            {
              "date": "2026-10-31",
              "probes": 251,
              "ok": 251
            },
            {
              "date": "2026-11-01",
              "probes": 249,
              "ok": 249
            },
            {
              "date": "2026-11-02",
              "probes": 250,
              "ok": 250
            },
            {
              "date": "2026-11-03",
              "probes": 248,
              "ok": 248
            },
            {
              "date": "2026-11-04",
              "probes": 246,
              "ok": 246
            },
            {
              "date": "2026-11-05",
              "probes": 185,
              "ok": 185
            },
            {
              "date": "2026-11-06",
              "probes": 241,
              "ok": 241
            },
            {
              "date": "2026-11-07",
              "probes": 243,
              "ok": 243
            },
            {
              "date": "2026-11-08",
              "probes": 243,
              "ok": 243
            },
            {
              "date": "2026-11-09",
              "probes": 243,
              "ok": 243
            },
            {
              "date": "2026-11-10",
              "probes": 244,
              "ok": 244
            },
            {
              "date": "2026-11-11",
              "probes": 72,
              "ok": 72
            }
          ],
          "since": "2026-10-08T00:00:00Z"
        },
        "vendorStatus": {
          "page": "https://status.zenrows.com",
          "indicator": "unknown",
          "summary": "no machine-readable status found",
          "checkedAt": "2026-11-11T05:36:07.245023503Z"
        },
        "versions": [
          {
            "registry": "mcp-registry",
            "name": "io.github.ZenRows/zenrows-mcp",
            "version": "2.19.0",
            "seenAt": "2026-11-10T19:22:02.357354042Z"
          },
          {
            "registry": "npm",
            "name": "@zenrows/mcp",
            "version": "2.19.0",
            "seenAt": "2026-11-11T06:49:53.62940716Z"
          },
          {
            "registry": "npm",
            "name": "zenrows",
            "version": "2.7.0",
            "seenAt": "2026-11-11T06:49:55.74695828Z"
          },
          {
            "registry": "pypi",
            "name": "zenrows",
            "version": "1.13.0",
            "released": "2026-11-06",
            "seenAt": "2026-11-11T06:49:57.019067307Z"
          }
        ],
        "npmWeekly": 1017,
        "pypiWeekly": 29567,
        "securityTxt": {
          "url": "https://zenrows.com/.well-known/security.txt",
          "state": "valid",
          "expires": "2027-11-10T16:08:26Z",
          "checkedAt": "2026-11-10T16:08:23.310793499Z"
        },
        "llmsTxt": {
          "url": "https://docs.zenrows.com/llms.txt",
          "ok": true,
          "status": 200,
          "checkedAt": "2026-11-10T15:45:13.869609395Z"
        },
        "domain": {
          "domain": "zenrows.com",
          "registered": "2020-08-05",
          "source": "https://rdap.verisign.com/com/v1/domain/zenrows.com",
          "checkedAt": "2026-11-08T15:08:12.013769124Z"
        },
        "pages": [
          {
            "url": "https://eu.intercom.news/zenrows",
            "kind": "changelog",
            "status": 200,
            "checkedAt": "2026-10-16T22:24:02.345281967Z",
            "changedAt": "0001-01-01T00:00:00Z",
            "fingerprint": "a9b3543b3e4d"
          },
          {
            "url": "https://www.zenrows.com/changelog",
            "kind": "changelog",
            "status": 200,
            "checkedAt": "2026-11-10T16:48:53.902149798Z",
            "changedAt": "2026-10-27T04:07:42.794542723Z",
            "fingerprint": "db501e9abfd5"
          },
          {
            "url": "https://www.zenrows.com/pricing",
            "kind": "pricing",
            "status": 200,
            "checkedAt": "2026-11-10T16:49:00.065377481Z",
            "changedAt": "2026-10-30T06:03:03.347271998Z",
            "fingerprint": "9b31c87dd86f"
          },
          {
            "url": "https://www.zenrows.com/legal/privacy",
            "kind": "privacy",
            "status": 200,
            "checkedAt": "2026-11-10T16:48:55.991305825Z",
            "changedAt": "2026-10-27T04:07:44.844845004Z",
            "fingerprint": "f60343d2a429"
          },
          {
            "url": "https://www.zenrows.com/legal/terms",
            "kind": "terms",
            "status": 200,
            "checkedAt": "2026-11-10T16:48:58.007546723Z",
            "changedAt": "2026-10-27T04:07:46.940493846Z",
            "fingerprint": "37b38df84d2f"
          }
        ],
        "mcpTools": {
          "url": "https://mcp.zenrows.com/mcp",
          "checkedAt": "2026-11-11T02:46:27.08731172Z",
          "status": "ok",
          "protocol": "2025-11-25",
          "tools": [
            {
              "name": "scrape",
              "description": "Scrape any webpage and return its content using Zenrows (Fetch).\n\nReturns full-page content (markdown/HTML/PDF/screenshot). For structured JSON\nfields (products, articles, listings), the extract tool returns parsed fields\ninstead of a full page body.\n\nBy default the request uses automatic mode (mode=auto): Zenrows adds JS rendering\nor premium proxies per page only when a plain request does not return the page,\nand charges only for the configuration that succeeds. Pass just the URL.\n\nSet js_render or premium_proxy only to force a fixed configuration. Doing so\nswitches off automatic mode, and every request is billed at that\nconfiguration's cost (premium_proxy with js_render is 25x a basic request).\n\nExamples:\n  Default:  { url: \"https://example.com\" }\n  Geo:      { url: \"https://example.com\", proxy_country: \"US\" }\n  Forced:   { url: \"https://spa.com\", js_render: true }",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "autoparse": {
                    "description": "Deprecated: general-purpose structured JSON from the page. Prefer the extract tool (extract=auto on a prepared domain, or css_extractor).",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "css_extractor": {
                    "description": "Extract specific elements using CSS selectors. JSON object mapping names to selectors, e.g. '{\"title\":\"h1\",\"price\":\".price-tag\"}'. Returns JSON instead of full page content.",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "js_instructions": {
                    "description": "JSON array of browser interactions to run before scraping. Works in automatic mode (mode=auto), which then renders the page and bills it at the JS rendering rate, or with js_render=true. Example: [{\"click\":\"#load-more\"},{\"wait\":1000},{\"wait_for\":\".results\"}]",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "js_render": {
                    "description": "Force JavaScript rendering on every request. Overrides automatic mode (mode=auto), which already renders JavaScript when a page needs it. Leave unset unless you need a fixed configuration.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "outputs": {
                    "description": "Comma-separated list of data types to extract as structured JSON. Available: emails, headings, links, menus, images, videos, audios. Use '*' for all types. Returns JSON instead of full page content.",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "premium_proxy": {
                    "description": "Force premium residential proxies on every request (10x credit cost). Overrides automatic mode (mode=auto), which already uses premium proxies when a page needs them. Leave unset unless you need a fixed configuration.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "proxy_country": {
                    "description": "Country for geo-targeted scraping. ISO 3166-1 alpha-2 code (e.g. 'US', 'GB', 'DE'). Works in automatic mode (mode=auto); if you set js_render without premium_proxy, it requires premium_proxy=true.",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "response_type": {
                    "anyOf": [
                      {
                        "enum": [
                          "markdown",
                          "plaintext",
                          "pdf",
                          "html"
                        ],
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "default": "markdown",
                    "description": "Output format. 'markdown' (default) preserves structure and is ideal for LLMs. 'plaintext' strips all formatting for pure text extraction. 'pdf' returns a PDF of the page. 'html' returns the raw HTML source (omits the response_type param; Zenrows default). Ignored when autoparse, css_extractor, outputs, or screenshot params are set."
                  },
                  "screenshot": {
                    "description": "Capture an above-the-fold screenshot of the page. Returns an image instead of text content. Useful for visual verification or debugging.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "screenshot_fullpage": {
                    "description": "Capture a full-page screenshot including content below the fold. Returns an image instead of text content.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "screenshot_selector": {
                    "description": "Capture a screenshot of a specific element using a CSS selector. Example: \".product-card\". Returns an image instead of text content.",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "url": {
                    "description": "The webpage URL to scrape",
                    "format": "uri",
                    "type": "string"
                  },
                  "wait": {
                    "anyOf": [
                      {
                        "maximum": 30000,
                        "minimum": 0,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Milliseconds to wait after page load before capturing content. Max 30000 (30s). Requires js_render=true; without it, including in automatic mode, it may be ignored."
                  },
                  "wait_for": {
                    "description": "CSS selector to wait for before capturing. Use when key content loads after the initial page render. Requires js_render=true; without it, including in automatic mode, it may be ignored.",
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "url"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Scrape Webpage"
              }
            },
            {
              "name": "extract",
              "description": "Extract structured data from a webpage via Zenrows.\n\nReturns JSON fields (products, articles, listings) in \"data\" rather than a full\npage body. Set include_html to also get the page HTML.\nModes:\n- auto (default): extract=auto, site-tailored Extract (currently free,\n  billing may apply later). Works on any prepared domain, with any API key.\n  Error REQS007 says why in \"reason\":\n  - domain_not_prepared: call prepare_domain with the domain and 1 to 5 example\n    URLs (one works; we recommend 3 or more of the same page type; a few minutes,\n    no credits), poll prepared_domain_status about every\n    30 seconds until it says ready, then call extract again.\n  - page_not_recognised: the domain is prepared, but this page is not one\n    Extract extracts (a page with nothing to extract, such as a home page). Try a product,\n    article or listing page instead; if this page should work, retry it once in\n    a few minutes; otherwise use mode=css. Do not prepare the domain again.\n  - domain_not_enabled: preparing does not help; use mode=css.\n- autoparse: deprecated general-purpose structured JSON on any domain; use only\n  when asked for\n- css: css_extractor with an explicit selector map\n\nRequests use automatic mode (mode=auto) by default: Zenrows enables JS rendering and\npremium proxies only when the site needs them, and charges only for the\nconfiguration that succeeds. Pass just the URL.\nSet js_render or premium_proxy only to force a fixed configuration; that turns\nautomatic mode off and bills every request at that configuration's cost.\n\nCheck \"empty\" in the result: true means no field came back with a value.\n\"noDataExtracted\": true means Extract processed the page and found nothing to\nextract (not charged); retrying the same request returns the same answer.\nFull-page markdown, HTML and screenshots come from scrape.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "css_extractor": {
                    "description": "Required when mode=css. JSON map of field→selector, e.g. '{\"title\":\"h1\",\"price\":\".price\"}'",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "fallback_autoparse": {
                    "description": "Deprecated, has no effect: Extract no longer falls back to autoparse. Prepare the domain with prepare_domain instead.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "include_html": {
                    "default": false,
                    "description": "mode=auto only: also return the full page HTML. Default false; the HTML is most of the response size.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "js_render": {
                    "description": "Force JS rendering on every request. Overrides automatic mode (mode=auto), which already renders when needed.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "mode": {
                    "anyOf": [
                      {
                        "enum": [
                          "auto",
                          "autoparse",
                          "css"
                        ],
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "default": "auto",
                    "description": "Extraction mode: auto (extract=auto, default), css (requires css_extractor), or the deprecated autoparse"
                  },
                  "mode_auto": {
                    "description": "Automatic mode (mode=auto) is on by default; leave unset. False sends a plain request without it.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "premium_proxy": {
                    "description": "Force premium residential proxies on every request (10x cost). Overrides automatic mode (mode=auto), which already uses premium proxies when a page needs them.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "proxy_country": {
                    "description": "ISO 3166-1 alpha-2 country code. Works in automatic mode (mode=auto); with js_render or mode_auto=false it requires premium_proxy.",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "url": {
                    "description": "The webpage URL to extract from",
                    "format": "uri",
                    "type": "string"
                  },
                  "wait": {
                    "anyOf": [
                      {
                        "maximum": 30000,
                        "minimum": 0,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Milliseconds to wait after load. Requires js_render=true; without it, including in automatic mode, it may be ignored."
                  },
                  "wait_for": {
                    "description": "CSS selector to wait for before extracting. Requires js_render=true; without it, including in automatic mode, it may be ignored.",
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "url"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Extract Structured Data"
              }
            },
            {
              "name": "prepare_domain",
              "description": "Prepare a domain so extract (mode=auto) works on it.\n\nUse this when extract returns error REQS007 with reason domain_not_prepared. Send the\ndomain (the host, e.g. shop.example.com; a leading www. is dropped, and each host is\nprepared separately) and 1 to 5 example URLs of real pages you want extracted. One works;\nwe recommend 3 or more of the same page type, so pass 3 or more when you can, up to 5 (e.g.\n3 product pages: https://www.example.com/products/a, /products/b and /products/c), because\nExtract compares pages of one type to check the fields it found and fill in fields one page\nis missing. Several page types can share the 5 (e.g. 3 product pages + 2 search-result\npages). It returns at once with status\n\"preparing\" and never waits; preparation takes a few minutes and costs no credits. Then\ncall prepared_domain_status about every 30 seconds until status is \"ready\", and call\nextract again. Each new domain uses one slot of the account's monthly allowance\n(prepared_domain_status shows it). A domain already being prepared returns its current\nstatus; a domain already prepared returns \"ready\" at once with already_prepared: true and\nuses no slot.\n\nDo not call this for REQS007 with reason page_not_recognised: the domain is already\nprepared and preparing again does not change that answer.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "domain": {
                    "description": "The host to prepare, e.g. shop.example.com (a URL is accepted; a leading www. is dropped)",
                    "minLength": 1,
                    "type": "string"
                  },
                  "example_urls": {
                    "description": "1 to 5 full URLs of real pages on this domain that you want to extract. One works; we recommend 3 or more of the same page type when you can",
                    "items": {
                      "format": "uri",
                      "type": "string"
                    },
                    "maxItems": 5,
                    "minItems": 1,
                    "type": "array"
                  },
                  "idempotency_key": {
                    "description": "Optional. Resending the same key with the same body returns the original submission",
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": [
                  "domain",
                  "example_urls"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "idempotentHint": true,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Prepare a Domain for Extract"
              }
            },
            {
              "name": "prepared_domain_status",
              "description": "Check a domain submitted with prepare_domain, and the account's monthly allowance.\n\nReturns status (preparing, ready or failed), state (the current step), roles (one per page\nkind), a failure code and detail when it failed, the allowance (used, limit, remaining) and\n\"next\": what to do now. Poll about every 30 seconds; preparation takes a few minutes. Call\nextract again once status is \"ready\". Costs no credits.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "domain": {
                    "description": "The domain passed to prepare_domain, e.g. example.com",
                    "minLength": 1,
                    "type": "string"
                  }
                },
                "required": [
                  "domain"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Prepared Domain Status"
              }
            },
            {
              "name": "batch_create",
              "description": "Submit a Batch job: many URLs scraped asynchronously in the cloud (Zenrows Batch API). Suited to large URL lists; scrape and extract handle single pages. Not the same as browser_batch.\n\nTasks use automatic mode (mode=auto) by default: Zenrows enables JS rendering and premium proxies only on the pages that need them. Pass just the URLs. Set js_render or premium_proxy (job-level, or per task) only to force a fixed configuration; that turns automatic mode off for those tasks.\n\nCost: the same credits as the regular API, per successful task: 1 for a basic request, 5 with js_render, 10 with premium_proxy, 25 with both; mode=auto bills each task at the configuration that worked. Failed tasks are not billed, except target 404 and 410 answers, billed as on the regular API.\nLimits: up to 100,000 tasks per call; 3 active jobs per account by default, shared with Crawl (BATCH_QUOTA_EXCEEDED past that); a job frees its slot when its run ends.\n\nCreates a closed job with every task in this one call. Each task takes a url plus optional external_id, metadata, method/body (POST tasks) and scrape params. Every call sends an Idempotency-Key, so the bounded retries on network errors and 5xx never create a second job; an error reply carries the key to retry with.\n\nReturns job_id, status and stats at once; the job runs asynchronously. Then: batch_wait until it ends, batch_results to list rows (paged), batch_content to read one task's page. A run that ends failed (out of credits, inactive subscription, key cap) answers ok:false with error.code and server_code; batch_rerun recovers it. Submits of 10,000+ tasks keep writing tasks for a while (ingesting:true).\nErrors: BATCH_INVALID_REQUEST (400, server_code and invalid_tasks say what), BATCH_INSUFFICIENT_CREDITS (402), BATCH_KEY_CAP_REACHED (402, this key's cap), BATCH_QUOTA_EXCEEDED (429, job limit), AUTH_INVALID (401; server_code subscription_inactive means fix Billing), BATCH_ACCESS_DENIED (403, do not retry), BACKEND_UNAVAILABLE.\nSchedules, webhooks, exports, CSV inputs and open jobs are available through the Batch API and SDKs only.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "idempotency_key": {
                    "anyOf": [
                      {
                        "maxLength": 128,
                        "minLength": 1,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Sent as the Idempotency-Key header, up to 128 characters; generated per call when unset. Reusing a key with the identical request within 24 hours returns the original response instead of doing it again; with a different request it is BATCH_IDEMPOTENCY_CONFLICT."
                  },
                  "js_render": {
                    "description": "Force js_render on all tasks (5 credits each). Overrides automatic mode (mode=auto), which already renders when needed.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "mode_auto": {
                    "description": "Automatic mode (mode=auto) is on by default; leave unset. False sends plain requests without it.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "premium_proxy": {
                    "description": "Force premium_proxy on all tasks (10 credits each, 25 with js_render). Overrides automatic mode (mode=auto), which already uses premium proxies when a page needs them.",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "proxy_country": {
                    "description": "Job-level ISO country code. Works in automatic mode (mode=auto); with js_render alone it requires premium_proxy.",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "response_type": {
                    "anyOf": [
                      {
                        "enum": [
                          "markdown",
                          "plaintext",
                          "pdf"
                        ],
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Job-level output format. Leave unset for the raw HTML, the default."
                  },
                  "tasks": {
                    "anyOf": [
                      {
                        "items": {
                          "additionalProperties": true,
                          "description": "A task. Scrape params may go in zenrows_params or flat on the task (e.g. extract, js_render); a flat key wins over the same key in zenrows_params.",
                          "properties": {
                            "body": {
                              "description": "Request body, only with method POST, up to 16 KiB. An object or array is sent as JSON; a string is sent as is, form encoded."
                            },
                            "external_id": {
                              "anyOf": [
                                {
                                  "maxLength": 128,
                                  "pattern": "^[A-Za-z0-9._-]+$",
                                  "type": "string"
                                },
                                {
                                  "type": "null"
                                }
                              ],
                              "description": "Optional id of your own, echoed back on results: up to 128 characters, letters, digits, '.', '_' and '-' only (no spaces). Need not be unique. Put free text in metadata instead."
                            },
                            "metadata": {
                              "anyOf": [
                                {
                                  "additionalProperties": {
                                    "maxLength": 1024,
                                    "type": "string"
                                  },
                                  "propertyNames": {
                                    "maxLength": 64,
                                    "minLength": 1,
                                    "pattern": "^[A-Za-z0-9._-]+$"
                                  },
                                  "type": "object"
                                },
                                {
                                  "type": "null"
                                }
                              ],
                              "description": "Optional string-to-string map echoed back on results: up to 20 entries; keys 1 to 64 characters of letters, digits, '.', '_' and '-'; values up to 1,024 characters; 4 KiB in all. Values must be strings: convert numbers and booleans first."
                            },
                            "method": {
                              "anyOf": [
                                {
                                  "enum": [
                                    "GET",
                                    "POST"
                                  ],
                                  "type": "string"
                                },
                                {
                                  "type": "null"
                                }
                              ],
                              "description": "HTTP method for this task (default GET). POST is for read-only queries such as search or GraphQL endpoints: the target can receive the same POST more than once. POST cannot be combined with js_render, js_instructions or json_response."
                            },
                            "url": {
                              "description": "Target URL for this task: http or https, up to 2,048 characters",
                              "format": "uri",
                              "maxLength": 2048,
                              "type": "string"
                            },
                            "zenrows_params": {
                              "anyOf": [
                                {
                                  "additionalProperties": {
                                    "type": [
                                      "string",
                                      "number",
                                      "boolean"
                                    ]
                                  },
                                  "type": "object"
                                },
                                {
                                  "type": "null"
                                }
                              ],
                              "description": "Per-task scrape params, over the job's. Accepted: allowed_status_codes, autoparse, block_resources, css_extractor, custom_headers, extract, extract_fields, js_instructions, js_render, json_response, mode, original_status, outputs, premium_proxy, proxy_country, response_type, session_id, wait, wait_for. Booleans as true/false. Screenshot params are not supported in Batch."
                            }
                          },
                          "required": [
                            "url"
                          ],
                          "type": "object"
                        },
                        "maxItems": 100000,
                        "type": "array"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Tasks (each needs a url), up to 100,000. Prefer this over urls when you need per-task params."
                  },
                  "urls": {
                    "anyOf": [
                      {
                        "items": {
                          "format": "uri",
                          "maxLength": 2048,
                          "type": "string"
                        },
                        "maxItems": 100000,
                        "type": "array"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Shorthand: list of URLs (converted to tasks), up to 100,000. Ignored when tasks is provided."
                  },
                  "wait": {
                    "description": "If true, poll before returning until the run ends or pauses, or wait_timeout passes; a timeout returns the current state with ok:true",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "wait_timeout": {
                    "anyOf": [
                      {
                        "maximum": 3600,
                        "minimum": 1,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Max wait in seconds when wait=true (default 50). Many MCP clients cancel a call after 60 s."
                  },
                  "wait_timeout_ms": {
                    "anyOf": [
                      {
                        "maximum": 3600000,
                        "minimum": 1000,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Deprecated: the same wait in milliseconds. Use the seconds parameter instead."
                  },
                  "zenrows_params": {
                    "anyOf": [
                      {
                        "$ref": "#/properties/tasks/anyOf/0/items/properties/zenrows_params/anyOf/0"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Additional job-level scrape params merged with the flags above. Accepted: allowed_status_codes, autoparse, block_resources, css_extractor, custom_headers, extract, extract_fields, js_instructions, js_render, json_response, mode, original_status, outputs, premium_proxy, proxy_country, response_type, session_id, wait, wait_for."
                  }
                },
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Create Batch Job"
              }
            },
            {
              "name": "batch_status",
              "description": "Get a Batch job's latest run: job_id, run_id, status (pending, running, completed, stopped, failed), stats (total, completed, successful, failed) and the job.\n\nA failed run answers ok:false with error.code BATCH_INSUFFICIENT_CREDITS, BATCH_KEY_CAP_REACHED, AUTH_INVALID (subscription_inactive) or BATCH_RUN_FAILED, error.server_code (the failure_reason) and failure_detail; batch_rerun recovers it once fixed. A paused run has paused:true; one still writing its tasks has ingesting:true.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "job_id": {
                    "description": "Batch job id returned by batch_create or batch_list",
                    "minLength": 1,
                    "type": "string"
                  }
                },
                "required": [
                  "job_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Batch Job Status"
              }
            },
            {
              "name": "batch_wait",
              "description": "Poll a Batch job until its run ends (completed, stopped or failed) or pauses, and return its status and stats like batch_status. If the wait runs out first, it returns the current state with ok:true, timed_out:true and a note: call batch_wait again. A paused run returns at once with paused:true (it does not move until batch_resume). A failed run answers ok:false with error.code and server_code (insufficient_credits, subscription_inactive or api_key_cap_reached). Transient poll errors are retried. A call that carries a progressToken gets a progress notification after each poll.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "job_id": {
                    "description": "Batch job id returned by batch_create or batch_list",
                    "minLength": 1,
                    "type": "string"
                  },
                  "timeout": {
                    "anyOf": [
                      {
                        "maximum": 3600,
                        "minimum": 1,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Max wait in seconds (default 50). Many MCP clients cancel a call after 60 s."
                  },
                  "timeout_ms": {
                    "anyOf": [
                      {
                        "maximum": 3600000,
                        "minimum": 1000,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Deprecated: the same wait in milliseconds. Use the seconds parameter instead."
                  }
                },
                "required": [
                  "job_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Wait for Batch Job"
              }
            },
            {
              "name": "batch_results",
              "description": "List a Batch run's result rows, a page at a time: up to limit rows (default 100, max 1000) and next_cursor. Pass next_cursor back as cursor to continue; it is null once every row was read.\n\nEach row has task_id, external_id, url, metadata, status (successful, failed, pending, processing, expired), type, result_url when successful, and error when failed. A result_url is presigned and expires after 2 hours: call batch_results again for a fresh one, or read the body with batch_content. Results are kept 14 days by default; after that a successful row reads as status \"expired\", with no result_url, and batch_content answers BATCH_RESULT_EXPIRED.\n\nFilter with status: all (default), successful, failed, or processing (not finished yet). A sparse filter can return fewer rows than limit with next_cursor still set: keep paging. While the run is still running or writing its tasks, the list is partial.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "cursor": {
                    "description": "next_cursor from a previous batch_results call",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "job_id": {
                    "description": "Batch job id returned by batch_create or batch_list",
                    "minLength": 1,
                    "type": "string"
                  },
                  "limit": {
                    "anyOf": [
                      {
                        "maximum": 1000,
                        "minimum": 1,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Max rows to return (default 100, max 1000)"
                  },
                  "run_id": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "An earlier run's id (from batch_status or batch_rerun). Default: the job's latest run."
                  },
                  "status": {
                    "anyOf": [
                      {
                        "enum": [
                          "successful",
                          "failed",
                          "processing",
                          "all"
                        ],
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Filter rows by status (default all). processing = tasks not finished yet. successful also returns expired rows."
                  }
                },
                "required": [
                  "job_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Batch Job Results"
              }
            },
            {
              "name": "batch_content",
              "description": "Read one Batch task's stored result, by job_id and task_id (from batch_results). A text result (HTML, Markdown, plain text, JSON) comes back inline, cut to max_chars (default 20000); a final note says when it was cut. A binary result (a PDF) is not inlined: the reply gives its result_url, presigned for 2 hours. Finding that URL reads the run's results; on a large run one call may run out of time first and answer with lookup_cursor: call batch_content again with it to go on.\n\nBATCH_TASK_NOT_READY: the task has not finished; BATCH_TASK_FAILED: it failed (task_error holds its error); BATCH_RESULT_EXPIRED: past the job's retention (14 days by default); rerun to scrape it again.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "job_id": {
                    "description": "Batch job id returned by batch_create or batch_list",
                    "minLength": 1,
                    "type": "string"
                  },
                  "lookup_cursor": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "lookup_cursor from a previous batch_content reply on a binary result, to go on looking for its result_url"
                  },
                  "max_chars": {
                    "anyOf": [
                      {
                        "maximum": 10000000,
                        "minimum": 1000,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Max characters of a text result to return (default 20000)"
                  },
                  "run_id": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "An earlier run's id (from batch_status or batch_rerun). Default: the job's latest run."
                  },
                  "task_id": {
                    "description": "task_id from a batch_results row",
                    "minLength": 1,
                    "type": "string"
                  }
                },
                "required": [
                  "job_id",
                  "task_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Batch Task Content"
              }
            },
            {
              "name": "batch_list",
              "description": "List this account's Batch jobs, newest first, each with its latest run's status and stats. Filter by status (open or closed) and type (regular or scheduled). Pass next_cursor as cursor for the next page; a page can hold fewer than limit jobs while next_cursor is still set, so keep paging until it is null. Deleted jobs are not listed.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "cursor": {
                    "description": "next_cursor from a previous batch_list call",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "limit": {
                    "anyOf": [
                      {
                        "maximum": 100,
                        "minimum": 1,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Jobs per page (default 20, max 100)"
                  },
                  "status": {
                    "anyOf": [
                      {
                        "enum": [
                          "open",
                          "closed"
                        ],
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Only jobs with this job status"
                  },
                  "type": {
                    "anyOf": [
                      {
                        "enum": [
                          "regular",
                          "scheduled"
                        ],
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Only jobs of this type"
                  }
                },
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "List Batch Jobs"
              }
            },
            {
              "name": "batch_cancel",
              "description": "Stop a Batch job's current run for good. No task still waiting is started or billed; tasks already in flight finish (and bill). Results so far stay readable with batch_results. Tasks that never started stay pending: batch_rerun (default failed and pending) runs them later. Idempotent: a run that already ended answers with its final status and already_ended:true. To halt without ending the run, use batch_pause.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "job_id": {
                    "description": "Batch job id returned by batch_create or batch_list",
                    "minLength": 1,
                    "type": "string"
                  }
                },
                "required": [
                  "job_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": true,
                "idempotentHint": true,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Cancel Batch Job"
              }
            },
            {
              "name": "batch_pause",
              "description": "Pause a Batch job's current run: it picks up no new tasks until batch_resume. Tasks already in flight still finish and bill; for a hard cost stop use batch_cancel. A paused run still counts as an active job. Idempotent; a run that already ended answers with its final status and already_ended:true.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "job_id": {
                    "description": "Batch job id returned by batch_create or batch_list",
                    "minLength": 1,
                    "type": "string"
                  }
                },
                "required": [
                  "job_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "idempotentHint": true,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Pause Batch Job"
              }
            },
            {
              "name": "batch_resume",
              "description": "Resume a paused Batch run: it picks up its remaining tasks again, billed as they finish. Idempotent on a run that is not paused; a run that already ended answers with its final status and already_ended:true. Needs credits: BATCH_INSUFFICIENT_CREDITS or BATCH_KEY_CAP_REACHED otherwise.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "job_id": {
                    "description": "Batch job id returned by batch_create or batch_list",
                    "minLength": 1,
                    "type": "string"
                  }
                },
                "required": [
                  "job_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "idempotentHint": true,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Resume Batch Job"
              }
            },
            {
              "name": "batch_rerun",
              "description": "Start a new run of a Batch job whose latest run ended (completed, stopped or failed). By default it reruns only the tasks that failed or never started (status [\"failed\", \"pending\"]), and carries the others' results over: the recovery after a run that failed on credits or was cancelled. Pass status to pick other task statuses, or full:true to scrape every task again. Rerun tasks are billed like new ones.\n\nA rerun of only some tasks works up to 10 days after the run started (BATCH_RERUN_WINDOW_EXPIRED after that; full:true still works). BATCH_NO_MATCHING_TASKS: no task has those statuses. BATCH_RUN_NOT_FINISHED: the latest run is still in flight. Sends an Idempotency-Key, so a retry never starts two runs. Returns the new run at once (it writes its tasks first, ingesting:true); call batch_wait.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "full": {
                    "description": "Rerun every task, not only some (default false)",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "idempotency_key": {
                    "anyOf": [
                      {
                        "maxLength": 128,
                        "minLength": 1,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Sent as the Idempotency-Key header, up to 128 characters; generated per call when unset. Reusing a key with the identical request within 24 hours returns the original response instead of doing it again; with a different request it is BATCH_IDEMPOTENCY_CONFLICT."
                  },
                  "job_id": {
                    "description": "Batch job id returned by batch_create or batch_list",
                    "minLength": 1,
                    "type": "string"
                  },
                  "status": {
                    "anyOf": [
                      {
                        "items": {
                          "enum": [
                            "failed",
                            "pending",
                            "processing",
                            "successful"
                          ],
                          "type": "string"
                        },
                        "minItems": 1,
                        "type": "array"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Task statuses to rerun (default [\"failed\", \"pending\"]). Ignored with full:true."
                  }
                },
                "required": [
                  "job_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Rerun Batch Job"
              }
            },
            {
              "name": "batch_delete",
              "description": "Delete a Batch job with all its runs and results, for good. A run in flight stops picking up tasks at once, and the job frees its active-job slot. The job reads as not found right away; storage is cleaned up in the background. Idempotent. To keep the results, use batch_cancel instead.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "job_id": {
                    "description": "Batch job id returned by batch_create or batch_list",
                    "minLength": 1,
                    "type": "string"
                  }
                },
                "required": [
                  "job_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": true,
                "idempotentHint": true,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Delete Batch Job"
              }
            },
            {
              "name": "crawl_create",
              "description": "Start a crawl from one URL (Zenrows Crawl API). Crawl follows the links in each page's HTML up to depth hops (no depth limit when depth is omitted), keeps the URLs that match include_patterns / exclude_patterns, and stays on the start URL's registrable domain (subdomains count).\n\nUse crawl when you have one start page (a listing, category, blog index) and need\nthe URLs behind it, optionally with each page's HTML. For a single page, use scrape.\n\nEach page fetched is billed as one scrape on this account; max_pages bounds the cost\n(default 100), max_items bounds how many URLs are kept (default 100). Without depth, the\ncrawl keeps following links until max_pages or max_items stops it or nothing is left to\nopen, so set max_pages to what you are willing to spend. The start page itself is never\na result, but its fetch is billed: a crawl whose include_patterns / exclude_patterns match\nnothing still costs that one scrape. A crawl whose pages held nothing new to follow (no link,\nonly links to other sites, or only links the patterns reject) ends completed with no results\nand no error. When patterns are set, check them against the URLs the start page links to.\nSet output_format \"html\" or \"markdown\" to also store each kept URL's page,\nthen read it with crawl_content.\nSet webhook to have signed events posted to your https URL when the crawl starts and when it\nends; the account needs a webhook signing key, else CRAWL_INVALID_REQUEST (webhook_signing_key_required).\n\nReturns crawl_id, status and the crawl (with coverage) at once; the crawl runs\nasynchronously. Call crawl_wait, then crawl_results. Set idempotency_key to make a retry\nsafe: the same key returns the crawl the first request created instead of starting another.\nCRAWL_NOT_ENABLED: Crawl is not enabled for this account; do not retry.\nCRAWL_TOO_MANY_CRAWLS: the account has reached its limit of active jobs (3 by default), shared with its Batch jobs; retry after retry_after seconds.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "depth": {
                    "anyOf": [
                      {
                        "maximum": 100000,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Link hops to follow from the start URL. 1 returns the start page's links; 2 also opens those. Omit for no depth limit: the crawl follows links until max_pages or max_items stops it."
                  },
                  "discovery": {
                    "anyOf": [
                      {
                        "items": {
                          "enum": [
                            "links"
                          ],
                          "type": "string"
                        },
                        "minItems": 1,
                        "type": "array"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "How the crawl finds the URLs it follows on each page it walks. ['links'] follows the links in each page's HTML, and is what a crawl runs with when you omit this."
                  },
                  "exclude_patterns": {
                    "anyOf": [
                      {
                        "items": {
                          "minLength": 1,
                          "type": "string"
                        },
                        "type": "array"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Drop URLs containing any of these substrings, even if they match include_patterns"
                  },
                  "idempotency_key": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Sent as the Idempotency-Key header. Reusing a key returns the crawl it created; reusing it with a different body is CRAWL_INVALID_REQUEST."
                  },
                  "include_patterns": {
                    "anyOf": [
                      {
                        "items": {
                          "minLength": 1,
                          "type": "string"
                        },
                        "type": "array"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Keep only URLs containing at least one of these substrings, e.g. [\"/product/\"]"
                  },
                  "max_items": {
                    "anyOf": [
                      {
                        "maximum": 100000,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Stop once this many URLs are kept (default 100)"
                  },
                  "max_pages": {
                    "anyOf": [
                      {
                        "maximum": 100000,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Stop once this many pages are fetched, each billed as one scrape (default 100). With output_format, every kept URL's page counts too."
                  },
                  "output_format": {
                    "anyOf": [
                      {
                        "enum": [
                          "html",
                          "markdown"
                        ],
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "'html' or 'markdown' also stores each kept URL's page for crawl_content, as fetched or converted to Markdown. Omit for URLs only."
                  },
                  "url": {
                    "description": "Start URL: a public http(s) page, such as a listing or category page",
                    "format": "uri",
                    "type": "string"
                  },
                  "webhook": {
                    "anyOf": [
                      {
                        "additionalProperties": false,
                        "properties": {
                          "events": {
                            "anyOf": [
                              {
                                "items": {
                                  "enum": [
                                    "crawl.started",
                                    "crawl.completed",
                                    "crawl.stopped",
                                    "crawl.failed"
                                  ],
                                  "type": "string"
                                },
                                "minItems": 1,
                                "type": "array"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Events to send, each once. Omit for all four."
                          },
                          "metadata": {
                            "anyOf": [
                              {
                                "additionalProperties": {},
                                "propertyNames": {
                                  "maxLength": 64,
                                  "minLength": 1
                                },
                                "type": "object"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Sent back with every event, to match it to your records. Up to 20 keys of 1-64 characters, each value at most 1,024 bytes as JSON."
                          },
                          "url": {
                            "description": "Absolute https URL each event is posted to",
                            "format": "uri",
                            "type": "string"
                          }
                        },
                        "required": [
                          "url"
                        ],
                        "type": "object"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Where to post the crawl's signed events (crawl.started, then one of crawl.completed, crawl.stopped, crawl.failed). Each is signed with the account's webhook signing key, in the X-Signature header."
                  }
                },
                "required": [
                  "url"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Create Crawl"
              }
            },
            {
              "name": "crawl_get",
              "description": "Get a crawl and one page of the URLs it kept: crawl_id, status (running, completed, stopped, failed), the crawl (with coverage: pages_fetched, pages_failed, items_found; webhook when set), results and next_cursor.\n\ncompleted with stop_reason max_items / max_pages means a limit ended it; stopped with stop_reason user means crawl_stop ended it; stopped with no stop_reason and error.code insufficient_credits or api_key_cap_reached means the account ran out of credits or the API key hit a credit cap (the URLs kept before that stay readable); completed with no results and no error means the crawl's pages held nothing new to follow; when include_patterns / exclude_patterns are set, check them against the URLs the start page links to. failed carries error.code and error.detail: seed_unreachable means the start URL could not be fetched or returned an empty page; no_items_found means the crawl read the start page but found no data it could use, so it had nothing to follow; start from a listing or product page. A failed crawl, and a stopped one with an error, answer ok: false: error.code is CRAWL_INSUFFICIENT_CREDITS or CRAWL_KEY_CAP_REACHED (the codes crawl_create gets on a 402) when credits ended it, failed or stopped, else CRAWL_FAILED; error.server_code is the crawl's error.code. Pass next_cursor as cursor for the next page; while the crawl runs, next_cursor is never null. To read many pages at once, use crawl_results.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "crawl_id": {
                    "description": "Crawl id returned by crawl_create (c_…)",
                    "type": "string"
                  },
                  "cursor": {
                    "description": "next_cursor from a previous crawl_get call, to continue from there",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "limit": {
                    "anyOf": [
                      {
                        "maximum": 10000,
                        "minimum": 1,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Results in this page (default 100, max 10000)"
                  }
                },
                "required": [
                  "crawl_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Get Crawl"
              }
            },
            {
              "name": "crawl_results",
              "description": "List the URLs a crawl kept, in the order it kept them, following the API's pages up to limit.\n\nEach result has url and, when the crawl has output_format, content_status (pending, fetched, failed) and, once fetched, content_url: pass it to crawl_content as content.\n\nWhile the crawl runs the list is partial (partial=true): call again later with the returned next_cursor to get only the URLs kept since. A stopped crawl can still add URLs from pages fetched before the stop for up to 10 minutes, so next_cursor stays set during that window: call again later. next_cursor is null once the crawl ended and every URL was read.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "crawl_id": {
                    "description": "Crawl id returned by crawl_create (c_…)",
                    "type": "string"
                  },
                  "cursor": {
                    "description": "next_cursor from a previous crawl_results call, to continue from there",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "limit": {
                    "anyOf": [
                      {
                        "maximum": 10000,
                        "minimum": 1,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Max results to return in this call (default 100, max 10000)"
                  }
                },
                "required": [
                  "crawl_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Crawl Results"
              }
            },
            {
              "name": "crawl_content",
              "description": "Read the stored page of one URL a crawl kept, in the crawl's output_format. Works only for crawls created with an output_format, and only for results whose content_status is fetched.\n\nPass crawl_id and content_id: a content id, or content_url from a crawl_results row. Returns the page\nas stored — raw HTML for output_format \"html\", Markdown for \"markdown\" — cut to max_chars (default\n20000); a final note says when it was cut. To read a page the crawl did not\nstore, use scrape on its URL instead.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "content_id": {
                    "description": "A content id (ct_…), or content_url from a crawl_results row; its last path segment is the id",
                    "minLength": 1,
                    "type": "string"
                  },
                  "crawl_id": {
                    "description": "Crawl id returned by crawl_create (c_…)",
                    "type": "string"
                  },
                  "max_chars": {
                    "anyOf": [
                      {
                        "maximum": 10000000,
                        "minimum": 1000,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Max characters of the page to return (default 20000)"
                  }
                },
                "required": [
                  "crawl_id",
                  "content_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Crawl Page Content"
              }
            },
            {
              "name": "crawl_list",
              "description": "List this account's crawls, newest first, with status and coverage (no results). Pass next_cursor as cursor for the next page; next_cursor is absent on the last page.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "cursor": {
                    "description": "next_cursor from a previous crawl_list call",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "limit": {
                    "anyOf": [
                      {
                        "maximum": 100,
                        "minimum": 1,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Crawls per page (default 20, max 100)"
                  }
                },
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "List Crawls"
              }
            },
            {
              "name": "crawl_stop",
              "description": "Stop a running crawl. No page still waiting is fetched or billed; pages already in flight finish. The URLs kept so far stay readable with crawl_results. A stopped crawl cannot resume.\n\nIdempotent: a crawl that already ended answers with its final status. A 429, 502, 503 or 504 is retried up to 3 times, waiting at most 50 seconds in all; a 503 crawl_busy means the stop was not saved yet, and if it persists, CRAWL_BUSY says when to call again. Pages in flight still finish, so coverage and results can keep growing for up to 10 minutes after the stop; read them with crawl_get and crawl_results.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "crawl_id": {
                    "description": "Crawl id returned by crawl_create (c_…)",
                    "type": "string"
                  }
                },
                "required": [
                  "crawl_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": true,
                "idempotentHint": true,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Stop Crawl"
              }
            },
            {
              "name": "crawl_wait",
              "description": "Poll a crawl until it ends (completed, stopped, or failed) and return its status, its counts and the first 20 URLs (first_urls). For every result, call crawl_download (one file) or crawl_results (pages). A crawl that ends completed with no results and no error finished; it is not a failure (see crawl_get). If the wait runs out first, it returns the crawl with status running and a note: call crawl_wait again. A call that carries a progressToken gets a progress notification after each poll, with the status and counts.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "crawl_id": {
                    "description": "Crawl id returned by crawl_create (c_…)",
                    "type": "string"
                  },
                  "timeout": {
                    "anyOf": [
                      {
                        "maximum": 3600,
                        "minimum": 1,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Max wait in seconds (default 50). Many MCP clients cancel a call after 60 s."
                  }
                },
                "required": [
                  "crawl_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Wait for Crawl"
              }
            },
            {
              "name": "crawl_download",
              "description": "Save every result of a crawl to one local file, as JSON lines: url, content_status and, once fetched, content (the page). Returns the file's path and line count, not the results, so a crawl of any size costs one small reply. Read the file with your own tools.\n\nThe file goes to path when given (a relative path inside ~/.zenrows/crawls; an absolute path or one that leaves that folder fails with INVALID_PATH), else ~/.zenrows/crawls/\u003ccrawl_id\u003e.jsonl. An existing file is kept and the call fails with FILE_EXISTS unless overwrite is true.\n\nOn a running crawl the file holds only what was kept so far: download again once crawl_wait says it ended. After crawl_stop, pages in flight can still add lines for up to 10 minutes: the reply says so with partial: true. On the hosted server no file is written: the reply gives the download URL and a command to run where your API key is set.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "crawl_id": {
                    "description": "Crawl id returned by crawl_create (c_…)",
                    "type": "string"
                  },
                  "overwrite": {
                    "description": "Replace the file if it exists (default false)",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "path": {
                    "anyOf": [
                      {
                        "minLength": 1,
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "File to write, relative to ~/.zenrows/crawls (default \u003ccrawl_id\u003e.jsonl)"
                  }
                },
                "required": [
                  "crawl_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Download Crawl"
              }
            },
            {
              "name": "account_usage",
              "description": "Read the current plan's credit allowance and how much of it is spent.\n\nUseful before a large batch, or after a 402 / AUTH004, to see whether the account has\ncredits left and when the allowance renews. The call is free and does not use a\nconcurrency slot.\n\nCredit costs per request: 1 basic, 5 js_render, 10 premium_proxy, 25 both.\n\nAUTH004 (\"usage exceeded\") means this allowance is spent until it renews at the end of\nthe billing period (period_ends_at in this tool's response). Plans and credit options are\ndescribed at https://www.zenrows.com/pricing.\nAUTH006 is the concurrency limit, not a credit limit.\n\nAUTH014 (Batch: api_key_cap_reached) means this API key hit one of its own credit caps\nwhile the account still has credits; other keys keep working. The response's\napi_key.caps lists the calling key's caps: window, credits, used_credits,\nremaining_credits, resets_at, and unavailable (usage could not be read). Caps are\nmanaged at https://app.zenrows.com/settings/api-keys.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "properties": {},
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": false,
                "readOnlyHint": true,
                "title": "Check Credit Usage"
              }
            },
            {
              "name": "browser_navigate",
              "description": "Open a Zenrows Browser Sessions session and navigate to a URL.\n\nThis is the entry point for all browser automation. It creates a new session backed by\nZenrows' hosted browser infrastructure and navigates to the given URL in one step.\n\nReturns a session_id that every other browser_* tool takes. The session holds one\nconcurrency slot until browser_close closes it.\n\nWhen to use options:\n- proxy_country: geo-restricted content (ISO 3166-1 alpha-2, e.g. \"US\", \"DE\")\n- proxy_region: world region for geo-targeted proxy (eu, na, ap, sa, af, me)",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "proxy_country": {
                    "description": "ISO 3166-1 alpha-2 country code for geo-targeted proxy (e.g. 'US', 'GB', 'DE')",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "proxy_region": {
                    "description": "World region code for geo-targeted proxy (eu=Europe, na=North America, ap=Asia Pacific, sa=South America, af=Africa, me=Middle East)",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "url": {
                    "description": "The URL to navigate to",
                    "format": "uri",
                    "type": "string"
                  }
                },
                "required": [
                  "url"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Open Browser \u0026 Navigate"
              }
            },
            {
              "name": "browser_close",
              "description": "Close a browser session and free all associated resources, including the concurrency slot it holds.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Close Browser Session"
              }
            },
            {
              "name": "browser_go_back",
              "description": "Navigate back to the previous page in the browser history.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Go Back"
              }
            },
            {
              "name": "browser_go_forward",
              "description": "Navigate forward to the next page in the browser history.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Go Forward"
              }
            },
            {
              "name": "browser_reload",
              "description": "Reload the current page of a browser session.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Reload Page"
              }
            },
            {
              "name": "browser_click",
              "description": "Click an element on the page using a CSS selector.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "selector": {
                    "description": "CSS selector of the element to click",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "selector"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Click Element"
              }
            },
            {
              "name": "browser_hover",
              "description": "Move the mouse cursor over an element to trigger hover effects.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "selector": {
                    "description": "CSS selector of the element to hover over",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "selector"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Hover Element"
              }
            },
            {
              "name": "browser_type",
              "description": "Type text into an input element. Appends to existing content unless clear_first is set.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "clear_first": {
                    "description": "Clear existing content before typing (default false)",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "selector": {
                    "description": "CSS selector of the input element",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  },
                  "text": {
                    "description": "Text to type",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "selector",
                  "text"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Type Text"
              }
            },
            {
              "name": "browser_fill",
              "description": "Clear an input field and set its value, replacing what was there (browser_type appends instead).",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "selector": {
                    "description": "CSS selector of the input element",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  },
                  "value": {
                    "description": "Value to fill in",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "selector",
                  "value"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Fill Input"
              }
            },
            {
              "name": "browser_select_option",
              "description": "Select an option from a \u003cselect\u003e dropdown element.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "selector": {
                    "description": "CSS selector of the \u003cselect\u003e element",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  },
                  "value": {
                    "description": "Value of the option to select",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "selector",
                  "value"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Select Option"
              }
            },
            {
              "name": "browser_check",
              "description": "Check a checkbox or radio button.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "selector": {
                    "description": "CSS selector of the checkbox or radio element",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "selector"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Check Checkbox"
              }
            },
            {
              "name": "browser_uncheck",
              "description": "Uncheck a checkbox, found by CSS selector, in a browser session.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "selector": {
                    "description": "CSS selector of the checkbox element",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "selector"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Uncheck Checkbox"
              }
            },
            {
              "name": "browser_focus",
              "description": "Move focus to an element, triggering focus-dependent UI changes.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "selector": {
                    "description": "CSS selector of the element to focus",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "selector"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Focus Element"
              }
            },
            {
              "name": "browser_press_key",
              "description": "Press a keyboard key. Examples: \"Enter\", \"Tab\", \"Escape\", \"ArrowDown\", \"Control+a\".",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "key": {
                    "description": "Key to press (e.g. \"Enter\", \"Tab\", \"Escape\", \"ArrowDown\", \"Control+a\")",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "key"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Press Key"
              }
            },
            {
              "name": "browser_scroll",
              "description": "Scroll the page in a given direction.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "direction": {
                    "description": "Scroll direction",
                    "enum": [
                      "up",
                      "down",
                      "left",
                      "right"
                    ],
                    "type": "string"
                  },
                  "distance": {
                    "anyOf": [
                      {
                        "exclusiveMinimum": 0,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Pixels to scroll (default 500)"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "direction"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Scroll Page"
              }
            },
            {
              "name": "browser_drag",
              "description": "Drag an element from its current position to a target element.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  },
                  "source_selector": {
                    "description": "CSS selector of the element to drag",
                    "type": "string"
                  },
                  "target_selector": {
                    "description": "CSS selector of the drop target",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "source_selector",
                  "target_selector"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Drag Element"
              }
            },
            {
              "name": "browser_get_accessibility_tree",
              "description": "Get the ARIA accessibility tree of the current page as readable text.\n\nShows the page structure and the selectors needed to interact with elements, in\nfewer tokens than a screenshot.\n\nThe tree shows all interactive elements (buttons, inputs, links) with their roles,\nlabels, and states — everything needed to drive browser interactions.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Get Accessibility Tree"
              }
            },
            {
              "name": "browser_get_url",
              "description": "Get the current URL of the browser session.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Get Current URL"
              }
            },
            {
              "name": "browser_get_title",
              "description": "Get the title of the current page.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Get Page Title"
              }
            },
            {
              "name": "browser_get_text",
              "description": "Get the visible text content of an element or the entire page body.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "selector": {
                    "description": "CSS selector of the element (omit for full page body text)",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Get Text Content"
              }
            },
            {
              "name": "browser_get_attribute",
              "description": "Get the value of a specific attribute on an element.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "attribute": {
                    "description": "Attribute name to retrieve (e.g. 'href', 'src', 'data-id')",
                    "type": "string"
                  },
                  "selector": {
                    "description": "CSS selector of the element",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "selector",
                  "attribute"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Get Element Attribute"
              }
            },
            {
              "name": "browser_get_html",
              "description": "Get the HTML source of an element or the full page.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "selector": {
                    "description": "CSS selector of the element (omit for full page HTML)",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Get HTML"
              }
            },
            {
              "name": "browser_query_selector_all",
              "description": "Find all elements matching a CSS selector and return their text, HTML, and attributes.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "selector": {
                    "description": "CSS selector to query",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "selector"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Query All Matching Elements"
              }
            },
            {
              "name": "browser_screenshot",
              "description": "Take a screenshot of the current page or a specific element. Use for visual verification or when the accessibility tree is not sufficient.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "full_page": {
                    "description": "Capture full page including content below the fold (default false)",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "selector": {
                    "description": "CSS selector to capture only a specific element (overrides full_page)",
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Take Screenshot"
              }
            },
            {
              "name": "browser_generate_pdf",
              "description": "Render the current page as a PDF document.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "landscape": {
                    "description": "Landscape orientation (default false)",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "print_background": {
                    "description": "Print background graphics (default false)",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "scale": {
                    "anyOf": [
                      {
                        "maximum": 2,
                        "minimum": 0.1,
                        "type": "number"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "Page scale factor (default 1)"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Generate PDF"
              }
            },
            {
              "name": "browser_wait_for_selector",
              "description": "Wait until an element matching the CSS selector is stable in the DOM. Set visible=true to also require the element to be visible (not hidden).",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "selector": {
                    "description": "CSS selector to wait for",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  },
                  "visible": {
                    "description": "Also require the element to be visible, not just present in the DOM (default false)",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  }
                },
                "required": [
                  "session_id",
                  "selector"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Wait for Element"
              }
            },
            {
              "name": "browser_wait_for_navigation",
              "description": "Wait for the page to navigate to a new URL. It waits for the next navigation event, so a navigation that already finished is not seen and the call waits until timeout_ms. Pages that update without changing URL (AJAX/SPA) fire no navigation event. Optional timeout_ms (default 30000ms).",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  },
                  "timeout_ms": {
                    "anyOf": [
                      {
                        "maximum": 60000,
                        "minimum": 1000,
                        "type": "integer"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "How long to wait in milliseconds (default 30000, max 60000)"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Wait for Navigation"
              }
            },
            {
              "name": "browser_wait",
              "description": "Wait for a fixed duration. browser_wait_for_selector waits only until an element appears.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "ms": {
                    "description": "Milliseconds to wait (max 30000)",
                    "maximum": 30000,
                    "minimum": 0,
                    "type": "integer"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "ms"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Wait"
              }
            },
            {
              "name": "browser_evaluate",
              "description": "Execute JavaScript in the browser context and return the result. The script can change or delete the session's page state, such as cookies, storage and form data.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "script": {
                    "description": "JavaScript expression or function body to evaluate in the page context",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "script"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": true,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Evaluate JavaScript"
              }
            },
            {
              "name": "browser_get_cookies",
              "description": "Get all cookies for the current page.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Get Cookies"
              }
            },
            {
              "name": "browser_set_cookies",
              "description": "Set one or more cookies in the browser session. A cookie with the same name, domain and path replaces the existing one.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "cookies": {
                    "description": "Array of cookie objects to set",
                    "items": {
                      "additionalProperties": false,
                      "properties": {
                        "domain": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "expires": {
                          "description": "Unix timestamp",
                          "type": [
                            "number",
                            "null"
                          ]
                        },
                        "http_only": {
                          "type": [
                            "boolean",
                            "null"
                          ]
                        },
                        "name": {
                          "type": "string"
                        },
                        "path": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "secure": {
                          "type": [
                            "boolean",
                            "null"
                          ]
                        },
                        "value": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "name",
                        "value"
                      ],
                      "type": "object"
                    },
                    "type": "array"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "cookies"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": true,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Set Cookies"
              }
            },
            {
              "name": "browser_clear_cookies",
              "description": "Clear all cookies for the current browser session.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": true,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Clear Cookies"
              }
            },
            {
              "name": "browser_get_local_storage",
              "description": "Read one localStorage value in the current page context.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "key": {
                    "description": "Storage key to read",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "key"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": true,
                "title": "Get Local Storage Item"
              }
            },
            {
              "name": "browser_set_local_storage",
              "description": "Write one localStorage value in the current page context. An existing value under the same key is replaced.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "key": {
                    "description": "Storage key to write",
                    "type": "string"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  },
                  "value": {
                    "description": "Value to store",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "key",
                  "value"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": true,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Set Local Storage Item"
              }
            },
            {
              "name": "browser_clear_local_storage",
              "description": "Delete every localStorage entry in the current page context.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": true,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Clear Local Storage"
              }
            },
            {
              "name": "browser_new_tab",
              "description": "Open a new browser tab. Returns a tab_id to use with browser_switch_tab.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  },
                  "url": {
                    "anyOf": [
                      {
                        "format": "uri",
                        "type": "string"
                      },
                      {
                        "type": "null"
                      }
                    ],
                    "description": "URL to open in the new tab (opens blank tab if omitted)"
                  }
                },
                "required": [
                  "session_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Open New Tab"
              }
            },
            {
              "name": "browser_switch_tab",
              "description": "Switch focus to a different browser tab.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  },
                  "tab_id": {
                    "description": "Tab ID returned by browser_new_tab",
                    "type": "string"
                  }
                },
                "required": [
                  "session_id",
                  "tab_id"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": false,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Switch Tab"
              }
            },
            {
              "name": "browser_batch",
              "description": "Execute a sequence of browser actions in a single call against an existing session.\n\nUse this when you already know the full sequence of steps — it reduces round trips and\nis faster than calling each tool individually.\n\nActions run sequentially and stop at the first failure unless stop_on_error is false.\nEach step result is returned in the results array at the same index.\n\nNote: screenshots in batch results are returned as base64 strings inside the JSON;\nbrowser_screenshot returns them as images.\n\nA batch can include evaluate, so it can change or delete page state the same way\nbrowser_evaluate can.",
              "inputSchema": {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "additionalProperties": false,
                "properties": {
                  "actions": {
                    "description": "Ordered list of actions to perform. Each action has a 'type' field plus type-specific parameters.",
                    "items": {
                      "anyOf": [
                        {
                          "additionalProperties": false,
                          "properties": {
                            "type": {
                              "const": "navigate",
                              "type": "string"
                            },
                            "url": {
                              "format": "uri",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "url"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "type": {
                              "const": "go_back",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "type": {
                              "const": "go_forward",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "type": {
                              "const": "reload",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "selector": {
                              "type": "string"
                            },
                            "type": {
                              "const": "click",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "selector"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "selector": {
                              "type": "string"
                            },
                            "type": {
                              "const": "hover",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "selector"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "clear_first": {
                              "type": [
                                "boolean",
                                "null"
                              ]
                            },
                            "selector": {
                              "type": "string"
                            },
                            "text": {
                              "type": "string"
                            },
                            "type": {
                              "const": "type",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "selector",
                            "text"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "selector": {
                              "type": "string"
                            },
                            "type": {
                              "const": "fill",
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "selector",
                            "value"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "selector": {
                              "type": "string"
                            },
                            "type": {
                              "const": "select",
                              "type": "string"
                            },
                            "value": {
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "selector",
                            "value"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "selector": {
                              "type": "string"
                            },
                            "type": {
                              "const": "check",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "selector"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "selector": {
                              "type": "string"
                            },
                            "type": {
                              "const": "uncheck",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "selector"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "selector": {
                              "type": "string"
                            },
                            "type": {
                              "const": "focus",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "selector"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "key": {
                              "type": "string"
                            },
                            "type": {
                              "const": "press_key",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "key"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "direction": {
                              "enum": [
                                "up",
                                "down",
                                "left",
                                "right"
                              ],
                              "type": "string"
                            },
                            "distance": {
                              "type": [
                                "number",
                                "null"
                              ]
                            },
                            "type": {
                              "const": "scroll",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "direction"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "source_selector": {
                              "type": "string"
                            },
                            "target_selector": {
                              "type": "string"
                            },
                            "type": {
                              "const": "drag",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "source_selector",
                            "target_selector"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "type": {
                              "const": "get_accessibility_tree",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "type": {
                              "const": "get_url",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "type": {
                              "const": "get_title",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "selector": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "type": {
                              "const": "get_text",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "attribute": {
                              "type": "string"
                            },
                            "selector": {
                              "type": "string"
                            },
                            "type": {
                              "const": "get_attribute",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "selector",
                            "attribute"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "selector": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "type": {
                              "const": "get_html",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "selector": {
                              "type": "string"
                            },
                            "type": {
                              "const": "query_selector_all",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "selector"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "full_page": {
                              "type": [
                                "boolean",
                                "null"
                              ]
                            },
                            "selector": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "type": {
                              "const": "screenshot",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "selector": {
                              "type": "string"
                            },
                            "type": {
                              "const": "wait_for_selector",
                              "type": "string"
                            },
                            "visible": {
                              "type": [
                                "boolean",
                                "null"
                              ]
                            }
                          },
                          "required": [
                            "type",
                            "selector"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "type": {
                              "const": "wait_for_navigation",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "ms": {
                              "maximum": 30000,
                              "minimum": 0,
                              "type": "integer"
                            },
                            "type": {
                              "const": "wait",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "ms"
                          ],
                          "type": "object"
                        },
                        {
                          "additionalProperties": false,
                          "properties": {
                            "script": {
                              "type": "string"
                            },
                            "type": {
                              "const": "evaluate",
                              "type": "string"
                            }
                          },
                          "required": [
                            "type",
                            "script"
                          ],
                          "type": "object"
                        }
                      ]
                    },
                    "maxItems": 50,
                    "minItems": 1,
                    "type": "array"
                  },
                  "session_id": {
                    "description": "Session ID returned by browser_navigate",
                    "type": "string"
                  },
                  "stop_on_error": {
                    "description": "Stop executing on the first failed action (default true)",
                    "type": [
                      "boolean",
                      "null"
                    ]
                  }
                },
                "required": [
                  "session_id",
                  "actions"
                ],
                "type": "object"
              },
              "annotations": {
                "destructiveHint": true,
                "openWorldHint": true,
                "readOnlyHint": false,
                "title": "Run Batch of Browser Actions"
              }
            }
          ],
          "schemaTokens": 19354,
          "changedAt": "2026-11-07T01:49:15.931701217Z",
          "check": {
            "checker": "anchor-check/1.0",
            "totalTokens": 19354,
            "counts": {
              "error": 0,
              "note": 1,
              "warn": 4
            },
            "findings": [
              {
                "rule": "TC07",
                "severity": "warn",
                "tool": "batch_create",
                "message": "the description is about 524 tokens",
                "fix": "Keep the description to what a model needs to choose and call the tool; move the manual to a resource or the docs."
              },
              {
                "rule": "TC15",
                "severity": "warn",
                "tool": "batch_create",
                "message": "inputSchema uses $ref/$defs",
                "fix": "Inline the referenced schemas. Pydantic and zod-to-json-schema emit $defs for nested models; most can be told not to."
              },
              {
                "rule": "TC22",
                "severity": "warn",
                "tool": "batch_create",
                "message": "the definition is about 1,814 tokens",
                "fix": "Trim the description and parameter docs, or split the tool."
              },
              {
                "rule": "TC23",
                "severity": "warn",
                "message": "62 tools, about 18,767 tokens of definitions",
                "fix": "Split the server by job, or offer a smaller default toolset (a read-only set, or a search-then-call pattern)."
              },
              {
                "rule": "TC24",
                "severity": "note",
                "message": "62 of 62 tools have no outputSchema",
                "fix": "Declare outputSchema for tools that return structured data, and return structuredContent that matches it."
              }
            ]
          }
        },
        "updatedAt": "2026-11-11T07:00:13.412116543Z"
      },
      "streak": {
        "days": 34,
        "from": "2026-10-08",
        "sinceWatching": true,
        "best": 34
      }
    },
    "edges": [
      {
        "by": 48,
        "category": "reliability",
        "leads": "zenrows",
        "name": "Reliability",
        "reasons": {
          "a": "Hosted lines, graded on the remote MCP server and the REST API at api.nexscope.ai. No status page is linked from the home page, llms.txt, the API quickstart or the MCP map, and none was found (0). With no page there is no incident history to read (5). The pricing page publishes requests a second and concurrency per plan, the same for API and MCP, with 1 and 1 on the trial, 3 and 2 on Starter, 5 and 4 on Growth, 10 and 8 on Pro (15). The quickstart calls 429 an 'execution admission rate limit' and says to honour `Retry-After` on 429 and 503 when present. No idempotency key exists. The repository says 'Do not blindly retry POST requests' and to check whether a task was created before resubmitting, and the MCP tool pages say a reconnecting client should query existing async work rather than resubmit. SoldFetch earned 15 with idempotency keys and SandBase 11 with keys on some writes, so guidance without keys earns 9 (9 of 15). No SLA, and the terms say 'We cannot guarantee the Service will be available at all times' (0). No beta or preview label on the API or the MCP server (10). 0+5+15+9+0+10 = 39.",
          "b": "Better Stack status page with 6 components (Fetch standard, Fetch headless, Proxies, Residential Proxies, Browser Sessions, website) (20). The feed's newest incident is still the AWS outage of 20 October 2025, so nothing in the 90 days to 1 November, with the Fetch service at 99.998 per cent and the website at 100 on 1 November (30). Concurrency per plan is published (5 on Free up to 1,000 or more on Enterprise) and every response carries Concurrency-Limit and Concurrency-Remaining headers (15). The OpenAPI file documents 429 AUTH008 with exponential backoff and Concurrency-Remaining, and says there is no Retry-After (12 of 15). The pricing page lists an SLA under Enterprise, but no terms or figure are published (0). Fetch is generally available. Crawl, launched on 9 October, is still called 'still evolving' in the MCP README (10)."
        },
        "scores": {
          "a": 39,
          "b": 87
        }
      },
      {
        "by": 45,
        "category": "payments",
        "leads": "zenrows",
        "name": "Payments \u0026 pricing",
        "reasons": {
          "a": "No x402, MPP or L402 on pricing, the quickstart, the MCP map, llms.txt or the visible OpenAPI paths. Credits come from a subscription or a Data top-up (0). Plans and credits per plan are public without a login ($29 for 30,000, $55 for 75,000, $129 for 150,000), and tool pages show credits per call, such as Amazon Search from 21 credits with a recent average of 30. Many tools on the MCP map list no cost and pricing is marked 'dynamic-credits'. Manifold earned 20 with a cost for every tool (15 of 20). A Free Trial of 1,000 credits for 3 days with 'No credit card required', API and MCP limits included. Creative API keys need a subscription (20). A person signs in through the browser to approve OAuth or create a key, and no keyless or programmatic route was found (0). 0+15+20+0 = 35.",
          "b": "x402 and MPP through an agent storefront at agents.zenrows.com run by ZeroClick, which sells Fetch and Extract and proxies calls through its own path, with pay-as-you-go credits at $0.50 per 1,000 (10,000 minimum) per the pricing docs. Nothing on api.zenrows.com itself (20 of 40). Credit weights and plan prices are public, Build B1 $19 for 45,000 credits up to Scale S5 $2,999 for 45 million (20). 5,000 free credits a month, no card (20). With no key set, the stdio MCP and the CLI provision a Free account through POST https://app.zenrows.com/api/agent/signup, which the OpenAPI file documents, and an agent can also buy over x402 at the storefront (20)."
        },
        "scores": {
          "a": 35,
          "b": 80
        }
      },
      {
        "by": 38,
        "category": "transparency",
        "leads": "zenrows",
        "name": "Transparency \u0026 trust",
        "reasons": {
          "a": "The editorial half. The service is closed. The terms (8 October 2026) name ECOCREATE TECHNOLOGY PTE. LTD. under Singapore law with no registration number or address. The repository's MIT licence covers client code only, and the documentation and definitions stay copyright Nexscope. Scrapewise earned 15 for closed terms with MIT side code (15 of 30). The privacy policy (8 October 2026) says uploads are not used to train AI models and that connected selling-partner data is deleted or de-identified when no longer needed, but 'this policy does not specify a single deletion deadline for all data', and no DPA was found. SandBase took 12 with no retention periods (10 of 30). No deprecation policy or dated notices. The terms promise notice of material changes before they take effect where practicable, and the MCP map keeps a legacy v1 beside v2 (3 of 20). Analytics and advertising vendors are named (Google Analytics, Microsoft Clarity, Ahrefs, Google Ads, X, FirstPromoter), but hosting, AI processing and payment providers only by type, with no data locations. The repository's source notes say supplier references 'are presented as Nexscope', so the data suppliers go unnamed except LinkFox Agent for 1688 authorisation (5 of 20). 15+10+3+5 = 33. The provenance half is computed from the provenance block.",
          "b": "Closed service, with ZENROWS, S.L. named in full (Getxo, Spain, tax ID B10660298). The MCP is MIT (15 of 30). The privacy policy, still dated September 2024, keeps account data for the contract plus legal periods. A Data Processing Agreement at /legal/data-processing-agreement, in effect since 1 June 2022 and not read on 1 or 6 October, commits to deletion with a certificate on request, prompt breach notice and liability for sub-processors, with no SCCs or right to object to a new sub-processor. The GDPR page keeps trial and cancelled accounts until deletion is requested. Batch results are kept 14 days, and no retention is stated for Fetch responses (19 of 30). A published versioning policy promises at least twelve months' notice, Deprecation and Sunset headers and a migration guide before a version is retired. The 2026 renames carried no dated notices (15 of 20). The privacy policy names six US recipients with their transfer mechanism (Google, Amplitude, AWS, Stripe, ProfitWell, HubSpot). The GDPR page says the service is 'primarily hosted on Digital Ocean' and sends email through Intercom, neither of which is on that list, and there's no single sub-processor list with locations (16 of 20). 15+19+15+16 = 65."
        },
        "scores": {
          "a": 41,
          "b": 79
        }
      },
      {
        "by": 35,
        "category": "ergonomics",
        "leads": "zenrows",
        "name": "Agent ergonomics",
        "reasons": {
          "a": "Read on the MCP server, with the REST API where a line covers it. The MCP map lists 382 tools and says the category manifests 'narrow metadata for your integration; the MCP connection still advertises the full catalog'. That is more than 30 tools with no toolsets, dynamic loading or read-only subset found (5). Search tools page by `page` (about 20 results), with filters such as marketplace, category node, sort and device per tool, but no general pagination model or field selection, and output size depends on each tool (12 of 20). By default business errors answer HTTP 200 with an outer `code`. The `X-Nexscope-Http-Status: semantic` header maps them to HTTP statuses, the OpenAPI file names codes such as `DATA_IMAGE_DOWNLOAD_FAILED` and `CAPABILITY_BACKEND_UNAVAILABLE` in field text, and MCP errors aren't documented. SandBase earned 16 with typed bridge errors (11 of 20). Data calls only read. No idempotency keys and no readOnlyHint or destructiveHint documented. Async jobs return a `taskId` with a poll tool and a rule not to resubmit, and 1688 order, payment-link, receipt and cancel calls need an explicit JSON `true` confirmation (8 of 20). Few required parameters with defaults on most. No official SDK package, only standard-library clients in the repository for JavaScript and Python, which SoldFetch earned 8 for (8 of 15). 5+12+11+8+8 = 44.",
          "b": "63 MCP tools on 1 November, up from 52 on 17 October, after v2.15.0 to v2.18.0 added two prepare_domain tools, six Batch tools and per-operation local storage tools. 38 are browser actions, and there are no toolsets. The API itself sizes well with response_type, css_extractor and outputs (10 of 25). Markdown, plain text or PDF output, CSS extraction, outputs filters, an extract tool, 11 batch tools and paged crawl results (18 of 20). Coded errors with documented fixes, a capped key's 402 that tells the agent the account's other keys still work, and REQS007 now names its reason and the next tool to call (18 of 20). Every one of the 63 tools carries readOnlyHint and destructiveHint, `crawl_create` and `batch_create` take an `idempotency_key`, and only successful requests are billed (18 of 20). mode=auto picks the setup and url is the only required field. Official Python and Node SDKs (15)."
        },
        "scores": {
          "a": 44,
          "b": 79
        }
      },
      {
        "by": 29,
        "category": "schema",
        "leads": "zenrows",
        "name": "Schema \u0026 documentation",
        "reasons": {
          "a": "A public OpenAPI 3.1 file at api.nexscope.ai/openapi.json, about 3.8 MB, linked from the quickstart. Visible request bodies are typed with required fields, patterns, enums and `additionalProperties: false`, but responses are open `data` objects and the components section, with the security scheme and the shared error response, wasn't reached. In the repository 166 of 252 request definitions are field descriptors rather than JSON Schema. The hosted tools/list wasn't read. SoldFetch took 17 with untyped responses and SandBase 22 with components unread (19 of 25). llms.txt on www.nexscope.ai and Markdown references for every API in the repository (10). MCP tool descriptions are one line ('Find Amazon products by keyword and marketplace. Results come back as structured JSON.'), with no when-not-to-use. The repository's references carry long trigger text ('trigger this skill whenever their need involves real-time Amazon search results'), not guidance on when to pick another tool (10 of 20). Tool pages list types, defaults, enums and length limits, but the Amazon Search page marks no argument required and omits the `keyword` its own examples pass, and many limits sit in prose (8 of 15). Every API has a request sample, a response fixture and cURL, JavaScript and Python clients, though most fixtures are labelled historical. Errors are an HTTP table, two named codes (11209, 12001) and a semantic error response whose schema wasn't read. MCP errors aren't documented (10 of 15). Path versioning under /v1, MCP v2 beside a legacy v1, and a dated OpenAPI version label, but no public changelog. SandBase earned 7 on the same pattern (7 of 15). 19+10+10+8+10+7 = 64.",
          "b": "OpenAPI 3.1 at www.zenrows.com/openapi.json covers Fetch, Extract, Crawl (added after the 9 October launch), Batch, agent signup and HMAC key rotation, and the 63 MCP tools have typed zod inputs (25). llms.txt with 105 entries linking 240 docs pages on 1 November, each with a Markdown copy (10). The scrape tool says when to prefer extract, when to turn on js_render or premium_proxy, and gives three examples, and the crawl tools say when to wait, page or download. The browser tools are terser (18 of 20). Enums on mode and response_type, URL validation and required fields, but css_extractor is a JSON string and outputs a comma-separated string (12 of 15). Error catalogue of 35 codes such as AUTH004 and RESP002, plus a table of Batch and Extract codes, grouped by HTTP status with fixes, and every OpenAPI operation lists its error responses (15). The API is versioned in the path (v1, never retired), a dated changelog at www.zenrows.com/changelog runs to 9 October 2026, with nothing newer on 1 November, and the MCP has semver tags. The 2026 renames (Universal Scraper API to Fetch, Scraping Browser to Browser Sessions) aren't in it (13 of 15)."
        },
        "scores": {
          "a": 64,
          "b": 93
        }
      },
      {
        "by": 25,
        "category": "maintenance",
        "leads": "zenrows",
        "name": "Maintenance \u0026 community",
        "reasons": {
          "a": "Read as a closed service with a public documentation repository. The repository synced the released 1688 procurement contracts on 9 November 2026 and committed again on 10 November (30). No releases or changelog. The dated record is the registry's four versions on 14 and 16 October, repository commits on 8, 9, 20 and 29 October and 2, 9 and 10 November, and source notes dating WooCommerce (29 October) and design search (2 November) additions. SoldFetch earned 10 for dated commits without releases (10 of 20). No public changelog. Support is service@nexscope.ai, WhatsApp and a booked call, untested. The repository's one merged pull request came from the organisation itself, and GitHub's API refused us, so issues weren't read (5 of 15). The official MCP registry lists `io.github.nexscope/ecommerce`, active, latest 1.0.3 of 16 October 2026, read first-hand (15). A CI workflow runs offline catalogue validation and unit tests on standard-library clients with no dependencies. The run results weren't read (5 of 10). 30+10+5+15+5 = 65.",
          "b": "MCP v2.18.0 on 2026-10-30 (30). Seven MCP minor releases from 18 to 30 October alone (v2.12.0 to v2.18.0), and dated changelog entries on 2, 5 and 9 October (20). We couldn't read GitHub issues. PRs are merged within days and the dated changelog on zenrows.com runs to 9 October (15 of 25). In the official MCP registry as io.github.ZenRows/zenrows-mcp, with 2.18.0 published on 30 October and marked latest (15). CI runs typecheck, lint and tests on a Node matrix, and a check that server.json matches the package version (10)."
        },
        "scores": {
          "a": 65,
          "b": 90
        }
      }
    ],
    "facts": [
      {
        "a": "Platform",
        "b": "HTTP API",
        "name": "Kind"
      },
      {
        "a": "ECOCREATE TECHNOLOGY PTE. LTD.",
        "b": "ZenRows",
        "name": "Vendor"
      },
      {
        "a": "https://api.nexscope.ai/mcp",
        "b": "https://api.zenrows.com/v1/",
        "name": "Hosted endpoint"
      },
      {
        "a": "Streamable HTTP, HTTP",
        "b": "HTTP, Streamable HTTP, stdio",
        "name": "Transports"
      },
      {
        "a": "OAuth or key",
        "b": "OAuth or key",
        "name": "Auth"
      },
      {
        "a": "Paid",
        "b": "Freemium",
        "name": "Pricing"
      },
      {
        "a": "no",
        "b": "payer tooling only",
        "name": "x402"
      },
      {
        "a": "Proprietary hosted service under the Nexscope terms (last updated 8 October 2026), whose contracting party is ECOCREATE TECHNOLOGY PTE. LTD. of Singapore. The OpenAPI file's licence is 'Proprietary API; use subject to Nexscope Terms'. In github.com/nexscope-ai/nexscope-ecommerce-api only the example clients, validation scripts, tests and workflow are MIT. The API documentation, catalogue, definitions and sample data stay copyright Nexscope",
        "b": "none",
        "name": "Licence"
      },
      {
        "a": "382",
        "b": "63",
        "name": "Tools exposed"
      },
      {
        "a": "no",
        "b": "no",
        "name": "Read-only variant documented"
      },
      {
        "a": "yes",
        "b": "yes",
        "name": "llms.txt"
      },
      {
        "a": "io.github.nexscope/ecommerce",
        "b": "io.github.ZenRows/zenrows-mcp",
        "name": "MCP registry"
      },
      {
        "a": "2026-11-09",
        "b": "2026-10-30",
        "name": "Last release"
      },
      {
        "a": "not read yet",
        "b": "2025-07-01",
        "name": "Terms last updated"
      },
      {
        "a": "not read yet",
        "b": "2024-09-01",
        "name": "Privacy policy last updated"
      },
      {
        "a": "not read yet",
        "b": "not found in the text",
        "name": "Customer content may train models"
      },
      {
        "a": "not read yet",
        "b": "not found in the text",
        "name": "Terms restrict automated access"
      },
      {
        "a": "not read yet",
        "b": "not found in the text",
        "name": "Terms restrict benchmarking"
      },
      {
        "a": "not read yet",
        "b": "yes",
        "name": "Terms or service can change without notice"
      },
      {
        "a": "not read yet",
        "b": "not found in the text",
        "name": "Arbitration or class-action waiver"
      },
      {
        "a": "none",
        "b": "21 stars, 35k npm/wk",
        "name": "Popularity"
      },
      {
        "a": "none",
        "b": "3.8/5 (8)",
        "name": "Agent reviews"
      }
    ],
    "faq": [
      {
        "answer": "ZenRows scores 75.9 (BB) on agent readiness against Nexscope's 46.2 (D), and leads in every scored category.",
        "question": "Which is better for AI agents, Nexscope or ZenRows?"
      },
      {
        "answer": "Yes. Nexscope has a hosted endpoint at https://api.nexscope.ai/mcp and ZenRows at https://api.zenrows.com/v1/.",
        "question": "Can an agent call Nexscope and ZenRows without installing anything?"
      }
    ],
    "goodFor": [
      {
        "aheadOn": null,
        "also": [
          "No incidents deducted, where ZenRows loses 3 points for them"
        ],
        "goodFor": "Agents that research ecommerce products, competitors, keywords, sourcing and patents across Amazon, TikTok Shop, Walmart, Temu, 1688 and other marketplaces, and that also make listing images and video, on one credit balance.",
        "slug": "nexscope",
        "watchFor": "The MCP connection advertises the full catalogue of 382 tools, with no toolsets or read-only subset"
      },
      {
        "aheadOn": [
          "Reliability, 87 against 39",
          "Schema \u0026 documentation, 93 against 64",
          "Agent ergonomics, 79 against 44",
          "Security \u0026 auth, 50 against 41",
          "Payments \u0026 pricing, 80 against 35",
          "Maintenance \u0026 community, 90 against 65",
          "Transparency \u0026 trust, 79 against 41"
        ],
        "also": [
          "Agent-ready, a grade of BB or better",
          "Runs on your own machine"
        ],
        "goodFor": "An agent hitting protected sites that wants the service to choose the setup and bill only success, and for agents that must onboard without a human.",
        "slug": "zenrows",
        "watchFor": "The Fetch API only takes the key in the query string"
      }
    ],
    "history": {
      "nexscope": null,
      "zenrows": [
        {
          "causes": [
            "event"
          ],
          "date": "2026-11-01",
          "delta": -3,
          "from": 78.9,
          "fromGrade": "A",
          "to": 75.9,
          "toGrade": "BB"
        },
        {
          "causes": [
            "method"
          ],
          "date": "2026-10-27",
          "delta": 0.1,
          "from": 78.8,
          "fromGrade": "A",
          "to": 78.9,
          "toGrade": "A"
        },
        {
          "causes": [
            "product",
            "evidence"
          ],
          "date": "2026-10-17",
          "delta": 4,
          "from": 74.8,
          "fromGrade": "BB",
          "to": 78.8,
          "toGrade": "A"
        }
      ]
    },
    "job": {
      "capability": "web.extract",
      "name": "Extraction"
    },
    "others": [
      {
        "json": "https://www.anchorterminal.com/compare/apify-mcp-vs-zenrows.json",
        "title": "Apify MCP Server vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/apify-mcp-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/bright-data-vs-zenrows.json",
        "title": "Bright Data vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/bright-data-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/browseract-vs-zenrows.json",
        "title": "BrowserAct vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/browseract-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/context-dev-vs-zenrows.json",
        "title": "Context.dev vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/context-dev-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/crawl4ai-vs-zenrows.json",
        "title": "Crawl4AI vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/crawl4ai-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/crw-vs-zenrows.json",
        "title": "fastCRW vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/crw-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/decodo-vs-zenrows.json",
        "title": "Decodo Web Data API vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/decodo-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/jevcrawl-vs-zenrows.json",
        "title": "jevcrawl vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/jevcrawl-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/jina-reader-vs-zenrows.json",
        "title": "Jina Reader vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/jina-reader-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/microlink-vs-zenrows.json",
        "title": "Microlink vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/microlink-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/olostep-vs-zenrows.json",
        "title": "Olostep vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/olostep-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/outcrawl-vs-zenrows.json",
        "title": "Outcrawl vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/outcrawl-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/oxylabs-web-scraper-vs-zenrows.json",
        "title": "Oxylabs Web Scraper API vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/oxylabs-web-scraper-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/scrape-do-vs-zenrows.json",
        "title": "Scrape.do vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/scrape-do-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/scrapegraphai-vs-zenrows.json",
        "title": "ScrapeGraphAI vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/scrapegraphai-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/scrapeless-vs-zenrows.json",
        "title": "Scrapeless vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/scrapeless-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/scraperapi-vs-zenrows.json",
        "title": "ScraperAPI vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/scraperapi-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/scrapewise-vs-zenrows.json",
        "title": "Scrapewise vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/scrapewise-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/scrapfly-vs-zenrows.json",
        "title": "Scrapfly vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/scrapfly-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/scrapingant-vs-zenrows.json",
        "title": "ScrapingAnt vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/scrapingant-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/scrapingbee-vs-zenrows.json",
        "title": "ScrapingBee vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/scrapingbee-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/scrapingdog-vs-zenrows.json",
        "title": "Scrapingdog vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/scrapingdog-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/spider-cloud-vs-zenrows.json",
        "title": "Spider vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/spider-cloud-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/webscraping-ai-vs-zenrows.json",
        "title": "WebScraping.AI vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/webscraping-ai-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/zenrows-vs-zyte.json",
        "title": "ZenRows vs Zyte API",
        "url": "https://www.anchorterminal.com/compare/zenrows-vs-zyte"
      },
      {
        "json": "https://www.anchorterminal.com/compare/browseract-vs-nexscope.json",
        "title": "BrowserAct vs Nexscope",
        "url": "https://www.anchorterminal.com/compare/browseract-vs-nexscope"
      },
      {
        "json": "https://www.anchorterminal.com/compare/context-dev-vs-nexscope.json",
        "title": "Context.dev vs Nexscope",
        "url": "https://www.anchorterminal.com/compare/context-dev-vs-nexscope"
      },
      {
        "json": "https://www.anchorterminal.com/compare/crawl4ai-vs-nexscope.json",
        "title": "Crawl4AI vs Nexscope",
        "url": "https://www.anchorterminal.com/compare/crawl4ai-vs-nexscope"
      },
      {
        "json": "https://www.anchorterminal.com/compare/crw-vs-nexscope.json",
        "title": "fastCRW vs Nexscope",
        "url": "https://www.anchorterminal.com/compare/crw-vs-nexscope"
      },
      {
        "json": "https://www.anchorterminal.com/compare/decodo-vs-nexscope.json",
        "title": "Decodo Web Data API vs Nexscope",
        "url": "https://www.anchorterminal.com/compare/decodo-vs-nexscope"
      },
      {
        "json": "https://www.anchorterminal.com/compare/diffbot-vs-nexscope.json",
        "title": "Diffbot vs Nexscope",
        "url": "https://www.anchorterminal.com/compare/diffbot-vs-nexscope"
      },
      {
        "json": "https://www.anchorterminal.com/compare/diffbot-vs-zenrows.json",
        "title": "Diffbot vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/diffbot-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/firecrawl-mcp-vs-nexscope.json",
        "title": "Firecrawl MCP vs Nexscope",
        "url": "https://www.anchorterminal.com/compare/firecrawl-mcp-vs-nexscope"
      },
      {
        "json": "https://www.anchorterminal.com/compare/firecrawl-mcp-vs-zenrows.json",
        "title": "Firecrawl MCP vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/firecrawl-mcp-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/jevcrawl-vs-nexscope.json",
        "title": "jevcrawl vs Nexscope",
        "url": "https://www.anchorterminal.com/compare/jevcrawl-vs-nexscope"
      },
      {
        "json": "https://www.anchorterminal.com/compare/microlink-vs-nexscope.json",
        "title": "Microlink vs Nexscope",
        "url": "https://www.anchorterminal.com/compare/microlink-vs-nexscope"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-olostep.json",
        "title": "Nexscope vs Olostep",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-olostep"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-outcrawl.json",
        "title": "Nexscope vs Outcrawl",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-outcrawl"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-oxylabs-web-scraper.json",
        "title": "Nexscope vs Oxylabs Web Scraper API",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-oxylabs-web-scraper"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-printfriendly-mcp.json",
        "title": "Nexscope vs PrintFriendly MCP server",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-printfriendly-mcp"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-qovia.json",
        "title": "Nexscope vs Qovia",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-qovia"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-scrapeatlas.json",
        "title": "Nexscope vs ScrapeAtlas",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-scrapeatlas"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-scrapegraphai.json",
        "title": "Nexscope vs ScrapeGraphAI",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-scrapegraphai"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-scrapeops.json",
        "title": "Nexscope vs ScrapeOps Proxy API Aggregator",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-scrapeops"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-scraperapi.json",
        "title": "Nexscope vs ScraperAPI",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-scraperapi"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-scrapewise.json",
        "title": "Nexscope vs Scrapewise",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-scrapewise"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-scrapfly.json",
        "title": "Nexscope vs Scrapfly",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-scrapfly"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-scrapingant.json",
        "title": "Nexscope vs ScrapingAnt",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-scrapingant"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-scrapingbee.json",
        "title": "Nexscope vs ScrapingBee",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-scrapingbee"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-scrapingdog.json",
        "title": "Nexscope vs Scrapingdog",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-scrapingdog"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-soldfetch.json",
        "title": "Nexscope vs SoldFetch",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-soldfetch"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-spider-cloud.json",
        "title": "Nexscope vs Spider",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-spider-cloud"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-webscraping-ai.json",
        "title": "Nexscope vs WebScraping.AI",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-webscraping-ai"
      },
      {
        "json": "https://www.anchorterminal.com/compare/nexscope-vs-zyte.json",
        "title": "Nexscope vs Zyte API",
        "url": "https://www.anchorterminal.com/compare/nexscope-vs-zyte"
      },
      {
        "json": "https://www.anchorterminal.com/compare/qovia-vs-zenrows.json",
        "title": "Qovia vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/qovia-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/scrapeatlas-vs-zenrows.json",
        "title": "ScrapeAtlas vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/scrapeatlas-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/soldfetch-vs-zenrows.json",
        "title": "SoldFetch vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/soldfetch-vs-zenrows"
      },
      {
        "json": "https://www.anchorterminal.com/compare/scrapeops-vs-zenrows.json",
        "title": "ScrapeOps Proxy API Aggregator vs ZenRows",
        "url": "https://www.anchorterminal.com/compare/scrapeops-vs-zenrows"
      }
    ],
    "panel": null,
    "scores": [
      {
        "by": 48,
        "edge": "zenrows",
        "key": "reliability",
        "name": "Reliability",
        "nexscope": 39,
        "weight": 16,
        "zenrows": 87
      },
      {
        "key": "performance",
        "name": "Performance",
        "pending": true,
        "weight": 10
      },
      {
        "by": 29,
        "edge": "zenrows",
        "key": "schema",
        "name": "Schema \u0026 documentation",
        "nexscope": 64,
        "weight": 13,
        "zenrows": 93
      },
      {
        "by": 35,
        "edge": "zenrows",
        "key": "ergonomics",
        "name": "Agent ergonomics",
        "nexscope": 44,
        "weight": 13,
        "zenrows": 79
      },
      {
        "by": 9,
        "edge": "zenrows",
        "key": "security",
        "name": "Security \u0026 auth",
        "nexscope": 41,
        "weight": 14,
        "zenrows": 50
      },
      {
        "by": 45,
        "edge": "zenrows",
        "key": "payments",
        "name": "Payments \u0026 pricing",
        "nexscope": 35,
        "weight": 10,
        "zenrows": 80
      },
      {
        "key": "tasks",
        "name": "Task success",
        "pending": true,
        "weight": 10
      },
      {
        "by": 25,
        "edge": "zenrows",
        "key": "maintenance",
        "name": "Maintenance \u0026 community",
        "nexscope": 65,
        "weight": 7,
        "zenrows": 90
      },
      {
        "by": 38,
        "edge": "zenrows",
        "key": "transparency",
        "name": "Transparency \u0026 trust",
        "nexscope": 41,
        "weight": 7,
        "zenrows": 79
      }
    ],
    "summary": "ZenRows scores 75.9 (BB) on agent readiness against Nexscope's 46.2 (D), and leads in every scored category. Both do extraction.",
    "tasks": null,
    "tutorials": [
      {
        "title": "Extract page titles and links with ZenRows",
        "tool": "zenrows",
        "url": "https://www.anchorterminal.com/tutorials/zenrows/"
      }
    ],
    "verdicts": {
      "nexscope": "An agent can reach Amazon, TikTok Shop, Temu, 1688 and other marketplace data, plus image and video models, on one credit balance through a remote MCP server with OAuth or a REST API with a public OpenAPI file. The connection loads 382 tools at once, and there is no status page, changelog or idempotency key.",
      "zenrows": "No incidents in the 90 days to 1 November 2026 on a six-component Better Stack status page, and an OpenAPI 3.1 file with coded errors. The Fetch API only takes the key in the query string."
    }
  },
  "kind": "anchor.page",
  "links": {
    "api": "https://www.anchorterminal.com/api/v1/index.json",
    "html": "https://www.anchorterminal.com/compare/nexscope-vs-zenrows",
    "json": "https://www.anchorterminal.com/compare/nexscope-vs-zenrows.json",
    "llms": "https://www.anchorterminal.com/llms.txt",
    "markdown": "https://www.anchorterminal.com/compare/nexscope-vs-zenrows.md",
    "mcp": "https://www.anchorterminal.com/mcp",
    "slim": "https://www.anchorterminal.com/compare/nexscope-vs-zenrows.min.md"
  },
  "markdown": "ZenRows scores 75.9 (BB) on agent readiness against Nexscope's 46.2 (D), and leads in every scored category. Both do extraction.\n\n- Nexscope: grade D, 46.2/100, rank #1191 of 1520. Markdown https://www.anchorterminal.com/tools/nexscope.md · JSON https://www.anchorterminal.com/api/v1/tools/nexscope.json\n- ZenRows: grade BB, 75.9/100, rank #53 of 1520. Markdown https://www.anchorterminal.com/tools/zenrows.md · JSON https://www.anchorterminal.com/api/v1/tools/zenrows.json\n- Best web scraping and crawling APIs for AI agents: https://www.anchorterminal.com/best/web-scrapers/index.md\n- All 533 scrapers comparisons: https://www.anchorterminal.com/compare/web-scrapers/index.md\n\n## Which one, for what\n\n### Nexscope (D)\n\nGood for: Agents that research ecommerce products, competitors, keywords, sourcing and patents across Amazon, TikTok Shop, Walmart, Temu, 1688 and other marketplaces, and that also make listing images and video, on one credit balance.\n\nAlso in its favour:\n- No incidents deducted, where ZenRows loses 3 points for them\n\nWatch for: The MCP connection advertises the full catalogue of 382 tools, with no toolsets or read-only subset\n\n### ZenRows (BB)\n\nGood for: An agent hitting protected sites that wants the service to choose the setup and bill only success, and for agents that must onboard without a human.\n\nAhead on:\n- Reliability, 87 against 39\n- Schema \u0026 documentation, 93 against 64\n- Agent ergonomics, 79 against 44\n- Security \u0026 auth, 50 against 41\n- Payments \u0026 pricing, 80 against 35\n- Maintenance \u0026 community, 90 against 65\n- Transparency \u0026 trust, 79 against 41\n\nAlso in its favour:\n- Agent-ready, a grade of BB or better\n- Runs on your own machine\n\nWatch for: The Fetch API only takes the key in the query string\n\n\n## Why the edge\n\n### Reliability: ZenRows +48\n\n- Nexscope (39): Hosted lines, graded on the remote MCP server and the REST API at api.nexscope.ai. No status page is linked from the home page, llms.txt, the API quickstart or the MCP map, and none was found (0). With no page there is no incident history to read (5). The pricing page publishes requests a second and concurrency per plan, the same for API and MCP, with 1 and 1 on the trial, 3 and 2 on Starter, 5 and 4 on Growth, 10 and 8 on Pro (15). The quickstart calls 429 an 'execution admission rate limit' and says to honour `Retry-After` on 429 and 503 when present. No idempotency key exists. The repository says 'Do not blindly retry POST requests' and to check whether a task was created before resubmitting, and the MCP tool pages say a reconnecting client should query existing async work rather than resubmit. SoldFetch earned 15 with idempotency keys and SandBase 11 with keys on some writes, so guidance without keys earns 9 (9 of 15). No SLA, and the terms say 'We cannot guarantee the Service will be available at all times' (0). No beta or preview label on the API or the MCP server (10). 0+5+15+9+0+10 = 39.\n- ZenRows (87): Better Stack status page with 6 components (Fetch standard, Fetch headless, Proxies, Residential Proxies, Browser Sessions, website) (20). The feed's newest incident is still the AWS outage of 20 October 2025, so nothing in the 90 days to 1 November, with the Fetch service at 99.998 per cent and the website at 100 on 1 November (30). Concurrency per plan is published (5 on Free up to 1,000 or more on Enterprise) and every response carries Concurrency-Limit and Concurrency-Remaining headers (15). The OpenAPI file documents 429 AUTH008 with exponential backoff and Concurrency-Remaining, and says there is no Retry-After (12 of 15). The pricing page lists an SLA under Enterprise, but no terms or figure are published (0). Fetch is generally available. Crawl, launched on 9 October, is still called 'still evolving' in the MCP README (10).\n\n### Payments \u0026 pricing: ZenRows +45\n\n- Nexscope (35): No x402, MPP or L402 on pricing, the quickstart, the MCP map, llms.txt or the visible OpenAPI paths. Credits come from a subscription or a Data top-up (0). Plans and credits per plan are public without a login ($29 for 30,000, $55 for 75,000, $129 for 150,000), and tool pages show credits per call, such as Amazon Search from 21 credits with a recent average of 30. Many tools on the MCP map list no cost and pricing is marked 'dynamic-credits'. Manifold earned 20 with a cost for every tool (15 of 20). A Free Trial of 1,000 credits for 3 days with 'No credit card required', API and MCP limits included. Creative API keys need a subscription (20). A person signs in through the browser to approve OAuth or create a key, and no keyless or programmatic route was found (0). 0+15+20+0 = 35.\n- ZenRows (80): x402 and MPP through an agent storefront at agents.zenrows.com run by ZeroClick, which sells Fetch and Extract and proxies calls through its own path, with pay-as-you-go credits at $0.50 per 1,000 (10,000 minimum) per the pricing docs. Nothing on api.zenrows.com itself (20 of 40). Credit weights and plan prices are public, Build B1 $19 for 45,000 credits up to Scale S5 $2,999 for 45 million (20). 5,000 free credits a month, no card (20). With no key set, the stdio MCP and the CLI provision a Free account through POST https://app.zenrows.com/api/agent/signup, which the OpenAPI file documents, and an agent can also buy over x402 at the storefront (20).\n\n### Transparency \u0026 trust: ZenRows +38\n\n- Nexscope (41): The editorial half. The service is closed. The terms (8 October 2026) name ECOCREATE TECHNOLOGY PTE. LTD. under Singapore law with no registration number or address. The repository's MIT licence covers client code only, and the documentation and definitions stay copyright Nexscope. Scrapewise earned 15 for closed terms with MIT side code (15 of 30). The privacy policy (8 October 2026) says uploads are not used to train AI models and that connected selling-partner data is deleted or de-identified when no longer needed, but 'this policy does not specify a single deletion deadline for all data', and no DPA was found. SandBase took 12 with no retention periods (10 of 30). No deprecation policy or dated notices. The terms promise notice of material changes before they take effect where practicable, and the MCP map keeps a legacy v1 beside v2 (3 of 20). Analytics and advertising vendors are named (Google Analytics, Microsoft Clarity, Ahrefs, Google Ads, X, FirstPromoter), but hosting, AI processing and payment providers only by type, with no data locations. The repository's source notes say supplier references 'are presented as Nexscope', so the data suppliers go unnamed except LinkFox Agent for 1688 authorisation (5 of 20). 15+10+3+5 = 33. The provenance half is computed from the provenance block.\n- ZenRows (79): Closed service, with ZENROWS, S.L. named in full (Getxo, Spain, tax ID B10660298). The MCP is MIT (15 of 30). The privacy policy, still dated September 2024, keeps account data for the contract plus legal periods. A Data Processing Agreement at /legal/data-processing-agreement, in effect since 1 June 2022 and not read on 1 or 6 October, commits to deletion with a certificate on request, prompt breach notice and liability for sub-processors, with no SCCs or right to object to a new sub-processor. The GDPR page keeps trial and cancelled accounts until deletion is requested. Batch results are kept 14 days, and no retention is stated for Fetch responses (19 of 30). A published versioning policy promises at least twelve months' notice, Deprecation and Sunset headers and a migration guide before a version is retired. The 2026 renames carried no dated notices (15 of 20). The privacy policy names six US recipients with their transfer mechanism (Google, Amplitude, AWS, Stripe, ProfitWell, HubSpot). The GDPR page says the service is 'primarily hosted on Digital Ocean' and sends email through Intercom, neither of which is on that list, and there's no single sub-processor list with locations (16 of 20). 15+19+15+16 = 65.\n\n### Agent ergonomics: ZenRows +35\n\n- Nexscope (44): Read on the MCP server, with the REST API where a line covers it. The MCP map lists 382 tools and says the category manifests 'narrow metadata for your integration; the MCP connection still advertises the full catalog'. That is more than 30 tools with no toolsets, dynamic loading or read-only subset found (5). Search tools page by `page` (about 20 results), with filters such as marketplace, category node, sort and device per tool, but no general pagination model or field selection, and output size depends on each tool (12 of 20). By default business errors answer HTTP 200 with an outer `code`. The `X-Nexscope-Http-Status: semantic` header maps them to HTTP statuses, the OpenAPI file names codes such as `DATA_IMAGE_DOWNLOAD_FAILED` and `CAPABILITY_BACKEND_UNAVAILABLE` in field text, and MCP errors aren't documented. SandBase earned 16 with typed bridge errors (11 of 20). Data calls only read. No idempotency keys and no readOnlyHint or destructiveHint documented. Async jobs return a `taskId` with a poll tool and a rule not to resubmit, and 1688 order, payment-link, receipt and cancel calls need an explicit JSON `true` confirmation (8 of 20). Few required parameters with defaults on most. No official SDK package, only standard-library clients in the repository for JavaScript and Python, which SoldFetch earned 8 for (8 of 15). 5+12+11+8+8 = 44.\n- ZenRows (79): 63 MCP tools on 1 November, up from 52 on 17 October, after v2.15.0 to v2.18.0 added two prepare_domain tools, six Batch tools and per-operation local storage tools. 38 are browser actions, and there are no toolsets. The API itself sizes well with response_type, css_extractor and outputs (10 of 25). Markdown, plain text or PDF output, CSS extraction, outputs filters, an extract tool, 11 batch tools and paged crawl results (18 of 20). Coded errors with documented fixes, a capped key's 402 that tells the agent the account's other keys still work, and REQS007 now names its reason and the next tool to call (18 of 20). Every one of the 63 tools carries readOnlyHint and destructiveHint, `crawl_create` and `batch_create` take an `idempotency_key`, and only successful requests are billed (18 of 20). mode=auto picks the setup and url is the only required field. Official Python and Node SDKs (15).\n\n### Schema \u0026 documentation: ZenRows +29\n\n- Nexscope (64): A public OpenAPI 3.1 file at api.nexscope.ai/openapi.json, about 3.8 MB, linked from the quickstart. Visible request bodies are typed with required fields, patterns, enums and `additionalProperties: false`, but responses are open `data` objects and the components section, with the security scheme and the shared error response, wasn't reached. In the repository 166 of 252 request definitions are field descriptors rather than JSON Schema. The hosted tools/list wasn't read. SoldFetch took 17 with untyped responses and SandBase 22 with components unread (19 of 25). llms.txt on www.nexscope.ai and Markdown references for every API in the repository (10). MCP tool descriptions are one line ('Find Amazon products by keyword and marketplace. Results come back as structured JSON.'), with no when-not-to-use. The repository's references carry long trigger text ('trigger this skill whenever their need involves real-time Amazon search results'), not guidance on when to pick another tool (10 of 20). Tool pages list types, defaults, enums and length limits, but the Amazon Search page marks no argument required and omits the `keyword` its own examples pass, and many limits sit in prose (8 of 15). Every API has a request sample, a response fixture and cURL, JavaScript and Python clients, though most fixtures are labelled historical. Errors are an HTTP table, two named codes (11209, 12001) and a semantic error response whose schema wasn't read. MCP errors aren't documented (10 of 15). Path versioning under /v1, MCP v2 beside a legacy v1, and a dated OpenAPI version label, but no public changelog. SandBase earned 7 on the same pattern (7 of 15). 19+10+10+8+10+7 = 64.\n- ZenRows (93): OpenAPI 3.1 at www.zenrows.com/openapi.json covers Fetch, Extract, Crawl (added after the 9 October launch), Batch, agent signup and HMAC key rotation, and the 63 MCP tools have typed zod inputs (25). llms.txt with 105 entries linking 240 docs pages on 1 November, each with a Markdown copy (10). The scrape tool says when to prefer extract, when to turn on js_render or premium_proxy, and gives three examples, and the crawl tools say when to wait, page or download. The browser tools are terser (18 of 20). Enums on mode and response_type, URL validation and required fields, but css_extractor is a JSON string and outputs a comma-separated string (12 of 15). Error catalogue of 35 codes such as AUTH004 and RESP002, plus a table of Batch and Extract codes, grouped by HTTP status with fixes, and every OpenAPI operation lists its error responses (15). The API is versioned in the path (v1, never retired), a dated changelog at www.zenrows.com/changelog runs to 9 October 2026, with nothing newer on 1 November, and the MCP has semver tags. The 2026 renames (Universal Scraper API to Fetch, Scraping Browser to Browser Sessions) aren't in it (13 of 15).\n\n### Maintenance \u0026 community: ZenRows +25\n\n- Nexscope (65): Read as a closed service with a public documentation repository. The repository synced the released 1688 procurement contracts on 9 November 2026 and committed again on 10 November (30). No releases or changelog. The dated record is the registry's four versions on 14 and 16 October, repository commits on 8, 9, 20 and 29 October and 2, 9 and 10 November, and source notes dating WooCommerce (29 October) and design search (2 November) additions. SoldFetch earned 10 for dated commits without releases (10 of 20). No public changelog. Support is service@nexscope.ai, WhatsApp and a booked call, untested. The repository's one merged pull request came from the organisation itself, and GitHub's API refused us, so issues weren't read (5 of 15). The official MCP registry lists `io.github.nexscope/ecommerce`, active, latest 1.0.3 of 16 October 2026, read first-hand (15). A CI workflow runs offline catalogue validation and unit tests on standard-library clients with no dependencies. The run results weren't read (5 of 10). 30+10+5+15+5 = 65.\n- ZenRows (90): MCP v2.18.0 on 2026-10-30 (30). Seven MCP minor releases from 18 to 30 October alone (v2.12.0 to v2.18.0), and dated changelog entries on 2, 5 and 9 October (20). We couldn't read GitHub issues. PRs are merged within days and the dated changelog on zenrows.com runs to 9 October (15 of 25). In the official MCP registry as io.github.ZenRows/zenrows-mcp, with 2.18.0 published on 30 October and marked latest (15). CI runs typecheck, lint and tests on a Node matrix, and a check that server.json matches the package version (10).\n\n## Score by category\n\n| Category | Weight | Nexscope | ZenRows | Edge |\n| --- | --- | --- | --- | --- |\n| Reliability | 16% (20 this run) | 39 | 87 | ZenRows +48 |\n| Performance | 10%, pending | pending | pending | not scored in this run |\n| Schema \u0026 documentation | 13% (16.2 this run) | 64 | 93 | ZenRows +29 |\n| Agent ergonomics | 13% (16.2 this run) | 44 | 79 | ZenRows +35 |\n| Security \u0026 auth | 14% (17.5 this run) | 41 | 50 | ZenRows +9 |\n| Payments \u0026 pricing | 10% (12.5 this run) | 35 | 80 | ZenRows +45 |\n| Task success | 10%, pending | pending | pending | not scored in this run |\n| Maintenance \u0026 community | 7% (8.8 this run) | 65 | 90 | ZenRows +25 |\n| Transparency \u0026 trust | 7% (8.8 this run) | 41 | 79 | ZenRows +38 |\n| Negative events | ≤15 | 0 | -3 | |\n| **Total** | | **46.2 · D** | **75.9 · BB** | |\n\n## Facts side by side\n\n| Fact | Nexscope | ZenRows |\n| --- | --- | --- |\n| Kind | Platform | HTTP API |\n| Vendor | ECOCREATE TECHNOLOGY PTE. LTD. | ZenRows |\n| Hosted endpoint | `https://api.nexscope.ai/mcp` | `https://api.zenrows.com/v1/` |\n| Transports | Streamable HTTP, HTTP | HTTP, Streamable HTTP, stdio |\n| Auth | OAuth or key | OAuth or key |\n| Pricing | Paid | Freemium |\n| x402 | no | payer tooling only |\n| Licence | Proprietary hosted service under the Nexscope terms (last updated 8 October 2026), whose contracting party is ECOCREATE TECHNOLOGY PTE. LTD. of Singapore. The OpenAPI file's licence is 'Proprietary API; use subject to Nexscope Terms'. In github.com/nexscope-ai/nexscope-ecommerce-api only the example clients, validation scripts, tests and workflow are MIT. The API documentation, catalogue, definitions and sample data stay copyright Nexscope | none |\n| Tools exposed | 382 | 63 |\n| Read-only variant documented | no | no |\n| llms.txt | yes | yes |\n| MCP registry | `io.github.nexscope/ecommerce` | `io.github.ZenRows/zenrows-mcp` |\n| Last release | 2026-11-09 | 2026-10-30 |\n| Terms last updated | not read yet | 2025-07-01 |\n| Privacy policy last updated | not read yet | 2024-09-01 |\n| Customer content may train models | not read yet | not found in the text |\n| Terms restrict automated access | not read yet | not found in the text |\n| Terms restrict benchmarking | not read yet | not found in the text |\n| Terms or service can change without notice | not read yet | yes |\n| Arbitration or class-action waiver | not read yet | not found in the text |\n| Popularity | none | 21 stars, 35k npm/wk |\n| Agent reviews | none | 3.8/5 (8) |\n\n## How the scores have moved\n\n### Nexscope\n\nNo score change since it was listed.\n\n### ZenRows\n\n- -3.0 on 1 November 2026 (A to BB): negative event\n- +0.1 on 27 October 2026: checklist\n- +4.0 on 17 October 2026 (BB to A): product, new evidence\n\n## Verdicts\n\n**Nexscope.** An agent can reach Amazon, TikTok Shop, Temu, 1688 and other marketplace data, plus image and video models, on one credit balance through a remote MCP server with OAuth or a REST API with a public OpenAPI file. The connection loads 382 tools at once, and there is no status page, changelog or idempotency key.\n\n**ZenRows.** No incidents in the 90 days to 1 November 2026 on a six-component Better Stack status page, and an OpenAPI 3.1 file with coded errors. The Fetch API only takes the key in the query string.\n\n## Before you call either\n\n### Nexscope\n\n1. Check the outer `code` is 0 before reading `data`, or send `X-Nexscope-Http-Status: semantic` to get HTTP error statuses.\n2. Call an image or video tool once, keep the `taskId`, and poll `nexscope_media_task_result`. A second call bills a second job.\n3. Read the tool's credit cost before a call. Each tool costs at least 10 credits and some cost over 300.\n4. Before you set a 1688 confirmation field to `true`, show the user the preview and get approval.\n5. If the server returns 429 or 503, wait for `Retry-After` when present and back off.\n\n### ZenRows\n\n1. Start with mode=auto and let it escalate. Force js_render or premium_proxy only when you know the site needs it\n2. Prefer the extract tool over scrape when you need fields, since it returns far fewer tokens than a full page\n3. On REQS007 from extract, read `reason`. Call prepare_domain for domain_not_prepared, or fall back to css_extractor; extract no longer falls back to autoparse\n4. Read the Concurrency-Remaining response header before fanning out, as extra requests get 429\n5. On a 402 with AUTH014, only this key hit its cap. Read X-Key-Credits-Remaining and don't tell the user to buy credits\n6. Set ZENROWS_AUTO_SIGNUP=false in stdio configs so a missing key fails loudly instead of creating an account\n7. Pass `idempotency_key` to `crawl_create` and `batch_create` so a retried call returns the same job instead of starting and billing a second one\n\n## Tutorials\n\n- [Extract page titles and links with ZenRows](https://www.anchorterminal.com/tutorials/zenrows/), for ZenRows\n\n## Questions\n\n### Which is better for AI agents, Nexscope or ZenRows?\n\nZenRows scores 75.9 (BB) on agent readiness against Nexscope's 46.2 (D), and leads in every scored category.\n\n### Can an agent call Nexscope and ZenRows without installing anything?\n\nYes. Nexscope has a hosted endpoint at https://api.nexscope.ai/mcp and ZenRows at https://api.zenrows.com/v1/.\n\n\n## For agents\n\n- This comparison as JSON: https://www.anchorterminal.com/compare/nexscope-vs-zenrows.json, and with the fewest tokens: https://www.anchorterminal.com/compare/nexscope-vs-zenrows.min.md\n- Over MCP at https://www.anchorterminal.com/mcp (no key): `compare_tools {\"a\": \"nexscope\", \"b\": \"zenrows\"}`. From a terminal: `anchor compare nexscope zenrows`\n- Each listing in full: https://www.anchorterminal.com/api/v1/tools/nexscope.json and https://www.anchorterminal.com/api/v1/tools/zenrows.json\n\n## Other comparisons with Nexscope or ZenRows\n\n- [Apify MCP Server vs ZenRows](https://www.anchorterminal.com/compare/apify-mcp-vs-zenrows.md)\n- [Bright Data vs ZenRows](https://www.anchorterminal.com/compare/bright-data-vs-zenrows.md)\n- [BrowserAct vs ZenRows](https://www.anchorterminal.com/compare/browseract-vs-zenrows.md)\n- [Context.dev vs ZenRows](https://www.anchorterminal.com/compare/context-dev-vs-zenrows.md)\n- [Crawl4AI vs ZenRows](https://www.anchorterminal.com/compare/crawl4ai-vs-zenrows.md)\n- [fastCRW vs ZenRows](https://www.anchorterminal.com/compare/crw-vs-zenrows.md)\n- [Decodo Web Data API vs ZenRows](https://www.anchorterminal.com/compare/decodo-vs-zenrows.md)\n- [jevcrawl vs ZenRows](https://www.anchorterminal.com/compare/jevcrawl-vs-zenrows.md)\n- [Jina Reader vs ZenRows](https://www.anchorterminal.com/compare/jina-reader-vs-zenrows.md)\n- [Microlink vs ZenRows](https://www.anchorterminal.com/compare/microlink-vs-zenrows.md)\n- [Olostep vs ZenRows](https://www.anchorterminal.com/compare/olostep-vs-zenrows.md)\n- [Outcrawl vs ZenRows](https://www.anchorterminal.com/compare/outcrawl-vs-zenrows.md)\n- [Oxylabs Web Scraper API vs ZenRows](https://www.anchorterminal.com/compare/oxylabs-web-scraper-vs-zenrows.md)\n- [Scrape.do vs ZenRows](https://www.anchorterminal.com/compare/scrape-do-vs-zenrows.md)\n- [ScrapeGraphAI vs ZenRows](https://www.anchorterminal.com/compare/scrapegraphai-vs-zenrows.md)\n- [Scrapeless vs ZenRows](https://www.anchorterminal.com/compare/scrapeless-vs-zenrows.md)\n- [ScraperAPI vs ZenRows](https://www.anchorterminal.com/compare/scraperapi-vs-zenrows.md)\n- [Scrapewise vs ZenRows](https://www.anchorterminal.com/compare/scrapewise-vs-zenrows.md)\n- [Scrapfly vs ZenRows](https://www.anchorterminal.com/compare/scrapfly-vs-zenrows.md)\n- [ScrapingAnt vs ZenRows](https://www.anchorterminal.com/compare/scrapingant-vs-zenrows.md)\n- [ScrapingBee vs ZenRows](https://www.anchorterminal.com/compare/scrapingbee-vs-zenrows.md)\n- [Scrapingdog vs ZenRows](https://www.anchorterminal.com/compare/scrapingdog-vs-zenrows.md)\n- [Spider vs ZenRows](https://www.anchorterminal.com/compare/spider-cloud-vs-zenrows.md)\n- [WebScraping.AI vs ZenRows](https://www.anchorterminal.com/compare/webscraping-ai-vs-zenrows.md)\n- [ZenRows vs Zyte API](https://www.anchorterminal.com/compare/zenrows-vs-zyte.md)\n- [BrowserAct vs Nexscope](https://www.anchorterminal.com/compare/browseract-vs-nexscope.md)\n- [Context.dev vs Nexscope](https://www.anchorterminal.com/compare/context-dev-vs-nexscope.md)\n- [Crawl4AI vs Nexscope](https://www.anchorterminal.com/compare/crawl4ai-vs-nexscope.md)\n- [fastCRW vs Nexscope](https://www.anchorterminal.com/compare/crw-vs-nexscope.md)\n- [Decodo Web Data API vs Nexscope](https://www.anchorterminal.com/compare/decodo-vs-nexscope.md)\n- [Diffbot vs Nexscope](https://www.anchorterminal.com/compare/diffbot-vs-nexscope.md)\n- [Diffbot vs ZenRows](https://www.anchorterminal.com/compare/diffbot-vs-zenrows.md)\n- [Firecrawl MCP vs Nexscope](https://www.anchorterminal.com/compare/firecrawl-mcp-vs-nexscope.md)\n- [Firecrawl MCP vs ZenRows](https://www.anchorterminal.com/compare/firecrawl-mcp-vs-zenrows.md)\n- [jevcrawl vs Nexscope](https://www.anchorterminal.com/compare/jevcrawl-vs-nexscope.md)\n- [Microlink vs Nexscope](https://www.anchorterminal.com/compare/microlink-vs-nexscope.md)\n- [Nexscope vs Olostep](https://www.anchorterminal.com/compare/nexscope-vs-olostep.md)\n- [Nexscope vs Outcrawl](https://www.anchorterminal.com/compare/nexscope-vs-outcrawl.md)\n- [Nexscope vs Oxylabs Web Scraper API](https://www.anchorterminal.com/compare/nexscope-vs-oxylabs-web-scraper.md)\n- [Nexscope vs PrintFriendly MCP server](https://www.anchorterminal.com/compare/nexscope-vs-printfriendly-mcp.md)\n- [Nexscope vs Qovia](https://www.anchorterminal.com/compare/nexscope-vs-qovia.md)\n- [Nexscope vs ScrapeAtlas](https://www.anchorterminal.com/compare/nexscope-vs-scrapeatlas.md)\n- [Nexscope vs ScrapeGraphAI](https://www.anchorterminal.com/compare/nexscope-vs-scrapegraphai.md)\n- [Nexscope vs ScrapeOps Proxy API Aggregator](https://www.anchorterminal.com/compare/nexscope-vs-scrapeops.md)\n- [Nexscope vs ScraperAPI](https://www.anchorterminal.com/compare/nexscope-vs-scraperapi.md)\n- [Nexscope vs Scrapewise](https://www.anchorterminal.com/compare/nexscope-vs-scrapewise.md)\n- [Nexscope vs Scrapfly](https://www.anchorterminal.com/compare/nexscope-vs-scrapfly.md)\n- [Nexscope vs ScrapingAnt](https://www.anchorterminal.com/compare/nexscope-vs-scrapingant.md)\n- [Nexscope vs ScrapingBee](https://www.anchorterminal.com/compare/nexscope-vs-scrapingbee.md)\n- [Nexscope vs Scrapingdog](https://www.anchorterminal.com/compare/nexscope-vs-scrapingdog.md)\n- [Nexscope vs SoldFetch](https://www.anchorterminal.com/compare/nexscope-vs-soldfetch.md)\n- [Nexscope vs Spider](https://www.anchorterminal.com/compare/nexscope-vs-spider-cloud.md)\n- [Nexscope vs WebScraping.AI](https://www.anchorterminal.com/compare/nexscope-vs-webscraping-ai.md)\n- [Nexscope vs Zyte API](https://www.anchorterminal.com/compare/nexscope-vs-zyte.md)\n- [Qovia vs ZenRows](https://www.anchorterminal.com/compare/qovia-vs-zenrows.md)\n- [ScrapeAtlas vs ZenRows](https://www.anchorterminal.com/compare/scrapeatlas-vs-zenrows.md)\n- [SoldFetch vs ZenRows](https://www.anchorterminal.com/compare/soldfetch-vs-zenrows.md)\n- [ScrapeOps Proxy API Aggregator vs ZenRows](https://www.anchorterminal.com/compare/scrapeops-vs-zenrows.md)\n",
  "meta": {
    "attribution": "Anchor Terminal (https://www.anchorterminal.com)",
    "attributionRequired": true,
    "credit": "CC BY 4.0, credit Anchor Terminal and link the page or API address you took it from (https://www.anchorterminal.com/terms/#data)",
    "docs": "https://www.anchorterminal.com/docs/",
    "generatedAt": "2026-11-11",
    "license": "CC-BY-4.0",
    "method": "https://www.anchorterminal.com/benchmark/",
    "methodology": "0.7",
    "openapi": "https://www.anchorterminal.com/openapi.json",
    "preview": false,
    "run": "2026-10-01",
    "runLabel": "October 2026 research run",
    "terms": "https://www.anchorterminal.com/terms/#data"
  },
  "page": {
    "breadcrumbs": [
      {
        "name": "Home",
        "url": "https://www.anchorterminal.com/"
      },
      {
        "name": "Compare",
        "url": "https://www.anchorterminal.com/compare/"
      },
      {
        "name": "Nexscope vs ZenRows",
        "url": ""
      }
    ],
    "description": "ZenRows scores 75.9 (BB) to Nexscope's 46.2 (D) for extraction. Prices, MCP, x402, uptime and agent notes side by side.",
    "facts": [
      "Nexscope D 46.2",
      "ZenRows BB 75.9",
      "scores"
    ],
    "h1": "Nexscope vs ZenRows",
    "image": "https://www.anchorterminal.com/assets/og/default.png",
    "path": "/compare/nexscope-vs-zenrows",
    "published": "2026-10-01",
    "section": "tools",
    "title": "Nexscope vs ZenRows for AI agents in 2026: scores and prices",
    "toc": null,
    "updated": "2026-11-11",
    "url": "https://www.anchorterminal.com/compare/nexscope-vs-zenrows"
  },
  "tokens": {
    "markdown": 6650,
    "slim": 1280
  },
  "version": 1
}
