Every change Wellknown observed on this MCP server, newest first, with what it was before and what it became. Tool-surface changes carry the definition diff. Nothing here is edited after the fact.
Changed the definition of "browser_batch", "browser_evaluate", "browser_set_cookies" and 1 more
⟨74 unchanged words⟩ inside the JSON; browser_screenshot returns them as images. A batch can include evaluate, so it can change or delete page state the same way browser_evaluate can.
{"destructiveHint":falsetrue,"openWorldHint":true,"readOnlyHint":false,"title" ⟨5 unchanged words⟩
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.{"destructiveHint":falsetrue,"openWorldHint":true,"readOnlyHint":false,"title":"Evaluate JavaScript"}
Set one or more cookies in the browser session. A cookie with the same name, domain and path replaces the existing one.{"destructiveHint":falsetrue,"openWorldHint":true,"readOnlyHint":false,"title":"Set Cookies"}
Write one localStorage value in the current page context. An existing value under the same key is replaced.{"destructiveHint":falsetrue,"openWorldHint":true,"readOnlyHint":false,"title" ⟨4 unchanged words⟩
Added "batch_content", "batch_delete", "batch_list" and 8 more; removed "browser_local_storage"; changed the definition of "batch_cancel", "batch_create", "batch_results" and 5 more (52 tools before, 62 now)
Stopan in-flighta Batchjobjob's current run for good. No task still waiting is started or billed; tasks already in flight finish (POSTand/jobs/:id/stopbill). 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.
Authorization not required, issuer https://mcp.zenrows.com
Authorization required → not required, issuer https://mcp.zenrows.com
Changed the definition of "crawl_create", "crawl_get" and "crawl_wait"
⟨152 unchanged words⟩ exclude_patterns match nothing still costs that one scrape. A crawl whose pages held nothing new to follow (no link, only links to other sites, or only links the patterns reject) ends completed with no results and no error. When patterns are set, check them against the URLs the start page links to. Set output_format "html" or "markdown" to ⟨83 unchanged words⟩
⟨70 unchanged words⟩ 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 anderror.detail.
Changed the definition of "crawl_content", "crawl_create", "crawl_download" and 1 more
Read the storedHTMLpage of one URL a crawlkept.kept, in the crawl's output_format. Works only for crawls created withoutput_formatan"html"output_format, and only for results whose content_status is ⟨8 unchanged words⟩ , or content_url from a crawl_results row. Returns the page as stored — raw HTML for output_format "html",Markdown for "markdown" — cut to max_chars (default20000); a final note says when it was cut.
First tool surface recorded: 52 tools (server version 2.9.1)
Authorization required, Bearer, issuer https://mcp.zenrows.com
Authorization required, issuer https://mcp.zenrows.com
Authorization required, issuer https://mcp.zenrows.com
Authorization required, issuer https://mcp.zenrows.com
Authorization required, issuer https://mcp.zenrows.com
Authorization required, issuer https://mcp.zenrows.com
Authorization required, issuer https://mcp.zenrows.com
Authorization required, issuer https://mcp.zenrows.com
Authorization required, issuer https://mcp.zenrows.com
Authorization required, issuer https://mcp.zenrows.com
Authorization required, issuer https://mcp.zenrows.com
Authorization required, issuer https://mcp.zenrows.com
Authorization required, issuer https://mcp.zenrows.com
Certificate recorded, valid to 2027-03-08
Authorization required, issuer https://mcp.zenrows.com
Showing the latest 22 events. The API returns up to 500 and filters by kind: ?kind=tool_surface_changed
⟨6 unchanged words⟩ "job_id":{"description":"Batch job idtoreturnedstopby batch_create or batch_list","minLength":1,"type":"string"}},"required":[ ⟨3 unchanged words⟩
{"destructiveHint":true,"idempotentHint":true,"openWorldHint":true,"readOnlyHint":false,"title":"Cancel Batch Job"}
Submit acloudBatch jobthat fans out: many URLs scraped asynchronously in the cloud (Zenrows Batch API).NOTthe same as browser_batch — this hits https://async.api.zenrows.com/v1 with X-API-Key.Suited to large URL lists; scrape and extract handle single pages. Not the same as browser_batch. Tasks use automatic mode (mode=auto) by default: Zenrows enables JSrendering and premium proxies only on the pages that needthem, and charges only for the configuration that succeeds.them. Pass just the URLs. Set js_render orpremium_proxy (job-level, orin a task'sperzenrows_paramstask) only to force a fixedconfiguration; that turns automatic mode off for those tasks. Cost: theaffectedsame 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 andbills410 answers, billed as on the regular API.themLimits:atup to 100,000 tasks per call; 3 active jobs per account by default, shared with Crawl (BATCH_QUOTA_EXCEEDED past that);configuration'sacost.job frees its slot when its run ends. Creates 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. Returns job_id,+statuslatest_run.status/stats.andbatch_statusstatsandat once; the job runs asynchronously. Then: batch_waitreportuntilprogress;it ends, batch_resultsliststothelistresults. Ifrowsyou(paged),getbatch_contentBATCH_ACCESS_DENIEDto read one task's page. A run that ends failed (out of credits,Batchinactiveissubscription,notkeyenabledcap) 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). Errors: BATCH_INVALID_REQUEST (400, server_code and invalid_tasks say what), BATCH_INSUFFICIENT_CREDITS (402), BATCH_KEY_CAP_REACHED (402, thisaccountkey'sorcap), 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. Schedules, webhooks, exports, CSV inputs and open jobs are available through the Batch APIkey.and SDKs only.
{"$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 alltasks.tasks (5 credits each). Overrides automatic mode (mode=auto), which already renders ⟨26 unchanged words⟩ "description":"Force premium_proxy on all tasks (10x10costcredits each, 25 with js_render). Overrides automatic mode (mode=auto), which ⟨35 unchanged words⟩ [{"enum":["markdown","plaintext","html","pdf"],"type":"string"},{"type":"null"}],"description":"Job-levelresponse_typeoutput format. Leave unset for the raw HTML, the default."},"tasks":{"anyOf":[{"items":{"additionalProperties":falsetrue,"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."},"
List a Batch run's result rows,fora page at aBatchtime:jobup(cursor-paginatedtoserver-side;limitreturnsrowsthe(defaultfull100,listmax 1000).and next_cursor. Pass next_cursor back as cursor to continue; it is null once every row was read. Each rowmay includehas task_id, external_id, url, metadata, status (successful, failed, pending, processing, expired), type, result_url when successful, andaerrorshort-livedwhen failed. A result_url is presigned and expires after 2 hours: call batch_results again for a fresh one, or read thebody. Downloadbody with batch_content. Results are kept 14 days by default; after that a successful row reads as status "expired", with no result_url,soonand—batch_contentpresignedanswerslinksBATCH_RESULT_EXPIRED. Filterexpire.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.
{"$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":"Filterresultsrows by status (default:all). processing = tasks not finished yet. successful also returns expired rows."}},"required":["job_id"],"type":"object"}
Get a Batch job's latest run: job_id, run_id, statusand(pending, running, completed, stopped, failed), statsfor(total,acompleted,Zenrowssuccessful,Batchfailed)joband the job. A failed run answers ok:false with error.code BATCH_INSUFFICIENT_CREDITS, BATCH_KEY_CAP_REACHED, AUTH_INVALID (latest_run.statussubscription_inactive)+orlatest_run.statsBATCH_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.
⟨7 unchanged words⟩ "description":"Batch job id returned by batch_create or batch_list","minLength":1,"type":"string"}},"required":[ ⟨3 unchanged words⟩
Pollbatch_status untilatheBatch jobreachesuntilaitsterminalrunstateends (completed, stopped or failed) or pauses,stoppedand return its status and stats like batch_status. If the wait runs out first,oritdeleted).returns the current state with ok:true, timed_out:true and a note: call batch_wait again. A paused runthatreturnshitsatanonceAPIwithkeypaused:truecredit(itcapdoesendsnotasmove until batch_resume). A failed run answers ok:false withfailure_reasonerror.codeapi_key_cap_reached.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.
⟨6 unchanged words⟩ {"job_id":{"description":"Batch job id returned by batch_create or batch_list","minLength":1,"type":"string"},"timeout_mstimeout":{"anyOf":[{"maximum":36000003600,"minimum":10001,"type":"integer"},{"type":"null"}],"description":"Max waittimeinmsseconds (default60000050). 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"}
{"destructiveHint":falsetrue,"openWorldHint":true,"readOnlyHint":false,"title":"Clear Cookies"}
⟨8 unchanged words⟩ Returns JSON fields (products, articles, listings) in "data" rather than a fullpage body. Set include_html to also get the page HTML. Modes: - auto (default): extract=auto, ⟨4 unchanged words⟩ billing may apply later). Works on anydomain Zenrows hasprepared domain, with anyAPIkey;key. ErrorfallsREQS007backsays why in "reason": - domain_not_prepared: call prepare_domain with the domain and 1 toautoparse5whenexample URLs (a few minutes, no credits), poll prepared_domain_status about every 30 seconds until it says ready, then call extract again. - page_not_recognised: the domainisn'tis prepared,yetbut this page is not one Extract extracts (REQS007a page with nothing to extract, such as a home page). Try a product, article or listing page instead; if this page should work, retry it once in a few minutes; otherwise use mode=css. Do not prepare the domain again. - domain_not_enabled: preparing does not help; use mode=css. - autoparse: deprecated general-purpose structured JSON on anydomaindomain; use only when asked for - css: css_extractor with an explicit selector ⟨101 unchanged words⟩
⟨27 unchanged words⟩ "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":truefalse,"description":"Whenmode=autoand theonly:domainalsoisn'treturnpreparedtheforfullExtractpageyetHTML.(REQS007,Defaultorfalse; thelegacy AUTH010),HTMLretryis
⟨5 unchanged words⟩ ,"properties":{"autoparse":{"description":"AutomaticallyDeprecated:extractgeneral-purpose structureddataJSON from thepagepage.intoPreferJSON.theBestextractfortoolproduct(extract=autopages,onarticlesa prepared domain,andorlistings.css_extractor).","type":["boolean","null"]} ⟨441 unchanged words⟩
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. BATCH_TASK_NOT_READY: the task has not finished; BATCH_TASK_FAILED: it failed (task_error holds its error); BATCH_RESUL…
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.
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.
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.
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. A 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…
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.
Delete every localStorage entry in the current page context.
Read one localStorage value in the current page context.
Write one localStorage value in the current page context.
Prepare a domain so extract (mode=auto) works on it. Use this when extract returns error REQS007 with reason domain_not_prepared. Send the domain (the host, e.g. shop.example.com; a leading www. is dropped, and each host is prepared separately) and 1 to 5 example URLs: real pages you want extracted, one per page kind (for example one product page and one listing page). It returns at once with status "preparing" and never waits; preparation takes a few minutes and costs no credits. Then call prepared_domain_status about every 30 seconds until status is "ready", and call extract again. Each ne…
Check a domain submitted with prepare_domain, and the account's monthly allowance. Returns status (preparing, ready or failed), state (the current step), roles (one per page kind), a failure code and detail when it failed, the allowance (used, limit, remaining) and "next": what to do now. Poll about every 30 seconds; preparation takes a few minutes. Call extract again once status is "ready". Costs no credits.
Read, write, or clear localStorage in the current page context.
⟨28 unchanged words⟩ (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 ⟨29 unchanged words⟩
⟨48 unchanged words⟩ null"}],"description":"Max characters ofHTMLthe page to return (default 20000)"}},"required ⟨4 unchanged words⟩
⟨156 unchanged words⟩ costs that one scrape. Set output_format "html" or "markdown" to also store each kept URL's page, then ⟨76 unchanged words⟩
⟨42 unchanged words⟩ 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":{" ⟨127 unchanged words⟩ :{"anyOf":[{"enum":["html","markdown"],"type":"string"},{"type":"null"}],"description":"'html' or 'markdown' also stores each kept URL's page forcrawl_content.crawl_content, as fetched or converted to Markdown. Omit for URLs only."},"url":{ ⟨23 unchanged words⟩
⟨103 unchanged words⟩ : 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: ⟨17 unchanged words⟩
⟨30 unchanged words⟩ 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); failed carries error.code and error.detail. 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; ⟨16 unchanged words⟩