# AI Web Scraper: JSON Schema Extractor (`tiger19935/schema-ai-extractor`) Actor

AI web scraper with strict JSON Schema extraction: give URLs and a schema, get validated JSON per page. HTTP-first, so far cheaper than browser scrapers. Bring your own LLM key at $0.003 per page, failed pages are never charged.

- **URL**: https://apify.com/tiger19935/schema-ai-extractor.md
- **Developed by:** [Andrew Boiko](https://apify.com/tiger19935) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 page extracted (your own llm key)s

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## AI Web Scraper: JSON Schema Extractor

**AI web scraper** that turns page URLs into JSON that is validated against *your* JSON Schema. Give it URLs, a schema (or just a list of field names) and optional instructions. It downloads each page over plain HTTP, cleans it into compact Markdown, asks an LLM for structured output, validates the answer with a real JSON Schema validator (ajv), and retries with the validation errors fed back to the model. Pages that cannot be extracted or validated are **never charged**.

This **AI scraper** is built for people who want predictable, typed data from messy pages (products, listings, articles, job posts, company pages, documentation) without writing one parser per site. It works with your own OpenAI, OpenRouter, Anthropic or Gemini key (BYOK), so the LLM tokens are billed directly by your provider at their price.

### What does AI Web Scraper: JSON Schema Extractor do?

- Takes a list of page URLs and a **JSON Schema** (draft-07 style) or a plain field list like `["title", "price: number", "tags: string[]"]`.
- Fetches each page with plain HTTP (no browser), strips scripts, styles, navigation and footers, keeps headings, tables, lists, absolute links and JSON-LD structured data, and converts it to Markdown.
- Sends the Markdown plus your schema to an LLM and asks for one JSON object.
- Validates the answer with ajv. If it does not match, the exact validation errors are sent back to the model and it tries again (default 2 retries, up to 3).
- Pushes one dataset item per page with `status`, `data`, token counts and the model used.
- Optional **list-page to detail-page crawl**: give a listing URL, turn on "Follow links", and the Actor finds the detail links and extracts each one, with hard limits (`maxDetailPagesPerListing`, `maxPages`, `maxItems`).
- Pages that render their content only with JavaScript are reported clearly as `needs-javascript` (no tokens spent, no charge). There is no browser fallback in this version.

### Why use AI Web Scraper: JSON Schema Extractor?

1. **Strict schema, not just a prompt.** Output is validated with ajv and retried with the errors. You get the shape you asked for, or a clearly marked failure.
2. **You pay only for pages that work.** `page-passthrough` is billed only after a page is extracted and validated. Fetch errors, blocked pages, JavaScript-only pages and validation failures cost $0 in Actor fees.
3. **HTTP-first is much cheaper.** No browser means a page costs a fraction of the compute of a headless Chrome session. With your own key the Actor fee is $3 per 1,000 pages (FREE plan price, lower on paid plans), plus tokens at your provider's price. Check the current price of other AI scraping Actors on the Store and compare the per-page cost.
4. **Bring your own key and model.** OpenAI-compatible endpoints (OpenAI, OpenRouter with a custom base URL, Groq, Together, Mistral, self-hosted), Anthropic and Google Gemini. Model tiers: a cheap fast model by default and an accurate model when you need it.
5. **Built for agents and automation.** Array input, JSON in and JSON out, a saved OUTPUT summary and a stable dataset format make it easy to call from MCP clients, n8n, Make, Zapier and plain HTTP.

### How much does it cost to scrape with an AI web scraper?

Two events exist. Use `page-passthrough` (the default) with your own API key. `page-inclusive` is an optional all-inclusive mode for which no key is needed; it only works if the Actor owner has enabled it.

| Event | What is billed | FREE | BRONZE | SILVER | GOLD |
|---|---|---|---|---|---|
| `page-passthrough` | One page extracted and validated (LLM tokens billed by your provider) | $0.0030 | $0.0027 | $0.0024 | $0.0021 |
| `page-inclusive` | One page extracted and validated, LLM cost included (fast tier) | $0.0080 | $0.0072 | $0.0064 | $0.0056 |

Apify's standard run start event applies as usual. No charge for failed pages.

**Example:** 1,000 pages with your own key on the FREE plan = 1,000 x $0.003 = **$3.00** in Actor fees, plus your provider's tokens. As a rough guide (approximate public list prices, check your provider), a typical product page is about 3,000 to 8,000 input tokens and 300 to 600 output tokens, which costs around $1 per 1,000 pages on a Gemini Flash-Lite class model and a few dollars per 1,000 pages on a GPT-4.1-mini class model. Accurate-tier models cost several times more. Pages are truncated to 60,000 characters by default (`maxInputChars`) so one huge page cannot create a surprise bill.

**Cost limits:** set Apify's **Maximum cost per run** (`maxTotalChargeUsd`) to cap the Actor fee. Also use `maxItems` and `maxPages`. For LLM tokens, set a spend limit with your provider as well, because those are billed outside Apify.

**Free plan:** free Apify plan users get up to 25 results per run, then the Actor stops normally with the message "Free tier limit reached (25 results). Upgrade to a paid Apify plan for unlimited results."

### Input

| Field | Type | Description |
|---|---|---|
| `urls` | array of strings | Page URLs to extract. Main input. |
| `schema` | object | JSON Schema of the object to extract (type `object` at the top). |
| `fields` | array of strings | Simple alternative to `schema`: `name`, `name: type`, optional ` - description`. Types: string, number, integer, boolean, string\[], number\[]. |
| `instructions` | string | Optional hints, for example "Prices are in EUR". |
| `llmProvider` | select | `openai-compatible` (default), `anthropic`, `gemini`. |
| `apiKey` | secret string | Your own LLM API key. Empty means preview mode (no LLM call, no charge). |
| `baseUrl` | string | For OpenAI-compatible APIs, for example `https://openrouter.ai/api/v1`. |
| `modelTier` | select | `fast` (default) or `accurate`. |
| `model` | string | Exact model name override. Required with a custom base URL. |
| `billingMode` | select | `byok` (default) or `inclusive` (only if enabled by the owner). |
| `maxRetries` | integer | Validation retries 0 to 3 (default 2). |
| `maxItems` | integer | Stop after this many extracted pages (default 20). |
| `followLinks` | boolean | Treat URLs as listing pages and extract their detail pages. |
| `detailLinkSelector` | string | CSS selector of detail links (optional). |
| `detailUrlPattern` | string | Regex that detail URLs must match (optional). |
| `maxDetailPagesPerListing` | integer | Hard limit per listing page (default 10). |
| `maxPages` | integer | Hard limit of all fetches, including listings and failures (default 50). |
| `contentSelector` | string | Restrict the content sent to the model to a part of the page. |
| `includeImages` | boolean | Keep image URLs (auto-enabled when the schema mentions images). |
| `includeMarkdown` | boolean | Add the cleaned Markdown to every item. |
| `maxInputChars` | integer | Max characters of page content sent to the model (default 60,000). |
| `maxConcurrency` | integer | Pages processed in parallel (default 3). |
| `requestTimeoutSecs` | integer | Page download timeout (default 30). |
| `proxyConfiguration` | object | Apify proxy settings (default: datacenter proxy). |
| `useResidentialFallback` | boolean | Retry blocked pages through residential proxy (needs access on your plan). |

Default behavior of the prefilled run: it fetches one public demo page and, because no API key is given, returns a preview (the Markdown that would be sent to the model) without charging anything.

#### Example 1: schema with your own OpenAI key

```json
{
  "urls": ["https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"],
  "schema": {
    "type": "object",
    "properties": {
      "title": { "type": "string" },
      "price": { "type": ["number", "null"], "description": "Price as a number" },
      "in_stock": { "type": ["boolean", "null"] }
    },
    "required": ["title", "price"],
    "additionalProperties": false
  },
  "llmProvider": "openai-compatible",
  "apiKey": "sk-...",
  "modelTier": "fast"
}
```

#### Example 2: plain field list through OpenRouter

```json
{
  "urls": ["https://example.com/jobs/123", "https://example.com/jobs/124"],
  "fields": ["job_title", "company", "salary_min: number", "salary_max: number", "remote: boolean", "skills: string[]"],
  "instructions": "Salaries are yearly in USD. Leave a number empty if not stated.",
  "llmProvider": "openai-compatible",
  "baseUrl": "https://openrouter.ai/api/v1",
  "apiKey": "sk-or-...",
  "model": "google/gemini-2.5-flash-lite"
}
```

#### Example 3: listing page to detail pages with hard limits

```json
{
  "urls": ["https://books.toscrape.com/catalogue/category/books/mystery_3/index.html"],
  "followLinks": true,
  "maxDetailPagesPerListing": 10,
  "maxPages": 15,
  "maxItems": 10,
  "fields": ["title", "price: number", "upc", "availability"],
  "llmProvider": "anthropic",
  "apiKey": "sk-ant-...",
  "modelTier": "fast"
}
```

### Output example

This is an illustrative item (not from a live run):

```json
{
  "url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html",
  "status": "success",
  "data": { "title": "A Light in the Attic", "price": 51.77, "in_stock": true },
  "error": null,
  "attempts": 1,
  "provider": "openai-compatible",
  "model": "gpt-4.1-mini",
  "inputTokens": 1480,
  "outputTokens": 41,
  "markdownChars": 3620,
  "truncated": false,
  "sourceListingUrl": null,
  "charged": "page-passthrough",
  "extractedAt": "2026-10-19T12:00:00.000Z"
}
```

`status` is one of: `success`, `validation-failed`, `llm-error`, `needs-javascript`, `blocked`, `not-found`, `fetch-failed`, `unsupported-content-type`, `no-links-found`, `dry-run` (preview mode) and `error`. Only `success` rows are charged. Failed rows are pushed for free so you can see why. A run summary (counts, charged events, tokens, warnings, stop reason) is saved in the key-value store under `OUTPUT`.

### How to use the AI web scraper (tutorial)

1. **Open the Actor** on Apify and paste your page URLs into "Page URLs".
2. **Describe the data.** Paste a JSON Schema into "JSON Schema", or leave it empty and list fields in "Fields". Add short property descriptions, they guide the model.
3. **Add your API key.** Choose the provider, paste the key, and pick the "fast" tier. For OpenRouter pick OpenAI-compatible and set the base URL to `https://openrouter.ai/api/v1`.
4. **Start with a small run.** Keep `maxItems` at 5 and check the dataset. If rows fail validation, add instructions, tighten descriptions, set a `contentSelector`, or switch to the "accurate" tier.
5. **Scale up.** Raise `maxItems`, schedule the run, set Maximum cost per run, and export the dataset as JSON, CSV or Excel or fetch it by API.

### Run via API

```bash
curl -X POST "https://api.apify.com/v2/acts/tiger19935~schema-ai-extractor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": ["https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"],
    "fields": ["title", "price: number"],
    "apiKey": "sk-...",
    "maxItems": 1
  }'
```

Node.js:

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('tiger19935/schema-ai-extractor').call({
    urls: ['https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html'],
    fields: ['title', 'price: number'],
    apiKey: process.env.OPENAI_API_KEY,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((i) => i.status === 'success').map((i) => i.data));
```

**MCP:** the input is plain JSON with arrays and simple fields, so the Actor can be exposed as a tool through the Apify MCP server. An agent passes `urls`, a `schema` and your key, and receives validated JSON rows. Never paste an API key into a shared agent prompt, store it as a secret in your MCP client configuration instead.

### Integrations

- **n8n and Make:** use the Apify module, run the Actor, then read dataset items. Filter on `status = success` and use the `data` object.
- **Zapier:** trigger the Actor from a schedule or a form, then send `data` to your app.
- **Google Sheets:** use the Apify integration or export CSV/Excel from the dataset.
- **Webhooks:** call a URL when a run finishes and fetch the dataset items.
- **MCP and agents:** see the section above.

### Legal / ethical use

The Actor downloads publicly available pages without logging in and does not bypass authentication. You are responsible for how you use the data. Check the target site's terms of service and robots.txt, respect copyright and database rights, and do not collect personal data without a legal basis (for example under GDPR). Page content is sent to the LLM provider you choose, so make sure that is acceptable for the data involved, and review your provider's data handling terms. Do not use the Actor on pages that require authentication or that you are not permitted to process.

### FAQ and support

**Which sites work?** Pages whose content is present in the raw HTML (server-rendered or static pages, many shops, blogs, directories, documentation). Pages that load content only with JavaScript return `needs-javascript`. Sites that block automated requests may return `blocked`; you can try the residential fallback if your plan has it. The Actor does not work on every site.

**Do I need an API key?** For extraction, yes (BYOK), unless the optional `inclusive` mode is enabled by the Actor owner. Without a key the Actor runs in preview mode and shows the Markdown that would be sent, with no charge.

**What is charged when a page fails?** Nothing in Actor fees. Your LLM provider may still bill tokens for attempts that did not validate, so keep `maxRetries` low when cost matters.

**How accurate is it?** It depends on the model and the page. Validation guarantees the shape, not the truth of every value. Use clear property descriptions, a `contentSelector` for noisy pages and the accurate tier for hard cases. Always spot check results.

**Can it extract lists of items from one page?** Yes. Define an array property in the schema (for example `products` with an object `items` definition). Very long pages are cut at `maxInputChars`, so split big lists across pages or raise the limit.

**Can it follow pagination or crawl a whole site?** No. It can follow links from a listing page to detail pages, up to `maxDetailPagesPerListing` per listing and `maxPages` overall. Pass each listing page URL yourself for more.

**Which models are used by default?** Fast tier: gpt-4.1-mini, claude-haiku-4-5, gemini-2.5-flash-lite. Accurate tier: gpt-4.1, claude-sonnet-4-5, gemini-2.5-pro. Override with the `model` field if your account uses different names.

**Is my API key safe?** It is stored as a secret input and is never written to logs or the dataset.

**Need help or a feature?** Open an issue in the Issues tab of this Actor. Replies come within 12 hours.

### More tools by the same author

- [Prozorro & TED Tenders Scraper](https://apify.com/tiger19935/prozorro-ted-tenders-scraper) - public tenders from Ukraine and the EU
- [Billing & Payment Stack Detector](https://apify.com/tiger19935/billing-stack-detector) - which payment gateway a website uses
- [Website Technology Detector](https://apify.com/tiger19935/website-technology-detector) - tech stack of any site
- [Decision-Maker Contacts](https://apify.com/tiger19935/decision-maker-contacts) - people and roles at a company

### Related searches

ai web scraper, ai web scraper api, ai web scraper data, ai web scraper to csv, ai web scraper monitor, ai web scraper apify, ai web scraper mcp, ai scraper, ai scraper api, ai scraper data, json schema extraction, llm web scraper, structured data extraction with openai, openrouter scraper, schema based web scraping.

# Changelog

This Actor's version history is a separate document: https://apify.com/tiger19935/schema-ai-extractor/changelog.md

# Actor input Schema

## `urls` (type: `array`):

Pages to extract data from. Static or server-rendered HTML pages work; pages that need JavaScript to show content are reported as 'needs-javascript'. If 'Follow links' is on, these are listing pages and detail pages are extracted instead.

## `schema` (type: `object`):

JSON Schema (draft-07 style) of the object to extract, with type 'object' at the top. Property descriptions guide the model. Output is validated against it. Leave empty to use 'Fields' instead.

## `fields` (type: `array`):

Used only when 'JSON Schema' is empty. One field per line: 'name', 'name: type' (string, number, integer, boolean, string\[], number\[]) and optionally ' - description'. Example: 'price: number - price without currency symbol'. All fields are required but nullable.

## `instructions` (type: `string`):

Optional plain-language hints for the model, for example 'Prices are in EUR; ignore sponsored items'. Max 2,000 characters.

## `llmProvider` (type: `string`):

Whose API your key belongs to. 'OpenAI-compatible' covers OpenAI, OpenRouter (set Base URL to https://openrouter.ai/api/v1), Groq, Together, Mistral and self-hosted servers. Ignored when billing mode is 'inclusive'.

## `apiKey` (type: `string`):

Your LLM provider API key. Tokens are billed by your provider, not by this Actor. Stored as a secret and never logged. Empty = preview mode (no LLM call, no charge).

## `baseUrl` (type: `string`):

API base URL. Leave empty for OpenAI (https://api.openai.com/v1). For OpenRouter use https://openrouter.ai/api/v1. A custom Base URL needs an explicit 'Model'.

## `modelTier` (type: `string`):

'fast' = cheapest small model (default: gpt-4.1-mini, claude-haiku-4-5, gemini-2.5-flash-lite). 'accurate' = stronger model (gpt-4.1, claude-sonnet-4-5, gemini-2.5-pro) for messy pages and complex schemas. Overridden by 'Model'.

## `model` (type: `string`):

Exact model name to use instead of the tier default, for example 'google/gemini-2.5-flash' on OpenRouter. Required with a custom Base URL.

## `billingMode` (type: `string`):

'byok' (default): you use your own API key; this Actor charges the lower 'page-passthrough' event and your provider bills the tokens. 'inclusive': no key needed, LLM cost included in the higher 'page-inclusive' event; uses the fast tier only and is available only if the Actor owner enabled it.

## `maxRetries` (type: `integer`):

How many times to send the validation errors back to the model when its JSON does not match the schema (0 to 3). Each retry costs tokens. Pages that still fail are not charged.

## `maxItems` (type: `integer`):

Stop after this many successfully extracted pages. Also the upper bound of what the run can charge.

## `followLinks` (type: `boolean`):

Treat each URL as a listing page: find links to detail pages and extract those instead (the listing itself is not extracted or charged).

## `detailLinkSelector` (type: `string`):

Only with 'Follow links'. CSS selector of the links (or of containers holding them), e.g. 'article.product_pod h3 a'. Empty = automatic detection of the main group of similar links.

## `detailUrlPattern` (type: `string`):

Only with 'Follow links'. Regular expression a detail URL must match, e.g. '/catalogue/.+\_\d+/'. Empty = no filter.

## `maxDetailPagesPerListing` (type: `integer`):

Hard limit of detail pages followed from each listing page.

## `maxPages` (type: `integer`):

Hard limit of all HTTP page fetches in the run (listings and detail pages), including pages that fail.

## `contentSelector` (type: `string`):

Restrict the text sent to the model to this part of the page, e.g. 'main' or '#product'. Smaller input = fewer tokens and better accuracy. Empty = whole page without scripts, navigation and footer.

## `includeImages` (type: `boolean`):

Keep image links in the Markdown. Turned on automatically when the schema mentions image, photo, thumbnail, picture or logo.

## `includeMarkdown` (type: `boolean`):

Add the cleaned Markdown sent to the model to each dataset item (useful for debugging, makes items larger).

## `maxInputChars` (type: `integer`):

Page Markdown longer than this is cut (roughly 4 characters per token). Lower = cheaper. Inclusive mode caps this at 40,000.

## `maxConcurrency` (type: `integer`):

Pages processed at the same time. Lower it if your LLM provider rate-limits you.

## `requestTimeoutSecs` (type: `integer`):

Timeout for each page download.

## `proxyConfiguration` (type: `object`):

Proxy for downloading pages. Default is Apify datacenter proxy. Sites that block datacenter IPs may need the residential fallback below.

## `useResidentialFallback` (type: `boolean`):

Retry blocked pages (HTTP 403/429) through Apify residential proxy. Needs residential proxy access on your Apify plan and costs extra proxy traffic.

## Actor input object example

```json
{
  "urls": [
    "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"
  ],
  "schema": {
    "type": "object",
    "properties": {
      "title": {
        "type": "string",
        "description": "Book title"
      },
      "price": {
        "type": [
          "number",
          "null"
        ],
        "description": "Price as a number, without currency symbol"
      },
      "currency": {
        "type": [
          "string",
          "null"
        ],
        "description": "ISO currency code or symbol"
      },
      "in_stock": {
        "type": [
          "boolean",
          "null"
        ],
        "description": "True if the book is in stock"
      },
      "rating_stars": {
        "type": [
          "integer",
          "null"
        ],
        "minimum": 1,
        "maximum": 5
      }
    },
    "required": [
      "title",
      "price"
    ],
    "additionalProperties": false
  },
  "llmProvider": "openai-compatible",
  "modelTier": "fast",
  "billingMode": "byok",
  "maxRetries": 2,
  "maxItems": 5,
  "followLinks": false,
  "maxDetailPagesPerListing": 10,
  "maxPages": 50,
  "includeImages": false,
  "includeMarkdown": false,
  "maxInputChars": 60000,
  "maxConcurrency": 3,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "useResidentialFallback": false
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `overview` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"
    ],
    "schema": {
        "type": "object",
        "properties": {
            "title": {
                "type": "string",
                "description": "Book title"
            },
            "price": {
                "type": [
                    "number",
                    "null"
                ],
                "description": "Price as a number, without currency symbol"
            },
            "currency": {
                "type": [
                    "string",
                    "null"
                ],
                "description": "ISO currency code or symbol"
            },
            "in_stock": {
                "type": [
                    "boolean",
                    "null"
                ],
                "description": "True if the book is in stock"
            },
            "rating_stars": {
                "type": [
                    "integer",
                    "null"
                ],
                "minimum": 1,
                "maximum": 5
            }
        },
        "required": [
            "title",
            "price"
        ],
        "additionalProperties": false
    },
    "instructions": "",
    "maxItems": 5,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("tiger19935/schema-ai-extractor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "urls": ["https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"],
    "schema": {
        "type": "object",
        "properties": {
            "title": {
                "type": "string",
                "description": "Book title",
            },
            "price": {
                "type": [
                    "number",
                    "null",
                ],
                "description": "Price as a number, without currency symbol",
            },
            "currency": {
                "type": [
                    "string",
                    "null",
                ],
                "description": "ISO currency code or symbol",
            },
            "in_stock": {
                "type": [
                    "boolean",
                    "null",
                ],
                "description": "True if the book is in stock",
            },
            "rating_stars": {
                "type": [
                    "integer",
                    "null",
                ],
                "minimum": 1,
                "maximum": 5,
            },
        },
        "required": [
            "title",
            "price",
        ],
        "additionalProperties": False,
    },
    "instructions": "",
    "maxItems": 5,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("tiger19935/schema-ai-extractor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"
  ],
  "schema": {
    "type": "object",
    "properties": {
      "title": {
        "type": "string",
        "description": "Book title"
      },
      "price": {
        "type": [
          "number",
          "null"
        ],
        "description": "Price as a number, without currency symbol"
      },
      "currency": {
        "type": [
          "string",
          "null"
        ],
        "description": "ISO currency code or symbol"
      },
      "in_stock": {
        "type": [
          "boolean",
          "null"
        ],
        "description": "True if the book is in stock"
      },
      "rating_stars": {
        "type": [
          "integer",
          "null"
        ],
        "minimum": 1,
        "maximum": 5
      }
    },
    "required": [
      "title",
      "price"
    ],
    "additionalProperties": false
  },
  "instructions": "",
  "maxItems": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call tiger19935/schema-ai-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tiger19935/schema-ai-extractor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/4Sdu2sTZKixrcaVH3/builds/becTbvPBJDQ9c8Ntk/openapi.json
