Website Metadata Extractor: Meta Tags, Open Graph, JSON-LD
Pricing
Pay per event
Website Metadata Extractor: Meta Tags, Open Graph, JSON-LD
Extract metadata from any list of URLs: title, meta description, canonical, Open Graph and Twitter card tags, schema.org JSON-LD, favicon, RSS feeds and hreflang. For link previews, SEO checks and data enrichment. Fast bulk HTTP, no browser.
Pricing
Pay per event
Rating
0.0
(0)
Developer
Scott Williams
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
18 hours ago
Last modified
Categories
Share
Website Metadata Extractor: meta tags, Open Graph and JSON-LD from any URL list
Website Metadata Extractor reads a list of URLs and returns clean metadata for each page: title, meta description, meta keywords, canonical URL, meta robots, Open Graph tags, Twitter card tags, schema.org JSON-LD, favicon, RSS and Atom feeds, language, hreflang alternates and article dates. Use it as a bulk meta tag extractor, an Open Graph checker, a link preview data source, or a structured data (JSON-LD) extractor.
One fast HTTP page request per URL (plus robots.txt once per site). No browser, no proxy, no login. It obeys robots.txt.
At a glance: $0.001 per URL that returns metadata ($1.00 per 1,000); rows for URLs that could not be read are free. Pay per result with no subscription, set a maximum cost per run, export to JSON, CSV, Excel or HTML, or call it from the Apify API, n8n, Make or Zapier.
Who it's for
- Developers building link previews, bookmarking tools or content cards that need a title, description and image for each URL.
- SEO teams checking titles, meta descriptions, canonicals, Open Graph tags and structured data across many pages.
- Data and sales teams enriching a list of company websites with name, description, logo image and feeds.
- AI and RAG pipelines that need a short, clean summary of each page before deciding what to read in full.
What you get for each URL
| Group | Fields |
|---|---|
| Basic meta tags | title, metaDescription, metaKeywords, canonicalUrl, metaRobots, language, charset, viewport, themeColor |
| Open Graph | openGraph with title, description, image, type, url, site_name, locale |
| Twitter card | twitterCard with card, title, description, image, site |
| Structured data | jsonLd (parsed schema.org blocks), jsonLdTypes (for example Organization, Product, BlogPosting), jsonLdErrors (number of blocks that failed to parse) |
| Links | faviconUrl, feedUrls (RSS and Atom), hreflang (each with lang and url) |
| Dates | publishedTime, modifiedTime when the page declares them |
| Response | url, finalUrl after redirects, statusCode, contentType, error, extractedAt |
Personal fields are removed from JSON-LD: email, telephone, faxNumber, author, creator, contributor, editor and reviewedBy, and Person objects are reduced to {"@type": "Person"}.
How to use it
- Open the Actor in Apify Console and click Try for free.
- Paste your URLs into URLs, one per line. Bare domains get
https://added, and duplicates are removed. - Optional: turn off Include JSON-LD data for smaller rows, or turn off Include failed URLs to skip pages that could not be read.
- Click Start and export the dataset to JSON, CSV or Excel.
Input
| Field | Type | Default | Description |
|---|---|---|---|
urls | array (required) | ["https://www.python.org/"] | Pages to read. Each one is fetched once. |
includeJsonLd | boolean | true | Include the parsed JSON-LD blocks. jsonLdTypes and jsonLdErrors are always included. |
includeFailedUrls | boolean | true | Also save rows for URLs that could not be read (HTTP 400 and above, non-HTML pages, DNS errors, timeouts, robots.txt). These rows are free. Turn off to skip them. |
maxConcurrency | integer, 1 to 30 | 10 | How many URLs to fetch at the same time. |
maxResults | integer | 0 | Stop after this many rows. 0 means no limit. |
Example input
{"urls": [{"url": "https://www.python.org"},{"url": "https://apify.com"}],"includeJsonLd": true,"includeFailedUrls": true,"maxConcurrency": 10}
Output
One row per URL. This is a real row from a test run on October 29, 2026 (the jsonLd blocks are left out here to keep it short):
{"url": "https://www.python.org","finalUrl": "https://www.python.org","statusCode": 200,"contentType": "text/html; charset=utf-8","title": "Welcome to Python.org","metaDescription": "The official home of the Python Programming Language","metaKeywords": "Python programming language object oriented web free open source software license documentation download community","canonicalUrl": null,"metaRobots": null,"language": "en","charset": "utf-8","viewport": "width=device-width, initial-scale=1.0","themeColor": null,"faviconUrl": "https://www.python.org/static/favicon.ico","feedUrls": ["https://peps.python.org/peps.rss","https://www.python.org/jobs/feed/rss/","https://pyfound.blogspot.com/feeds/posts/default?alt=rss","https://blog.python.org/feeds/posts/default?alt=rss","https://www.python.org/downloads/feed.rss"],"hreflang": [],"openGraph": {"title": "Welcome to Python.org","description": "The official home of the Python Programming Language","image": "https://www.python.org/static/opengraph-icon-200x200.png","type": "website","url": "https://www.python.org/","site_name": "Python.org","locale": null},"twitterCard": {"card": null, "title": null, "description": null, "image": null, "site": null},"publishedTime": null,"modifiedTime": null,"jsonLdTypes": ["SearchAction", "WebSite"],"jsonLdErrors": 0,"error": null,"extractedAt": "2026-10-30T01:31:18.994149+00:00"}
extractedAt is the time the URL was fetched (UTC). Rows for URLs that could not be read have url, error and extractedAt, plus finalUrl, statusCode and contentType when the server answered. The RUN_SUMMARY record in the key-value store has the number of URLs, how many succeeded, failed or were disallowed by robots.txt, rows saved, and whether the run stopped at your cost limit.
Pricing
This Actor uses pay-per-event pricing. You pay per URL, not for compute time.
| Event | Price |
|---|---|
| URL (one row) | $0.001 |
| Actor start (charged by Apify, once per GB of run memory; 1 event at the default 1 GB) | $0.00005 |
Examples:
- 100 URLs: 100 × $0.001 + $0.00005 = about $0.10.
- 1,000 URLs: about $1.00.
- 10,000 URLs: about $10.00.
Rows for URLs that could not be read (HTTP 400 and above, non-HTML pages, DNS or connection errors, timeouts, robots.txt) are free. You pay only for pages that returned metadata. Include failed URLs only decides whether those free rows are saved; they still count toward Max results.
Set a maximum cost per run. In Apify Console set Maximum cost per run, or pass maxTotalChargeUsd through the API. The Actor stops cleanly when the limit is reached and the status message says so.
Integrations and API
The Actor ID is fecklesspleb/website-metadata-extractor (in API URLs: fecklesspleb~website-metadata-extractor).
- n8n: use the Apify node, choose Run an Actor with this Actor ID, then read the dataset items.
- Make: use the Apify module Run an Actor, then Get Dataset Items.
- Zapier: use the Apify app with Run Actor, then a dataset items step, for example to add a title and image to each new link in a sheet.
- Schedules: create an Apify schedule to re-check a list of pages, and a webhook to get notified when a run finishes.
- AI agents: call it through the Apify API, the Apify clients, or Apify's MCP server.
Run it with curl
For a few URLs, the synchronous endpoint returns the rows directly:
curl -X POST "https://api.apify.com/v2/acts/fecklesspleb~website-metadata-extractor/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"urls": [{"url": "https://www.python.org"}], "includeJsonLd": false}'
Python
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("fecklesspleb/website-metadata-extractor").call(run_input={"urls": [{"url": "https://www.python.org"}, {"url": "https://apify.com"}]},max_total_charge_usd=1,)for row in client.dataset(run["defaultDatasetId"]).iterate_items():og = row.get("openGraph") or {}print(row["url"], row.get("title"), og.get("image"))
JavaScript
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });const run = await client.actor('fecklesspleb/website-metadata-extractor').call({urls: [{ url: 'https://www.python.org' }, { url: 'https://apify.com' }],});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.map((r) => ({ url: r.url, title: r.title, image: r.openGraph?.image })));
Limits
- It reads the HTML the server sends, without running JavaScript. Tags that are added only by JavaScript are not seen.
- Sites that block automated requests may return an error row or less data.
- On the Apify platform, URLs whose address is private, loopback or link-local (also after a redirect) are not fetched. They get a free error row:
not fetched: private, loopback and link-local addresses are not allowed. - It reads only the URLs you give and does not crawl. To crawl a whole site and score every page, use Website SEO Audit.
faviconUrlcomes from the page's<link rel="icon">tags; it isnullwhen the page has none.
Common searches this Actor answers
- extract meta tags from a list of URLs
- bulk Open Graph checker
- get og:image and title for link previews
- extract JSON-LD schema from web pages
- get the canonical URL of many pages
- find RSS feeds on a website
- website metadata API
FAQ
How do I get the title, description and image of a URL for a link preview?
Run the Actor with your URLs. Use title or openGraph.title, metaDescription or openGraph.description, and openGraph.image (or twitterCard.image).
Can I extract meta tags from thousands of URLs? Yes. Paste the whole list. URLs are fetched up to 30 at a time, at $0.001 per URL that returns metadata.
Does it extract schema.org JSON-LD structured data?
Yes. jsonLd has the parsed blocks (when Include JSON-LD data is on), jsonLdTypes lists every @type found, and jsonLdErrors counts blocks that are not valid JSON.
Does it check Open Graph and Twitter card tags?
It extracts them. Tags the page does not have come back as null, so missing og:image or twitter:card tags are easy to filter.
Does it crawl the whole website? No. It reads each URL you give. For a crawl with on-page SEO checks, use Website SEO Audit.
Why is a field null?
The page does not declare it in the HTML the server sends, or adds it only with JavaScript.
Is it legal? The Actor reads public pages the same way a link preview or search engine does, obeys robots.txt, never logs in, and removes personal fields from structured data. You are responsible for how you use the data.
Related Actors
- Website SEO Audit: crawl a site and check every page for on-page SEO issues with a 0 to 100 score.
- Tech Stack Detector: which CMS, frameworks, analytics and hosting each website uses.
- Broken Link Checker: find 404s and dead links on a site.