Extract API
Name the fields you want, in plain words or as a JSON Schema, and get them from any public page, each with how sure the extractor is. AI fills only what the page does not state plainly, if you allow it.
- 1 credit per call
- Failed calls are free
- Updated
- web.extract
{ "schema_valid": true, "semantic_valid": true, "unresolved_fields": null, "validation_errors": null, "data": { "batch": "S09", "company": "Stripe", "founded": "2009", "team_size": "7000" }, "fields": { "batch": { "confidence": 0.99, "source": "attribute_json", "value": "S09" }, "company": { "confidence": 0.99, "source": "attribute_json", "value": "Stripe" }, "founded": { "confidence": 0.99, "source": "attribute_json", "value": "2009" }, "team_size": { "confidence": 0.99, "source": "attribute_json", "value": "7000" } }, "semantic_validation_errors": []}
What you send
The input
object of the request, with every field the endpoint accepts.
| Field | Type | Required | What it does | Example |
|---|---|---|---|---|
| url | string | yes | The public page or file to read. | https://www.ycombinator.com/companies/stripe |
| fields | object | one of | The fields you want, each with a plain description, such as {"price": "the current price"}. Use this or output_schema. | |
| mode | string | one of | A ready-made shape instead of your own fields: product (a product record), selectors (CSS selectors you give) or highlights (passages that answer a question). | product · selectors · highlights |
| output_schema | object | one of | A JSON Schema of the result you want. Each property's description tells the extractor what to look for. | {…} |
| accept_statuses | array<integer> | no | Error statuses you still want returned, such as [404], to inspect the page. | |
| ai | string | no | never: only what the page states. auto: AI fills the fields the page leaves out. always: AI reads every field. | never · auto · always |
| allow_browser_fallback | boolean | no | Open the page in a real browser when it needs JavaScript or blocks a plain request. On by default. | |
| allow_truncated | boolean | no | Return what was read when a page is larger than the size limit, instead of failing. | |
| document | object | no | Options for PDFs and other files. | |
| follow_links | boolean | no | Also follow the page's own links on the same site and merge what they hold. | |
| instructions | string | no | Extra guidance for the extractor, in plain words. | |
| max_body_bytes | integer | no | The largest page or file to read, in bytes. | |
| max_pages | integer | no | With follow_links, how many pages to visit, the first included. | |
| max_total_bytes | integer | no | The most bytes to read in all, redirects included. | |
| question | string | no | For highlights mode: the question the passages should answer. | |
| selectors | object | no | For selectors mode: each field and the CSS selector to read it from, such as {"price": ".price"}. |
Fields it returns
What each record in the response holds, with the values from the sample above.
| Field | Type | What it is | Example |
|---|---|---|---|
| data | object | The fields you asked for, filled in from the page. | 4 fields |
| data.company | string | The company property of the schema in this request: its name. | Stripe |
| data.batch | string | The batch property: the startup's Y Combinator batch. | S09 |
| data.founded | string | The founded property: the year it was founded. | 2009 |
| data.team_size | string | The team_size property: how many people work there, as the page states. | 7000 |
| fields | object | Each field you asked for, with its value, how sure the extraction is and where on the page it was found. | 4 fields |
| fields.* | object | The same field with its value, how sure the extraction is and where it was found. | 3 fields |
| fields.*.confidence | number | How sure the extraction is, from 0 to 1. | 0.99 |
| fields.*.source | string | Where on the page the value was found, such as the page's structured data or its text. | attribute_json |
| fields.*.value | string | The value found for the field. | S09 |
| schema_valid | boolean | Whether the fields came back in the shape you asked for. | true |
| semantic_valid | boolean | Whether the values passed the checks you set. | true |
| semantic_validation_errors | array | Checks the values did not pass, when you set checks in your schema. | empty in this sample |
| unresolved_fields | null | Fields the page did not hold; empty when every field was found. | null |
| validation_errors | null | Where the result did not fit your schema; empty when it fits. | null |
What this endpoint covers
- Values come back as the page writes them, such as "USD 100". Ask for a number in output_schema to get one.
- With ai set to never, a field the page does not state stays empty and is listed in unresolved_fields; nothing is guessed.
- Each value carries its confidence and source, so you can drop answers that are not sure enough.
- A page that needs JavaScript is opened in a real browser for you; that is still 1 credit.
Call it from your code, or ask your agent
Set UPSCRAPE_API_KEY to your key and copy a working request.
curl --request POST \ --url https://data.upscrape.com/execute \ --header "Authorization: Bearer $UPSCRAPE_API_KEY" \ --header "Content-Type: application/json" \ --header "Prefer: wait=30" \ --data '{ "capability": "web.extract", "input": { "output_schema": { "properties": { "batch": { "type": "string" }, "company": { "type": "string" }, "founded": { "type": "string" }, "team_size": { "type": "string" } }, "type": "object" }, "url": "https://www.ycombinator.com/companies/stripe" }}'
import jsonimport osimport requestspayload = json.loads(r'''{ "capability": "web.extract", "input": { "output_schema": { "properties": { "batch": { "type": "string" }, "company": { "type": "string" }, "founded": { "type": "string" }, "team_size": { "type": "string" } }, "type": "object" }, "url": "https://www.ycombinator.com/companies/stripe" }}''')response = requests.post( "https://data.upscrape.com/execute", headers={ "Authorization": f"Bearer {os.environ['UPSCRAPE_API_KEY']}", "Content-Type": "application/json", "Prefer": "wait=30", }, json=payload,)response.raise_for_status()print(json.dumps(response.json(), indent=2))
const response = await fetch("https://data.upscrape.com/execute", { method: "POST", headers: { "Authorization": `Bearer ${process.env.UPSCRAPE_API_KEY}`, "Content-Type": "application/json", "Prefer": "wait=30", }, body: JSON.stringify({ "capability": "web.extract", "input": { "output_schema": { "properties": { "batch": { "type": "string" }, "company": { "type": "string" }, "founded": { "type": "string" }, "team_size": { "type": "string" } }, "type": "object" }, "url": "https://www.ycombinator.com/companies/stripe" }}),});if (!response.ok) { throw new Error(`Upscrape request failed: ${response.status}`);}console.log(JSON.stringify(await response.json(), null, 2));
https://data.upscrape.com/mcp
Using Upscrape, read ycombinator.com/companies/stripe and give me the company name, its batch, the year it was founded and its team size.
The other website tools
Extract API FAQ
The short answers. The docs have the long ones.
How much does the Extract API cost?
1 credit per successful call, shown before it runs. You buy credits once, and paid credits never expire.
What do I send?
Send url and one of fields, output_schema or mode. The input fields below list every option.
Which sites does it work on?
Any public page a visitor can open without logging in. A page that is blocked or gone fails with its reason.
Can my AI agent call it?
Yes, over MCP: the agent finds web.extract, checks its price and runs it with the same credits as the REST API.
Your first page is free.
Up to 100 free credits to start, no card needed.