POST /ai-generate-extraction-rules

Generate Extraction Rules

Generate a reusable CSS/XPath extract_rules object from 1-3 sample URLs, then run it on any page with the same layout via /scrape for fetch credits only.

Web Scraping API

Give this endpoint 1 to 3 sample URLs that share the same page layout, plus a schema or a plain-English prompt describing what you want. The model writes a reusable extract_rules object once, validates it across your sample pages (per-page validation report plus a matched_fields verdict), and returns it ready to paste into Scrape . From then on, /scrape runs those rules on every future page with that layout for fetch credits only: no more model calls, no extraction surcharge. This is the cheap path at volume.

HTTP Request

1
2
POST /ai-generate-extraction-rules
GET  /ai-generate-extraction-rules

Both verbs run the same handler and bill the same. On GET, pass urls comma-separated (up to 3, URL-encode each) and schema as a JSON-object string. Use POST for long URL lists or big schemas.

Parameters

ParameterTypeRequiredDefaultDescription
urlsarray of stringsYes1 to 3 sample URLs sharing the same page layout. Rules are written from the first reachable (non-blocked) URL; the rest only validate the rules. Put your best sample first.
schemaobjectNo*nullThe fields you want, as a full JSON Schema or compact shorthand, e.g. {"products": [{"title": "string", "price": "number", "url": "url"}]}. Leaf types: string, number, integer, boolean, url. Max 50 leaf fields, nesting depth 3. Required unless prompt is given.
promptstringNo*nullPlain-English description of what to extract (max 2000 chars). Required unless schema is given. Prefer schema when you can: it makes the response validatable per field.
render_jsstringNoautoauto, true, or false. auto tries plain HTTP first and escalates to a headless browser only when blocked. Only the winning attempt is billed.
proxy_typestringNodatacenterdatacenter or isp. ISP exits are static-residential addresses with higher trust on strict targets, at a higher fetch price.
session_idstringNogeneratedSticky-session handle (1-64 chars, A-Za-z0-9_-). The same value always exits from the same IP.
cookiesobject, string, or arrayNonullCookies to send: {"a": "1"}, "a=1; b=2", or the cookie list returned by /unlock. HTTP path only.
user_agentstringNonullCustom User-Agent; also selects the matching TLS/header fingerprint. HTTP path only.
headersobjectNo{}Extra request headers. Reserved names (Host, Cookie, User-Agent, Authorization, …) are rejected; use cookies / user_agent instead.
methodstringNoGETGET or POST for fetching the sample pages.
bodystringNonullRequest body for the fetch. Only with method=POST and a Content-Type in headers.
wait_forstringNonullCSS selector to wait for before capture. Browser path only.
timeoutintegerNo20Total request budget in seconds (max 27). Recommended: 25. At the default, the fetch and first model call usually eat the whole budget, so the repair pass (the normal recovery when the first pass misses fields) rarely gets to run.

* At least one of schema or prompt is required.

There is no url, fields, or source parameter on this endpoint. It always reads a cleaned-up copy of the page markup, because selectors need the underlying HTML, not just visible text.

The Reuse Workflow

  1. POST /ai-generate-extraction-rules with 1 to 3 sample URLs of the same layout and a schema.
  2. Take data.extract_rules from the response.
  3. POST /scrape on any page with that layout, passing it as extract_rules. Fetch credits only, no further AI cost, no further model calls.

Credits

Sum of fetch credits for every non-blocked sample URL, plus 15 generation credits when extract_rules was produced and matched at least one field on at least one page (matched_fields is all or some). Rules that matched nothing anywhere (matched_fields: "none") are still returned so you can inspect what was tried, but the 15 generation credits are not billed. If every URL is blocked: 0 credits and ai_error: "blocked".

Fetch credits per URL follow the /scrape table: datacenter 1 (HTTP) / 5 (browser), isp 5 (HTTP) / 20 (browser). At most two model calls happen per request regardless of URL count, so 3 sample URLs do not cost 3x the generation price.

Response

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "status": true,
  "request_id": "a35488c9-6d45-3b35-e7a4-f9e75acd",
  "data": {
    "extract_rules": {
      "title": "h1.product-title",
      "price": {"selector": ".price", "output": "text"}
    },
    "sample": {"title": "14-inch Ultrabook", "price": "899.00"},
    "validation": [
      {"url": "https://shop.example/p/14-ultrabook", "http_status": 200, "render_used": "http", "blocked": false, "fetch_error": null, "empty_fields": [], "list_counts": {}},
      {"url": "https://shop.example/p/16-workstation", "http_status": 200, "render_used": "http", "blocked": false, "fetch_error": null, "empty_fields": [], "list_counts": {}}
    ],
    "matched_fields": "all",
    "warnings": [],
    "ai_error": null,
    "credits": 17,
    "elapsed_ms": 3820,
    "session_id": "5e4cdb8ab2a90424",
    "proxy_type": "datacenter"
  }
}

Response Fields

FieldTypeDescription
statusbooleanWhether the request was successful. false when the AI step failed (error mirrors data.ai_error).
request_idstringUnique identifier for the request.
data.extract_rulesobject | nullPaste-ready for /scrape’s extract_rules parameter. null when generation failed (see ai_error).
data.sampleobject | nullResult of running the rules on the first (primary) page: a preview of what /scrape will return.
data.validationarrayOne entry per URL you sent, produced by the same deterministic engine /scrape uses.
data.validation[].urlstringThe sample URL this entry reports on.
data.validation[].http_statusinteger | nullHTTP status the page returned. null when the fetch itself failed.
data.validation[].render_usedstring | nullhttp or browser: which path fetched this page. null when the fetch failed.
data.validation[].blockedbooleanWhether the target served an anti-bot challenge instead of content.
data.validation[].fetch_errorstring | nullSet when this URL’s fetch failed: one of the fetch-failure slugs (dns_error, connection_refused, timeout, …), plus unsupported_content or target_not_allowed. That page took no part in rule validation.
data.validation[].empty_fieldsarrayDotted paths (e.g. products[].price) that matched nothing on this page. For list fields, a nested field surfaces here only when it is empty on every item of the list.
data.validation[].list_countsobjectItem counts per list field on this page.
data.matched_fieldsstring | nullVerdict over the rules’ data-carrying fields: all (every field matched on at least one page), some (at least one field never matched, see warnings), or none (no field matched anywhere, generation not billed). null when no rules were produced.
data.warningsarrayHuman-readable notes, e.g. "price matched on 2/3 pages" or "input truncated to token budget".
data.ai_errorstring | nullSet when the AI step failed. Same values as /ai-extract.
data.creditsintegerCredits billed for this call (fetch sum + 15 generation when applicable). Same value as the X-RapidAPI-Billing header.
data.elapsed_msintegerTotal server-side time for this call.
data.session_idstringSticky-session handle used (yours, or a generated one). Reuse it to keep the same IP.
data.proxy_typestringProxy pool this request exited from.

Error Responses

StatusDescription
400Invalid request: bad URL, more than 3 urls, both schema and prompt missing, schema breaking a cap, prompt over 2000 chars, out-of-range timeout, or a URL pointing at a non-public address. Not billed.
415The URL returned a non-textual document, e.g. image/png
502A target could not be fetched: DNS failure, connection refused, TLS error, timeout. Body: could not fetch target: <reason>. Not billed.
503Our infrastructure is unavailable: proxy pool failure, browser pool exhausted, or a requested proxy_type pool not configured. Not billed. Target-side failures are always 502, never 503.

Generation failures (the pages fetched fine but the model produced no usable rules) are returned as HTTP 200 with status: false and data.ai_error set, never as an HTTP error status.

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
import requests

url = "https://ai-web-scraper-api1.p.rapidapi.com/ai-generate-extraction-rules"

payload = {
    "urls": [
        "https://shop.example/p/14-ultrabook",
        "https://shop.example/p/16-workstation"
    ],
    "schema": {"title": "string", "price": "number"},
    "timeout": 25
}

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

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

print("Verdict:", data["matched_fields"])
print("Rules:", data["extract_rules"])
print("Sample:", data["sample"])
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const url = "https://ai-web-scraper-api1.p.rapidapi.com/ai-generate-extraction-rules";

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

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

console.log("Verdict:", data.matched_fields);
console.log("Rules:", data.extract_rules);
console.log("Sample:", data.sample);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
curl -X POST "https://ai-web-scraper-api1.p.rapidapi.com/ai-generate-extraction-rules" \
  -H "Content-Type: application/json" \
  -H "X-RapidAPI-Key: YOUR_API_KEY" \
  -H "X-RapidAPI-Host: ai-web-scraper-api1.p.rapidapi.com" \
  -d '{
    "urls": [
      "https://shop.example/p/14-ultrabook",
      "https://shop.example/p/16-workstation"
    ],
    "schema": {"title": "string", "price": "number"},
    "timeout": 25
  }'

Reusing the Rules on /scrape

Take data.extract_rules from the response above and pass it to /scrape on any page with the same layout. Fetch credits only, no model call:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import requests

rules = data["extract_rules"]  # from the generation response above

response = requests.post(
    "https://ai-web-scraper-api1.p.rapidapi.com/scrape",
    json={"url": "https://shop.example/p/17-tablet", "extract_rules": rules},
    headers={
        "Content-Type": "application/json",
        "X-RapidAPI-Key": "YOUR_API_KEY",
        "X-RapidAPI-Host": "ai-web-scraper-api1.p.rapidapi.com",
    },
)

print(response.json()["data"]["extract"])
# {"title": "17-inch Tablet", "price": "499.00"}
  • Scrape — Run the generated extract_rules on any page with the same layout, for fetch credits only
  • AI Extract — One-off AI extraction from a single page, no rules needed
Start building today

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

Get Your API Key on RapidAPI