Grab a key (500 free pages, no card), install the SDK, describe the data. That's the whole tutorial.
# install pip install plainscrape # or: npm i plainscrape # extract from plainscrape import scrape data = scrape( url="news.example.com", instruction="every article title, author and date this week", max_pages=100, ) print(len(data), data.cost_usd) # 312 0.158
One request, one finished dataset. Synchronous up to 25 pages; larger jobs return a job_id to poll or receive by webhook.
| Param | Description | |
|---|---|---|
url | required | Start URL. Any public page. |
instruction | required | Plain-language description of the data — fields, filters, and scope in one sentence. |
max_pages | optional | Hard page budget. Crawling also stops early once the instruction is satisfied. |
schema | optional | JSON Schema for guaranteed output shape. Derived automatically if omitted, then reused for consistency. |
fields | optional | Shorthand alternative to schema: ["name","price","rating"]. |
actions | optional | Browser steps in English: ["click 'Load more' until done"]. |
output | optional | json (default) · csv · markdown. |
# every response, always: { "rows": 312, "pages_used": 100, "cost_usd": 0.158, "result_id": "res_8xk2…", "data": [ … ] }
Follow-up instructions update the dataset in place. Plainscrape remembers what it already extracted, so no pages are re-crawled and you're billed only a refinement fee.
POST /v1/extract/{result_id}/refine
{ "instruction": "also note which plans have a free trial;
split price into amount and currency" }
# → same rows, new columns, "pages_used": 0Site-wide, instruction-scoped. Set the boundary in the request ("only /products/", "stop at last month") or with max_pages. Async by default; results stream to a webhook or paginate via the SDK iterator.
for page in client.crawl(url, instruction, max_pages=500).pages():
save(page.data)Standing instructions on a schedule. You're billed only for pages checked; unchanged results are summarized, changes fire your webhook.
{ "url": "competitor.example/pricing",
"instruction": "every plan with monthly price",
"every": "1d", "notify": "https://hooks.you.dev/pricing" }Python (pip install plainscrape) and JavaScript (npm i plainscrape), both typed, with auto-paginating iterators for crawls and batches. LangChain loader and LlamaIndex reader ship as extras.
One command web-enables Claude Code, Claude Desktop, Cursor, or Windsurf:
$ claude mcp add plainscrape -- npx -y plainscrape-mcp
Tools: plainscrape_extract · refine · crawl · markdown · monitor · status. Every tool result includes cost_usd so agents can budget themselves.
Fields the page genuinely doesn't contain come back as "NOT_FOUND" — never a guessed value. Failed page fetches are free and listed in skipped[] with a reason (blocked, 404, timeout) so you can retry deliberately.