Website Metadata Extractor: Meta Tags, Open Graph, JSON-LD avatar

Website Metadata Extractor: Meta Tags, Open Graph, JSON-LD

Pricing

Pay per event

Go to Apify Store
Website Metadata Extractor: Meta Tags, Open Graph, JSON-LD

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

Scott Williams

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

18 hours ago

Last modified

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

GroupFields
Basic meta tagstitle, metaDescription, metaKeywords, canonicalUrl, metaRobots, language, charset, viewport, themeColor
Open GraphopenGraph with title, description, image, type, url, site_name, locale
Twitter cardtwitterCard with card, title, description, image, site
Structured datajsonLd (parsed schema.org blocks), jsonLdTypes (for example Organization, Product, BlogPosting), jsonLdErrors (number of blocks that failed to parse)
LinksfaviconUrl, feedUrls (RSS and Atom), hreflang (each with lang and url)
DatespublishedTime, modifiedTime when the page declares them
Responseurl, 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

  1. Open the Actor in Apify Console and click Try for free.
  2. Paste your URLs into URLs, one per line. Bare domains get https:// added, and duplicates are removed.
  3. Optional: turn off Include JSON-LD data for smaller rows, or turn off Include failed URLs to skip pages that could not be read.
  4. Click Start and export the dataset to JSON, CSV or Excel.

Input

FieldTypeDefaultDescription
urlsarray (required)["https://www.python.org/"]Pages to read. Each one is fetched once.
includeJsonLdbooleantrueInclude the parsed JSON-LD blocks. jsonLdTypes and jsonLdErrors are always included.
includeFailedUrlsbooleantrueAlso 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.
maxConcurrencyinteger, 1 to 3010How many URLs to fetch at the same time.
maxResultsinteger0Stop 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.

EventPrice
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 ApifyClient
client = 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.
  • faviconUrl comes from the page's <link rel="icon"> tags; it is null when 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.