Extract Structured Data From Any Webpage, in bulk avatar

Extract Structured Data From Any Webpage, in bulk

Pricing

from $0.65 / 1,000 page extracteds

Go to Apify Store
Extract Structured Data From Any Webpage, in bulk

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

Steadydata Team

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

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 @graph block 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_DISALLOWED row (measured: Google's /search path).

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

FieldTypeRequired or defaultWhat it does
urlslist of textrequiredOne per row, up to 500: full page URLs (https://...). Each host's robots.txt is respected.
includeRawJsonLdtrue/falsetrueOn: 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

FieldTypeWhat it holdsExample
urltextThe page the structured data was read from.https://www.bbcgoodfood.com/recipes/classic-victoria-sand...
finalUrltextWhere the page ended up after redirects; compare it with url to spot a redirect.https://www.bbcgoodfood.com/recipes/classic-victoria-sand...
statusCodenumberThe HTTP status the page answered with; anything but 200 means a visitor sees something else.200
titletextThe page title as it stands in the HTML.Classic Victoria sandwich recipe | Good Food
metaDescriptiontextFilled when the page has a meta description.Bake a classic Victoria sponge cake with this easy recipe...
canonicaltextFilled when the page declares a canonical link.https://www.bbcgoodfood.com/recipes/classic-victoria-sand...
languagetextFilled when the html tag declares a language.en
robotsMetatextFilled when the page has a robots meta tag; without one the page is indexable by default.max-image-preview:standard
keywordstextThe old meta keywords tag. Filled when the page still uses it; most sites dropped it years ago.
publishedTimetextFilled when the page declares a publication time, which article pages usually do and product pages usually do not.
modifiedTimetextFilled when the page declares a last-modified time.
ogTitletextOpen Graph decides how the page looks when shared. Empty when the page has no Open Graph tags.Classic Victoria sandwich recipe
ogDescriptiontextOpen 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...
ogImagetextOpen 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/...
ogTypetextOpen Graph decides how the page looks when shared. Empty when the page has no Open Graph tags.article
ogSiteNametextOpen Graph decides how the page looks when shared. Empty when the page has no Open Graph tags.Good Food
ogUrltextOpen 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...
twitterCardtextFilled when the page declares Twitter Card tags; many pages rely on Open Graph only.summary_large_image
twitterTitletextFilled when the page declares Twitter Card tags; many pages rely on Open Graph only.BBC News - Breaking news, video and the latest top storie...
twitterImagetextFilled when the page declares Twitter Card tags; many pages rely on Open Graph only.
jsonLdTypeslistThe schema.org types on the page, for example Product or Article; empty when the page has no JSON-LD.["VideoObject", "Recipe"]
jsonLdCountnumberHow many JSON-LD blocks the page carries; 0 when it has none.4
jsonLdlistFilled 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...
hreflanglistFilled when the page declares language alternatives.[{"lang": "en", "url": "https://www.bbc.com/news"}, {"lan...
feedslistRSS or Atom feeds the page links to; empty for a page that offers none.
favicontextThe first icon the page links to, made absolute.https://static.files.bbci.co.uk/bbcdotcom/web/20260922-09...
hasStructuredDatatrue/falseTrue 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"
}

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.