# SnoopScan > SnoopScan is a web scraping API and MCP server for AI agents. One call turns any public web page into clean markdown, links, a screenshot or JSON in your own schema, including pages that need JavaScript and pages that block ordinary scrapers. It also crawls whole sites, maps every URL on a site, searches the web, extracts structured data, reads PDFs and documents, lists a store's products or a blog's posts, enriches a company from its own site, reports on domains, and watches pages for changes. People use SnoopScan from inside an AI chat (Claude Code, Codex, Cursor, VS Code, Windsurf, the Claude app, ChatGPT). Setup is done by the agent, not the person: when someone asks you to set up SnoopScan, read https://snoopscan.com/agent-onboarding/SKILL.md and follow it. Never tell the person to run a command in a terminal; run it yourself. The person only signs in and presses Approve in their browser. The line people paste into their agent: "Read and follow https://snoopscan.com/agent-onboarding/SKILL.md" ## Set up - [Agent onboarding](https://snoopscan.com/agent-onboarding/SKILL.md): step by step for Claude Code, Codex, Cursor, VS Code, Windsurf, the Claude app, ChatGPT and any other MCP client, including how to get a real key through a browser sign-in, the command-line tool, the SDKs, REST and troubleshooting. - MCP server: `https://api.snoopscan.com/mcp` (streamable HTTP, `Authorization: Bearer `). Sign-in address with no key: `https://api.snoopscan.com/mcp-oauth` (OAuth, for the Claude app, ChatGPT and any client that signs in). - Never write a placeholder key such as `sk_...` into anyone's setup. Get a real one with the browser sign-in in the agent onboarding guide. - No key yet, and the person cannot sign up right now: `https://api.snoopscan.com/mcp` with no `Authorization` header, or `POST https://api.snoopscan.com/v1/scrape`, `/search` and `/parse` with none, is a free trial of scrape, search, parse: 20 free successful calls a day from each address, plain pages only. Every answer shows the calls left, and a blocked page does not use one up. When a page needs a browser or the calls run out, follow the sign-in steps in the agent onboarding guide. - [Integrations](https://snoopscan.com/integrations): setup pages for more than forty clients. ## Tools The MCP tools, and what each is for: - `scrape`: One page as clean markdown. Set maxChars to cap how much comes back. - `fetchMore`: The rest of a page that scrape cut short, picked up from the token it left. - `crawl`: Start a crawl, get a job id back at once. - `crawlStatus`: Where a crawl has got to: pages done, pages found, whether it has finished. - `crawlPages`: The pages a crawl has collected so far, without waiting for it to finish. - `map`: Every URL on a site, no page content. The cheap way to plan. - `search`: Web search; titles and snippets by default, page bodies only when asked. - `extract`: JSON to your schema from up to 10 pages, validated, never invented. - `batchScrape`: Scrape up to 50 pages as one background job. Follow it with crawlStatus and read the pages with crawlPages. - `listProducts`: Every product a store publishes, from its own catalogue: title, price, stock, variants and link. Use it instead of crawling a shop. - `listPosts`: Every post a blog or forum publishes, from its own API or feed, newest first. Use it instead of crawling a blog. - `checkChanges`: Has this page changed since it was last fetched, with a diff if wanted. - `watchPages`: Start a monitor that re-reads up to 50 pages on a schedule and records which are new, changed or failing. - `listMonitors`: List your page monitors with their schedule and when each last ran. - `checkMonitor`: Run a monitor now and report which of its pages are new, changed, unchanged or failing. - `searchPlaces`: Search Google Maps for businesses by trade and town, each with its category, address, rating, phone and website. Up to 20 a call. - `domain`: Domain age, registrar, DNS and known backlinks. Use it to judge a site rather than read one. - `domainReport`: A buyer's report on a domain: key findings, concerns and the questions nobody can answer from outside, each tied to its evidence. Quick, buyer or deep. - `domainSnapshots`: Read the archived homepage snapshots a buyer report left pending: what the site was about each year, and whether it was parked or for sale. - `domainScreen`: Which of up to 500 domain names can be registered, from each registry's own record and DNS. Cut a long list to a shortlist before running domainReport. - `findLeads`: Find businesses by what they do and where, each with its phone, website and the emails it publishes, and optionally your own yes/no questions answered from each business's website. Runs for a few minutes. - `leadsStatus`: Follow a Find Leads run, and read its leads 25 at a time once it has finished. - `company`: Everything a company's own site says about itself: firmographics, contact emails, LinkedIn and socials. Enrich one company, not a directory. - `findContacts`: A website's contact page, contact form, published email addresses (with where each was found) and social links. - `hiring`: What a company is currently recruiting for, read from its applicant tracking system's own public job feed rather than the careers page, which usually renders its roles client-side and looks empty. - `people`: Find the people at a company by function (engineering, sales, procurement, talent, finance and more) and seniority (exec, vp, director, manager, ic). Says whether each employer was confirmed, and flags anyone who has left. - `social`: Structured data from YouTube, TikTok, Instagram, X, LinkedIn, Facebook, Threads and Pinterest: profiles, posts, videos, comments, transcripts and search, as named fields. - `socialEndpoints`: List every social endpoint with its inputs and price, optionally for one platform. - `watchMentions`: Save a watch: keywords, words to ignore and places to look (Reddit, Hacker News, Bluesky, YouTube, Threads, GitHub, the web). New mentions are checked on a schedule and sorted by what the person wants. - `listMentions`: Read the mentions a watch found, newest first, filtered by kind (buying intent, bug report, question, praise, competitor), place or status. - `testMentions`: Try keywords against the last seven days before saving a watch, to see what it would catch. - `markMention`: Mark a mention seen, done or not relevant. - `googleSerp`: Read a Google results page: who ranks, and what the AI Overview says and cites. Give your domain to see where it ranks and whether it is cited. - `parse`: A document at a URL, such as a PDF, as markdown. Use it for a link to a document rather than a web page. The product and post listings, the domain report, its snapshots, the domain screen, and the company, contact, people, hiring and lead tools run on the hosted service at https://snoopscan.com only; a self-hosted copy of the open-source core answers them as not available. ## When to use it - An agent needs what a web page says, as text it can read: use `scrape` rather than a raw HTTP fetch, which returns navigation, cookie banners and script instead of the content. - A page is built by JavaScript, or blocks ordinary scrapers: SnoopScan handles it with no extra setup. - Many pages from one site: `map` lists the URLs first (one flat charge), then `crawl` reads the ones that matter. - Rows rather than prose: `extract` fills a JSON schema you give it, across many pages at once. For a store's catalog or a blog's posts, `listProducts` and `listPosts` return everything in a few calls, cheaper and more complete than crawling. - A recurring check: `checkChanges` (MCP) or the monitor API watches pages and reports only what changed. - Not for: pages behind a login, anything that needs submitting a form, posting, buying or signing in as someone. SnoopScan only reads public pages. ## Pricing Credits, one allowance for every tool. Every plan has every tool and every output format; plans differ in monthly credits and how many requests run at once. Failed requests cost nothing, and re-reading a page you already fetched is free. - Free: free, no card, 1,500 credits a month, 5 requests at once - Starter: $12 a month or $120 a year, 10,000 credits a month, 15 requests at once - Standard: $59 a month or $588 a year, 100,000 credits a month, 50 requests at once - Growth: $249 a month or $2,388 a year, 500,000 credits a month, 100 requests at once - Scale: $449 a month or $4,428 a year, 1,000,000 credits a month, 150 requests at once What a call costs: - Standard page: 1 credit a request. A page that loads with a standard request. Most pages do. - Premium proxy page: 2 credits a request. A page that needs a premium proxy to load. - Browser page: 1 credit a request. A page that needs a real browser to render. - Browser page with premium proxy: 9 credits a request. A page that needs a real browser and a premium proxy. - PDF parsing: 1 credit a 10 pages. Per 10 pages parsed (or part of 10), added to the fetch cost. - Cached page, your own: 0 credits a request. A page you already fetched, served again within maxAge. - Web search: 2 credits a request. Per search call. Result pages fetched are metered as scrapes on top. - Site map: 1 credit a request. Per map call, however many URLs come back. - Catalog or feed page: 1 credit a page. Up to 250 products, or 100 posts, in a single call. - Domain lookup: 1 credit a request. Registration, DNS and known backlinks for one domain. - Company enrichment: 3 credits a request. Firmographics, contact emails, LinkedIn and social profiles for one company. - Places search: 10 credits a request. One search for business listings, however many come back. - Place detail: 2 credits a place. Website, phone and contacts for one business. Only when you ask for them. - Lead: 4 credits a lead. One business found by Find Leads, with its phone, website and address. Only leads delivered are charged. - Lead contacts: 4 credits a lead. The emails, social profiles and contact form a lead publishes. Only when found. - Named contact: 8 credits a person. A named person at a lead, found by the role you ask for. Only when found. - Domain availability screen: 1 credit a name. Whether a name is available to register. Up to 500 names a call; names we cannot check are not charged. - Domain report: quick: 5 credits a report. Registration, DNS, email records and what the website shows today. - Domain report: buyer: 33 credits a report. The quick report plus archive history, known backlinks and a check that linking pages still link. Six archived snapshots included. - Domain report: deep: 160 credits a report. The buyer report with larger samples: up to 50 linking pages checked and twelve archived snapshots included. - Fit check: 3 credits a business. Your own questions answered from a business's website, with a quoted line. Only when its site was read. - Social data: 1 credit a call. One structured answer from a social platform: a profile, a post, a video, a page of comments or a transcript. Only when data comes back. - Social data (heavy pages): 2 credits a call. The same, for the platforms whose public pages are the largest to read. Only when data comes back. Every response carries a `cost` object with what the call was charged. ## Docs - [Documentation](https://snoopscan.com/docs): every endpoint, field and error code. - [Quickstart](https://snoopscan.com/docs/quickstart): set up in chat, or make one API call from code. - [MCP server](https://snoopscan.com/docs/mcp): the tools and how clients connect. - [Credits](https://snoopscan.com/docs/credits): what each call costs. - [Errors](https://snoopscan.com/docs/errors): every error code and what to do about it. - [Pricing](https://snoopscan.com/pricing): plans and the full rate card. - REST base URL: `https://api.snoopscan.com/v1` (scrape, crawl, map, search, extract, batch/scrape, products, posts, monitor, places/search, domain, domain/report, domain/screen, leads, company). ## Optional - [Full reference in one file](https://snoopscan.com/llms-full.txt): the agent onboarding guide, every tool, every endpoint's parameters, pricing and the FAQ. - [Open-source core](https://github.com/SnoopScan/snoopscan-core): the engine, the MCP server and the SDKs (AGPL-3.0; SDKs MIT). --- # SnoopScan — agent onboarding SnoopScan is a web scraping API: one call turns any public page into markdown, links, or JSON in your own schema — including pages that block everything else. Beyond single pages it can crawl a whole site, search the web, pull structured data against a schema, enrich a company from its own site, report on a domain before you buy it, and watch a page for changes on a schedule. Pick the path below that matches what you are doing. Every command block is meant to be run as written. ## Setting SnoopScan up for someone? Read this first The person uses SnoopScan from the chat, so the setup is yours to do: - **Run every command yourself. Never tell the person to run a command in a terminal.** The only things they do are sign in (or create a free account) and press Approve in their browser. - **Never write a placeholder key** like `sk_...` or `YOUR_API_KEY` into a config and call it done. Get them a real key (below). - **Keep the key out of the chat.** Never show it in your replies, and never ask the person to paste it unless nothing else works (step 4 below). Pass it by command substitution where you can, as in the Claude Code command below, so it is written into the config without ever appearing in the conversation. - **Ask before you change anything else on their machine**, such as installing Node or Python. - **Finish with a test**: read one page through SnoopScan and show them it works. You are Claude Code? Read the next section. Any other client (Codex, Cursor, VS Code, Windsurf, the Claude app, ChatGPT, anything else that speaks MCP) is in Path D. ## Fastest: you are Claude Code 1. Get a key with the browser login in "Get a key first" below. The person presses Approve; the key is saved for you. 2. Add SnoopScan for every project, with the key filled in by the command itself: ```bash claude mcp add --transport http snoopscan https://api.snoopscan.com/mcp \ --header "Authorization: Bearer $(npx -y snoopscan@latest config get api_key)" --scope user ``` Use `uvx snoopscan config get api_key` inside the `$( )` if you logged in with uv. If there is no `claude` command (the Claude desktop app's Code tab can lack it), add the server yourself: in `~/.claude.json`, under the top-level `"mcpServers"` object (create it if missing, keep everything else), put `"snoopscan": { "type": "http", "url": "https://api.snoopscan.com/mcp", "headers": { "Authorization": "Bearer " } }`. 3. `claude mcp get snoopscan` should say Connected. 4. **Tell the person, in these words or close to them:** > SnoopScan is set up. Its tools load in every new Claude Code session > from now on. In this session I can already use it: give me a page to > read. **Use the command line in this session.** A server added during a session loads when the next session starts, so until then do the work with the CLI you just logged in with: `npx -y snoopscan@latest scrape https://example.com` (Path A). **The sign-in address instead of a key** needs no install at all: `claude mcp add --transport http snoopscan https://api.snoopscan.com/mcp-oauth --scope user`. Its sign-in has to run once, and you cannot run it for them: `claude mcp login snoopscan` refuses to work without an interactive terminal, which your shell is not. So tell the person: > SnoopScan is added. Start a new session, type /mcp, pick snoopscan and > choose Authenticate. Your browser opens: log in, or create a free account > (1,500 credits a month, no card), and press Approve. Then ask me to read > any page. That costs the person a slash command and a new session, which is why the key route above comes first. ## Get a key first — and what to tell the person Every path below except Path E and the free trial needs a key. **Never write a placeholder like `sk_...` or `YOUR_API_KEY` into anyone's config and call it done.** Get them a real key, the easy way: 1. If `SNOOPSCAN_API_KEY` is set, or `snoopscan config get api_key` prints a key, you already have one. Skip to your path. 2. Otherwise, **tell the person, in these words or close to them:** > To use SnoopScan I need a free API key — the free plan has 1,500 credits > a month and needs no card. I'll open a login page in your browser: sign > in or create an account, check the code matches the one I show you, and > press Approve. The key is saved for me automatically. 3. Then get the key with **whichever of these the machine can already run**. Check before you install anything, and never change anything on the person's machine without asking them first. If their Node or Python is too old, **give them the choice**: update it (worth it if they will use the command line or an SDK: Node from https://nodejs.org or `brew install node`; Python 3.10+ from https://www.python.org/downloads or `brew install python`), or skip the install altogether with step 4, which needs nothing at all. ```bash node --version # v18 or newer? -> use (a) uv --version # installed? -> use (b) python3 --version # 3.10 or newer? -> use (c) ``` **(a) Node 18+: nothing to install, nothing on the PATH to go wrong.** ```bash npx -y snoopscan@latest login npx -y snoopscan@latest status npx -y snoopscan@latest config get api_key # prints the saved key ``` **(b) uv: brings its own Python, so an old system Python does not matter.** ```bash uvx snoopscan login uvx snoopscan status uvx snoopscan config get api_key ``` **(c) Python 3.10+ only:** ```bash python3 -m pip install --user snoopscan snoopscan login ``` **Run `login` in the background, or with a timeout of at least 10 minutes.** It waits until the person presses Approve, and a normal command timeout (often 2 minutes) kills it before they have finished signing up. Read its first lines as soon as they appear: show the person the link and the code in your reply, and tell them to press Approve in the browser. When it prints `Logged in`, carry on. `login` opens the browser and prints the link and a short code as well. On a machine with no browser (SSH, a container), add `--no-browser` and tell the person to open the link on any device, their phone included. 4. **If none of those will run, or an install fails, stop installing.** Tell the person: > No problem, we can skip the install. Please sign up (or sign in) at > https://snoopscan.com/register, open https://snoopscan.com/app/keys, > create a key, and paste it here. Then use the key directly: in an MCP config, a `.env`, or the `Authorization` header. SnoopScan's MCP server and REST API need no install at all; the command-line tool only exists to make getting the key easier. 5. **If the person can't sign up right now** (no time, no email to hand, or they want to see it work first), don't stall: use the free trial below, which needs no key at all ("Can't sign up right now?" below), and come back to this section when it runs out. ### When an install goes wrong Say what happened in one plain line, then take the next route. Do not retry the same failing command, and do not start upgrading the person's system. | What you see | What it means | Do this | |---|---|---| | `requires a different Python`, `No matching distribution`, or `unsatisfiable` | The Python is older than 3.10 (a Mac's built-in one is 3.9) | Use (a) or (b). If neither is there, offer: update Python, or step 4 | | `npx: command not found`, or Node older than 18 | No usable Node | Use (b) or (c). If neither, offer: install or update Node, or step 4 | | `snoopscan: command not found` right after `pip install` | pip put it somewhere not on the PATH | Run it as `python3 -m snoopscan`, or use (a) or (b) | | `EACCES` or `permission denied` from npm | A global install needs admin rights | Use `npx`, which installs nothing globally; never `sudo` | | `externally-managed-environment` from pip | The system forbids pip installs | Use (a) or (b); do not pass `--break-system-packages` | | SSL, certificate or proxy errors | A company network is in the way | Step 4 | | `Could not reach snoopscan.com` | The site is not reachable from this machine | Step 4; try again later | | `Too many login attempts` | Rate limit on logins | Wait a minute, then run login once more | | The login page says the link expired | Links last ten minutes and work once | Run login again for a fresh one | ### Keep it current, and check an install - `snoopscan doctor` (or `npx -y snoopscan@latest doctor`, `uvx snoopscan doctor`) checks everything at once and says how to fix what is wrong: this tool's version against the latest, the Node or Python it runs on, the config file, whether the key is set and accepted (on a free call), and whether the API is up. Run it after any install, and whenever something fails, before guessing. - An installed CLI prints `A newer snoopscan is available` on stderr when there is one. Pass it on and update: `npm install -g snoopscan@latest`, `pipx upgrade snoopscan`, `uv tool upgrade snoopscan`, or `python3 -m pip install -U snoopscan`. `npx ...@latest` and `uvx` always run the newest release, which is why they are the first choice above. After login, `config get api_key` (run the same way you ran login) prints the saved key, so you can put the real value into an MCP config or `.env` yourself instead of asking the person to paste it. Every request carries the key as `Authorization: Bearer `. A request without one is refused with a message that says how to get one; pass that on rather than guessing. A 401 with a key that looks right almost always means it was copied with a trailing newline — strip whitespace. ## Can't sign up right now? The free trial, no key SnoopScan answers a few calls with **no key at all**, so you can do the job now and sign up later: - **MCP:** add `https://api.snoopscan.com/mcp` with **no** `Authorization` header. `scrape`, `search` and `parse` work on the trial; every other tool answers with the sign-up steps. In Claude Code: ```bash claude mcp add --transport http snoopscan https://api.snoopscan.com/mcp --scope user ``` (The server loads in the next session. In this one, use REST below.) - **REST:** `POST /v1/scrape`, `/v1/search` and `/v1/parse` with **no** `Authorization` header: ```bash curl -X POST https://api.snoopscan.com/v1/scrape \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com/pricing", "formats": ["markdown"]}' ``` `/v1/parse` takes a file upload (up to 10 MB) as it does with a key. What the trial is, so you can plan around it: - **20 free successful calls a day per visitor** (per address), reset at midnight UTC. No card, no account. - **Plain pages only**: a page that needs a browser needs a key. Formats are `markdown`, `html`, `rawHtml` and `links`; screenshots, JSON extraction, page actions and a chosen country need a key. Search returns up to 10 results, with page content for the first 3. - **Every answer shows the calls left**: a `trial` object on REST (`remaining` of `limit`, plus `X-RateLimit-Remaining`), a closing line on MCP ("Free trial: 19 of 20 free calls left today"). Pass it on when it gets low. - **A blocked page doesn't use up the allowance.** - **Never send a placeholder or empty `Authorization` header.** Any header at all, even a wrong one, is treated as a key and refused. **Go back to "Get a key first" when** an answer says the page needs a browser ("This page needs a browser"), or the calls run out (a 429 `RATE_LIMITED`, or "This address has used all 20 free SnoopScan calls for today"). Tell the person: > That page needs SnoopScan's browser, which comes with a free account > (1,500 credits a month, no card). I'll open a login page: sign in or create > an account and press Approve, and I'll carry on from there. (Say "You've used today's free calls" instead of the first sentence when that is the reason.) Then swap the no-key server for the keyed one: remove it (`claude mcp remove snoopscan --scope user`) and add it again with the key as in "Fastest" above, or add the header to the config you wrote. ## Choose your path - **Shell access, want results now** → Path A - **Writing application code (Python/JS)** → Path B - **No install, one-off REST call** → Path C - **Want this as a callable tool in Claude Code, Codex, Cursor, the Claude app, ChatGPT, etc.** → "Fastest" above, or Path D - **No key yet, just checking what this does** → Path E - **Can't sign up right now, but the job needs doing** → the free trial above ## Path A — CLI Needs Node 18+ or Python 3.10+; pick the install from "Get a key first" above. For a lasting install rather than `npx`/`uvx` each time: ```bash npm install -g snoopscan # or: uv tool install snoopscan, or: pipx install snoopscan snoopscan login # browser sign-in; saves the key (see above) snoopscan status # checks the key and that the API is reachable ``` Every command shares `-o/--output` (write to a file instead of stdout), `--json` (full response, not just the content), `--pretty`, `--tier` (`auto` by default; `browser` for a page that only works in a real browser), `--timeout` (ms), `--max-age` (accept a cache hit this many ms old), and `--formats` (comma-separated: `markdown,html,rawHtml,links`). ```bash snoopscan scrape https://example.com/pricing --formats markdown,links snoopscan crawl https://example.com --limit 50 --wait > site.jsonl snoopscan crawl-status snoopscan map https://example.com # every URL on the site, no page bodies snoopscan search "site:example.com pricing" --scrape --limit 10 snoopscan extract https://example.com/product/1 https://example.com/product/2 \ --schema schema.json --prompt "price and stock status" snoopscan parse ./quarterly-report.pdf # local file to markdown — PDF, DOCX, XLSX, HTML snoopscan products https://shop.example.com # a store's whole product catalog snoopscan posts https://blog.example.com # every post on a blog or forum snoopscan company https://acme.com # firmographics + contacts from a company's own site snoopscan company https://acme.com --no-contacts # firmographics only, cheaper snoopscan domain example.com # registration + DNS + backlinks, all three by default snoopscan domain example.com --no-backlinks snoopscan monitor create --name "Pricing" --urls https://example.com/pricing \ --interval 60 --goal "Alert when the price or plan names change" snoopscan monitor list snoopscan monitor run ``` `company` enriches one company from its own site: name, phone, address, LinkedIn, headcount, industry, contact emails, social links and contact form. To find businesses by trade and town, use the `findLeads` MCP tool or `POST /v1/leads`. Full command list: `scrape`, `crawl`, `crawl-status`, `map`, `search`, `extract`, `parse`, `products`, `posts`, `company`, `domain`, `monitor`, `config`, `status`. The domain buyer's report and the bulk domain screen have no command yet: use the MCP tools (`domainReport`, `domainSnapshots`, `domainScreen`) or REST (`/v1/domain/report`, `/v1/domain/screen`). The JS CLI mirrors every command and flag exactly: `npm install -g snoopscan`. ## Path B — SDKs Put the real key in the project's environment first: `echo "SNOOPSCAN_API_KEY=$(snoopscan config get api_key)" >> .env` (and make sure `.env` is git-ignored). ```python import os from snoopscan import SnoopScan snoop = SnoopScan(api_key=os.environ["SNOOPSCAN_API_KEY"]) # the real key, never a placeholder page = snoop.scrape("https://example.com/pricing") print(page.markdown) pages = snoop.crawl_and_wait("https://example.com", limit=50) # blocks until the crawl finishes for page in pages: print(page.url, len(page.markdown or "")) ``` ```javascript import { SnoopScan } from 'snoopscan'; const snoop = new SnoopScan({ apiKey: process.env.SNOOPSCAN_API_KEY! }); // the real key const page = await snoop.scrape('https://example.com/pricing'); console.log(page.markdown); ``` The SDKs use the same names and fields as the CLI and the REST API: `scrape`, `crawl`, `map`, `search`, `extract`, `company`, `domain` and `monitor` work the same way in all three. ## Path C — REST ```bash curl -X POST https://api.snoopscan.com/v1/scrape \ -H "Authorization: Bearer $SNOOPSCAN_API_KEY" -H "Content-Type: application/json" \ -d '{"url": "https://example.com/pricing", "formats": ["markdown", "links"], "onlyMainContent": true}' ``` The main fields for each endpoint: - **`/v1/scrape`** — `formats` (`markdown`, `html`, `rawHtml`, `links`, `media`, `summary`, `screenshot`, or a `json` object with your schema — ask for several at once), `onlyMainContent` (default `true`, drops nav/ footer/cookie banners), `includeTags`/`excludeTags` (CSS selectors), `waitFor`, `timeout`, `maxAge` (accept a cached hit this old). - **`/v1/crawl`** — `url`, `limit` (default 100, up to 100,000), `maxDepth` (default 3), `maxConcurrency` (default 5), `includePaths`/ `excludePaths`, `allowExternalLinks`, `ignoreSitemap`, `deduplicateSimilarURLs` (default `true`). Async: returns a job id, poll `/v1/crawl/{id}`. - **`/v1/map`** — `url`, `search` (filter the URL list by a term), `limit` (default 5,000, up to 30,000), `includeSubdomains`, `ignoreSitemap`. No page bodies are fetched — this is discovery only. - **`/v1/search`** — `query`, `limit` (default 10, up to 50), `sources`, `location`, and an optional `scrapeOptions` to fetch each result too (same shape as `/v1/scrape`'s body). - **`/v1/extract`** — `urls` (1–100), `schema` (your JSON schema), `prompt`, and an optional `scrapeOptions`. Pass your own `model` (provider and key) and model calls are billed to your key, at no credit cost. - **`/v1/company`** — `url` (a domain or any URL on it — `acme.com` and `https://acme.com/about` enrich the same company), and `contacts` (default `true`). Returns company details and the contacts the site publishes. - **`/v1/domain`** — `domain`, plus three booleans that default to `true`: `registration`, `dns`, `backlinks`. - **`/v1/domain/report`** — `domain`, `depth` (`quick`, `buyer` by default, or `deep`), and optionally `snapshots` and `verifyLinks`. A buyer's report before purchasing a domain: registration, DNS, today's site, archive history, backlinks and whether linking pages still link, with findings and concerns tied to their evidence. Archived snapshots it could not read in time come back later from `/v1/domain/history/snapshots`. Hosted API only. - **`/v1/domain/screen`** — `domains` (up to 500) and `dns` (default `true`). Which names can be registered, from each registry's own record and DNS: cut a long list to a shortlist, then report on the few that matter. Hosted API only. - **`/v1/monitor`** — create with `name`, `urls`, `intervalMinutes` (default 60, minimum 5), `webhook`, and `goal` (a note of what you are watching for). `GET /v1/monitor/{id}/checks` for history. Every endpoint above, plus `/v1/parse`, `/v1/products` and `/v1/posts`, is documented in full at https://snoopscan.com/docs. ## Path D — MCP SnoopScan runs an MCP server at `https://api.snoopscan.com/mcp` (streamable HTTP, `Authorization: Bearer `), and a sign-in address with no key at `https://api.snoopscan.com/mcp-oauth`. Every tool the API has is a tool there: `scrape`, `fetchMore`, `crawl`, `crawlStatus`, `crawlPages`, `map`, `search`, `parse` (a document at a URL, such as a PDF, as markdown), `extract`, `batchScrape`, `listProducts`, `listPosts`, `checkChanges`, `watchPages`, `listMonitors`, `checkMonitor`, `googleSerp`, `searchPlaces`, `social` and `socialEndpoints` (profiles, posts, videos, comments and transcripts from YouTube, TikTok, Instagram, X, LinkedIn, Facebook, Threads and Pinterest), `watchMentions`, `listMentions`, `testMentions` and `markMention` (keyword alerts from Reddit, Hacker News, Bluesky, YouTube and Threads, sorted by what people want), `domain`, `company`, `findContacts`, `people`, `hiring`, `findLeads`, `leadsStatus`, and the domain buyer's tools `domainReport`, `domainSnapshots` and `domainScreen`. The domain buyer's tools, the product and post listings, the social tools and the company, contact, people, hiring and lead tools run on the hosted API only. Where a client below takes a key, get it first ("Get a key first" above) and write it into the config without repeating it in the chat. A server added during a session loads in the next one; use Path A meanwhile. **Claude Code** — see "Fastest: you are Claude Code" above. **Codex** (the Codex CLI, the IDE extension and the Codex app share `~/.codex/config.toml`) signs in by itself, so no key is needed: ```bash codex mcp add snoopscan --url https://api.snoopscan.com/mcp-oauth codex mcp login snoopscan # in the background, with a long timeout ``` `login` prints a link: put it in your reply and tell the person to sign in or create a free account, then press Approve. `codex mcp list` should show snoopscan. With a key instead: `url = "https://api.snoopscan.com/mcp"` and `http_headers = { Authorization = "Bearer " }` under `[mcp_servers.snoopscan]`. **Cursor** — merge into `~/.cursor/mcp.json` (every project) or `.cursor/mcp.json` (this one): ```json { "mcpServers": { "snoopscan": { "url": "https://api.snoopscan.com/mcp", "headers": { "Authorization": "Bearer " } } } } ``` Or `"url": "https://api.snoopscan.com/mcp-oauth"` with no headers, and Cursor asks the person to sign in when it connects. **VS Code and GitHub Copilot** — merge into `.vscode/mcp.json`: ```json { "servers": { "snoopscan": { "type": "http", "url": "https://api.snoopscan.com/mcp", "headers": { "Authorization": "Bearer " } } } } ``` For every workspace, `code --add-mcp` takes the same server as one JSON object with `"name": "snoopscan"` added. The `-oauth` address with no headers signs in instead. **Windsurf** — under `"mcpServers"` in `~/.codeium/windsurf/mcp_config.json` (or `~/.config/devin/mcp_config.json` on newer releases; use whichever exists): ```json { "mcpServers": { "snoopscan": { "serverUrl": "https://api.snoopscan.com/mcp", "headers": { "Authorization": "Bearer " } } } } ``` Then tell the person to press refresh in Cascade's MCP panel if it is not listed yet. **If the person uses the Claude app** (desktop, claude.ai or the phone), there is no command and nothing to run. Connectors there take a web address, and this one signs in, so there is no key to copy. Tell them: "In Claude, open Settings, then Connectors. Click + and choose Add custom connector. Name it SnoopScan, paste `https://api.snoopscan.com/mcp-oauth`, and click Add. Then click Connect, log in or create a free account, and press Approve." On a Team or Enterprise plan, an owner adds the connector for the organization first. **If the person uses ChatGPT**, it connects through developer mode (Plus, Pro, Business, Enterprise and Education, on the web). Tell them: "In ChatGPT, open Settings, then Security and login, and turn on Developer mode. Then go to chatgpt.com/plugins, press +, and create an app named SnoopScan with the server address `https://api.snoopscan.com/mcp-oauth` and OAuth sign-in. Sign in or create a free account, and press Approve. In a chat, pick it from Developer mode in the + menu." **Anything else** that speaks MCP over streamable HTTP takes `https://api.snoopscan.com/mcp` with the header `Authorization: Bearer `, or `https://api.snoopscan.com/mcp-oauth` with no header if it signs in. A client that only runs local servers can bridge with `npx -y mcp-remote https://api.snoopscan.com/mcp --header "Authorization: Bearer "`. Setup pages for forty-odd clients: https://snoopscan.com/integrations. If `/mcp` was added without a key, it still connects: `scrape`, `search` and `parse` run on the free trial (see "Can't sign up right now?" above), and every other tool answers with the setup steps — follow them. ## Path E — no key yet, just checking what this even does `https://snoopscan.com` has a free playground on the homepage: type a URL, pick read, browse, map, crawl or search, and see the result. No signup. For an agent that needs the answers itself, use the free trial above over MCP or REST. ## If something looks wrong - A 401 almost always means the key was copied with a trailing newline — the whitespace survives shell substitution more often than not. - `snoopscan status` (or `GET /health`) tells you whether the key is bad or the API is down. Check it before assuming either. - Branch on the error's `code`, not its message: `INVALID_REQUEST`, `UNAUTHORIZED`, `FORBIDDEN_SCOPE`, `RATE_LIMITED`, `TIMEOUT`, `BLOCKED`, `FETCH_FAILED`, `TARGET_ERROR`, `EXTRACTION_FAILED`, `ROBOTS_DENIED`, `JOB_NOT_FOUND`, `INSUFFICIENT_CREDITS`, `PROXY_UNAVAILABLE`, `SEARCH_UNAVAILABLE`, `PLACES_UNAVAILABLE`, `SERP_UNAVAILABLE`, `COMPANY_UNAVAILABLE`, `PLATFORMS_UNAVAILABLE`, `ENGINE_REFUSED`, `INTERNAL`. - `BLOCKED` or `TARGET_ERROR` on a page that loads in a normal browser: retry with `--tier browser` (CLI) or `"tier": "browser"` in the body before calling the page unreachable. - `PLACES_UNAVAILABLE`, `COMPANY_UNAVAILABLE` or `PLATFORMS_UNAVAILABLE`: the endpoint is only on the hosted API, `https://api.snoopscan.com`, not on a self-hosted copy. `PROXY_UNAVAILABLE`: set `proxy` to `auto`. --- # SnoopScan API reference Base URL `https://api.snoopscan.com/v1`. Every request carries `Authorization: Bearer ` and a JSON body. A success is `{"success": true, "data": {...}}`; a failure is `{"success": false, "error": {"code": "...", "message": "..."}}` with a code to branch on. Every response reports what it cost. ## Scrape: `POST /v1/scrape` One URL into clean markdown for a RAG pipeline, an LLM prompt or an archive. Navigation, cookie walls and boilerplate stay out of it. Example body: `{"url":"https://example.com/pricing","formats":["markdown","links"],"onlyMainContent":true}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `url` | string | yes | | The absolute http or https URL to read. | | `actions` | array of any | no | | Steps to run in a browser before the page is read: click, type, scroll, wait or `captchaCheckbox`. A `captchaCheckbox` step needs `successSelector`. | | `blockAssets` | boolean | no | true | Skip images, fonts and media when the page is rendered in a browser. Faster. | | `captchaEvidence` | boolean | no | false | Return screenshots from before and after an automatic checkbox click. | | `captchaHandling` | auto · off | no | auto | Click a challenge checkbox once if one appears. Set `off` to never click. | | `excludeTags` | array of string | no | | CSS selectors to drop before the page is read. | | `formats` | array of string or object | no | | What to return: `markdown`, `html`, `rawHtml`, `links`, `media`, `summary`, `screenshot`, or a `json` object carrying your schema. Ask for several in one call. | | `headers` | object | no | | Extra headers to send. `User-Agent` and other browser-identity headers are set for you and cannot be changed. | | `includeTags` | array of string | no | | CSS selectors to keep even when they sit outside the main content. | | `location` | object | no | | Fetch from a country, in its language, e.g. `{"country": "US"}`. | | `maxAge` | integer | no | 0 | Serve a cached copy if one was taken within this many milliseconds. A cache hit costs nothing. Set `0` to force a fresh fetch. | | `mobile` | boolean | no | false | Read the page as a phone would see it. | | `onlyMainContent` | boolean | no | true | Return the article and drop navigation, headers, footers and cookie banners. Turn it off to keep the whole page. | | `parsers` | array of string | no | | Which document parsers may run, for example `pdf`. | | `proxy` | object | no | auto | Leave on `auto` and the route is chosen for you. | | `removeBase64Images` | boolean | no | true | Strip inline base64 images out of the returned markdown and HTML. | | `storeInCache` | boolean | no | true | Keep this response in the cache so a later request can be served free. | | `timeout` | integer | no | 90000 | Give up on this request after this many milliseconds. | | `waitFor` | integer | no | 0 | Milliseconds to wait after the page loads before reading it, for content that loads late. Renders the page in a browser, and is billed as a browser page. | Docs: https://snoopscan.com/docs/api/scrape ## Crawl: `POST /v1/crawl` A documentation site, a help center or a whole blog, page by page, with depth and path filters. Poll the job or take a webhook. Example body: `{"url":"https://example.com","limit":100,"maxDepth":3,"includePaths":["/blog/*"]}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `url` | string | yes | | The page to start from. An absolute http or https URL. | | `allowBackwardLinks` | boolean | no | false | Follow links above the starting path on the same host. | | `allowExternalLinks` | boolean | no | false | Follow links onto other domains. Off by default, since with a high `limit` a crawl can reach many unrelated sites. | | `deduplicateSimilarURLs` | boolean | no | true | Collapse URLs that differ only in tracking parameters or a trailing slash. | | `delay` | integer | no | 0 | Minimum milliseconds between requests to the same host. | | `excludePaths` | array of string | no | | Skip URLs whose path and query match any of these regexes. Wins over `includePaths`. | | `ignoreQueryParameters` | boolean | no | false | Treat URLs that differ only in their query string as the same page. | | `ignoreSitemap` | boolean | no | false | Find pages by following links only, without reading the site's sitemap. | | `includePaths` | array of string | no | | Only crawl URLs whose path and query match one of these regexes, e.g. `^/blog/`. Empty means every path. | | `limit` | integer | no | 100 | The most pages to crawl, 1 to 100,000. | | `maxConcurrency` | integer | no | 5 | How many pages to fetch at once, 1 to 50. | | `maxDepth` | integer | no | 3 | How many links deep to follow from the start page. 0 is the start page alone. | | `respectRobots` | boolean | no | false | Honor the site's robots.txt for this job. | | `scrapeOptions` | object | no | | How each page is fetched and what comes back: the same options /v1/scrape takes. | | `webhook` | object | no | | Where to send job events as the crawl progresses. | Docs: https://snoopscan.com/docs/api/crawl ## Map: `POST /v1/map` Every URL on a site in seconds, for a content audit, a migration inventory, or to find the pages worth scraping before you spend on them. Example body: `{"url":"https://example.com","search":"pricing"}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `url` | string | yes | | The site to map. An absolute http or https URL. | | `ignoreSitemap` | boolean | no | false | Find URLs without reading the site's sitemap. | | `includeSubdomains` | boolean | no | false | Include URLs on the site's subdomains. | | `limit` | integer | no | 5000 | The most URLs to return, 1 to 30,000. | | `search` | string | no | | Only return URLs whose address or page title contains this text. Not case-sensitive. | Docs: https://snoopscan.com/docs/api/map ## Search: `POST /v1/search` Web search with every result already scraped, so a research agent reads whole pages instead of guessing from snippets. Example body: `{"query":"best headless browsers","limit":5,"scrapeOptions":{"formats":["markdown"]}}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `query` | string | yes | | What to search for. | | `autoCorrect` | boolean | no | true | Set `false` to search the query exactly as typed, e.g. a part number or a brand name. | | `device` | desktop · mobile | no | | `desktop` or `mobile`. Mobile results can differ from desktop ones. | | `freshness` | string | no | | Only results from the last `hour`, `day`, `week`, `month` or `year`. | | `language` | string | no | | The language results should be in, e.g. `en`. | | `limit` | integer | no | 10 | How many results, 1 to 50. | | `location` | object | no | | The country to search from, which changes the results, e.g. `{"country": "GB"}`. | | `page` | integer | no | 1 | Which page of results, starting at 1. | | `place` | string | no | | Where the searcher is standing, in free text, e.g. "Austin, Texas, United States". Finer than `location`. | | `safeSearch` | off · moderate · strict | no | | `off`, `moderate` or `strict`. | | `scrapeOptions` | object | no | | Also fetch every result page with these options. Each page fetched is charged like a scrape. | | `sources` | array of web · news · images | no | | Which kinds of result: `web`, `news`, `images`. | Docs: https://snoopscan.com/docs/api/search ## Extract: `POST /v1/extract` A JSON schema or a named template, and up to 100 URLs in, rows out — pricing tables, spec sheets, job listings. Example body: `{"urls":["https://example.com/pricing"],"schema":{"type":"object","properties":{"plan":{"type":"string"},"price":{"type":"number"}}},"prompt":"The cheapest paid plan"}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `urls` | array of string | yes | | The pages to extract from, 1 to 100. Each page gets its own result. | | `model` | object | no | | Your own model provider and key. Model calls are billed to your key, at no credit cost. | | `prompt` | string | no | | Plain-language guidance on what to pick out, e.g. "the cheapest paid plan". | | `schema` | object | no | | Your own JSON Schema for the fields you want. Give this or `template`, not both. | | `scrapeOptions` | object | no | | How each page is fetched: the same options /v1/scrape takes. | | `template` | string | no | | A named template instead of a schema — `product`, `article`, `jobPosting` and more. GET /v1/templates lists them with their fields. | Docs: https://snoopscan.com/docs/api/extract ## Batch: `POST /v1/batch/scrape` Thousands of URLs as one job, for a backfill or a nightly refresh, running at whatever concurrency your plan allows. Poll it or take a webhook. Example body: `{"urls":["https://example.com/a","https://example.com/b"],"maxConcurrency":10,"scrapeOptions":{"formats":["markdown"]}}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `urls` | array of string | yes | | The pages to scrape as one job, 1 to 10,000. | | `maxConcurrency` | integer | no | 10 | How many pages to fetch at once, 1 to 50. | | `scrapeOptions` | object | no | | How each page is fetched and what comes back: the same options /v1/scrape takes. | | `webhook` | object | no | | Where to send job events as pages complete. | Docs: https://snoopscan.com/docs/api/batch ## Products: `POST /v1/products` A whole store catalog with prices, variants and stock, hundreds of products in one call. Competitor pricing without a crawl. Example body: `{"url":"https://store.example.com","limit":500}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `url` | string | yes | | The store or blog to read, e.g. `https://shop.example.com`. | | `limit` | integer | no | 500 | The most items to return, 1 to 10,000. | Docs: https://snoopscan.com/docs/api/products ## Posts: `POST /v1/posts` Every article from a blog or forum, hundreds at a time, for a content aggregator, a newsroom feed or a training set. Example body: `{"url":"https://blog.example.com","limit":200}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `url` | string | yes | | The store or blog to read, e.g. `https://shop.example.com`. | | `limit` | integer | no | 500 | The most items to return, 1 to 10,000. | Docs: https://snoopscan.com/docs/api/posts ## Monitor: `POST /v1/monitor` Watch a page on a schedule and get a webhook only when it really changed. Price drops, job boards, terms and docs. Example body: `{"name":"Pricing","urls":["https://example.com/pricing"],"intervalMinutes":60,"webhook":"https://hooks.example.com/snoop"}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `name` | string | yes | | A name for the monitor, up to 120 characters. | | `goal` | string | no | | What you are watching for, in your own words. Stored and returned with the monitor; it does not yet affect which changes are reported. | | `intervalMinutes` | integer | no | 60 | How often to check, in minutes: at least 5, at most a week (10,080). | | `url` | string | no | | A page to watch. Give this, `urls`, or both. | | `urls` | array of string | no | | Pages to watch in the one monitor, up to 50. | | `webhook` | string | no | | A URL to POST to when a check finds a page changed, new or failing. | Docs: https://snoopscan.com/docs/api/monitor ## Places: `POST /v1/places/search` Business listings by trade and town, with the website, the phone number and the people behind it. Lead lists, ready to work. Example body: `{"query":"coffee shops","location":"Austin, TX","limit":20,"enrich":true}` Docs: https://snoopscan.com/docs/api/places ## Domain: `POST /v1/domain` Domain age, registrar, hosting and backlinks for any site. Judge a source, size up a competitor, or check a domain was not registered last week. Example body: `{"domain":"https://example.com","backlinkLimit":100}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `domain` | string | yes | | A domain, or any URL on it. `https://www.example.com/a` and `example.com` are the same request. | | `backlinkLimit` | integer | no | 100 | How many referring domains to list, busiest first. | | `backlinks` | boolean | no | true | Domains known to link to this one. | | `dns` | boolean | no | true | A, AAAA, MX, NS and TXT records. | | `registration` | boolean | no | true | Registration and expiry dates, age, registrar and nameservers. | Docs: https://snoopscan.com/docs/api/domain ## Domain report: `POST /v1/domain/report` Check a domain before you buy it: its archive history, whether the backlinks it is sold on still exist, and the questions to ask the seller. Example body: `{"domain":"example.com","depth":"buyer"}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `domain` | string | yes | | A domain, or any URL on it. `https://www.example.com/a` and `example.com` are the same request. | | `depth` | quick · buyer · deep | no | buyer | `quick` for registration, DNS and today's site; `buyer` adds history, backlinks and link checks; `deep` uses larger samples. | | `snapshots` | integer | no | | How many archived homepage snapshots to read, one per year at most. Defaults to 6 for `buyer` and 12 for `deep`. | | `verifyLinks` | integer | no | | How many linking pages to check for the link. Defaults to 20 for `buyer` and 50 for `deep`. | Docs: https://snoopscan.com/docs/api/domain-report ## Domain screen: `POST /v1/domain/screen` Check up to 500 domain names in one call to see which are available. Cut a drop list down to a shortlist, then run a report on the few that matter. Example body: `{"domains":["example.com","example.io","example.net"],"dns":true}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `domains` | array of string | yes | | Up to 500 domains, or URLs on them. Duplicates are checked once. | | `dns` | boolean | no | true | Check DNS for names the registry has no record of, so they can read `likely_available`. Off, they read `no_registry_record`. | Docs: https://snoopscan.com/docs/api/domain-screen ## Find Leads: `POST /v1/leads` Local businesses by trade and town, each with its phone, website, address and the emails it publishes, ready for outreach. Example body: `{"who":"roofing contractors","where":"Houston, TX","limit":50}` Docs: https://snoopscan.com/docs/api/leads ## Company: `POST /v1/company` One company domain in, the details a lead list sells out: name, phone, LinkedIn, headcount, industry, plus the emails and socials the site publishes. Example body: `{"url":"https://example.com","contacts":true}` | Field | Type | Required | Default | What it does | |---|---|---|---|---| | `url` | string | yes | | A company domain, or any URL on it. `https://acme.com/about` and `acme.com` enrich the same company. | | `contacts` | boolean | no | true | Also return contact emails, the contact form and social links. Set `false` for company details only. | Docs: https://snoopscan.com/docs/api/company --- # Questions people ask ## The basics **What is SnoopScan?** A web scraping API for AI agents. Give it a URL and it hands back the page as clean markdown, HTML, links or JSON in your own schema. It handles the fetching, the proxies, the browser and the parsing, so you never build or babysit scraping infrastructure. **Who is it for?** Developers and teams whose agents, research pipelines or products need pages from the web: agent builders, deep research, lead enrichment, price and stock monitoring, RAG and search indexes. **Which sites can it reach?** Most public pages, including pages that need JavaScript and pages that block bots. Pages behind a login are not supported. **Is web scraping legal?** Scraping public pages is lawful in most places; what you do with the data is governed by the site's terms and by privacy law where you are. You are responsible for how you use what you collect. ## From your AI chat **Does it work in Claude Code, Codex, Cursor or ChatGPT?** Yes. SnoopScan is an MCP server, so any AI app or agent that supports MCP can use it: Claude Code, Codex, Cursor, VS Code, Windsurf, the Claude app, ChatGPT and more. Paste "Read and follow https://snoopscan.com/agent-onboarding/SKILL.md" into the chat and the agent sets it up. You sign in and press Approve. **Is there an MCP server?** Yes, at https://api.snoopscan.com/mcp. Its tools scrape, crawl, map, search and extract, list a store's products or a blog's posts, check pages for changes, and look up domains and companies. The Claude app and ChatGPT connect at https://api.snoopscan.com/mcp-oauth by signing in, with no key to copy. **Do I need to install anything?** No. The MCP server and the API are hosted. When an agent sets SnoopScan up, it runs any command itself; you only sign in and press Approve in your browser. ## How it works **What does a credit buy?** One page. Most pages cost 1 credit. Pages that need a premium proxy or a browser cost more, and re-reading a page you already fetched is free. The rate card on the pricing page lists every unit, and your activity log shows what each call cost. **Am I charged for failed requests?** No. A request that fails carries no cost and never counts against your balance. You only pay for pages that come back. **What is the difference between scrape and crawl?** Scrape reads the pages you name. Crawl discovers pages by following links from a start URL, with depth and path filters, and reads each one. Map lists a site's URLs without reading them, which is the cheap way to decide what to crawl. **What formats come back?** Markdown, HTML, raw HTML, links, a summary, a screenshot, or JSON shaped to a schema you give it. Ask for several in one call. PDFs and Word documents come back as text through Parse. ## The API **Does it work with my stack?** It is plain REST and JSON. Python, Node, cURL, or anything that can make an HTTP request. Nothing to install. **Can I extract data with a prompt?** Yes. Extract takes a JSON schema and, optionally, a prompt, and answers per page with a confidence score. For fixed shapes at volume, a schema alone is more consistent than a prompt. **Do I need an AI key to use Extract?** No. Extract reads a page's own structured markup and fills your schema from that. For fields the markup cannot answer you can add your own Anthropic or OpenAI key in your account; it runs on your key and costs no credits. **How do long jobs report back?** Crawls and batches return a job id. Poll it, or give a webhook URL and the job calls you when it finishes. **Can my team share an account?** Yes. Invite people from Team. Everyone shares the credits and keys, and every request shows who made it. ## Billing **Is there a free plan?** Yes. 1,500 credits a month, refreshed on the day you signed up, no card needed. It is a real plan, not a trial that expires. **Do unused credits roll over?** No. Your free credits refresh monthly on the day you signed up, and your dashboard shows the date. Paid plans refresh on their billing date. **What happens when I run out?** Requests return a clear 402 with the reason, and nothing is charged. Move up a plan from Billing and the credits land the same day. **Can I switch plans later?** Yes, from Billing, up or down. A move up applies straight away; a move down applies when the period you paid for ends. Billing says which before you confirm. **Can I try it without signing up?** Yes. An AI agent can call scrape, search and parse with no key at all, over the MCP server or the API: 20 free successful calls a day, on plain pages. Every answer says how many are left, and a blocked page does not use one up. Pages that need a browser, and anything past 20 a day, need the free account. **Where does my data go?** Fetched pages are cached briefly, then dropped. Re-reading your own cached page is free. Nothing you scrape is used for anything else.