AI Web Scraper - Extract Structured Data & URL to JSON
Pricing
from $8.00 / 1,000 extracted pages
AI Web Scraper - Extract Structured Data & URL to JSON
AI scraper and AI extractor: list the fields or describe what you want, and an LLM reads each page and returns JSON. No selectors or code. One row per list item, follows detail links. $0.01/page.
Pricing
from $8.00 / 1,000 extracted pages
Rating
0.0
(0)
Developer
Yukai Lin
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
27 minutes ago
Last modified
Categories
Share
What does AI Web Scraper do?
Input: a bulk list of page URLs (product, job or listing pages), or the URL field of a crawler's dataset, up to 10,000 per run, plus the fields you want, or one sentence. Output: one typed JSON row per page, or one row per list item, with null for anything the page does not show. Price: $0.01 per page that returned data ($10 per 1,000); failed, blocked, timed-out and empty pages are free.
Ready-made fields: Choose a preset and clear the form's sample Fields. Replace these illustrative .example URLs with pages you own or may access:
- Property — input
{"urls":["https://your-agency.example/listings/123"],"preset":"property"}→ outputdatafieldsname,address,price,bedrooms,bathrooms,area_sqm(one row per page). - Hotel — input
{"urls":["https://your-hotel.example/rooms/garden"],"preset":"hotel"}→ outputdatafieldsname,address,nightly_rate,check_in_time,check_out_time,amenities(one row per page). - Menu — input
{"urls":["https://your-restaurant.example/menu"],"preset":"menu"}→ outputdatafieldsname,description,price,currency,category(one row per menu item; charged once per page).
You can also call the REST API version on RapidAPI.
Large batches in three steps:
- Test a small sample first: run 5–10 of your URLs and check the fields and the Output setting (
outputMode: one row per page or one row per list item) before the full run. - Run the batch: paste the whole URL list, or set Dataset ID to a crawler's dataset (chain it after a crawler). Each page that returned data is one
page-extractedcharge, also a list page that was only partly read; set Maximum cost per run to cap the total. - Re-run only the failed pages: in a large batch some pages can fail (blocked, slow, timed out). Those rows are free and say
charged: false; filter them in the export (or open the run'sRETRY_URLSrecord, up to 1,000 URLs) and start a new run with just those URLs.
Give it a list of URLs and the fields you want, or simply describe what you want in one sentence. AI reads each page and returns clean, structured JSON: no CSS selectors, no XPath, no code, and it keeps working when the site's layout changes.
{ "title": "string", "price": "number", "in_stock": "boolean", "stock_count": "integer", "upc": "string" }
on a book page that shows "£51.77" and "In stock (22 available)" becomes (values from a real run):
{ "title": "A Light in the Attic", "price": 51.77, "in_stock": true, "stock_count": 22, "upc": "a897fe39b1053632" }
Text is converted to real types: the price is a number, the stock line is true and 22.
- 🧠 Describe, don't code: list field names and types, or just write a prompt such as "Get every product with its name, price and rating"
- 📋 List pages → one row per item: products, jobs, search results, team members; long lists are read in parts, so a page with 250 rows still comes back whole and still costs one page
- 🔗 Follow links to detail pages: start from a category or search page and extract every linked product, job or story page that matches your pattern
- ✅ Completeness check on every row (free):
completeness(0–1) andmissingFieldstell you which values were not found; numbers, integers and yes/no values are converted to real types ("$1,299.00" → 1299, "In stock" → true) - 🔒 Stable columns from a prompt: in prompt-only mode the AI designs the fields once, keeps them for the whole run and saves them for reuse
- 🌐 Any website: product pages, job posts, real estate listings, company "About" pages, articles, events, docs
- 🧾 Honest output: values that are not on the page come back as
null; the AI is told never to invent data - 🧩 Nested data: supply a full JSON Schema for arrays and objects
- 🛡️ Pay only for success: blocked pages (403, bot checks), errors, empty pages and pages where none of the fields were found are free
- ⚡ Gets past more blocks: plain HTTP from our servers, then from Apify's network (optionally through your proxy), then a real browser. A thin JavaScript shell can go straight to browser rendering; our Chrome pool is tried when Cloudflare browser capacity or its monthly usage limit is reached.
How it compares
| This Actor | Apify's AI Web Scraper | Calling an LLM API yourself | |
|---|---|---|---|
| Price per 1,000 pages (Free plan) | $10 | $30 | Token cost, plus your own fetching, proxies and code |
| List pages | Charged per page, one row per item | Charged per page | Your code splits the list |
| Failed, blocked or empty pages | Free (charged: false on the row) | Not stated in its listing | You pay for the tokens used |
| Long lists | Read in parts: 250 of 250 rows in our test | Not stated | Limited by the model's context |
Typed values ("£51.77" → 51.77) | Built in | Not stated | Your code |
Per-row completeness and missingFields | Built in, free | Not stated | Your code |
| Finds pages from the sitemap | No: list the URLs or follow links from a list page | Yes (Scout and Agentic modes) | Your code |
Prices checked October 2026 on the Apify Store ($20 vs our $8 per 1,000 pages on Gold and higher plans).
How much does it cost?
| Event | Price |
|---|---|
| Page extracted | $10 per 1,000 pages ($0.01 per page; $0.009 on Silver, $0.008 on Gold and higher Apify plans) |
Example: extracting 500 product pages costs 500 × $0.01 = $5.00 on the Free plan, whether a page gives one item or 50.
No start fee, no extra charge for browser rendering, and item mode is still charged per page, however many items the page lists. Your maximum charge limit is always respected.
Control your cost
- What is charged: one
page-extractedevent per page (or text) that returned data. In item mode that is one charge per page, also when a long list was only partly read (itemsIncomplete: true). - What is free: lines that are not a URL, duplicates of a URL already in the list, pages disallowed by robots.txt, blocked pages, errors, time-outs, pages with no matching items and pages where none of the fields were found. A disallowed start page, listed URL or redirect destination returns one
errorType: "robots_disallowed"row withcharged: false; no AI extraction is run for it. Every row hascharged: true/false, and failed rows say "(not charged)". - Before the run starts, the log and the status message show the plan: how many pages, the worst-case cost and your max charge per run. The same numbers are saved as
costPlanin theSUMMARYrecord. - Max charge per run: set Maximum cost per run in the run options (or
maxTotalChargeUsdin the API). When it is reached, the run stops starting new pages and finishes cleanly:SUMMARY.statusisLIMIT_REACHEDandSUMMARY.notProcessedlists the pages that were not started (count and up to 100 inputs), so you can run just those next time. - Follow links reads start pages for free and charges only the linked pages it extracts; Max pages per start URL caps them.
- If Apify restarts the run (server migration or Resurrect), items already finished are skipped and not charged again (
SUMMARY.resumedSkipped). - Retry failed pages: the run's private key-value store has
RETRY_URLSwith a JSONurlsarray of free failed page URLs in input order. It excludes successful pages and plain-text failures; with Follow links, it uses the failed detail page URL. Duplicates are removed and the list holds at most 1,000 URLs.SUMMARY.failedUrlCount,SUMMARY.retryUrlsTruncated, andSUMMARY.retryUrlsKeyshow the unique total, omitted count, and key name. Copy the URLs into a new run yourself with your desired fields and settings; no run starts automatically.
Compared with Apify's own AI Web Scraper, which costs $30 per 1,000 pages on the Free plan and $20 per 1,000 on Gold and higher plans (checked October 2026), this Actor is 2–3× cheaper at every plan level.
Switching from Apify's AI Web Scraper
Paste the input JSON you already use. startUrls and prompt are read as they are, so this runs unchanged:
{"startUrls": [{ "url": "https://books.toscrape.com/" }],"prompt": "Every book with its title, price and whether it is in stock"}
The same pages cost about a third: $10 instead of $30 per 1,000 pages on the Free plan. Good to know when you switch:
promptis the same as our Instructions (used when Instructions is empty). With no Fields, the AI designs the columns from your prompt once and keeps them for the whole run.- List pages: add
"outputMode": "items"to get one row per book, product or job. The page is still charged once. - Crawl options (
extractionModeScout or Agentic,maxPagesToVisit,maxCrawlDepth) are ignored and the run log says so: only the start URLs are read. To extract the pages a list links to, add"followLinks": truewith alinkPattern. - Typed columns: for numbers and yes/no values, list Fields, e.g.
{"title": "string", "price": "number", "in_stock": "boolean"}. - Failed pages are free, and every row says
charged: trueorfalse.
How to use it
When Workers AI returns no items or leaves every required field empty, paid Actor extraction makes one Claude Haiku retry through the backend. A recovered page is charged once under the existing page price. If Claude is unavailable, its daily limit is reached, or the requested JSON Schema has constraints Claude cannot accept, the original empty result remains a free failure row. The backend /v1/extract response identifies the model path with engine; Dataset row fields stay the same.
- Paste your URLs or domains (one per line;
stripe.comworks too). - Choose a Ready-made fields preset, or describe what you want in one of three ways:
- Fields to extract:
{"company_name": "string", "founded_year": "integer", "headquarters": "string"} - Instructions only (leave Fields empty): "Get every job with its title, location, salary and whether it is remote"
- JSON Schema for nested results
- Fields to extract:
- For listing pages, set Output to One row per item, or turn on Follow links to detail pages to extract each linked page.
- Click Start. Export as JSON, CSV or Excel.
A line that is not a URL (a blank line, a company name, a typo) does not stop the run: it becomes one free row with errorType: "invalid_input" and the other lines are processed. If the whole input cannot be used (no valid URL, no fields or instructions, a JSON Schema that is not an object schema, an unknown field type), the run still ends normally with one free row that says what to fix (errorType: "invalid_input", SUMMARY.status: "INPUT_ERROR") instead of failing. The URLs (request list) field from earlier versions still works; for API calls and new integrations use urls, a plain list of strings.
Input example: one row per page
This is the example the input form opens with:
{"urls": ["https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html"],"fields": { "title": "string", "price": "number", "in_stock": "boolean", "stock_count": "integer", "upc": "string" }}
Result (values from a real run on this page, $0.01):
{"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html","success": true,"data": { "title": "A Light in the Attic", "price": 51.77, "in_stock": true, "stock_count": 22, "upc": "a897fe39b1053632" },"completeness": 1,"charged": true}
The page says "£51.77" and "In stock (22 available)"; the row has a number, true and an integer, ready for a spreadsheet.
Ready-made fields: property listing
For a property page on a website you own or may access, select property and clear the sample Fields. It uses one row per page with name, address, price, bedrooms, bathrooms, and area_sqm.
{ "urls": ["https://your-agency.example/listings/123"], "preset": "property" }
Illustrative output row (replace the .example URL with your permitted site):
{ "success": true, "data": { "name": "Oak Cottage", "address": "12 Oak Road", "price": 320000, "bedrooms": 3, "bathrooms": 2, "area_sqm": 95 }, "charged": true }
Ready-made fields: hotel page
For your hotel's own website, select hotel and clear the sample Fields. It uses one row per page with name, address, nightly_rate, check_in_time, check_out_time, and amenities.
{ "urls": ["https://your-hotel.example/rooms/garden"], "preset": "hotel" }
Illustrative output row:
{ "success": true, "data": { "name": "Garden Room", "address": "8 Harbor Lane", "nightly_rate": 120, "check_in_time": "15:00", "check_out_time": "11:00", "amenities": ["Wi-Fi", "parking"] }, "charged": true }
Ready-made fields: restaurant menu
For your restaurant's own menu page, select menu and clear the sample Fields. It uses one row per menu item with name, description, price, currency, and category. The page is charged once, regardless of the number of items.
{ "urls": ["https://your-restaurant.example/menu"], "preset": "menu" }
Illustrative output row:
{ "success": true, "itemIndex": 0, "data": { "name": "Tomato Pasta", "description": "Pasta with tomato sauce", "price": 12, "currency": "USD", "category": "Mains" }, "charged": true }
You can add Fields to any preset or override a preset field's type. A full JSON Schema still takes priority over both. The run's private SUMMARY.preset records only property, hotel, or menu for measuring use; it does not record the URL or page content there. Without a preset, output and charging follow the existing settings.
Input example: list page, one row per item
{"urls": ["https://books.toscrape.com/"],"fields": { "title": "string", "price": "number", "rating": "integer", "in_stock": "boolean" },"outputMode": "items","instructions": "rating is the number of stars (1-5)."}
Real result: 20 rows for the 20 books on the page, charged as one page:
[{ "url": "https://books.toscrape.com/", "itemIndex": 0, "itemCount": 20, "data": { "title": "A Light in the Attic", "price": 51.77, "rating": null, "in_stock": true } },{ "url": "https://books.toscrape.com/", "itemIndex": 1, "itemCount": 20, "data": { "title": "Tipping the Velvet", "price": 53.74, "rating": null, "in_stock": true } }]
rating is null because this site shows stars only as an image style, not as text: the AI does not guess values it cannot read.
Long lists: read in parts
A list page longer than about 12,000 characters is split into parts of about 5,000 characters (one paragraph repeated at each boundary, so an item cut in two is seen whole), up to 16 parts (about 80,000 characters), 4 at a time. The items are merged in page order, exact repeats are removed and an item split at a boundary is joined back together. The model is told to use only values written in each part; if an item cut off at the end of a part still comes back with different numbers than its full copy at the start of the next part, the full copy is kept. Placeholder words such as "None" or "N/A" are returned as null. Real result for https://www.scrapethissite.com/pages/simple/ (250 countries; fields country, capital, population, area; October 2026): 250 rows from 5 parts in 89 seconds, no repeats, charged as one page.
If some parts fail or run out of time, the items from the other parts are still returned and the page is charged once, because you got data: the rows then carry itemsIncomplete: true and chunksFailed, and SUMMARY.status is PARTIAL_RESULTS. A page is charged only when at least one item came back.
When no item is returned, the free failure row includes failureStage to help you retry: start_links means a followLinks start page queued no links; the row tells you whether none matched Link pattern (check the pattern and page links) or matching links were excluded by robots.txt (check the site's rules for those pages). list_items means the list extraction replied but returned no usable items (check whether the page shows the requested items and whether Fields match them); list_chunks means every list extraction call failed (check the row's chunk error). The first two keep errorType: "no_items"; an all-chunk timeout keeps errorType: "timeout". An empty model reply does not prove the website has no items. These rows have charged: false.
Input example: just a prompt
{"urls": ["https://news.ycombinator.com/", "https://news.ycombinator.com/news?p=2"],"instructions": "Get every story with its title, points, number of comments and the site domain","outputMode": "items"}
Real result: the AI chose the fields title, points, num_comments and site_domain from the first page, used them for both pages (60 rows) and saved them in the key-value store as SCHEMA:
{ "url": "https://news.ycombinator.com/news?p=2", "itemIndex": 3, "data": { "title": "MongoDB CEO resigns to join Meta", "points": 329, "num_comments": 270, "site_domain": "reuters.com" }, "schemaInferred": true }
To keep exactly the same columns next time, copy SCHEMA.fields into Fields to extract.
Input example: follow links from a list page to detail pages
{"urls": ["https://books.toscrape.com/"],"followLinks": true,"linkPattern": "https://books.toscrape.com/catalogue/*/index.html","maxPagesPerStartUrl": 5,"fields": { "title": "string", "price": "number", "in_stock": "boolean", "stock_count": "integer", "star_rating": "integer", "upc": "string", "isbn": "string" }}
The start page is read for free and only its links are used; the 5 linked book pages are extracted and charged ($0.05). Real result (one of 5 rows):
{"url": "https://books.toscrape.com/catalogue/a-light-in-the-attic_1000/index.html","foundOn": "https://books.toscrape.com/","success": true,"data": { "title": "A Light in the Attic", "price": 51.77, "in_stock": true, "stock_count": 22, "star_rating": null, "upc": "a897fe39b1053632", "isbn": null },"completeness": 0.71,"missingFields": ["star_rating", "isbn"]}
missingFields shows at a glance that the star rating (drawn with CSS icons) and the ISBN (not on the page) were not found; the other 5 of 7 fields were. linkPattern takes globs (* within one path segment, ** across segments) or plain text the link must contain, e.g. item?id= for Hacker News stories: with the instructions "Story title, points, author, number of comments, and the top comment text", 3 story pages from the front page came back with all 5 fields (completeness: 1). Leave it empty to follow every link to the same site (menus included, so a pattern is better).
Advanced: JSON Schema
For nested results, use JSON Schema instead of Fields (in item mode it describes one item):
{"type": "object","properties": {"jobs": {"type": "array","items": {"type": "object","properties": { "title": { "type": "string" }, "location": { "type": "string" }, "remote": { "type": "boolean" } }}}},"required": ["jobs"]}
Before the run, the schema is made safe for the AI: every property you list is asked for (so none is silently left out) and may be null, so a value that is not on the page comes back as null instead of an invented one, also where your schema says required. The top level must be an object with properties (up to 50, schema up to 40,000 characters); anything else ends the run with a free invalid_input row before any page is read. Fields can also be given as a JSON text.
Flat columns for Google Sheets, n8n and CSV
Turn on Flat columns ("flatOutput": true) to get every field in its own column instead of inside data. The number of rows and the price stay the same. The books example above with "flatOutput": true gives rows like this (the first book, and a failed page):
[{ "input": "https://books.toscrape.com/", "inputIndex": 0, "url": "https://books.toscrape.com/", "finalUrl": "https://books.toscrape.com/", "pageTitle": "All products | Books to Scrape - Sandbox", "success": true, "recordIndex": 0, "recordCount": 20, "title": "A Light in the Attic", "price": 51.77, "rating": null, "in_stock": true, "completeness": 0.75, "missingFields": "rating", "typeErrors": null, "charged": true, "error": null, "errorType": null, "mode": "fast", "via": "backend", "contentTruncated": false, "chunksRead": 1, "chunksFailed": 0, "itemsIncomplete": false, "extractedAt": "2026-10-01T00:00:00.000Z" },{ "input": "https://example.com/blocked", "inputIndex": 1, "url": "https://example.com/blocked", "finalUrl": null, "pageTitle": null, "success": false, "recordIndex": null, "recordCount": 0, "title": null, "price": null, "rating": null, "in_stock": null, "completeness": null, "missingFields": null, "typeErrors": null, "charged": false, "error": "blocked (not charged)", "errorType": "blocked", "mode": null, "via": null, "contentTruncated": null, "chunksRead": null, "chunksFailed": null, "itemsIncomplete": null, "extractedAt": "2026-10-01T00:00:00.000Z" }]
- Same columns, same order, in every row, failed pages and invalid input lines included (empty values,
recordCount: 0), so a Google Sheets "append row" step or an n8n node maps the columns once. The columns come from your fields, not from the values found.failureStageis a fixed page column besideerrorType; it isnullon successful rows and failures without a stage. - Nested objects (JSON Schema) become columns joined with
_:{"price": {"amount": 49, "currency": "EUR"}}→price_amount,price_currency. - Lists of values become one text cell joined with
,(["S", "M", "L"]→"S, M, L"); an empty list isnull. Lists of objects (e.g. ajobslist in one-row-per-page mode) become one JSON text cell; for one row per job, use One row per item instead. recordIndex/recordCountreplaceitemIndex/itemCount(one row per page:0/1). The page title is inpageTitle, so a field calledtitlekeeps its name. A field whose name is already a page column (e.g.url) getsdata_in front (data_url). An extracted field namedfailureStagebecomesdata_failureStage, leaving the page diagnostic infailureStage.missingFieldsis a comma-separated text,typeErrorsa JSON text.
Writing good prompts and field names
| Instead of | Write |
|---|---|
version | newest_stable_version |
price (when a page shows several) | sale_price and regular_price, plus the instruction "numbers only, without currency" |
| "Get the data" | "Get every job with its title, city, salary range and whether it is remote" |
| "Find the contact" | "The company's general contact email and phone number from the page; null if not shown" |
| "Summarize the product" | key_features (array) and a separate one_sentence_summary (string) |
- Name each field for exactly one fact, and say the unit or format in Instructions ("dates as YYYY-MM-DD", "prices in USD as numbers").
- Say which item to pick when a page shows several ("only the first job", "the main product, not recommendations"), or use item mode to get all of them.
- Ask only for what is on the page. The AI returns
nullfor missing values instead of guessing, sonullmeans "not on the page". - Long pages: set a Content selector (e.g.
main) so the AI reads the relevant part. With one row per page about 32,000 characters are read; in item mode up to about 80,000 characters, in parts (contentTruncated: truewhen more was cut).
Chain it after a crawler
Set Dataset ID to the dataset of another run (for example our Website to Markdown Crawler or a search results scraper) and Dataset field to the field with the URLs (empty = the first URL field found). The Actor then extracts data from every URL in that dataset.
Use with AI agents (MCP)
Connect Apify's MCP server (https://mcp.apify.com?tools=tidytools/ai-web-data-extractor) to Claude, Cursor or any MCP client, then ask e.g. "Get the name, price and rating of every product on these three category pages".
{ "urls": ["https://books.toscrape.com/"], "instructions": "Every book with title and price", "outputMode": "items" }
Failed pages are not charged and carry an errorType (robots_disallowed when the site's robots.txt excludes the page, blocked for 403s and bot checks such as a "Client Challenge" page, login_required for login walls, not_found, timeout, no_items, no_data when none of the fields were found…). The key-value store record SUMMARY has an overall status (SUCCESS, PARTIAL_RESULTS, FAILED, NO_RESULTS, LIMIT_REACHED, INPUT_ERROR when the input itself could not be used).
SUMMARY.timing shows where the time went: how many pages were read (read) and extracted by the AI (ai) with their average and longest time in seconds, how many pages ran out of time while reading and while extracting (timeoutByStage), and the maxConcurrency and itemTimeoutSecs the run used. If many pages time out, a higher itemTimeoutSecs (up to 900) gives each page more time.
Via API:
curl -X POST "https://api.apify.com/v2/acts/tidytools~ai-web-data-extractor/run-sync-get-dataset-items?token=YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"urls":["https://example.com"],"fields":{"title":"string","summary":"string"}}'
Schedules and integrations: run it daily or weekly with Apify Schedules, get a webhook when a run finishes, or send the results to Zapier, Make, n8n, Google Sheets, Slack and other apps with Apify integrations. Results can be exported as JSON, CSV, Excel or XML. For Google Sheets, n8n and CSV, turn on Flat columns (flatOutput) to get one plain column per field.
Output fields
| Field | Meaning |
|---|---|
input, inputIndex | The line you entered and its position in your list (after invalid lines and duplicates were removed), so every row maps back to your input |
data | The extracted values (one item in item mode) |
itemIndex, itemCount | Item mode: position of the item on the page and the number of items found |
recordIndex, recordCount, pageTitle | With Flat columns only: the extracted fields are top-level columns instead of data, recordIndex/recordCount replace itemIndex/itemCount (recordCount: 0 on failed rows) and the page title is pageTitle (see Flat columns) |
title, finalUrl | Page title and URL after redirects |
mode, via | fast or browser; fetched by backend (our servers), direct (Apify's network) or browser |
contentTruncated | true when the page was longer than the part the AI reads |
chunksRead, chunksFailed, itemsIncomplete | Item mode: parts of the page read, parts that failed or ran out of time, and true when some items may be missing (failed parts, or a page longer than 16 parts) |
schemaInferred | true when the fields were designed by the AI from your instructions |
completeness, missingFields | Share of fields (0–1) that have a value, and the fields that are empty (null, "", [], or a placeholder word such as "None" or "N/A", which is returned as null). Computed by the Actor, free |
typeErrors | Values that could not be converted to the field's type (kept as returned), e.g. {"field": "rating", "expected": "integer", "value": "three"} |
startUrl (also foundOn) | With Follow links: the start page the link was found on; input is that start URL as you entered it |
datasetIndex | With Dataset ID: position of the value in the source dataset |
charged | true when this page was charged (in item mode every row of a charged page says true; the page is charged once) |
error, errorType | For failed pages and invalid input lines (not charged): invalid_input, blocked, login_required, not_found, timeout, no_items, no_data… |
failureStage | On free no-item list rows: start_links, list_items, or list_chunks (see Long lists). |
Limitations
- AI extraction is very good but not perfect; verify critical values.
- Only public
http/httpspages; no logins. For sites that block data centers, add a proxy under Advanced settings (Apify proxy usage is billed to your Apify account). - One row per page reads about 32,000 characters of each page; item mode reads up to about 80,000 characters in 16 parts. Longer lists come back with
itemsIncomplete: true: list the paginated URLs instead. - Time limit per page (Advanced settings, default 180 seconds) stops a page that takes too long; it comes back as a free
timeoutrow. In item mode the items from the parts that finished in time are kept. Raise it for very long lists with a slower model. - AI model (Advanced settings, same price): Auto uses Llama 3.3 70B for one row per page and Qwen3 30B for item mode. On the 250-country page both found all 250 countries, and Qwen3 30B wrote the list about 3 times faster. With Auto, a call that fails or stalls is repeated once on Llama 4 Scout (same price), and a part of a list page that is only a menu (category links, breadcrumbs) is dropped instead of being returned as items.
- Values that exist only in images or styling (e.g. star icons) cannot be read.
- Follow links goes one level deep (start page → linked pages); it does not click "next page" buttons. List the paginated URLs as start URLs instead.
- Type conversion only touches top-level fields; values of nested JSON Schema objects are returned as the AI gave them.
- Flat columns joins lists of values with
,, so a value that itself contains a comma cannot be told apart in that cell; use the normal output when that matters. The Extracted data table view in the Output tab is made for the normal output; open All fields or export the dataset to see every flat column (integrations and the API always get every column).
Is it legal?
You are responsible for how you use extracted data. Respect the target site's terms of service, copyright and privacy laws, and don't collect personal data without a legal basis.
FAQ
Why does my run say "partial" / why did some pages come back as timeout? In a bulk run of hundreds or thousands of URLs, some pages can be slower than the Time limit per page (Advanced settings, default 180 seconds): a very long page, a slow site or a busy AI model. Such a page ends as a free errorType: "timeout" row (charged: false); the other pages are unaffected and the run still finishes normally (it is only marked partial because some rows failed). To get those pages: copy the url of the charged: false rows in the dataset, or the URLs from the run's RETRY_URLS key-value store record, into a new run, raise Time limit per page (up to 900), set AI model to another model (same price), or set a Content selector (e.g. main) so less text is read. The error text of each failed row says which step ran out of time.
Are failed pages charged? No. Blocked pages, login walls, unreachable sites, errors, time-outs and pages where none of the fields were found are free and say charged: false.
Can it extract every item from a list page? Yes. Item mode returns one row per product, job or result and reads long pages in parts (up to about 80,000 characters), still for one page price. Longer lists come back with itemsIncomplete: true.
What if my fields or JSON Schema are wrong? The run does not fail: it ends normally with one free row (errorType: "invalid_input") that says what to change, and nothing is charged. The same goes for a list with no valid URL.
What happens when a value is not on the page? It comes back as null; the AI is told never to invent data. Every row has completeness and missingFields, and pages where none of the fields were found are free. Yes/no fields are null (not false) when the page does not say.
Do I need an OpenAI or other LLM API key? No. The AI model runs on our side and is included in the price per page. Under AI model (Advanced settings) you can pick another model at the same price.
How is it different from a regular web scraper? You describe the fields instead of writing CSS selectors or XPath, so the same input works on many sites and keeps working when a site's layout changes.
Does the Actor collect usage data? The Actor sends one anonymous usage counter per run (input type, item count range, outcome) to improve the tool; no URLs, content or account data.
Support
Open an issue in the Issues tab with the URL and your input.
Found this useful? A short review on the Store helps other users find it.
