POST /ai-extract

AI Extract

Fetch any URL and extract the fields you describe as structured JSON, no CSS selectors needed.

Web Scraping API

Fetch a page and pull the fields you describe out of it. No selectors: an extraction model reads the page and returns JSON in data.json. Describe what you want with a schema (the exact shape you need), a prompt (what to look for, in words), or both; at least one is required. Every field is nullable: when the page does not contain a value, the model returns null instead of guessing. It is a good fit for one-off pages or layouts you have not mapped yet.

HTTP Request

1
POST /ai-extract

Both POST (JSON body) and GET (query-string parameters) work, run the same handler, and bill the same. POST is recommended: schema payloads are JSON objects and URLs should stay short. On GET, send schema as a URL-encoded JSON object string.

Parameters

ParameterTypeRequiredDefaultDescription
urlstringYesAbsolute http(s) URL of the page to fetch. Must point at a public address.
schemaobjectNo*nullWhat to extract: a JSON Schema (object at the top level) or the compact shorthand described below. Required unless prompt is given.
promptstringNo*nullFree-text instructions or hints, e.g. only in-stock items, prices in EUR. Max 2000 characters. Required unless schema is given. With prompt alone the model chooses the JSON shape.
sourcestringNo"auto"What the extraction step reads: markdown (visible text, cheaper, fine for text-only fields), html (a cleaned-up copy of the page that keeps links, images, and attributes), or auto, which picks markdown unless the schema or prompt asks for a URL, link, or image field.
render_jsstringNo"auto"false: plain HTTP fetch. true: headless-browser rendering. auto: HTTP first, escalating to the browser when the response looks blocked; only the winning attempt is billed.
proxy_typestringNo"datacenter"Proxy pool: datacenter or isp (static-residential addresses, higher trust with strict targets, higher fetch cost).
session_idstringNogeneratedSticky-session handle (1-64 chars, A-Za-z0-9_-). The same value always maps to the same outbound IP. Whatever was used is echoed in data.session_id.
cookiesobject, string, or listNonullCookies to send: {"a": "1"}, "a=1; b=2", or the cookie list returned by /unlock. Applied on the HTTP path only.
user_agentstringNonullUser-Agent to send; also selects the matching TLS/header fingerprint. HTTP path only.
headersobjectNo{}Extra request headers. Reserved names such as Host, Cookie, User-Agent, and Authorization are rejected; use cookies and user_agent instead.
methodstringNo"GET"HTTP method for the fetch: GET or POST.
bodystringNonullRequest body. Only allowed with method: "POST" and a Content-Type in headers.
wait_forstringNonullCSS selector to wait for before capturing the page. Browser path only; at most 15 seconds and never past timeout.
timeoutintegerNo25Total budget in seconds (1-27). The fetch gets timeout - 8s; the remainder goes to the extraction step.
fieldsstring or listNonullAllow-list of data keys to return, e.g. json,credits. Unknown names are rejected before any fetch.

* At least one of schema or prompt is required.

Schema shorthand

schema accepts a full JSON Schema, or a compact shorthand:

1
{"products": [{"title": "string", "price": "number", "url": "url"}]}
  • Leaf types: string, number, integer, boolean, url.
  • Lists: [{...}] with exactly one element describing the item shape.
  • Every field is nullable: the model returns null when the page does not have it, never an invented value.
  • Caps: 50 leaf fields total, nesting depth 3.

Use schema when you can: it makes the response validatable. prompt alone works too, but the model picks the JSON shape and there is no per-field validation.

Credits

Fetch credits (the same proxy_type by render_used table as /scrape) plus 5 extraction credits when json is produced:

Outcomeproxy_type=datacenterproxy_type=isp
Served over HTTP, json produced1 + 5 = 65 + 5 = 10
Served by the headless browser, json produced5 + 5 = 1020 + 5 = 25
Target blocked the request00
Extraction failed (ai_error set)fetch credits onlyfetch credits only

The extraction surcharge is billed only when output was actually produced. A blocked target costs 0 credits and no extraction is attempted.

Response

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
  "status": true,
  "request_id": "a35488c9-6d45-3b35-e7a4-f9e75acd",
  "data": {
    "url": "https://shop.example/category/laptops",
    "http_status": 200,
    "json": {
      "products": [
        {"title": "14-inch Ultrabook", "price": 899.0, "url": "https://shop.example/p/14-ultrabook"},
        {"title": "16-inch Workstation", "price": 1899.0, "url": "https://shop.example/p/16-workstation"}
      ]
    },
    "ai_error": null,
    "blocked": false,
    "block_reason": null,
    "detected_protection": null,
    "render_used": "http",
    "credits": 6,
    "elapsed_ms": 2140,
    "session_id": "5e4cdb8ab2a90424",
    "proxy_type": "datacenter"
  }
}

Response Fields

FieldTypeDescription
statusbooleantrue when extraction succeeded; false when the AI step failed (a top-level error then carries the same slug as data.ai_error)
request_idstringUnique identifier for the request
data.urlstringFinal URL after redirects
data.http_statusintegerHTTP status the target returned, never masked
data.jsonobject or nullThe extracted object. null when extraction did not run or failed; see data.ai_error
data.ai_errorstring or nullblocked, llm_timeout, llm_error, or invalid_output; null when json was produced
data.blockedbooleanThe target served an anti-bot challenge or rejection instead of content
data.block_reasonstring or nullStable slug for the block, e.g. forbidden, captcha, cloudflare_challenge
data.detected_protectionstring or nullDetected anti-bot vendor (cloudflare, akamai, datadome, perimeterx, incapsula); advisory, filled even when not blocked
data.render_usedstringWhich path produced the answer: http or browser
data.creditsintegerCredits billed for this call; same value as the X-RapidAPI-Billing header
data.elapsed_msintegerTotal server-side time for this call
data.session_idstringSticky-session handle used; reuse it to keep the same IP
data.proxy_typestringProxy pool this request went out of

Error Responses

Extraction failures never turn into an HTTP error. You always get a 200 with the fetch metadata, status: false, a top-level error, and data.ai_error set; the fetch is billed, the extraction is not:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "status": false,
  "request_id": "a35488c9-6d45-3b35-e7a4-f9e75acd",
  "error": "invalid_output",
  "data": {
    "url": "https://shop.example/category/laptops",
    "http_status": 200,
    "json": null,
    "ai_error": "invalid_output",
    "blocked": false,
    "credits": 1
  }
}
ai_errorMeaning
blockedThe target blocked the request; no extraction was attempted
llm_timeoutNot enough of the time budget was left to finish extraction; the fetch is billed, the extraction is not
llm_errorThe extraction step could not run
invalid_outputExtraction ran but its output did not match the requested schema

HTTP error statuses (not billed):

CodeWhen
400Invalid request: bad URL, both schema and prompt missing, schema breaking a cap, prompt over 2000 characters, out-of-range timeout, or a URL pointing at a non-public address
415The URL returned a non-textual document, e.g. image/png
502The target could not be fetched: DNS failure, connection refused, TLS error, timeout
503Our infrastructure is temporarily unavailable (proxy or browser pool); the target is fine, retry later

Code Examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import requests

url = "https://ai-web-scraper-api1.p.rapidapi.com/ai-extract"

payload = {
    "url": "https://shop.example/category/laptops",
    "schema": {
        "products": [
            {"title": "string", "price": "number", "url": "url"}
        ]
    }
}

headers = {
    "X-RapidAPI-Key": "YOUR_API_KEY",
    "X-RapidAPI-Host": "ai-web-scraper-api1.p.rapidapi.com",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)
data = response.json()["data"]

if data["json"]:
    for product in data["json"]["products"]:
        print(f"{product['title']}: {product['price']}")
        print(f"   {product['url']}\n")
else:
    print(f"Extraction failed: {data['ai_error']}")
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const url = "https://ai-web-scraper-api1.p.rapidapi.com/ai-extract";

const response = await fetch(url, {
  method: "POST",
  headers: {
    "X-RapidAPI-Key": "YOUR_API_KEY",
    "X-RapidAPI-Host": "ai-web-scraper-api1.p.rapidapi.com",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://shop.example/category/laptops",
    schema: {
      products: [{ title: "string", price: "number", url: "url" }],
    },
  }),
});

const { data } = await response.json();

if (data.json) {
  data.json.products.forEach((product) => {
    console.log(`${product.title}: ${product.price}`);
    console.log(`   ${product.url}\n`);
  });
} else {
  console.log(`Extraction failed: ${data.ai_error}`);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
curl -X POST "https://ai-web-scraper-api1.p.rapidapi.com/ai-extract" \
  -H "X-RapidAPI-Key: YOUR_API_KEY" \
  -H "X-RapidAPI-Host: ai-web-scraper-api1.p.rapidapi.com" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://shop.example/category/laptops",
    "schema": {
      "products": [
        {"title": "string", "price": "number", "url": "url"}
      ]
    }
  }'
  • Generate Extraction Rules — Same input, but writes a reusable extract_rules object from sample pages; the cheap path at volume (fetch credits only on every reuse)
  • Scrape — Fetch a URL and get its content plus optional CSS/XPath extraction
  • AI Summarize — Fetch a URL and get a text summary instead of structured JSON
Start building today

Get your API key and make your first request in under a minute.

Get Your API Key on RapidAPI