
Website Content Crawler
scrape.ly/store/querystone/website-content-crawlerAIDeveloper tools
1 monthly user

Extract JSON-LD, Microdata, RDFa, Open Graph, Twitter cards and SEO meta tags from any web page, sitemap or crawl. One row per page with a normalized primary entity (price, rating, author, address, event, recipe, job, FAQ) and schema validation hints.
Turn any web page into clean, structured JSON. Paste URLs, a sitemap or a whole website and get every JSON-LD, Microdata and RDFa entity, the Open Graph and Twitter card tags, the SEO meta tags (title, description, canonical, robots, hreflang) and the headings outline, plus a normalized primary entity with ready-to-use columns such as price, availability, rating, author, publish date, address and phone. No login, no browser, about $1 per 1,000 pages.
@graph blocks flattened and @id references resolved..gz included), or follow links on the same website to any depth.parseErrors when not.Product) or switch Output rows to one row per entity.| Field | What it does |
|---|---|
startUrls | Pages to extract. All listed pages are always processed. |
sitemapUrls | XML/text sitemaps or home pages whose robots.txt lists sitemaps. |
maxCrawlPages | Cap on pages found through sitemaps and crawling, on top of the start URLs (default 20, 0 = no limit). One start URL with link crawling and maxCrawlPages: 15 extracts up to 16 pages. |
crawlDepth | Follow same-site links this many levels deep (default 0). |
includeUrlPatterns / excludeUrlPatterns | Regular expressions or text that discovered URLs must / must not match. |
entityTypes | Keep only pages or entities with these schema.org types. |
onlyPagesWithStructuredData | Skip pages without JSON-LD, Microdata or RDFa. |
outputMode | pages (one row per page) or entities (one row per entity). |
syntaxes | Which markup to read: json-ld, microdata, rdfa, opengraph, twitter, meta. |
validateSchema, includeRawData, includeHeadings | Turn validation hints, raw markup and the headings outline on or off. |
proxyConfiguration | Datacenter by default; residential retry is automatic for blocked pages. |
{
"startUrls": ["https://www.apple.com/shop/buy-iphone/iphone-16"],
"sitemapUrls": ["https://crawlee.dev"],
"maxCrawlPages": 100,
"entityTypes": [],
"outputMode": "pages",
"proxyConfiguration": { "useScrapelyProxy": true, "scrapelyProxyGroups": ["DATACENTER"] }
}
One row per page. The table view shows the flat columns; the nested fields hold the complete data. Pages that could not be extracted (blocked, not found, unreachable, not HTML, invalid URL) are not saved as rows: the run's status message counts them and the OUTPUT record lists each one under failedInputs (input, reason, statusCode).
| Field | Description |
|---|---|
url, finalUrl, statusCode, status | The page, where it redirected, and its HTTP status (status is always ok: only extracted pages are saved). |
title, metaDescription, canonicalUrl, metaRobots, language, h1 | Core SEO meta. |
primaryType, primaryName | Type and name of the page's main entity. |
price, priceCurrency, availability, ratingValue, reviewCount, brand, sku | Commerce fields of the main entity. |
author, datePublished, startDate, telephone, address | Article, event and business fields of the main entity. |
primaryEntity | The normalized main entity with all type-specific fields (for example ingredients, instructions, salaryMin, jobLocations, openingHours, latitude). |
entities | All normalized entities on the page, with their source (json-ld, microdata, rdfa). |
faq, breadcrumbs | FAQ questions and answers, and the breadcrumb trail. |
validation, validationErrorCount | Missing required and recommended properties per entity. |
og, openGraph, twitter, twitterCard | Main and complete Open Graph and Twitter card tags. |
hreflang, alternates, headings, headingCounts, metaTags | Language alternates, feeds/AMP links, headings outline and all other meta tags. |
jsonLd, microdata, rdfa | Raw items as found on the page. |
schemaTypes, entityCount, hasJsonLd, hasMicrodata, hasRdfa, hasOpenGraph, hasTwitterCard, parseErrors | Summary flags and markup problems. |
Example row (trimmed):
{
"url": "https://www.apple.com/shop/buy-iphone/iphone-16",
"statusCode": 200,
"status": "ok",
"title": "Buy iPhone 16 - Apple",
"canonicalUrl": "https://www.apple.com/shop/buy-iphone/iphone-16",
"language": "en-US",
"h1": "Buy iPhone 16",
"primaryType": "Product",
"primaryName": "iPhone 16",
"price": 799.0,
"priceCurrency": "USD",
"schemaTypes": ["Product", "BreadcrumbList", "ListItem", "FAQPage", "Question"],
"entityCount": 3,
"hasJsonLd": true,
"hasOpenGraph": true,
"validationErrorCount": 0,
"primaryEntity": {
"type": "Product",
"kind": "Product",
"name": "iPhone 16",
"url": "https://www.apple.com/shop/buy-iphone/iphone-16",
"price": 799.0,
"priceCurrency": "USD",
"lowPrice": 799.0,
"highPrice": 829.0,
"source": "json-ld"
},
"faq": [{ "question": "Can I activate an iPhone 16 outside of the United States?", "answer": "iPhone 16 ... models purchased in the U.S. ... activate only using eSIM. ..." }],
"breadcrumbs": [
{ "position": 1, "name": "iPhone", "url": "https://www.apple.com/iphone" },
{ "position": 2, "name": "iPhone 16", "url": "https://www.apple.com/iphone-16" }
],
"validation": [
{ "type": "Product", "valid": true, "missingRequired": [], "missingRecommended": ["brand", "sku", "offers.availability"], "source": "json-ld" }
],
"og": { "title": "Buy iPhone 16", "type": "product", "siteName": "Apple", "locale": "en_US" },
"twitter": { "card": "summary_large_image", "site": "@apple" },
"headingCounts": { "h1": 1, "h2": 5, "h3": 24, "h4": 0, "h5": 0, "h6": 0 },
"jsonLd": [{ "@context": "https://schema.org", "@type": "Product", "name": "iPhone 16", "offers": [{ "@type": "AggregateOffer", "lowPrice": 799.0, "highPrice": 829.0, "priceCurrency": "USD" }] }]
}
In entity mode every row is one entity (pageUrl, pageTitle, type, kind, name, source, the normalized fields and the raw item).
You pay $1.00 per 1,000 extracted pages ($0.001 per page), plus the small platform usage of the run (compute and proxy traffic). Pages that fail (blocked, not found, unreachable, not HTML, invalid URL) and pages skipped by your filters are not charged. In entity mode you still pay per page, not per entity.
Example: extracting 1,000 product pages costs $1.00 in page events plus a few cents of platform usage.
Is it legal? The actor reads public pages, the same markup search engines read. Respect each site's terms and local laws, and do not collect personal data without a legal basis.
Do I need a login or my own proxy? No. The datacenter proxy is included and pages that block it are retried once over a residential proxy automatically.
How many pages can I extract? As many as you list, plus up to maxCrawlPages from sitemaps and crawling (0 = no limit). Large crawls of tens of thousands of pages work; rows are saved continuously.
Why is a field empty? The site simply does not publish it in its markup. validation tells you which important properties are missing. The actor does not guess values from the visible text.
Does it run JavaScript? No. It reads the HTML the server sends, which is where nearly all sites put their structured data for search engines. Markup injected only by client-side JavaScript is not seen.
Can I schedule it or use the API? Yes. Schedule runs, call it through the API, or connect it to your workflows and export the dataset in any format.
OUTPUT failedInputs with the reason, and not charged.Every field below can be set in the run form, passed through the API, or saved as a task. Unset fields fall back to the defaults shown.
startUrlsarrayOptionalStart URLs
Pages to extract, one per line. A missing https:// is added automatically. Duplicates are extracted once. Every listed page is extracted; Max discovered pages only limits pages found through sitemaps and link crawling.
sitemapUrlsarrayOptionalSitemap URLs
Optional XML or text sitemaps (sitemap indexes and .gz files are followed). A bare home page such as https://example.com reads the sitemaps listed in its robots.txt. Every page found is extracted, up to Max discovered pages.
maxCrawlPagesintegerOptionaldefault 20Max discovered pages
Maximum number of pages taken from sitemaps and link crawling (on top of the start URLs). 0 means no limit.
Discover more pages on the same websites by following links.
crawlDepthintegerOptionaldefault 0Link crawl depth
Follow links on the same website this many levels deep from each start URL. 0 extracts only the listed pages (and sitemap pages).
includeUrlPatternsarrayOptionalOnly URLs matching
Only follow discovered URLs that match one of these regular expressions or text fragments, for example /product/ or /blog/. Start URLs are always extracted.
excludeUrlPatternsarrayOptionalSkip URLs matching
Never follow discovered URLs that match one of these regular expressions or text fragments, for example /tag/ or \?page=.
Skip pages you do not need. Skipped pages are not charged.
entityTypesarrayOptionalOnly these schema.org types
Keep only pages (or entities in entity mode) that contain one of these schema.org types, for example Product, Recipe, JobPosting, Event, LocalBusiness or Article. Not case sensitive. Leave empty for everything.
onlyPagesWithStructuredDatabooleanOptionaldefault falseOnly pages with structured data
Skip pages that have no JSON-LD, Microdata or RDFa at all.
Choose what each row contains.
outputModeenumOptionaldefault "pages"Output rows
One row per page (with all entities nested), or one row per schema.org entity (handy for product or event feeds). Charging is per page either way.
syntaxesarrayOptionaldefault ["json-ld","microdata","rdfa","opengraph","twitter","meta"]Data to extract
Which kinds of markup to read. All are on by default; RDFa parsing is the slowest, so drop it for large crawls if you do not need it.
validateSchemabooleanOptionaldefault trueValidation hints
Check each entity against Google rich result requirements and list missing required and recommended properties.
includeRawDatabooleanOptionaldefault trueInclude raw markup data
Add the complete raw JSON-LD, Microdata and RDFa items to each row (next to the normalized fields).
includeHeadingsbooleanOptionaldefault trueInclude headings outline
Add the page's H1 to H6 outline (up to 200 headings).
Speed and timeouts.
maxConcurrencyintegerOptionaldefault 16Max parallel requests
How many pages are downloaded at the same time (at most 8 per website).
requestTimeoutSecsintegerOptionaldefault 20Page timeout (seconds)
Give up on a page after this many seconds per attempt.
proxyConfigurationobjectOptionaldefault {"useScrapelyProxy":true,"scrapelyProxyGroups":["DATACENTER…Proxy configuration
Datacenter proxies are the default. Pages that block them (HTTP 403, 429 or a bot check) are retried once over a residential proxy automatically. You can also choose residential for everything or supply your own proxy URLs.
Every run writes its results to a dataset. Preview it in the dashboard, then export it or read it through the API.
| Field | Type | Description |
|---|---|---|
| url | string | null | Page address as given or discovered |
| finalUrl | string | null | Address after redirects |
| statusCode | number | null | HTTP status of the final response |
| status | string | null | Always ok (pages that fail are not saved; they are listed in the run's OUTPUT record under failedInputs) |
| depth | number | null | Link depth from the start URL (0 for start and sitemap pages) |
| title | string | null | HTML title |
| metaDescription | string | null | Meta description |
| canonicalUrl | string | null | Canonical URL |
| metaRobots | string | null | Meta robots directives |
| language | string | null | Page language from the html lang attribute |
| h1 | string | null | First H1 heading |
| primaryType | string | null | schema.org type of the page's main entity |
| primaryName | string | null | Name or headline of the main entity |
| price | number | null | Price of the main entity (products, events, courses) |
| priceCurrency | string | null | Currency of the price |
| availability | string | null | Availability, for example InStock |
| ratingValue | number | null | Aggregate rating value |
| reviewCount | number | null | Number of reviews or ratings |
| brand | string | null | Product brand |
| sku | string | null | Product SKU |
| author | string | null | Author(s) of the main entity or the meta author |
| datePublished | string | null | Publish, posting or upload date of the main entity |
| startDate | string | null | Event start date |
| telephone | string | null | Business telephone |
| address | string | null | Business or event address as one line |
| schemaTypes | array | null | All schema.org types found on the page |
| schemaTypesText | string | null | schema.org types as comma separated text |
| entityCount | number | null | Number of schema.org entities reported |
| hasJsonLd | boolean | null | The page has JSON-LD |
| hasMicrodata | boolean | null | The page has Microdata |
| hasRdfa | boolean | null | The page has schema.org RDFa |
| hasOpenGraph | boolean | null | The page has Open Graph tags |
| hasTwitterCard | boolean | null | The page has Twitter card tags |
| validationErrorCount | number | null | Missing required properties across all entities |
| primaryEntity | object | null | Normalized main entity (type-specific fields such as price, author, address, startDate, ingredients, salary) |
| entities | array | null | All normalized schema.org entities |
| faq | array | null | FAQ questions and answers |
| breadcrumbs | array | null | Breadcrumb trail |
| validation | array | null | Validation hints per entity: missing required and recommended properties |
| og | object | null | Main Open Graph fields |
| object | null | Main Twitter card fields | |
| openGraph | object | null | All Open Graph tags |
| twitterCard | object | null | All Twitter card tags |
| hreflang | array | null | Language alternates (hreflang) |
| alternates | array | null | Other alternate links (feeds, AMP) |
| headings | array | null | H1 to H6 outline |
| headingCounts | object | null | Number of headings per level |
| jsonLd | array | null | Raw JSON-LD items (@graph flattened) |
| microdata | array | null | Raw Microdata items |
| rdfa | array | null | Raw schema.org RDFa items |
| metaTags | object | null | All other meta tags by name |
| parseErrors | array | null | Markup problems, for example invalid JSON-LD |
| pageUrl | string | null | Entity mode: page the entity was found on |
| pageTitle | string | null | Entity mode: title of that page |
| type | string | null | Entity mode: schema.org type of the entity |
| kind | string | null | Entity mode: entity family (Product, Article, Event, ...) |
| name | string | null | Entity mode: entity name |
| source | string | null | Entity mode: json-ld, microdata or rdfa |
You pay for the events the actor reports, such as each result or page it produces. Platform usage is included in the event prices.
| Event | Charged when | Price |
|---|---|---|
| Extracted page | One web page successfully fetched and extracted (failed, blocked and filtered pages are free). | $0.001 |
Run this actor from your own code. Swap in your API token and the examples work as-is.
import { ScrapelyClient } from 'scrapely-client'
const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN })
// Start the actor and wait for the run to finish.
const run = await client.actor('querystone/structured-data-extractor').call({
"startUrls": [
"https://www.allrecipes.com/recipe/158968/spinach-and-feta-turkey-burgers/",
"https://www.apple.com/shop/buy-iphone/iphone-16",
"https://www.rottentomatoes.com/m/shawshank_redemption",
"https://crawlee.dev/blog/crawlee-for-python-v1"
],
"maxCrawlPages": 20,
"crawlDepth": 0,
"proxyConfiguration": {
"useScrapelyProxy": true,
"scrapelyProxyGroups": [
"DATACENTER"
]
}
})
// Read the dataset the run produced.
const { items } = await client.dataset(run.defaultDatasetId).listItems()
console.log(items)Tokens live in your account settings. Keep them server-side: a token carries the full permissions of your account.
Connect the Scrape.ly MCP server once and your agent can run this actor as a tool. Pick your tool:
Fetch scrape.ly/agents.md and run querystone/structured-data-extractorPaste into Claude Code, Codex, Cursor or any AI agent. It signs you in once in the browser.
{
"mcpServers": {
"scrapely": {
"url": "https://api.scrape.ly/mcp?tools=actors,runs,storage,docs&actors=querystone/structured-data-extractor"
}
}
}No key in the file: your client opens the browser to sign you in the first time it connects.
Inputs the developer prepared for common jobs. Open one to see its input, then copy it to your account to run it as-is or adjust it.
BlogPosting entities found via the crawlee.dev sitemap.
Structured data from pages linked from a start URL.
Schema.org, JSON-LD and meta data from three pages.
Scrape.ly gives you the infrastructure, the tooling, and the team to extract, process, and operationalize web data at any scale. Setup takes minutes. The advantage lasts forever.