Skip to content

New AI assistant answers: ChatGPT, Gemini, Copilot and AI Mode by API

SerpKite
Get API key
Docs menu / Extract structured JSON from web pages

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.

View as Markdown

/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 failed with 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_error or summary_error and not charged; you pay only for the page.
  • With summary or output_schema, timeout defaults to 75 seconds and the last 25 are kept for the model. meta.llm reports 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.

Last updated: 2026-10-24