Extract
Describe the object you want — each field with a name, a type and what to take from the page — and get it back filled from the page: product details, prices, contact data, job listings, event dates, lists of items with their own attributes. Any value the page does not give comes back null; nothing is guessed.
This is an AI operation: the whole page — text, links, tables and its structured data — is read by a language model with reasoning, held to your schema. It costs 24 credits per call. See Credits. When the standard metadata is all you need, /meta gives it for one credit and no model.
Extract data
Body parameters
- Name
url- Type
- string
- Required
- Required
- Description
- The absolute URL of the page to process. Rendered with headless Chrome, so JavaScript runs and redirects are followed. It must not include a username or password (
https://user:pass@example.com).
- Name
fields- Type
- array
- Required
- Required
- Description
- The fields to fill, in the order you want them back. Each has a
name, atypeand, optionally but worth writing, adescription— see Fields.
- Name
instructions- Type
- string
- Description
- Guidance that applies to every field, up to 1,000 characters —
Prices in EUR, including VATorOnly the first product on the page.
- Name
page_options- Type
- object
- Description
- Wait for the page, and remove ads, cookie banners or your own elements from it before it is read — gone from this result, not merely hidden. See Page options.
- Name
residential- Type
- boolean
- Description
- Fetch the page from a residential exit — an address on a home broadband line rather than one in a datacentre. Reach for it when a site serves you less than it serves a browser, or nothing at all. Defaults to
false. Adds 25 credits per page fetch on top of what the operation costs, and its results are kept separate from the ordinary ones.
- Name
report_to- Type
- string
- Description
- Webhook URL — an
httporhttpsaddress URLpipe POSTs the result to when it's ready. Optional: without it we deliver to your project's default endpoint if it has one, and otherwise send no webhook at all — the result still waits for you at GET /result/:token. A value we cannot deliver to returns422. Ignored on async=truerequest. Deliveries can be signed so your endpoint can verify they came from us.
- Name
sync- Type
- boolean
- Description
- Process the request synchronously, returning the result inline in the response. Defaults to
false(async: return a token now, and either receive the result at a webhook or fetch it with GET /result/:token). See Async & sync modes for the full contract.
- Name
max_age- Type
- string | integer
- Description
- How fresh a cached result must be to be accepted. Either an integer number of seconds (
3600) or a duration string of the form"<number> <unit>"— unitss/min/h/d/w(e.g."2 hours","3 days","30m"). Defaults to7 days, clamped to a max of30 days;0always bypasses the cache. See Caching for all accepted units.
- Name
labels- Type
- object
- Description
- Your own keys to find and account for this request by — a client, a project, a campaign:
{"client": "acme"}. Returned with the result, in the webhook and in theX-Labelsheader, and your dashboard filters history and totals credits by them. Up to 16 keys; string values. See Labels.
Response
Content type application/json — an object with exactly your fields as keys, in your order. A value the page does not give, or that does not fit its type, is null; a list with nothing in it is [].
curl -X POST https://urlpipe.dev/extract \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "fields": [{"name":"name","type":"string","description":"The product's name"},{"name":"price","type":"number","description":"The current price, without the currency"},{"name":"currency","type":"string","description":"ISO 4217 code of the price's currency"},{"name":"in_stock","type":"boolean","description":"Whether it can be bought now"},{"name":"images","type":"array","items":"url","description":"Product photos"}]}'import requests
res = requests.post(
"https://urlpipe.dev/extract",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"url": "https://example.com", "fields": [{"name": "name", "type": "string", "description": "The product's name"}, {"name": "price", "type": "number", "description": "The current price, without the currency"}, {"name": "currency", "type": "string", "description": "ISO 4217 code of the price's currency"}, {"name": "in_stock", "type": "boolean", "description": "Whether it can be bought now"}, {"name": "images", "type": "array", "items": "url", "description": "Product photos"}]},
)const res = await fetch("https://urlpipe.dev/extract", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ url: "https://example.com", fields: [{"name":"name","type":"string","description":"The product's name"},{"name":"price","type":"number","description":"The current price, without the currency"},{"name":"currency","type":"string","description":"ISO 4217 code of the price's currency"},{"name":"in_stock","type":"boolean","description":"Whether it can be bought now"},{"name":"images","type":"array","items":"url","description":"Product photos"}] }),
})$ch = curl_init("https://urlpipe.dev/extract");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer YOUR_API_KEY",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode(["url" => "https://example.com", "fields" => [["name" => "name", "type" => "string", "description" => "The product's name"], ["name" => "price", "type" => "number", "description" => "The current price, without the currency"], ["name" => "currency", "type" => "string", "description" => "ISO 4217 code of the price's currency"], ["name" => "in_stock", "type" => "boolean", "description" => "Whether it can be bought now"], ["name" => "images", "type" => "array", "items" => "url", "description" => "Product photos"]]]),
]);
$response = curl_exec($ch);{
"name": "Trail Runner 3",
"price": 129.95,
"currency": "EUR",
"in_stock": true,
"images": [
"https://example.com/img/trail-runner-3-side.jpg",
"https://example.com/img/trail-runner-3-top.jpg"
]
}Fields
Each field is an object. name is the key it comes back under: letters, digits and underscores, starting with a letter or underscore. The description is what the model reads to decide which value on the page you mean, so say it the way you would to a person: The sale price if there is one, otherwise the regular price.
- Name
string- Type
- type
- Description
- Text, as the page writes it.
- Name
number- Type
- type
- Description
- A number, without currency symbols, units or separators.
- Name
integer- Type
- type
- Description
- A whole number.
- Name
boolean- Type
- type
- Description
- true or false.
- Name
date- Type
- type
- Description
- An ISO 8601 date,
2026-10-08.
- Name
datetime- Type
- type
- Description
- An ISO 8601 date and time, with its offset when the page gives one.
- Name
url- Type
- type
- Description
- An absolute URL. Relative links on the page are resolved against it.
- Name
email- Type
- type
- Description
- An email address.
- Name
object- Type
- type
- Description
- A group of values, with its own
fields.
- Name
array- Type
- type
- Description
- A list of every match on the page, in page order. Its
itemssay what it holds: a type on its own ("items": "url") or an object with fields, for a list of things with several attributes each.
{
"url": "https://example.com/careers",
"fields": [
{ "name": "company", "type": "string" },
{ "name": "jobs", "type": "array", "description": "Every open position", "items": {
"type": "object",
"fields": [
{ "name": "title", "type": "string" },
{ "name": "location", "type": "string", "description": "City, or Remote" },
{ "name": "posted_on", "type": "date" },
{ "name": "apply_url", "type": "url" }
]
} }
]
}Up to 50 fields in all, nested at most 3 levels deep. A schema that breaks these rules is refused with invalid_options and a message naming the field, before anything is fetched or spent.
How it works
- The page is rendered in a real browser, so content added by JavaScript is there.
- A URL that serves a PDF or a text file is read too, from its text — see Documents & files.
- The whole page is read — not only its article text — reduced to its text, links, tables, image alt text and its structured data (JSON-LD, microdata, meta tags), where prices, dates and identifiers often are.
- A model with a short reasoning step fills your schema. It is told to leave a value null rather than guess, and its answer is held to your schema: every key there, nothing else, and a value that does not fit its type turned into null.
max_age is answered for free. Change a field, its order or its description, and it is a new extraction.Responses
Whatever the status, the response carries metadata headers: the result token, whether it was served from cache and how old that result is, how long we took, what it cost in credits, and the allowance you have left.
200 OK422 Unprocessable Entity429 Too Many Requests504 Gateway Timeout401 UnauthorizedTry it live — no API key needed
Run this endpoint against any URL right in your browser.