Extract structured JSON from web pages
Turn web pages and PDFs into JSON with /v1/extract: send a JSON Schema and a prompt, get each page's data back. Classification, summaries, pricing and failures.
/v1/extract reads up to 20 URLs (HTML pages or PDFs) per call. Add output_schema and each page also comes back as JSON that matches your JSON Schema, written by Claude from the page’s content. No per-site parser, no HTML to maintain.
Extract with a schema
Describe the fields you want. An optional prompt (up to 4,096 characters) says what to pick and how to normalise it.
curl https://api.serpkite.com/v1/extract \
-H "Authorization: Bearer $SERPKITE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"urls":["https://www.example.com/pricing"],"output_schema":{"type":"object","properties":{"plans":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"price_per_month":{"type":["number","null"]},"seats":{"type":["integer","null"]}}}},"free_trial":{"type":"boolean"}}},"prompt":"Monthly prices in USD; null when a plan has no list price."}'Each entry in results keeps its usual fields (url, title, markdown…) and gains output:
{
"url": "https://www.example.com/pricing",
"title": "Pricing · Example",
"output": {
"plans": [
{ "name": "Starter", "price_per_month": 19, "seats": 1 },
{ "name": "Team", "price_per_month": 79, "seats": 5 },
{ "name": "Enterprise", "price_per_month": null, "seats": null }
],
"free_trial": true
}
}
Values come only from the page. Make fields nullable ("type": ["number", "null"]) and say “null when missing” in the prompt, so a field the page doesn’t have comes back as null instead of a guess.
Classification schemas
A schema whose fields are all booleans or enums is a classification (“is this a pricing page?”, “which plan tier is this?”). Those go to OpenAI’s Decisions API instead of Claude, which always answers with values the schema allows.
{
"urls": ["https://www.example.com/blog/launch", "https://www.example.com/pricing"],
"output_schema": {
"type": "object",
"properties": {
"page_type": { "enum": ["pricing", "docs", "blog", "login", "other"] },
"mentions_free_tier": { "type": "boolean" }
}
}
}
Summaries
summary: true adds a 3–6 sentence summary of each page in results[].summary, focused on query when you send one. It can be combined with output_schema and with highlights.
Pricing and failures
| What | Credits per page |
|---|---|
| Reading the page | 1 (0.5 from cache) |
output_schema |
+4 |
summary: true |
+4 |
- A URL that can’t be read is listed in
failedwith a reason and costs nothing. So is a short page that turns out to be a bot check, a login wall, a soft 404 or an empty app shell. - An extraction or summary that fails is reported in
results[].output_errororsummary_errorand not charged; you pay only for the page. - With
summaryoroutput_schema,timeoutdefaults to 75 seconds and the last 25 are kept for the model.meta.llmreports the provider, model and tokens.
Extract from a whole site
Combine extraction with the site endpoints: list the URLs with /v1/map (ranked by a search phrase), then send the ones you need to /v1/extract with your schema, 20 at a time.
from serpkite import SerpKite
sk = SerpKite()
urls = [u.url for u in sk.map("https://www.example.com/", search="pricing plans", limit=20).results]
Then post those URLs with your output_schema as above. The remote MCP server’s extract tool takes output_schema, prompt and summary too.
Privacy
Page text and your prompt are sent to the model provider (Anthropic, or OpenAI for classification schemas) under API terms that exclude training. SerpKite never logs them, and extractions are not cached. See Privacy and data retention.
Related
Last updated: 2026-10-24