Extract Structured Data From Any Webpage, in bulk
Pricing
from $0.65 / 1,000 page extracteds
Extract Structured Data From Any Webpage, in bulk
Extract structured data from any webpage: every JSON-LD block with its schema.org types, Open Graph and Twitter Card tags, title, meta description, canonical, hreflang and feeds, one row per URL. The clean facts a page states about itself, ready for an LLM. Pay per page.
Pricing
from $0.65 / 1,000 page extracteds
Rating
0.0
(0)
Developer
Steadydata Team
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Extract structured data from any webpage: every JSON-LD block with its schema.org types, Open Graph and Twitter Card tags, title, meta description, canonical, hreflang and feeds, one row per URL. The clean facts a page states about itself, ready for an LLM. Pay per page.
Why this scraper
- Only delivered results are charged. Inputs that fail come back as clear error records at no cost.
- One plain fetch per page, parsed with lxml, no browser. Measured on the platform: five pages (BBC News, Python.org, Wikipedia, GitHub, a BBC Good Food recipe) in 5 seconds for a tenth of a cent.
- Everything a page declares about itself in one row: every JSON-LD block as parsed JSON with its schema.org types (Recipe, Article, Product, FAQPage, BreadcrumbList, VideoObject and so on), Open Graph and Twitter Card tags, title, meta description, canonical, robots meta, keywords, language, hreflang alternates, RSS and Atom feeds, favicon, published and modified time. A
@graphblock is flattened to its objects; a list block likewise. - Robots-aware: each host's robots.txt is read once per run and a closed path comes back as a free
ROBOTS_DISALLOWEDrow (measured: Google's/searchpath).
Who this is for
Paste page URLs in urls (up to 500 per run). Leave includeRawJsonLd on to get the full JSON-LD objects; switch it off to keep rows small with only the types and count. Built for SEO audits of structured data and social tags across a site or a competitor's, for feeding recipe, product, article or event markup into a pipeline, for handing an LLM the clean facts a page states about itself instead of its raw HTML, and for checking canonicals, hreflang and feeds in bulk.
Who this is not for
No browser is used, so structured data that a page injects with JavaScript after loading is not seen; what the server sends is what you get. Microdata and RDFa attributes in the HTML body are not parsed, only JSON-LD, meta and link tags. A page with no structured data at all is still a valid, charged row with empty columns and hasStructuredData false (measured: GitHub's about page has Open Graph but no JSON-LD). article:author is dropped on purpose. Pages that answer 403 or 429 come back as a free BLOCKED row; 404 and other failures as a free FETCH_FAILED row.
Input fields
| Field | Type | Required or default | What it does |
|---|---|---|---|
urls | list of text | required | One per row, up to 500: full page URLs (https://...). Each host's robots.txt is respected. |
includeRawJsonLd | true/false | true | On: every JSON-LD block is delivered as parsed JSON in jsonLd. Off: only the types and count, which keeps rows small. |
Input example
{"urls": ["https://www.bbc.com/news","https://github.com/about","https://www.allrecipes.com/recipe/10813/best-chocolate-chip-cookies/"],"includeRawJsonLd": true}
Output example
| Field | Type | What it holds | Example |
|---|---|---|---|
url | text | The page the structured data was read from. | https://www.bbcgoodfood.com/recipes/classic-victoria-sand... |
finalUrl | text | Where the page ended up after redirects; compare it with url to spot a redirect. | https://www.bbcgoodfood.com/recipes/classic-victoria-sand... |
statusCode | number | The HTTP status the page answered with; anything but 200 means a visitor sees something else. | 200 |
title | text | The page title as it stands in the HTML. | Classic Victoria sandwich recipe | Good Food |
metaDescription | text | Filled when the page has a meta description. | Bake a classic Victoria sponge cake with this easy recipe... |
canonical | text | Filled when the page declares a canonical link. | https://www.bbcgoodfood.com/recipes/classic-victoria-sand... |
language | text | Filled when the html tag declares a language. | en |
robotsMeta | text | Filled when the page has a robots meta tag; without one the page is indexable by default. | max-image-preview:standard |
keywords | text | The old meta keywords tag. Filled when the page still uses it; most sites dropped it years ago. | |
publishedTime | text | Filled when the page declares a publication time, which article pages usually do and product pages usually do not. | |
modifiedTime | text | Filled when the page declares a last-modified time. | |
ogTitle | text | Open Graph decides how the page looks when shared. Empty when the page has no Open Graph tags. | Classic Victoria sandwich recipe |
ogDescription | text | Open Graph decides how the page looks when shared. Empty when the page has no Open Graph tags. | The perfect party cake, a Victoria sponge is a traditiona... |
ogImage | text | Open Graph decides how the page looks when shared. Empty when the page has no Open Graph tags. | https://images.immediate.co.uk/production/volatile/sites/... |
ogType | text | Open Graph decides how the page looks when shared. Empty when the page has no Open Graph tags. | article |
ogSiteName | text | Open Graph decides how the page looks when shared. Empty when the page has no Open Graph tags. | Good Food |
ogUrl | text | Open Graph decides how the page looks when shared. Empty when the page has no Open Graph tags. | https://www.bbcgoodfood.com/recipes/classic-victoria-sand... |
twitterCard | text | Filled when the page declares Twitter Card tags; many pages rely on Open Graph only. | summary_large_image |
twitterTitle | text | Filled when the page declares Twitter Card tags; many pages rely on Open Graph only. | BBC News - Breaking news, video and the latest top storie... |
twitterImage | text | Filled when the page declares Twitter Card tags; many pages rely on Open Graph only. | |
jsonLdTypes | list | The schema.org types on the page, for example Product or Article; empty when the page has no JSON-LD. | ["VideoObject", "Recipe"] |
jsonLdCount | number | How many JSON-LD blocks the page carries; 0 when it has none. | 4 |
jsonLd | list | Filled when includeRawJsonLd is on; off by default because raw blocks make rows much larger. jsonLdTypes and jsonLdCount are filled either way. | [{"@context": "https://schema.org", "@type": "VideoObject... |
hreflang | list | Filled when the page declares language alternatives. | [{"lang": "en", "url": "https://www.bbc.com/news"}, {"lan... |
feeds | list | RSS or Atom feeds the page links to; empty for a page that offers none. | |
favicon | text | The first icon the page links to, made absolute. | https://static.files.bbci.co.uk/bbcdotcom/web/20260922-09... |
hasStructuredData | true/false | True when the page carries JSON-LD, Open Graph or a Twitter Card. A false here is the useful signal: the page says nothing machine-readable about itself. | True |
Error codes: INVALID_URL, ROBOTS_DISALLOWED, NOT_HTML, FETCH_FAILED, BLOCKED.
One delivered row looks like this:
{"url": "https://en.wikipedia.org/wiki/Web_scraping","finalUrl": "https://en.wikipedia.org/wiki/Web_scraping","statusCode": 200,"title": "Web scraping - Wikipedia","metaDescription": null,"canonical": "https://en.wikipedia.org/wiki/Web_scraping","language": "en","robotsMeta": "max-image-preview:standard","keywords": null,"publishedTime": null,"modifiedTime": null,"ogTitle": "Web scraping - Wikipedia","ogDescription": null,"ogImage": null,"ogType": "website","ogSiteName": null,"ogUrl": null,"twitterCard": null,"twitterTitle": null,"twitterImage": null,"jsonLdTypes": ["Article"],"jsonLdCount": 1,"jsonLd": [],"hreflang": [],"feeds": ["https://en.wikipedia.org/w/index.php?title=Special:RecentChanges&feed=atom"],"favicon": "https://en.wikipedia.org/static/favicon/wikipedia.ico","hasStructuredData": true,"status": "ok"}
Related actors from steadydata
- webpage-to-markdown: the readable text of the same page
- page-links-extractor: every link on the page, internal and external
- technical-seo-audit: the technical issues of the same page, ranked
Pricing
Pay per event: one page-extracted event per delivered result. No charge for inputs
that fail, no separate platform-usage surcharge.
Free Apify plan: this actor delivers up to 25 rows per run for accounts on the Apify free plan, and then stops with a message. That limit is set by us, not by Apify. It exists so the actor keeps paying for itself for the people who do pay. Any paid Apify plan runs it at full size, billed per delivered row, with failed rows never charged.
Reviews: if this actor saves you time, a short review on this page is the one thing that helps most. Ratings are what other buyers look at first, and we have no other way to ask.
FAQ
Is personal data collected?
Nothing beyond what the page publishes about itself. The article:author tag is not delivered, and the actor reads only the URLs you give it.
Does it validate the JSON-LD? No. It parses whatever the page declares and passes it through as JSON; a block that is not valid JSON is skipped and does not count. Validation against schema.org is a separate step.
Why is canonical empty on some pages?
Because the page has no canonical link tag (measured: python.org). The row still carries finalUrl, the address after redirects.
Can it read pages behind a login or a consent wall? No. It fetches as an anonymous visitor; what an anonymous visitor cannot see, it cannot see either.
What does a run cost when a URL fails?
Nothing. ROBOTS_DISALLOWED, NOT_HTML, FETCH_FAILED, INVALID_URL and BLOCKED rows are free; only delivered pages are charged.
What happens when the source changes? Sources change from time to time; that is the nature of this work. The actor is monitored daily and fixed fast, and while it is broken you are not charged, because only delivered results cost anything.
Can I call it from my own code, like an API? Yes. Every run is available through the Apify API: start it with one HTTP request, then read the results as JSON, CSV or Excel from the dataset endpoint, or use the official Python and JavaScript clients. The input is the same JSON as in the input example above, so a scheduled script, a Make or Zapier step or an AI agent can call it without any changes.