Web Scraping
Scrape, search, map, extract, crawl, and monitor any public web page — clean markdown and structured data in the unified WebPage schema
Web Scraping
Scrape, search, map, extract, crawl, and monitor any public web page. Content-bearing responses return the unified WebPage schema — clean markdown/HTML, metadata, structured extraction, and fetch provenance under data.page — while search and map return a WebPageList (data.items[]).
This is the only platform on the API that sells stateful work: long-running jobs you poll, monitors that keep checking on a schedule, and browser sessions you drive step by step. Everything else here is one request, one answer.
Base URL: /v1/web/...
Getting Started
1. Scrape a page to markdown
curl "https://www.socialcrawl.dev/v1/web/scrape?url=https://example.com" \
-H "x-api-key: sc_your_api_key_here"The page content arrives at data.page.content.markdown (add formats=markdown,screenshot for a screenshot URL under data.page.media).
2. Search the web
curl "https://www.socialcrawl.dev/v1/web/search?query=social%20media%20data%20api&limit=10" \
-H "x-api-key: sc_your_api_key_here"Web, news, and image sources merge into one data.items[] list, each row tagged with source_type.
3. Pull typed fields instead of prose
curl "https://www.socialcrawl.dev/v1/web/extract?url=https://example.com&prompt=the%20page%20title%20and%20any%20pricing%20mentioned" \
-H "x-api-key: sc_your_api_key_here"GET /v1/web/extract needs either a schema (JSON) or a prompt — sending neither is a 400 before billing. Typed fields land under data.page.extraction.
The four synchronous endpoints
These four answer immediately and cover most integrations.
GET /v1/web/scrape— one known URL to clean markdown or HTML, with the resolved URL, status code, and fetch metadata. 1cr normally. It steps to 5cr when you ask for work the cheap path cannot do:proxy=auto,proxy=enhanced, orpdf_parse=true. Thedata.page.fetch.proxy_tierfield tells you which path actually ran.GET /v1/web/search— ranked web, news, and image results as one normalised list when you do not yet know which URLs you need. 2cr per 10 results, solimit=50is 10cr. Addinginclude_content=truescrapes each result inline and adds 1cr per result on top, which is how alimit=50content search reaches 60cr. Filter withinclude_domains/exclude_domains,country,time_range, andcategoriesbefore you widenlimit.GET /v1/web/map— every URL a site exposes, without fetching any page bodies. 1cr. Run it first to decide what is worth crawling;search(a substring filter over the discovered URLs) andinclude_subdomainsnarrow it.GET /v1/web/extract— structured fields from one page, shaped by yourschemaorprompt. 5cr flat.
The usual chain is map to find the pages, scrape or extract on the ones that matter. Reach for crawl only when you want the site walked for you.
# 1. What pages does this site have?
curl "https://www.socialcrawl.dev/v1/web/map?url=https://example.com&search=pricing" \
-H "x-api-key: sc_your_api_key_here"
# 2. Pull the one that matters
curl "https://www.socialcrawl.dev/v1/web/scrape?url=https://example.com/pricing&formats=markdown" \
-H "x-api-key: sc_your_api_key_here"Async jobs: submit, poll, settle
crawl, batch-scrape, and agent are too slow to answer inline, so they return a job id and you poll one unified surface. All three ids are prefixed job_, and all three read through the same four routes — there is no per-kind status path.
# 1. Submit — returns data.job_id, e.g. "job_9f3k2n8d1"
curl -X POST "https://www.socialcrawl.dev/v1/web/crawl" \
-H "x-api-key: sc_your_api_key_here" \
-H "content-type: application/json" \
-d '{"url":"https://example.com","limit":25,"max_depth":2}'
# 2. Poll until data.status is terminal
curl "https://www.socialcrawl.dev/v1/web/jobs/job_9f3k2n8d1" \
-H "x-api-key: sc_your_api_key_here"
# 3. Lost the id? List everything this key has running
curl "https://www.socialcrawl.dev/v1/web/jobs?limit=20" \
-H "x-api-key: sc_your_api_key_here"
# 4. Stop it early and get the unspent hold back
curl -X DELETE "https://www.socialcrawl.dev/v1/web/jobs/job_9f3k2n8d1" \
-H "x-api-key: sc_your_api_key_here"POST /v1/web/crawlwalks a site from a root URL and scrapes what it finds.limitcaps pages,max_depthcaps how far from the root it goes, andinclude_paths/exclude_pathskeep it in the section you care about.POST /v1/web/batch-scrapetakes aurlsarray when you already know every page you want.ignore_invalid_urlskeeps one bad entry from rejecting the whole submission.POST /v1/web/agenttakes aurland a plain-languagepromptand drives a browser toward the answer. Use it when the data is behind clicking and navigating rather than at a URL you can name.GET /v1/web/jobslists this key's jobs with cursor pagination;GET /v1/web/jobs/{job_id}returns status, progress, credits held and charged, and the result once terminal;DELETE /v1/web/jobs/{job_id}cancels and refunds the unspent hold. Reading and cancelling are free.POST /v1/web/crawlandPOST /v1/web/batch-scrapeaccept awebhook_urlif you would rather be told than poll. See Webhooks for the payload.
Credits are held, then settled. A crawl holds 1 credit per page of limit (so limit=25 holds 25) and charges only for the pages actually fetched. A batch scrape holds one credit per URL you submit. An agent job holds a flat 25 and settles against the work it did, with a 5-credit floor. Whatever is held and not spent comes back automatically — including on cancel.
limit, not against how big the site turns out to be. Submitting limit=1000 reserves 1000 credits the moment the job is accepted, even if the site only has 30 pages. Run GET /v1/web/map first and set limit from what you find.Per-page failures. Append /errors to a job read — GET /v1/web/jobs/{job_id}, then the same path with /errors on the end — to list the individual pages that failed inside an otherwise successful job. That sub-route is a convenience mount rather than a registry entry, so it does not appear in the roster below, in openapi.json, or in the llms-*.txt files. It works, but treat it as unversioned: do not generate an SDK method for it.
Monitors: watch a page on a schedule
A monitor re-runs a scrape or a search on a cadence and records every result, so you can ask what changed rather than diffing it yourself.
# Create one — returns data.monitor_id, e.g. "wm_5d1p8s3k7"
curl -X POST "https://www.socialcrawl.dev/v1/web/monitors" \
-H "x-api-key: sc_your_api_key_here" \
-H "content-type: application/json" \
-d '{"url":"https://example.com/pricing","name":"Pricing page","mode":"scrape","cadence_minutes":15}'
# Read what it has found
curl "https://www.socialcrawl.dev/v1/web/monitors/wm_5d1p8s3k7/checks?limit=20" \
-H "x-api-key: sc_your_api_key_here"
# Pause it without losing history
curl -X PATCH "https://www.socialcrawl.dev/v1/web/monitors/wm_5d1p8s3k7" \
-H "x-api-key: sc_your_api_key_here" \
-H "content-type: application/json" \
-d '{"status":"paused"}'POST /v1/web/monitorscreates one.modeisscrape(watch a page) orsearch(watch a query, viaquery). Schedule it withcadence_minutes,schedule_text("every 15 minutes"), orschedule_cron— the last two are mutually exclusive.retention_dayscontrols how long checks are kept,webhook_urlpushes each result, andjudge_enabledturns on the change assessment againstgoal.cadence_minutesis 5-60, or a whole number of hours up to 1440 (120, 180, and so on). Hour cadences are scheduled as cron under the hood. Values between those two bands are rejected.GET /v1/web/monitorslists them (cursor-paginated),GET /v1/web/monitors/{monitor_id}returns one monitor's settings pluslast_check_atandnext_check_at, andGET /v1/web/monitors/{monitor_id}/checksis the history — the results, not the configuration. That last one is the path a webhook'srun_idrefers back to.PATCH /v1/web/monitors/{monitor_id}changesstatus(pause/resume) or the schedule, keeping the check history.DELETE /v1/web/monitors/{monitor_id}stops future checks; past checks stay readable.- Creating, listing, reading, updating, and deleting a monitor are all free. You pay when a check runs: the underlying scrape or search cost plus 1 credit of orchestration. A paused monitor bills nothing.
Browser sessions: drive a live page
When content only appears after clicking, typing, or logging in, open a session and send it instructions.
# 1. Open — returns data.session_id, e.g. "ws_3g7x1v5m2"
curl -X POST "https://www.socialcrawl.dev/v1/web/sessions" \
-H "x-api-key: sc_your_api_key_here" \
-H "content-type: application/json" \
-d '{"url":"https://example.com","ttl_seconds":120}'
# 2. Drive it
curl -X POST "https://www.socialcrawl.dev/v1/web/sessions/ws_3g7x1v5m2/execute" \
-H "x-api-key: sc_your_api_key_here" \
-H "content-type: application/json" \
-d '{"code":"await page.click(\"#load-more\"); console.log(await page.title());","language":"node"}'
# 3. Close it
curl -X DELETE "https://www.socialcrawl.dev/v1/web/sessions/ws_3g7x1v5m2" \
-H "x-api-key: sc_your_api_key_here"POST /v1/web/sessionsopens a short-lived browser aturland returns aws_-prefixed id.ttl_secondssets the lifetime andactivity_ttl_secondsthe idle timeout;stream_web_view=truegives you a viewable stream.POST /v1/web/sessions/{session_id}/executeruns code inside it.languageisnode,python, orbash. Withnodeyou get the Playwrightpage,browser, andchromiumglobals and the final expression lands inresult;bashandpythonreport throughstdout. The response carriessuccess,stdout,stderr,exitCode, and akilledflag. Executing is free — you already paid for the session.GET /v1/web/sessionsandGET /v1/web/sessions/{session_id}show what is still open and when it expires.DELETE /v1/web/sessions/{session_id}closes it and settles the hold.- A session holds 5 credits minimum, and 20 credits per hour of
ttl_seconds— a 120-second session holds the 5-credit floor, a two-hour session holds 40. Close it as soon as you are done rather than waiting for expiry; the unused hold refunds on close.
Document parse
POST /v1/web/parse takes a multipart/form-data upload in the file field and returns the same data.page shape as a scrape, with page_count and total_page_count filled in. PDFs and office documents both work. 1cr. Use it when you hold the file itself; for a document sitting at a URL, scrape with pdf_parse=true gets there in one call.
curl -X POST "https://www.socialcrawl.dev/v1/web/parse" \
-H "x-api-key: sc_your_api_key_here" \
-F "file=@report.pdf" \
-F "filename=report.pdf"Endpoints
22 endpoints available.
| Endpoint | Path | Credit Tier |
|---|---|---|
| Start an async batch scrape | /v1/web/batch-scrape | standard (1cr) |
| Start an async web crawl | /v1/web/crawl | standard (1-10000cr)metered |
| List async web jobs | /v1/web/jobs | standard (0cr) |
| Get an async web job | /v1/web/jobs/{job_id} | standard (0cr) |
| Cancel an async web job | /v1/web/jobs/{job_id} | standard (0cr) |
| Map URLs on a site | /v1/web/map | standard (1cr) |
| Create a web monitor | /v1/web/monitors | standard (0cr) |
| List web monitors | /v1/web/monitors | standard (0cr) |
| Get a web monitor | /v1/web/monitors/{monitor_id} | standard (0cr) |
| Update a web monitor | /v1/web/monitors/{monitor_id} | standard (0cr) |
| Delete a web monitor | /v1/web/monitors/{monitor_id} | standard (0cr) |
| List web monitor checks | /v1/web/monitors/{monitor_id}/checks | standard (0cr) |
| Parse an uploaded document | /v1/web/parse | standard (1cr) |
| Scrape a web page | /v1/web/scrape | standard (1-5cr)metered |
| Search the web | /v1/web/search | standard (2-120cr)metered |
| List interactive web sessions | /v1/web/sessions | standard (0cr) |
| Get an interactive web session | /v1/web/sessions/{session_id} | standard (0cr) |
| Close an interactive web session | /v1/web/sessions/{session_id} | standard (0cr) |
| Execute an interaction in a web session | /v1/web/sessions/{session_id}/execute | standard (0cr) |
| Extract structured data from a web page | /v1/web/extract | advanced (5cr)metered |
| Create an interactive web session | /v1/web/sessions | advanced (5cr) |
| Start an async web agent job | /v1/web/agent | premium (25cr) |
Notes
- Method-aware surface: the sync data endpoints (
scrape,search,map,extract) and all reads areGET; async jobs, monitors, sessions, and parse usePOST/PATCH/DELETEas listed above - Authentication via
x-api-keyheader - Content responses follow the unified WebPage schema; job/monitor/session resources return envelope-wrapped status objects with cursor pagination on lists
- Job ids are
job_…, monitor idswm_…, session idsws_…. All three are scoped to the API key that created them, so listing only ever shows your own POST /v1/web/crawlandPOST /v1/web/batch-scrapehonour anIdempotency-Keyheader — resubmitting the same key returns the original job rather than starting a second one- Variable-cost work (crawl pages, PDF parsing, enhanced proxy, agent runs, session time) is metered honestly: held, settled to actual usage, and refunded when unused
