URL Metadata & Open Graph Extractor avatar

URL Metadata & Open Graph Extractor

Pricing

from $0.90 / 1,000 url metadata records

Go to Apify Store
URL Metadata & Open Graph Extractor

URL Metadata & Open Graph Extractor

Extract metadata from any list of URLs: title, meta description, canonical, language, favicon, Open Graph and Twitter Card tags, JSON-LD types, feeds, H1, word and link counts. One fast HTTP fetch per URL, no browser. $1 per 1,000 URLs; failed and missing pages are free.

Pricing

from $0.90 / 1,000 url metadata records

Rating

0.0

(0)

Developer

SFOLN LLC

SFOLN LLC

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

13 days ago

Last modified

Features

Limited permissions

Share

URL Metadata & Open Graph Extractor turns a list of URLs into clean, structured page metadata: title, meta description, canonical URL, language, favicon, Open Graph and Twitter Card tags, JSON-LD schema types, publish/modify dates, author, robots and generator tags, the first H1, a visible word count, internal/external link counts and RSS/Atom feed links. Built for link previews, SEO audits, content inventories, lead enrichment and AI agents that need to know what a page is about without rendering it.

  • Price: $1 per 1,000 URLs, charged only per analysed URL: invalid URLs, missing pages (404/410), dead domains, network failures and blocked pages are never charged.
  • One fast HTTP fetch per URL (browser-like headers, up to 5 redirects followed): no headless browser, so it is cheap and quick.
  • Stable, flat JSON output that works the same in the API, in integrations and in the Console.

Input

FieldTypeDefaultDescription
urlsstring[]–Pages to analyse, one per line. https:// is added when missing. Objects with a url key are accepted.
maxUrlsinteger1000Safety cap for this run.
timeoutSecsinteger10Max time per page (3–30 s); slow pages are retried once.
concurrencyinteger5Parallel fetches (1–10).
includeRawbooleanfalseAttach low-level fetch details (detected charset) under raw.
{
"urls": ["https://apify.com", "https://blog.apify.com"],
"timeoutSecs": 10
}

Output

One dataset record per URL:

{
"input": "https://apify.com",
"url": "https://apify.com/",
"finalUrl": "https://apify.com/",
"redirected": false,
"statusCode": 200,
"contentType": "text/html; charset=utf-8",
"title": "Apify: Full-stack web scraping and data extraction platform",
"description": "Cloud platform for web scraping, browser automation, AI agents, and data for AI...",
"canonical": "https://apify.com/",
"language": "en",
"favicon": "https://apify.com/favicon.ico",
"ogTitle": "Apify: Full-stack web scraping and data extraction platform",
"ogDescription": "Cloud platform for web scraping...",
"ogImage": "https://apify.com/og-image.png",
"ogType": "website",
"ogSiteName": "Apify",
"twitterCard": "summary_large_image",
"twitterSite": "@apify",
"jsonLdTypes": ["Organization", "WebSite"],
"publishedTime": null,
"modifiedTime": null,
"author": null,
"robots": "index, follow",
"generator": null,
"h1": "Build reliable web scrapers. Fast.",
"h1Count": 1,
"wordCount": 1432,
"linksInternal": 118,
"linksExternal": 21,
"feeds": [],
"pageBytes": 412339,
"truncated": false,
"responseTimeMs": 312,
"status": "ok",
"charged": true,
"chargedEvent": "url-metadata",
"source": "selfhosted",
"fetchedAt": "2026-10-14T10:00:00.000Z"
}
FieldDescription
finalUrl, redirected, statusCode, contentTypeWhere the request ended up and how the server answered.
title, description, canonical, language, favicon, keywords, themeColorClassic HTML/SEO tags. URLs are absolute. favicon falls back to the conventional /favicon.ico location when no icon link exists.
ogTitle, ogDescription, ogImage, ogType, ogSiteName, ogUrl, ogLocaleOpen Graph tags.
twitterCard, twitterTitle, twitterDescription, twitterImage, twitterSite, twitterCreatorTwitter / X card tags.
jsonLdTypesDistinct schema.org @type values in JSON-LD blocks (including @graph).
publishedTime, modifiedTime, authorFrom article/Dublin Core meta tags, falling back to JSON-LD datePublished / dateModified / author. Values are returned as written on the page.
robots, xRobotsTag, generatorRobots meta tag, X-Robots-Tag header and CMS generator tag.
h1, h1CountFirst H1 text and the number of H1 elements.
wordCountEstimate of visible words (scripts, styles and <head> excluded; CJK characters count as one word each).
linksInternal, linksExternalDistinct link targets on the same host (ignoring www.) vs other hosts.
feedsRSS, Atom and JSON Feed links: { url, type, title }.
pageBytes, truncatedBytes analysed; pages over 1 MB are cut at 1 MB and flagged.

status is ok for every analysed page (non-HTML documents such as PDFs return ok with empty HTML fields and a warning), not_found when the page answered HTTP 404 or 410 (not charged), error for host names that do not resolve (error.code dns_not_found), network errors, timeouts and other HTTP errors, including non-standard statuses such as LinkedIn's 999 (not charged; a temporary DNS failure is retried once), skipped_invalid for malformed or non-http(s) URLs, ports other than 80/443, and URLs or redirects that lead to private/loopback addresses (error.code blocked_host, not charged) and skipped_budget when your cost cap was reached. Error messages quote at most ~120 characters of a target site's error page. The OUTPUT record in the run's key-value store contains totals.

Pricing

Store discounts: the FREE and BRONZE tiers use the list prices below. SILVER receives 5% off; GOLD, PLATINUM and DIAMOND receive 10% off billable result events. The platform start fee is unchanged. Check the Actor's Store pricing table for the prices currently in effect.

EventPriceWhen charged
URL metadata record (url-metadata)$0.001 per URL ($1 / 1,000)once per URL whose page was fetched and analysed (ok)

Apart from Apify's automatic Actor-start charge ($0.00005 per GB of run memory, a fraction of a cent per run) there is no start fee or subscription. Use Maximum cost per run to cap spend: once it is reached, the remaining URLs are returned with status: "skipped_budget" and are not charged. Accounts on the Apify free plan can process up to 10 URLs per run.

Use with AI agents (MCP)

Use this Actor from Claude, ChatGPT, Cursor, VS Code or any other MCP client through the Apify MCP server. Add this server URL to your client and sign in with your Apify account when asked:

https://mcp.apify.com?tools=sfoln/url-metadata

To run the MCP server locally instead, start npx -y @apify/actors-mcp-server --tools sfoln/url-metadata with your APIFY_TOKEN in the environment.

Example prompt:

Get the title, description, Open Graph image and canonical URL of https://apify.com and https://blog.apify.com for a link preview.

Runs started by an agent are billed like any other run (see Pricing). Agents can cap what a run may spend with maxTotalChargeUsd.

API usage

Run the Actor and get its dataset items in one call (the call waits up to 5 minutes for the run to finish):

curl -X POST "https://api.apify.com/v2/acts/sfoln~url-metadata/run-sync-get-dataset-items" \
-H "Authorization: Bearer <APIFY_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://apify.com", "https://blog.apify.com"]}'

For large inputs, start the run asynchronously and download the dataset when it has finished:

# 1. Start a run: the response holds the run ID (data.id) and its dataset ID (data.defaultDatasetId)
curl -X POST "https://api.apify.com/v2/acts/sfoln~url-metadata/runs" \
-H "Authorization: Bearer <APIFY_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://apify.com", "https://blog.apify.com"]}'
# 2. Repeat until data.status is SUCCEEDED (each call waits up to 60 s)
curl "https://api.apify.com/v2/actor-runs/<runId>?waitForFinish=60" -H "Authorization: Bearer <APIFY_TOKEN>"
# 3. Download the results (format=json, csv or xlsx)
curl "https://api.apify.com/v2/datasets/<defaultDatasetId>/items?format=json" -H "Authorization: Bearer <APIFY_TOKEN>"

Python (apify-client):

from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("sfoln/url-metadata").call(run_input={"urls": ["https://apify.com", "https://blog.apify.com"]})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item)

Instead of polling, you can attach a webhook to the run (see Integrations). The API tab of this page shows the same calls for JavaScript and the Apify CLI.

More API examples

Synchronous (small batches, returns the records directly):

curl -X POST "https://api.apify.com/v2/acts/sfoln~url-metadata/run-sync-get-dataset-items?token=<APIFY_TOKEN>&timeout=120" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://apify.com", "https://blog.apify.com"]}'

Asynchronous (large lists):

curl -X POST "https://api.apify.com/v2/acts/sfoln~url-metadata/runs?token=<APIFY_TOKEN>" \
-H "Content-Type: application/json" -d @urls.json
# → poll /v2/actor-runs/<runId> then GET /v2/datasets/<defaultDatasetId>/items?format=csv

Python:

from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("sfoln/url-metadata").call(run_input={"urls": ["https://apify.com"]})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["url"], item["title"], item["ogImage"])

Integrations

  • Make, Zapier and n8n: run sfoln/url-metadata with the Apify app (in n8n, the Apify node) and pass the dataset items to the next step of your workflow.
  • Google Sheets: add the items to a sheet with the Google Sheets step of Make, Zapier or n8n, or download them as CSV or Excel from the run's Storage tab or the API (format=csv or format=xlsx).
  • Webhooks: get a POST request when a run succeeds or fails: add a webhook in the Actor's Integrations tab, or pass webhooks when you start a run through the API.
  • Schedules: run it hourly, daily or weekly with the same input from Apify Schedules; every run keeps its results in its own dataset.
  • More: Slack, Google Drive, GitHub, LangChain, LlamaIndex and other Apify integrations.

See all our Actors on Apify Store.

FAQ

How much does it cost, and am I charged for failed items?

You pay per event at the prices under Pricing above, plus a run start fee of $0.00005 per GB of memory, with no subscription; platform usage is included. Errors and skipped items (skipped_… statuses) are never charged; a lookup that finds nothing is charged only where Pricing says so, and every record's charged field shows whether it was billed. Set Maximum cost per run to cap what a single run can spend.

How fresh is the data?

Each run queries its source while it runs, so you get what the source returns at that moment. Source-specific details, such as how often a provider refreshes its own database, are under Limits & notes.

What are the limits?

Per-run caps (for example the maximum number of items) are listed under Input, source limits under Limits & notes, and the free-plan limit under Pricing. For big batches, start the run asynchronously (see API usage) and read the dataset when it has finished.

Can I schedule runs or get results by webhook?

Yes. Create a schedule in Apify Console to run it hourly, daily or weekly with the same input, and add a webhook to get a POST request when a run finishes (see Integrations).

What does this Actor record about my runs?

This Actor records operational metrics about each run (item counts, duration, charges, error codes and a pseudonymous hash of your Apify user ID) to monitor reliability and costs. It never stores your input or results.

How do I get help?

Open an issue in the Actor's Issues tab and include the link to the run, so we can reproduce the problem. Feature requests are welcome there too.

Limits & notes

  • The page is fetched once with a desktop-browser User-Agent; JavaScript is not executed, so metadata injected client-side (some single-page apps) is not visible.
  • At most 1 MB of each page is analysed; larger pages are flagged truncated and their word and link counts are lower bounds.
  • Sites that block automated requests (HTTP 403, CAPTCHAs) return status: "error" and are not charged. Private, loopback, link-local and other non-public addresses are never fetched: the host of the URL and of every redirect (at most 5) is resolved and checked before it is requested, the connection goes to the address that was checked (no DNS rebinding), and only ports 80 and 443 are used.
  • Data source: the target pages themselves, fetched live at run time by this Actor; nothing is cached or stored beyond your run's dataset.