Skip to main content
Glama

Most web scraping tools give your agent one of two bad outputs:

  • a blocked page, login wall, or empty app shell

  • raw HTML full of nav, scripts, styling, ads, and duplicated boilerplate

webclaw.io is the hosted web extraction API for webclaw. This repo contains the open-source CLI, MCP server, extraction engine, and self-hostable server.

webclaw turns a URL into clean content your tools can actually use.

webclaw https://example.com --format markdown
# Example Domain

This domain is for use in illustrative examples in documents.

You may use this domain in literature without prior coordination or asking for permission.

Use it from the terminal, wire it into Claude/Cursor through MCP, call the hosted API from your app, or self-host the OSS server.


Install

Agent setup

The fastest way to connect webclaw to Claude Code, Claude Desktop, Cursor, Windsurf, OpenCode, Codex CLI, and other MCP-compatible tools:

npx create-webclaw

The installer detects supported clients and configures the MCP server for you.

Homebrew

brew tap 0xMassi/webclaw
brew install webclaw

Prebuilt binaries

Download macOS, Linux, and Windows binaries from GitHub Releases.

Windows (x64)

The prebuilt ZIP is the easiest installation and does not require Rust. On the v0.6.22 release page, download webclaw-v0.6.22-x86_64-pc-windows-msvc.zip. Extract it in File Explorer, open PowerShell in the extracted folder containing webclaw.exe, and run:

.\webclaw.exe --version
.\webclaw.exe https://example.com --format markdown

PowerShell requires the .\ prefix for programs in the current directory. Add that directory to your user PATH only if you want to run webclaw from other folders. If Windows reports a missing Visual C++ runtime DLL, install the Microsoft Visual C++ Redistributable for x64. The ZIP contains x64 binaries; Windows ARM64 is not covered by the native installation check.

To build from source on Windows, install Rust with the x86_64-pc-windows-msvc toolchain, Visual Studio Build Tools with Desktop development with C++ and the Windows SDK, Git, CMake 3.22 or newer, LLVM (including libclang.dll), and NASM. Open a fresh Developer PowerShell for Visual Studio after installation. Ensure CMake and NASM are on PATH and set LIBCLANG_PATH to your LLVM bin directory if bindgen cannot find it, for example:

$env:LIBCLANG_PATH = "C:\Program Files\LLVM\bin"
cargo install --git https://github.com/0xMassi/webclaw.git --tag v0.6.22 --locked webclaw-cli
webclaw --version

The Cargo package is webclaw-cli; the executable is webclaw. These packages are installed from Git, not crates.io. A first source build can take several minutes. The Windows CI workflow checks the Git installation and published ZIP on a hosted runner with preinstalled build tools; it does not model a clean PC. Linux containers, including Docker on macOS, do not validate Windows support.

Docker

docker run --rm ghcr.io/0xmassi/webclaw https://example.com

Cargo

cargo install --git https://github.com/0xMassi/webclaw.git --tag v0.6.22 --locked webclaw-cli
cargo install --git https://github.com/0xMassi/webclaw.git --tag v0.6.22 --locked webclaw-mcp

If building from source fails because native build tools are missing, install the platform prerequisites:

OS

Command

Debian / Ubuntu

sudo apt install -y pkg-config libssl-dev cmake clang git build-essential

Fedora / RHEL

sudo dnf install -y pkg-config openssl-devel cmake clang git make gcc

Arch

sudo pacman -S pkg-config openssl cmake clang git base-devel

macOS

xcode-select --install

Python

The python/ directory builds a Python package that bundles the webclaw binary and calls it from Python: scrape, select, tables, find_text, similar, crawl, map and screenshot, with no API key and no Python dependencies.

cd python && uv build --wheel && pip install dist/webclaw_cli-*.whl
import webclaw_cli as wc

md = wc.scrape("https://example.com", "llm")
titles = wc.select("https://books.toscrape.com", css="h3 a::attr(title)")
for page in wc.crawl("https://quotes.toscrape.com", max_pages=10):
    print(page["url"])

See python/README.md for every function and option.


Related MCP server: mcp-playwright

Quick Start

Scrape one page

webclaw https://stripe.com --format markdown

Return LLM-optimized text

webclaw https://docs.anthropic.com --format llm

Keep only the main content

webclaw https://example.com/blog/post --only-main-content

Include or exclude selectors

webclaw https://example.com \
  --include "article, main, .content" \
  --exclude "nav, footer, .sidebar, .ad"

Pick values with CSS selectors or XPath

webclaw https://books.toscrape.com --select "h3 a::attr(href)"
webclaw https://books.toscrape.com --select "article.product_pod" \
  --field "title=h3 a::attr(title)" --field price=.price_color

--select prints a JSON array of what the selector matches: each element's text, or an attribute or the element's HTML when the selector ends in ::attr(NAME) or ::html. Links in href and src come back absolute. With --field NAME=SELECTOR, each match becomes a JSON object whose fields run inside it, taking the first value or null. Pages that need JavaScript render first, as with extraction.

webclaw https://books.toscrape.com --xpath "//li[@class='next']/a/@href"
webclaw https://books.toscrape.com --xpath "//article[@class='product_pod']" \
  --field "title=.//h3/a/@title" --field "price=.//p[@class='price_color']"

--xpath takes an XPath 1.0 expression instead, over the same parsed page: elements and text nodes give their text, attributes their value, and count() or string() style expressions one value. With --xpath, each --field is an expression evaluated from the match, so it usually starts with .. The MCP select tool takes xpath in place of selector.

Data tables as JSON

webclaw "https://en.wikipedia.org/wiki/List_of_S%26P_500_companies" --tables

--tables prints the page's data tables as a JSON array, each with its caption (when it has one), headers and rows of cell text. A cell that spans several rows or columns repeats its text in each one, so every row has one value per column. Stacked header rows are joined per column with /, as in Population / % of world. The MCP select tool takes tables: true in place of a selector.

Header rows are the rows of <thead> and the leading rows made only of <th>; a leading row that is one cell across the whole table becomes the caption. These tables are skipped as page layout:

  • tables marked role="presentation" or role="none";

  • tables with fewer than two columns of text;

  • tables without a header row that have a single body row, wrap another table, hold only links, or hold paragraphs, lists or other blocks in a row of more than one cell.

Text hidden with hidden, an inline display:none or <template> is left out. Text hidden by a stylesheet is kept, because pages are not styled. A cell keeps its first 64 KB of text, and a very large table is cut short with "truncated": true. Once the tables on a page reach 64 MB, the tables after that are left out.

Find elements by text, or everything like one example

webclaw https://books.toscrape.com --find-text "tipping the"
webclaw https://books.toscrape.com --find-regex '^£5\d\.\d\d$'
webclaw https://books.toscrape.com --find-text "Tipping the Velvet" --similar

--find-text prints the elements in the page body whose visible text contains the text, any case, as {"selector", "text"} objects. Each match is the deepest element holding the text, so text split by inline tags still matches, and its selector is the element's path from the nearest ancestor with a unique id, or from the root. That path picks the element alone, except on pages nested more than 64 levels deep with no such id, where it keeps only the last 64 steps and can pick more. --exact matches the whole text, --case-sensitive matches letter case, and --find-regex takes a regular expression instead.

--similar takes the first element that --find-text, --find-regex, --select or --xpath picks as an example and returns every element like it on the page, such as the other items of a list, grid or table, with one CSS selector that picks them all. When the example selector ends in ::attr(NAME) or ::text, or the XPath picks a text or attribute node, the element holding it is the example:

{
  "selector": "article.product_pod > h3 > a",
  "matches": [
    { "selector": "html > body > ... > li:nth-of-type(1) > article > h3 > a", "text": "A Light in the ..." },
    ...
  ]
}

Reuse the selector with --select, or add --field to get records straight away; with --similar the fields are CSS and the output is {"selector", "records"}. Pick the item itself as the example (for instance --select "article.product_pod" --similar) when the fields live inside it. The MCP select tool takes text or regex (with exact and case_sensitive) and similar the same way. One call takes one picker: --select, --xpath, --tables, --find-text or --find-regex (in MCP: selector, xpath, tables, text or regex), and --similar and --field do not apply to tables.

Keep only what answers a question

webclaw "https://en.wikipedia.org/wiki/Rust_(programming_language)" -f llm \
  --query "Who began the language as a personal project?"

--query (and query on the MCP scrape tool) scores each paragraph, list, table and code block against the question and keeps the best ones under their headings, so an agent reads the answer instead of the whole page. The page comes back unchanged when no block shares a word with the question.

Chunks for retrieval

webclaw https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html --chunk 256
webclaw https://quotes.toscrape.com --crawl --depth 1 --chunk 512 --chunk-overlap 50

--chunk prints the page as chunks for a search index or a RAG pipeline, one JSON object per line (one JSON array with -f json): url, index, heading_path (the headings in effect where the chunk starts, outermost first), tokens and the chunk's markdown text. Chunks are built from whole paragraphs, lists, tables and code blocks and stay under about the given number of tokens. A block too big for one chunk is cut at line breaks, then at sentence ends, then between words, and text with no spaces between characters: a code block is reopened in each piece and a table repeats its header row. Token counts are estimates made without a tokenizer. On the benchmark pages (prose, docs, code, tables and nine languages), for nine chunks in ten cl100k counted 0.77 to 1.12 times the estimate and o200k 0.72 to 0.97 times; 4.5% of chunks came out above the size asked for in cl100k tokens, and 0.5% in o200k tokens. --chunk-overlap repeats up to that many tokens from the end of each chunk at the start of the next. With several URLs or --crawl, each page is chunked on its own. The MCP scrape tool takes chunk and chunk_overlap and returns the chunks as a JSON array; crawl takes them too and returns an object with the crawl counts, the pages that failed and the chunks.

webclaw https://en.wikipedia.org/wiki/Web_scraping --citations

--citations moves every link and image URL out of the markdown into a numbered list at the end, written as markdown footnotes: [Data scraping](https://...) becomes Data scraping[^1], an image becomes ![alt][^2], and the page ends with ## Links and one [^1]: https://... per URL. Numbers follow the order in which URLs first appear, a URL used twice keeps its first number, and numbering starts after any numbered footnotes the page already has. With several URLs or --crawl, pages printed together keep counting, so a number means one URL in the whole output; with --output-dir, -f json or jsonl each page counts on its own.

Some things stay as they are: code blocks and inline code, reference-style links ([text][id]), autolinks (<https://...>) and raw HTML links. Links to a spot on the same page (#section) and javascript: links keep their text and lose the URL. A cited image is no longer an image to a markdown renderer (GitHub shows ![alt] as text); its URL is in the list. With -f markdown, a page's ## Structured Data block comes after the list.

On the 63 benchmark pages fetched live, the body before the list came out at about half the tokens of the plain markdown, and the whole output, list included, at 10.7% fewer tokens in total. That total comes mostly from link-heavy pages such as Wikipedia articles: the 5 pages that saved most hold 68% of the saving, the median page saved 2.5%, and 18 of 63 pages came out a little longer. Golden facts were the same with and without it. Reach for it to cite sources by a short, stable id or to keep URLs out of the text, not as a general way to cut tokens.

It works with -f markdown and with the markdown inside -f json and jsonl, for one URL, several or --crawl. It is refused with --chunk and with modes that print no page markdown (-f text, llm or html, --select, --map, --brand, --diff-with, --watch, the LLM modes and the like). The MCP scrape, crawl and batch tools take citations: true, and webclaw_core::to_citations (or to_citations_after, to keep counting across pages) does the same for any markdown.

Reuse fetched pages

webclaw https://example.com --cache          # fetch once, answer later runs from disk

--cache keeps every successful page in ~/.cache/webclaw (or WEBCLAW_CACHE_DIR), readable by you only, and answers later fetches of the same URL with the same browser profile and headers from there, with no network request. Crawls and batches use it page by page. Entries never expire; delete the directory to refresh. Error responses, challenge pages and Set-Cookie headers are never stored. The cache keeps the HTTP response only: a page that needs JavaScript still renders in the browser, which loads its scripts over the network.

Keep a web archive

webclaw https://example.com --warc page.warc.gz
webclaw https://docs.example.com --crawl --depth 2 --warc site.warc.gz > site.md

--warc FILE keeps every HTTP response webclaw fetches, with the request that asked for it, in a WARC file, the web archive format of ISO 28500 that web archives and replay tools read. The output goes where it always goes; the archive is written beside it. A name that ends in .gz gzips each record on its own, as .warc.gz files do. It works with one URL, several, --crawl (robots.txt and redirect responses included) and --map (the sitemaps it tried). Records are written as they arrive, so a crawl you stop keeps every page it fetched. A file that already exists is added to, never overwritten: each run starts with its own warcinfo record, and a WARC file made of several runs is still one valid WARC file. A file that ends inside a record, as a run stopped while writing can leave it, is refused, since records added after the cut would be unreadable; give --warc a new file then. Each record carries SHA-1 digests of its content.

The response is kept as webclaw's HTTP client hands it over, which is decoded: a compressed body is stored decompressed, without its Content-Encoding, Content-Length and Transfer-Encoding headers, and an HTTP/2 response gets an HTTP/1.1 status line. Each run's warcinfo record says so, and every record points at it. Replay tools read such records fine, but the payload digests are those of the decoded bodies, so they will not match, for deduplication, a copy of the same page that another archiver stored still compressed. The request record lists the headers webclaw sent, -H and --cookie values included, so keep the file as safe as those values; cookies a site set during the run are not listed. Every redirect gets its own response and request record, the redirect responses included, in a crawl or not; cookies and credentials you pass are not sent on to another site, as without --warc. Pages a browser renders are not in it, so --warc refuses --render always, --actions and --scroll; with --render auto, the HTTP response of a page that then gets rendered is kept. It also refuses --cache, whose answers never touch the network, and --cloud. Use --save-mhtml to keep a rendered page.

Render JavaScript pages

Build with the browser feature (cargo build --release --features browser) and webclaw renders pages in your local Chrome when the plain HTTP response has no content yet:

webclaw https://hn.algolia.com                    # --render auto: HTTP first, Chrome only when needed
webclaw https://example.com --render always --wait-for "#app li"
webclaw https://example.com --cdp-url ws://localhost:9222/devtools/browser/<id>   # use a running browser

auto renders when the page loads scripts and the HTTP response has almost no text, or little text next to an empty app root or a "please enable JavaScript" notice, and it keeps the rendered result only when it has more content.

The browser webclaw launches presents itself as regular Chrome: every page, frame and worker sends and reads your Chrome's own User-Agent, without the "Headless" that headless Chrome adds, so it matches the client hints Chrome sends. Some sites serve a headless browser an error or a pre-rendered page. A browser you connect with --cdp-url keeps its own User-Agent.

What a rendered page can reach, in the browser webclaw launches:

  • no HTTP request from the page, its frames or its workers, redirects included, reaches a private, loopback or link-local address;

  • WebSockets to those addresses are refused, though the TCP connection opens first. Behind a proxy, WebSockets to anything but loopback go through the proxy, so they are only as safe as the proxy;

  • speculative prefetching and preconnects are off;

  • WebRTC sends no UDP, though a TURN server over TCP can still open a connection to a local port;

  • without a proxy, a render fails when the page's document came from a private address, so DNS rebinding cannot return local content. The request itself still goes out, and popups are not checked.

Behind a proxy, the proxy resolves host names itself and the document check is off, so HTTP too is only as safe as the proxy. Service workers are not tested. A browser you connect with --cdp-url is checked page by page and your other tabs are left alone, but the frames, workers, WebSockets, WebRTC and speculative prefetching of the pages webclaw renders there are not covered.

--block images,fonts,media skips those resources while a page renders for its content. Stylesheets always load, since many apps fetch CSS on demand and break without it. Scripts and the data they fetch still load, so most pages keep all their text and download about 40% less. A page that shows some text only after a font or an image has loaded (through document.fonts.load(), FontFace.load(), an image's onload or decode()) loses that text when you block it. We found no such page among the real sites we tested, but compare with and without --block on yours. Rendering is not much faster, since webclaw already stops waiting once the text settles, so blocking stays off unless you ask. Screenshots and PDFs always load everything. The MCP scrape and crawl tools take the same list as block.

--screenshot page.png saves the rendered page's 1280x720 viewport, --full-page the whole page, and a .jpg name gives a JPEG. The MCP screenshot tool returns the same image to the agent.

--save-pdf page.pdf (or - for stdout) prints the rendered page to a PDF through the browser's print engine: every page, with the site's print styles and Chrome's default margins, without the accessibility tags some browsers add. --paper a4 changes the US Letter default, --landscape turns the paper sideways, --print-background keeps background colors and images, and --scale 0.8 zooms the content (0.1 to 2). It takes --wait-for, --actions and --scroll like any render, and loading plus printing must fit in --timeout. Chrome lays out the whole page to print it, so a very long page, such as a full web standard on one page, can take several GB of memory in Chrome while it prints. The flag is not --pdf because --pdf-mode is about reading PDFs you fetch, not making them. The MCP screenshot tool returns the same PDF with format: "pdf", as an application/pdf resource of up to 10 MiB, and takes paper, print_background and actions the same way.

--save-mhtml page.mhtml (or - for stdout) saves the rendered page as MHTML, the one-file web archive of "Save page as, single file": the page as it is after its scripts ran, with the images, styles and frames it loaded. Chrome opens it offline, without running its scripts. It takes --wait-for, --actions and --scroll like any render. An image that loads only once you scroll to it is in the file only if it loaded first, so add --scroll for pages with those. Chrome hands the file over in one piece, so it is in memory once while it is written: an 18.6 MB archive of the one-page HTML standard took about 100 MB more than a screenshot of the same page. The MCP screenshot tool returns the same file with format: "mhtml", as a multipart/related resource of up to 10 MiB.

--solve gets past Cloudflare challenge pages, the ones that say "Just a moment..." or "Performing security verification". When a page comes back as one, webclaw opens it in Chrome, waits for the challenge to clear, clicks its checkbox when it asks for a click, and reads the page it leads to, all within --timeout. When the challenge is still there after three quarters of it, the command fails with that as its error. Later pages of the same site, in a crawl or a batch, go over plain HTTP again with the clearance cookie Chrome got (cf_clearance only, never the site's other cookies) and Chrome's User-Agent; Cloudflare accepts it from the same IP address on about half the sites we tried, and when it does not, webclaw solves again. A Turnstile checkbox inside a page that webclaw renders, as on a sign-up form, is clicked too, so that page actions can submit the form; add --render always for pages that would not otherwise be rendered. webclaw waits up to 10 seconds for such a widget's token, then reads the page as it is. The clearance goes with Chrome's User-Agent, so --solve needs --browser chrome (the default), chrome-macos or edge. Headers you pass with -H still go to the page's other requests, but not to its documents, since rewriting a document request fails the challenge. A browser you connect with --cdp-url keeps its own User-Agent. The MCP scrape tool takes solve: true.

webclaw https://www.scrapingcourse.com/cloudflare-challenge --solve
webclaw https://gitlab.com/users/sign_in https://gitlab.com/explore --solve   # solves once, then plain HTTP

Crawls, batches, --watch and the MCP server render the same way and share one browser, started only when a page needs it. Per site, webclaw keeps count: once at least three renders show that rendering adds content (at least four in five did), it renders every page of that site that runs scripts, and once rendering stops adding content (at most one in five did), it stops rendering there.

Click, type and scroll before reading

With a browser build, --actions runs steps in the browser once the page has loaded and before webclaw reads it, in the same format as the hosted API's actions, so content behind infinite scroll, "load more" buttons, pagination buttons, forms or a slow script ends up in the output. --scroll alone scrolls to the end until the page stops growing, at most 20 times (--scroll=50 for more).

webclaw https://quotes.toscrape.com/scroll --scroll
webclaw https://github.com/topics/rust --actions '[{"type": "click", "selector": "button.ajax-pagination-btn", "repeat": 3}]'
webclaw https://quotes.toscrape.com/login --actions '[{"type": "type", "selector": "#username", "value": "me"}, {"type": "type", "selector": "#password", "value": "secret"}, {"type": "press", "key": "Enter"}]'
webclaw https://example.com --actions @steps.json

Step

Fields

What it does

click

selector, and nth, all or repeat

Clicks the first match, the match at index nth (from 0), or every match. With repeat, clicks the first visible match again and again, up to that many times, until none is left or two clicks in a row change nothing

type

selector, value

Focuses the element and types the value

press

key

Presses a key such as Enter, Tab or ArrowDown

scroll

direction (down or up), amount, selector, repeat, all optional

Scrolls the page, or the element, amount pixels, or without amount to its end. With repeat, scrolls again until two scrolls in a row add nothing; with amount it keeps stepping to the end, which loads lazy images on the way

wait

milliseconds

Pauses

waitForSelector

selector, timeout

Waits until an element matches, up to timeout milliseconds, 10 seconds by default

executeJavascript

code

Runs JavaScript, an expression, statements whose last one gives the value, or a function body with return, with await allowed anywhere, and keeps that value, awaited when it is a promise, as JSON in js_results. A later step may repeat the same top-level let, const or class declaration, but not switch its kind (let m then const m fails) or reuse a name the page's own scripts declare

After a click, a key press or a scroll, webclaw waits until the page and the site's own requests go quiet, up to 5 seconds, before the next step. Content a site draws on a timer after its request has finished can come later than that: add a waitForSelector step for it. A step that needs an element waits up to 10 seconds for it, and a selector the browser cannot parse fails at once. Alerts, confirms and prompts that steps open are dismissed, and tabs or windows they open are closed. The steps get their own time budget, equal to --timeout, on top of loading the page. The first step that fails or runs out of time fails the command and the error names it; a repeat that runs out of time before it is done fails too, rather than return part of the page. Use --timeout for long feeds. The values of all executeJavascript steps together are capped at 1 MiB. Steps run in the same browser under the same checks as the page's own scripts, and a step that navigates to a private or loopback address, or to a name that resolves to one, fails the command.

--actions takes one URL and renders the page even with --render auto. js_results comes in the output with -f json or -f jsonl and on stderr otherwise, and --raw-html prints the page after the steps. The MCP scrape and screenshot tools take the same list as actions and return js_results after the content. Local additions are nth, all and repeat on click, and selector, repeat and scrolling to the end on scroll. The hosted screenshot step is left out, since --screenshot does that.

Stay logged in between runs

With a browser build, --browser-profile DIR keeps the browser's cookies, local storage and IndexedDB in DIR, so a login made once still holds on the next run:

webclaw https://quotes.toscrape.com/login --browser-profile ~/.webclaw-profile \
  --actions '[{"type": "type", "selector": "#username", "value": "me"}, {"type": "type", "selector": "#password", "value": "secret"}, {"type": "click", "selector": "input[type=submit]"}]'
webclaw https://quotes.toscrape.com/ --browser-profile ~/.webclaw-profile        # a later run, still logged in
webclaw https://example.com/account --browser-profile ~/.webclaw-profile --cookie "session=..."   # or bring a session cookie in once

With a profile, every web page webclaw reads, in crawls and batches too, loads in the browser with the profile's cookies, after a plain HTTP request that tells web pages apart from PDFs, feeds and other files, which stay on HTTP. That makes every page a browser load: on our benchmark a 50-page crawl took 3.6 s without a profile, 12.4 s on a new one and 8.0 s on a warm one. --raw-html prints the page as the browser left it. When a page fails in the browser, webclaw warns and keeps the HTTP result. A profile that cannot be opened, because it is in use, refused (see below) or has unreadable preferences, stops the run with an error before the first page, crawls included; the MCP tools return that error. In a crawl, a redirect the browser meets is checked against robots.txt and the crawl's scope before it is followed, as over HTTP.

Session cookies are kept as well: Chrome drops them when it closes, even on a kept profile, and most sites keep a login in one. All pages share the profile's cookies. Cookies from --cookie and --cookie-file are saved in the profile when the run starts, for the URLs on the command line (or in --urls-file) only, even when no page then needs the browser; with a profile, the browser sends no other cookie than its own. The MCP scrape tool saves its cookies in the profile for the URL it was given, and they stay there for later calls. Without --browser-profile, which stays the default, each run starts from an empty profile and a page rendered with cookies gets a browser context of its own, so nothing carries over between pages or runs.

webclaw creates the directory when it is missing, readable by you only on Unix, and marks it as its own. It refuses a directory that is neither empty nor one it made, such as the profile of the Chrome you browse with, as well as a symbolic link and, on Unix, a directory other users can write to. Before each run it drops the tabs an earlier run left open and the service workers sites registered, and turns prefetching off in the profile's preferences, keeping the rest of them. The profile holds your logins, so treat it like a password. The checks above on what a rendered page can reach apply on a profile too.

One webclaw at a time per profile: a second run on a profile in use stops with an error that names the process holding it, instead of opening it a second time, which can damage it. Stopping webclaw with Ctrl-C or SIGTERM closes its browser first; after a kill -9, stop the Chrome the error names. --browser-profile cannot be combined with --cdp-url; the MCP server takes the directory in WEBCLAW_BROWSER_PROFILE.

On our benchmark, one run rendering a page took 1.7 s on a warm profile against 2.1 s on a new one, and the profile took about 9 MB on disk after six runs.

Capture the JSON a page loads

Single-page apps fetch their data as JSON and build the page from it. With a browser build, --capture-network renders the page and prints the responses it loaded as a JSON array instead of the page, so you get that JSON as the site's own API returned it:

webclaw https://quotes.toscrape.com/scroll --capture-network                  # every XHR and fetch response
webclaw https://github.com/rust-lang/cargo --capture-network=latest-commit
webclaw https://quotes.toscrape.com/scroll --scroll --capture-network=/api/quotes
webclaw https://example.com --capture-network --capture-types all             # documents, scripts, images too

Each response has its url, method, status, resource_type, mime_type, the request_headers the page set, and the body of text responses (JSON, HTML, JavaScript, XML, plain text). Binary bodies are left out. The pattern is a regular expression the URL must match, written after an equals sign. Only xhr and fetch responses are kept unless --capture-types names others, as a comma list of the browser's resource types or all. At most 100 responses are kept, each body is cut to 1 MB and all bodies together to 5 MB, and a cut body has truncated set.

Unless you pass --capture-credentials, request headers whose name marks a credential (Authorization, API keys, tokens, sessions, signatures) are left out, and URL query parameters named that way, such as access_token or key, read REDACTED. Cookies are added by the browser after the page sends a request, so they are never there. Response bodies are kept as the site sent them, so a token the site returns in its JSON stays in the output; check what you share.

A capturing render waits until no request it would keep is in flight and none has started for 1 second, up to a third of --timeout, before it reads the responses. A request the page starts later than that is missed; --wait-for or a wait step catches it. With --actions or --scroll the steps run first, so the responses they trigger are captured too. If the render fails or times out, the command fails and prints no responses.

The capture only sees what the browser was allowed to load: a request the address checks above or --block stop never gets a response, and a response that came from a private address is left out. The requests a cross-site frame or a dedicated worker makes itself are not captured. A page that ships its data inside its HTML calls no API, so there is nothing to capture: read the page itself, or keep its document with --capture-types document. The MCP scrape tool takes the same options as capture_network, capture_types and capture_credentials, cuts each body to 100 KB and all bodies together to 1 MB to fit a model's context, and returns the responses after the content, or under network with format: "json".

Crawl a documentation site

webclaw https://docs.rust-lang.org --crawl --depth 2 --max-pages 50

--delay (default 100 ms) is the shortest time between two page requests to the same host, shared by all --concurrency workers, so raising the concurrency never starts more than one page request per --delay on one site. The first page waits one --delay after the robots.txt and sitemap requests. While robots.txt is respected, each redirect hop counts as a request too; with --ignore-robots, redirects are followed inside one fetch and their hops are not spaced. --delay 0 turns the spacing off. The crawler follows the site's robots.txt: it skips disallowed URLs and honours Crawl-delay, using it instead of --delay when it is longer. Pass --ignore-robots to turn that off. While robots.txt is respected, each redirect is checked against robots.txt and the crawl's scope before it is followed, and a redirect to the same page with a slash added or the scheme changed is fetched once instead of dropped. The same path over http:// and https://, with or without a trailing slash, counts as one page, and links to the start URL's host in the other scheme are crawled on the start URL's scheme.

For long crawls, stream pages as JSON lines and checkpoint the crawl so a crash or kill resumes where it stopped. The checkpoint does not remember when the site was last requested, so after a quick restart the first request can come sooner than --delay after the last one of the previous run:

webclaw https://docs.rust-lang.org --crawl --max-pages 0 -f jsonl --crawl-state crawl.json >> pages.jsonl

Give the crawl a question and it fetches the links most likely to answer it first, instead of level by level:

webclaw https://docs.python.org/3/ --crawl --depth 4 --max-pages 25 \
  --query "How do I sort a list of dictionaries by a key?"

Each link is scored by the question's words in its text, its URL path and the paragraph or list item around it, plus how well the page that links to it answers the question; words that most pages share count for little. Every page then keeps only the parts that answer the question, carries a relevance from 0 to 1, and the output lists pages best match first (-f jsonl streams them in crawl order instead). --max-pages is the budget. A resumed --crawl-state keeps the order when it gets the same --query. The MCP crawl tool takes the same query, up to 1,000 characters.

Add --stop-when-answered to end the crawl before the budget once the answer looks found: no new page starts once a page rated at least 0.8 has been fetched and the 8 pages fetched after it rated no higher. Pages already in flight still finish. On our benchmark, with a 50-page budget, it fetched 32 pages on average instead of 50 on the 60 questions the rule was tuned on, and 39 on 48 held-out questions, where it lost one answer the full crawl found: a page that held every word of the question without answering it rated 1.0 earlier. Those held-out questions were also looked at while the rule was chosen. On 48 questions about four other sites, written after the rule was fixed, it kept all 40 answers the full crawl found and fetched 44 pages instead of 50, about 10% fewer: only 10 of those 48 crawls rated any page 0.8. So expect a small saving on most sites. A crawl that never rates a page 0.8 runs to the budget, and questions in other languages rarely reach 0.8. The MCP crawl tool takes stop_when_answered: true with a query, and CrawlConfig::stop_when_answered does the same in webclaw-fetch.

The scoring matches words, so it works best on English questions; questions in other languages reach their page later (Japanese, French, Spanish and Chinese questions in the benchmark: 3 of 16 by page 10 and a median of 18 pages, against 33 of 48 and 6 pages for English questions on sites the weights were not tuned on). Only the first 32 distinct words of a question count.

List a site's URLs

webclaw https://docs.python.org/3/ --map
webclaw https://docs.python.org/3/ --map --map-source sitemap,cc --path-prefix /3/library \
  --query "cancel an asyncio task" --map-limit 20

--map lists a site's URLs without extracting them: one per line, or a JSON array with -f json. It reads the sitemaps the site's robots.txt declares (or the usual sitemap paths), and when they hold fewer than 200 URLs it adds the links found by a short crawl (--map-pages, --no-map-crawl to turn it off). Each page is listed once: URLs that differ only by http/https, www., a trailing slash, a fragment or a tracking parameter (utm_*, ref, fbclid, gclid) count as one. A --crawl keeps the www. and bare-host URLs of a page apart.

--map-source sitemap,cc also asks the public Common Crawl index for the pages of the site it captured in its latest crawl, which finds pages that no sitemap lists and no crawl reaches in a few pages. --map-source cc asks the index alone. Only pages on the site's own host (with or without www.) that answered 200 with HTML are kept, without their tracking parameters; --map-all-captures keeps redirects, errors and other files too. When the sitemap already gives --map-limit URLs and there is no --query, the index is not asked.

The index is a free shared service, so webclaw sends it one request at a time, a second apart, retries a busy answer twice, and gives the whole lookup 2 minutes. It often takes 10 to 60 seconds and is sometimes down; when it stops answering, webclaw warns and lists the URLs it found until then, and fails only when it found none. Keep in mind:

  • It reads at most ten pages of index results (about 150,000 captures). The index sorts by URL, so on a big site that is an alphabetical slice of it, not a sample, and --query ranks only that slice.

  • One crawl does not capture every page. A small site may have only a few dozen captures in the latest collection, and a page you know exists may be missing.

--path-prefix, --include-paths and --exclude-paths filter the list as they filter a crawl, and the fallback crawl spends its pages inside them. --query lists the URLs best match first by the words in their paths, weighting words that few of the site's paths share, and putting whole-word matches ahead of longer words a query word only starts ("auto" in auto.html before autovacuum.html). It reads no page, so it only helps when the URL names the topic: "cancel an asyncio task" puts asyncio-task.html first among the docs.python.org URLs. --map-limit keeps the first N, after the ranking. The MCP map tool takes source, limit and query.

On 10 sites in our benchmark (docs, news, shops and blogs, half of them without a sitemap), --map-source sitemap,cc found 44,122 URLs on the sites' own hosts against 17,026 for plain --map, and 96% of a sample answered 200 with HTML. On the day we measured, the index failed on 4 of the 10 sites even so. See benchmarks.

Workflow examples

Extract brand assets

webclaw https://github.com --brand

Compare a page over time

webclaw https://example.com/pricing --format json > pricing-old.json
webclaw https://example.com/pricing --diff-with pricing-old.json

MCP Server

webclaw ships with an MCP server for AI agents.

Zero-install — point any MCP client at the npx launcher:

{
  "mcpServers": {
    "webclaw": {
      "command": "npx",
      "args": ["-y", "@webclaw/mcp"]
    }
  }
}

Or run npx create-webclaw to auto-detect your AI tools and write their configs for you.

Over HTTP

To share one server between agents, or reach it from another machine, serve it over streamable HTTP:

WEBCLAW_MCP_TOKEN=$(openssl rand -hex 16) webclaw-mcp --http 127.0.0.1:8000

Clients connect to http://127.0.0.1:8000/mcp and send Authorization: Bearer <token>:

{
  "mcpServers": {
    "webclaw": {
      "type": "http",
      "url": "http://127.0.0.1:8000/mcp",
      "headers": { "Authorization": "Bearer <token>" }
    }
  }
}

The server refuses to start over HTTP without a token, because anyone who reaches it can make the machine fetch any URL; --no-auth serves it open anyway. On a loopback address it also rejects requests whose Host header names another host, which blocks DNS-rebinding attacks from web pages.

Then ask your agent things like:

Scrape these competitor pricing pages and summarize the differences.
Crawl this documentation site and prepare clean context for a RAG index.
Extract the brand colors, fonts, and logos from this company website.

Use as an agent skill

Add webclaw to Claude Code, Cursor, Windsurf, and other MCP agents in one command:

npx skills add 0xMassi/webclaw-skill

Your agent gets scrape, crawl, map, extract, summarize, diff, brand, and search as native tools. Most sites extract locally with no API key. Set WEBCLAW_API_KEY to handle bot-protected and JavaScript-rendered pages.

Find it on skills.sh.


Tools

Tool

What it does

Local

scrape

Extract one URL as markdown, text, JSON, LLM format, or HTML

Yes

select

Pick values or records from a page with CSS selectors or XPath, its data tables, elements found by text, or every element like an example, as JSON

Yes

screenshot

Capture a page's viewport or the whole page as PNG or JPEG, print it to PDF, or save it as one MHTML file

Yes, with a browser build

crawl

Follow same-origin links and extract discovered pages, most relevant first with a query

Yes

map

Discover URLs from sitemaps, a short crawl and the Common Crawl index without extracting every page

Yes

batch

Scrape multiple URLs in parallel

Yes

extract

Convert page content into structured data

Yes, with local or configured LLM

summarize

Summarize a page

Yes, with local or configured LLM

diff

Compare page content snapshots

Yes

brand

Extract colors, fonts, logos, and metadata

Yes

search

Search the web and scrape results

Hosted API

research

Multi-source research workflow

Hosted API


SDKs

npm install @webclaw/sdk
pip install webclaw
go get github.com/0xMassi/webclaw-go
import { Webclaw } from "@webclaw/sdk";

const client = new Webclaw({ apiKey: process.env.WEBCLAW_API_KEY! });

const page = await client.scrape({
  url: "https://example.com",
  formats: ["markdown"],
  only_main_content: true,
});

console.log(page.markdown);
from webclaw import Webclaw

client = Webclaw(api_key="wc_your_key")

page = client.scrape(
    "https://example.com",
    formats=["markdown"],
    only_main_content=True,
)

print(page.markdown)
curl -X POST https://api.webclaw.io/v1/scrape \
  -H "Authorization: Bearer $WEBCLAW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "formats": ["markdown"],
    "only_main_content": true
  }'

Output Formats

Format

Use it when you need

markdown

Clean page content with structure preserved

llm

Compact context for agents and RAG pipelines

text

Plain text with minimal formatting

json

Structured metadata, links, images, and extracted fields

html

Cleaned HTML for custom processing


Local First, Hosted When Needed

The CLI and MCP server work locally without an account for the core extraction path.

Use the hosted API at webclaw.io when you need:

  • protected-site access without managing infrastructure

  • JavaScript rendering

  • async crawl and research jobs

  • web search

  • watches and production usage tracking

  • SDKs for application code

export WEBCLAW_API_KEY=wc_your_key

webclaw https://example.com --cloud

What You Can Build

Use case

Example

AI agent web access

Give Claude, Cursor, or another MCP client clean page context

RAG ingestion

Crawl docs, help centers, blogs, and knowledge bases

Competitor monitoring

Track pricing pages, changelogs, docs, and product pages

Structured extraction

Turn messy pages into typed JSON for automations

Research workflows

Search, scrape, summarize, and cite multiple sources

Brand intelligence

Extract logos, colors, fonts, and social metadata

Architecture

webclaw/
  crates/
    webclaw-core     HTML to markdown, text, JSON, and LLM-ready output
    webclaw-fetch    Fetching, crawling, batching, and mapping
    webclaw-llm      Local and hosted LLM provider support
    webclaw-pdf      PDF text extraction
    webclaw-mcp      MCP server for AI agents
    webclaw-cli      Command-line interface

webclaw-core is pure extraction logic: no network I/O, small surface area, and usable independently from the fetching layer.


Configuration

Variable

Description

WEBCLAW_API_KEY

Hosted API key

OLLAMA_HOST

Ollama URL for local LLM features

OPENAI_API_KEY

OpenAI-compatible LLM provider key

OPENAI_BASE_URL

OpenAI-compatible base URL

ANTHROPIC_API_KEY

Anthropic-compatible LLM provider key

ANTHROPIC_BASE_URL

Anthropic-compatible base URL

ORCAROUTER_API_KEY

OrcaRouter LLM provider key

ORCAROUTER_BASE_URL

OrcaRouter base URL (defaults to https://api.orcarouter.ai/v1)

WEBCLAW_PROXY

Single proxy URL

WEBCLAW_PROXY_FILE

Proxy pool file

WEBCLAW_RENDER

MCP server rendering: auto (default), always or never; needs a browser build

WEBCLAW_CDP_URL

MCP server renders with the browser at this DevTools endpoint instead of launching Chrome

WEBCLAW_BROWSER_PROFILE

MCP server keeps its browser's cookies and storage in this directory between runs; see --browser-profile

WEBCLAW_CHROME

Chrome executable to launch for rendering

WEBCLAW_MCP_TOKEN

Bearer token webclaw-mcp --http requires from every client


Contributing

The most useful contributions right now are practical and small:

  • add examples for real agent and RAG workflows

  • improve SDK snippets

  • report pages that extract poorly

  • add failing fixtures for messy HTML

  • improve docs for MCP clients and local setup

  • test the CLI on more Linux/macOS environments

Good first places to start:

If a page extracts badly, include:

URL:
Command or API request:
Expected output:
Actual output:
Format used: markdown / llm / text / json / html
CLI, MCP, SDK, or API:

Please remove secrets, cookies, private tokens, and customer data from logs before posting.


Strategic Partner


Infrastructure Partner


Studio Partners


Community Plugins

Third-party plugins that integrate webclaw with AI agent platforms:

Plugin

Platform

What it does

openclaw-webclaw

OpenClaw

Native webclaw v1 API plugin with 9 tools: scrape, search, crawl, extract, summarize, diff, map, batch, brand

hermes-webclaw

Hermes Agent

Web search provider and 9 dedicated tools for the full v1 API surface. Install with hermes plugins install jal-co/hermes-webclaw

Built a webclaw integration? Open a PR to add it here.


Contributors

Thanks to everyone improving webclaw through issues, examples, docs, bug reports, and pull requests.


Star History


License

AGPL-3.0-only

Available Tools

10 tools
batchB

Extract content from multiple URLs concurrently.

NameRequiredDescriptionDefault
concurrencyNoNumber of concurrent requests (default: 5)
formatNoOutput format: "markdown" (default), "llm", "text"
urlsYesList of URLs to extract content from

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must carry full behavioral disclosure. It successfully mentions 'concurrently' indicating parallel execution, but lacks critical safety information for a network tool: error handling behavior (what happens if one URL fails?), timeout behavior, rate limiting, or whether results preserve input ordering.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Extremely efficient at 6 words. Front-loaded with action verb ('Extract') and scope ('multiple URLs concurrently'). Zero redundancy or filler content. Every word earns its place without requiring editing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 100% input schema coverage, the description need not elaborate on parameters. However, lacking both annotations and output schema, the description should disclose error behavior or return structure for this concurrent network operation. It is minimal but adequate given the straightforward nature of the operation and good schema coverage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% (concurrency, format, urls all documented), establishing baseline 3. The description implies the 'urls' parameter through 'multiple URLs' but adds no semantic detail beyond what the schema already provides for parameters (no syntax examples, no clarification of 'llm' format value, no default explanations).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses specific verb 'Extract' and resource 'content from multiple URLs', and includes 'concurrently' which hints at the batch nature. However, it does not explicitly distinguish this from the sibling 'extract' tool (likely single-URL) or 'crawl' (which may also handle multiple URLs), leaving some ambiguity about when to choose this specific tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like 'extract', 'scrape', or 'crawl'. It does not mention prerequisites, rate limiting considerations, or appropriate use cases for concurrent processing versus sequential operations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

brandA

Extract brand identity (colors, fonts, logo, favicon) from a website's HTML and CSS. Automatically falls back to the webclaw cloud API when bot protection is detected.

NameRequiredDescriptionDefault
urlYesURL to extract brand identity from

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full disclosure burden. It adds valuable behavioral context about the automatic fallback to webclaw cloud API when bot protection is detected, which is critical for dependency understanding. However, it omits other important behavioral details like rate limits, authentication requirements, or what happens when extraction partially fails.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two efficiently structured sentences with zero waste. The first front-loads the core purpose with specific deliverables, while the second adds critical operational context (fallback behavior). Every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with full schema coverage and no output schema, the description adequately covers the primary unusual behavior (external API fallback). It could be improved by briefly mentioning the expected return structure or noting that this is a read-only operation, but the essential functional and behavioral context is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Despite 100% schema coverage (baseline 3), the description adds meaningful semantic context by specifying extraction occurs from 'HTML and CSS', implying the URL should point to a styled webpage rather than arbitrary resources. This adds clarity beyond the schema's basic 'URL to extract brand identity from'.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific extraction target (colors, fonts, logo, favicon) using the verb 'Extract', making the scope well-defined. However, it lacks explicit differentiation from the sibling 'extract' tool, which could cause confusion about when to choose 'brand' over general extraction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides implicit guidance by specifying the domain (brand identity extraction) and mentions automatic fallback behavior when bot protection is detected. However, it lacks explicit 'when to use' guidance contrasting with siblings like 'extract', 'scrape', or 'crawl'.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

crawlB

Crawl a website starting from a seed URL, following links breadth-first up to a configurable depth and page limit.

NameRequiredDescriptionDefault
concurrencyNoNumber of concurrent requests (default: 5)
depthNoMaximum link depth to follow (default: 2)
formatNoOutput format for each page: "markdown" (default), "llm", "text"
max_pagesNoMaximum number of pages to crawl (default: 50)
urlYesSeed URL to start crawling from
use_sitemapNoSeed the frontier from sitemap discovery before crawling

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It reveals the algorithm (breadth-first) and constraints (depth/page limits), but omits critical operational details: that it makes external HTTP requests, potential rate-limiting concerns, concurrency behavior implications, and what data structure it returns.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence with zero waste. It front-loads the operation ('Crawl a website') and logically flows from seed URL through traversal method to constraints.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (6 parameters, network I/O, potentially long-running) and the absence of annotations or output schema, the description is minimally adequate but omits important context. It fails to describe return values, error conditions, or external side effects that an agent would need to know.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, establishing a baseline of 3. The description mentions 'configurable depth and page limit' and 'seed URL', which reference parameters, but adds no additional semantic context, syntax guidance, or usage patterns beyond what the schema already documents.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description provides a clear specific verb ('Crawl') and resource ('website'), and explains the core mechanism ('following links breadth-first'). However, it does not explicitly differentiate from sibling tools like 'scrape' or 'map' that might overlap in functionality.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description offers no guidance on when to use 'crawl' versus siblings such as 'scrape', 'extract', or 'map'. There are no exclusion criteria or stated prerequisites for selection.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

diffA

Compare the current content of a URL against a previous extraction snapshot, showing what changed. Automatically falls back to the webclaw cloud API when bot protection is detected.

NameRequiredDescriptionDefault
previous_snapshotYesPrevious extraction snapshot as a JSON string (ExtractionResult)
urlYesURL to fetch current content from

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure and successfully reveals the automatic fallback to 'webclaw cloud API when bot protection is detected.' However, it omits other critical behavioral traits such as whether the operation is read-only, idempotent, or what error conditions might occur beyond bot protection.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description consists of exactly two sentences with zero wasted words. The first sentence front-loads the core functionality, while the second provides relevant operational context regarding the fallback mechanism, maintaining tight focus throughout.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (comparison logic with fallback) and the absence of an output schema, the description adequately covers the input requirements and operational model. However, it would benefit from explicitly stating the prerequisite relationship to the 'extract' sibling and describing the expected diff output format.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 100% description coverage for both parameters ('url' and 'previous_snapshot'), establishing a baseline of 3. The description references these parameters in context ('current content of a URL,' 'previous extraction snapshot') but does not add additional semantic details beyond what the schema already provides, such as validation rules or the expected format of the ExtractionResult.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Compare') and clearly identifies both resources involved ('current content of a URL' vs 'previous extraction snapshot'), along with the output ('showing what changed'). It effectively distinguishes this from siblings like 'extract' or 'scrape' by specifying the comparison paradigm.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The mention of 'previous extraction snapshot' implicitly signals that this tool should be used after an extraction has been performed, providing context for the prerequisite workflow. However, it lacks explicit guidance on when to choose this over siblings like 'crawl' or 'scrape' for monitoring changes, or what conditions make the fallback behavior trigger.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

extractA

Extract structured data from a web page using an LLM. Provide either a JSON schema or a natural language prompt. Automatically falls back to the webclaw cloud API when bot protection is detected.

NameRequiredDescriptionDefault
promptNoNatural language prompt describing what to extract
schemaNoJSON schema describing the structure to extract
urlYesURL to fetch and extract structured data from

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full transparency burden. It successfully discloses the automatic fallback to 'webclaw cloud API when bot protection is detected,' which is substantive behavioral context. However, it omits rate limits, auth requirements, and output format details.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tightly constructed sentences: purpose declaration, input guidance, and fallback behavior. Every sentence earns its place with no redundancy or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 9 sibling tools sharing similar domains ('scrape', 'crawl', 'summarize'), the description lacks explicit differentiation to aid tool selection. While the core functionality is covered, the absence of output schema disclosure and sibling comparisons leaves gaps for agent decision-making.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, establishing a baseline of 3. The description adds value by clarifying the relationship between 'schema' and 'prompt' parameters ('either... or'), indicating they are alternative specification methods—a semantic constraint not explicit in the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb ('Extract') and resource ('structured data from a web page') are clear, plus method ('using an LLM'). However, it does not explicitly differentiate from siblings like 'scrape' (raw HTML) or 'crawl' (multiple pages), only implying the distinction via the LLM mention.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implies usage by stating input options ('Provide either a JSON schema or a natural language prompt'), but lacks explicit when-to-use guidance versus alternatives like 'scrape' or 'summarize', and does not state prerequisites or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mapA

Discover URLs from a website's sitemaps (robots.txt + sitemap.xml).

NameRequiredDescriptionDefault
urlYesBase URL to discover sitemaps from (e.g. `<https://example.com>`)

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It adds valuable behavioral context by specifying it checks both 'robots.txt' and 'sitemap.xml'. However, missing critical behavioral details: whether it follows sitemap index files, rate limiting, output format, or error handling when sitemaps are absent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Extremely efficient at 9 words. Front-loaded with the action 'Discover URLs' and immediately specifies the source mechanism. Every word earns its place with zero redundancy or boilerplate.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Appropriately complete for a single-parameter discovery tool. The description covers the core function and specific data sources. Minor gap: does not describe the return value (list of URLs), though this is somewhat implied by 'Discover URLs'.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema has 100% description coverage with the 'url' parameter well-documented as 'Base URL to discover sitemaps from'. The description does not add additional semantics about the parameter (e.g., protocol requirements, trailing slashes), warranting the baseline score for high-coverage schemas.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb 'Discover' with clear resource 'URLs' and distinct mechanism 'sitemaps (robots.txt + sitemap.xml)'. This effectively distinguishes the tool from siblings like 'crawl' or 'scrape' by specifying it extracts URLs from sitemap files rather than page content.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implies usage through the specific mechanism mentioned (sitemaps), suggesting use when architectural URL discovery is needed. However, lacks explicit guidance on when to prefer this over 'crawl' or 'search' siblings, or prerequisites like requiring valid sitemap files.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

researchA

Run a deep research investigation on a topic or question. Requires WEBCLAW_API_KEY. Starts an async research job on the webclaw cloud API, then polls until complete.

NameRequiredDescriptionDefault
deepNoEnable deep research mode for more thorough investigation (default: false)
queryYesResearch query or question to investigate
topicNoTopic hint to guide research focus (e.g. "technology", "finance", "science")

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses async execution model (starts job, polls) and authentication requirement, which is valuable given no annotations. However, missing critical behavioral details: no description of return format (text? JSON? report?), no mention of rate limits, cost implications, or error states for the cloud API operation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences with zero waste: purpose front-loaded, prerequisites stated, execution model explained. No redundancy with structured fields.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Adequate for basic invocation but gaps remain: no output schema exists yet description doesn't specify return format (critical for a research tool), and lacks guidance on expected duration or result structure given the async polling pattern described.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 100% description coverage, establishing baseline 3. Description reinforces parameters by mentioning 'deep research' (deep), 'topic' (topic), and 'question' (query), but adds no syntax details, examples, or constraints beyond what the schema already provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clear verb+resource ('Run a deep research investigation') and distinguishes from siblings like 'search' by emphasizing 'deep' investigation and async execution ('polls until complete'). However, could more explicitly contrast with 'search' or 'summarize' siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides prerequisite ('Requires WEBCLAW_API_KEY') and implies usage context through 'deep' and async behavior, but lacks explicit when-to-use guidance versus alternatives like 'search' for quick lookups or 'scrape' for specific extraction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

scrapeA

Scrape a single URL and extract its content as markdown, LLM-optimized text, plain text, or full JSON. Automatically falls back to the webclaw cloud API when bot protection or JS rendering is detected.

NameRequiredDescriptionDefault
browserNoBrowser profile: "chrome" (default), "firefox", or "random"
exclude_selectorsNoCSS selectors to exclude from output
formatNoOutput format: "markdown" (default), "llm", "text", or "json"
include_selectorsNoCSS selectors to include (only extract matching elements)
only_main_contentNoIf true, extract only the main content (article/main element)
urlYesURL to scrape

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full disclosure burden. Adds valuable operational context about automatic fallback to webclaw cloud API for bot protection and JS rendering, but omits rate limits, authentication requirements, timeout behavior, and error handling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with zero waste. First sentence establishes core functionality and output options; second provides critical implementation detail about fallback behavior. Well-structured and appropriately front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Adequate for a 6-parameter tool with complete schema coverage. Description compensates for missing output schema by detailing return format options, though could enhance with error behavior or rate limit documentation given the web scraping domain.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 100% description coverage (baseline 3). Description adds semantic value by clarifying that 'llm' format means 'LLM-optimized text' and elaborating on format intentions beyond the schema's terse descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clear specific verb 'scrape' with scope 'single URL' that explicitly distinguishes from sibling tools like 'batch' and 'crawl'. Lists output formats (markdown, LLM-optimized text, plain text, JSON) to clarify extraction capabilities.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implicitly differentiates from batch/crawl via 'single URL' phrasing, but lacks explicit when-to-use guidance versus siblings like 'extract' or 'map'. No mention of prerequisites such as URL accessibility or when to prefer local vs cloud fallback.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

summarizeA

Summarize the content of a web page using an LLM. Automatically falls back to the webclaw cloud API when bot protection is detected.

NameRequiredDescriptionDefault
max_sentencesNoNumber of sentences in the summary (default: 3)
urlYesURL to fetch and summarize

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. It effectively discloses two key behaviors: (1) it uses an LLM (not just extraction), and (2) it 'automatically falls back to the webclaw cloud API when bot protection is detected' - crucial resilience behavior. Missing: output format, error handling on failure, or rate limit warnings.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, both essential. First sentence front-loads the core purpose (LLM summarization). Second sentence provides critical operational detail (fallback mechanism). Zero waste, appropriately sized for the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 2-parameter tool with no output schema, the description adequately covers core function and resilience behavior. Minor gap: no mention of return value format (string vs object) or what happens if the URL is unreachable even after fallback.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 100% description coverage ('URL to fetch and summarize', 'Number of sentences...'), establishing a baseline of 3. Description reinforces the 'web page' concept aligning with the url parameter, but adds no syntax details, format constraints, or semantic clarification beyond the schema definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states the tool 'Summarize[s] the content of a web page using an LLM' - providing specific verb (summarize), resource (web page content), and method (LLM). This distinguishes it from siblings like 'scrape' (raw extraction), 'extract' (structured data), and 'crawl' (multi-page), which don't imply LLM-based condensation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Description implies usage by mentioning LLM-based summarization, but provides no explicit guidance on when to choose this over siblings like 'scrape' or 'extract'. The fallback behavior hints at resilience but doesn't state prerequisites or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 10 tool updatesv0.1.0
    • First observedbatch
    • First observedbrand
    • First observedcrawl
    • First observeddiff
    • First observedextract
    • First observedmap
    • First observedresearch
    • First observedscrape
    • First observedsearch
    • First observedsummarize

TDQS

A3.8/5.0

Scored across 10 tools

Disambiguation4/5

Most tools have distinct purposes, but there is some potential overlap between 'extract' (structured data via LLM) and 'scrape' (content extraction in various formats), which could cause confusion. Other tools like 'brand', 'diff', 'map', and 'summarize' are clearly specialized, helping to minimize misselection.

Naming Consistency5/5

All tool names follow a consistent pattern of single, descriptive verbs (e.g., batch, brand, crawl, diff, extract, map, research, scrape, search, summarize). There are no mixed conventions or deviations, making the set predictable and easy to navigate.

Tool Count5/5

With 10 tools, the count is well-scoped for a web scraping and research server. Each tool appears to serve a specific function in the domain, from basic scraping to advanced research, without feeling excessive or insufficient for the intended purpose.

Completeness4/5

The toolset covers a broad range of web-related operations, including extraction, crawling, searching, and analysis. Minor gaps exist, such as the lack of explicit update or delete operations for stored data, but these are not critical for the server's primary focus on content retrieval and processing.

Maintenance

ActivityActive
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    C
    maintenance
    🚀 Active Fork of executeautomation/mcp-playwright This repository is an actively maintained continuation of the original MCP Playwright server: >👉 https://github.com/executeautomation/mcp-playwright A Model Context Protocol server that provides browser automation capabilities using Playwright.
    32
    7,757 npm
    1
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Web scraping, crawling, and structured data extraction for AI agents. 5 tools: scrape (clean markdown from any URL), crawl (entire sites), map (discover URLs), extract (structured JSON), and search. 833ms avg latency, single binary, self-hostable.
    8
    1,172
    AGPL 3.0
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI agents to extract clean, structured web content (articles, tables, links, visual layouts) optimized for LLM token efficiency, with fast response times and optional JavaScript support.
    5
    37 npm
    MIT