Link Preview API — Bulk OpenGraph & Metadata Unfurl avatar

Link Preview API — Bulk OpenGraph & Metadata Unfurl

Pricing

from $1.94 / 1,000 link previews

Go to Apify Store
Link Preview API — Bulk OpenGraph & Metadata Unfurl

Link Preview API — Bulk OpenGraph & Metadata Unfurl

High-volume link previews: OpenGraph, Twitter Cards, JSON-LD, titles, images, favicons, canonicals, authors, dates, language and feeds. No fixed run timeout, browser or third-party API key.

Pricing

from $1.94 / 1,000 link previews

Rating

0.0

(0)

Developer

Technical Dost Solutions

Technical Dost Solutions

Maintained by Community

Actor stats

0

Bookmarked

9

Total users

7

Monthly active users

16 days ago

Last modified

Security

Limited permissions

Share

Turn a URL list into production-ready link previews and web metadata. The Actor combines OpenGraph, Twitter Cards, standard meta tags, canonical links, favicons, authors, dates, language, feeds, hreflang, and schema.org JSON-LD into one clean record per URL.

It uses fast HTTP requests instead of a headless browser, streams results as they finish, and keeps only a small concurrent window in memory. That makes it suitable for both single-link API calls and large batch jobs.

Why use this Actor?

  • Rich link previews — title, description, image, site name, favicon, canonical URL, and oEmbed.
  • OpenGraph + Twitter Cards — reconciled preview fields plus complete normalized openGraph and twitter objects.
  • JSON-LD and SEO metadata — schema types, authors, publishers, dates, robots, keywords, language, charset, theme color, hreflang, web manifests, and RSS/Atom feeds.
  • High-volume streaming — no arbitrary URL-count cap and no fixed overall run timeout. Results are saved and billed continuously instead of being buffered until every URL finishes.
  • Tunable performance — 1–200 concurrent requests, configurable per-URL timeout, and retries for temporary errors.
  • Low overhead — no browser and no third-party API key.
  • Fair billing — successful previews are charged atomically; failed URLs return free diagnostics.

There is no artificial batch-size limit in the Actor. Practical throughput still depends on Apify platform limits, the size of your input and dataset, target-site response times, rate limits, and the spending limit you set for a run.

Input

FieldTypeDefaultDescription
urlsarrayrequiredURL strings or { "url": "..." } objects. A missing scheme is upgraded to HTTPS.
maxItemsinteger0Optional safety cap; 0 processes every supplied URL.
maxConcurrencyinteger50Total parallel requests, from 1 to 200.
maxConcurrencyPerDomaininteger10Parallel requests to any one website. Defaults to 10 when maxConcurrency is not set, otherwise to maxConcurrency.
requestTimeoutSecsinteger20Per-URL timeout, from 3 to 120 seconds. The overall Actor run has no fixed timeout.
maxRetriesinteger1Retries for timeouts, HTTP 429, and temporary 5xx errors; 0 to 3.
includeJsonLdbooleantrueReturn parsed JSON-LD and detected schema.org types.
includeRawTagsbooleanfalseReturn every normalized meta tag in metaTags; useful for audits but increases output size.
{
"urls": ["github.com", "https://stripe.com", "https://www.apify.com"],
"maxItems": 0,
"requestTimeoutSecs": 20,
"maxRetries": 1,
"includeJsonLd": true,
"includeRawTags": false
}

Output

Each URL produces one dataset record. Existing link-preview fields remain stable; richer fields are additive.

{
"url": "https://example.com/article",
"finalUrl": "https://example.com/article",
"ok": true,
"status": 200,
"contentType": "text/html; charset=utf-8",
"responseTimeMs": 184,
"attempts": 1,
"title": "Example article",
"description": "A concise article description.",
"image": "https://example.com/article-cover.jpg",
"siteName": "Example",
"type": "article",
"canonical": "https://example.com/article",
"favicon": "https://example.com/favicon.ico",
"appleTouchIcon": "https://example.com/apple-touch-icon.png",
"manifestUrl": "https://example.com/site.webmanifest",
"feedUrl": "https://example.com/feed.xml",
"feeds": [{ "url": "https://example.com/feed.xml", "type": "application/rss+xml", "title": "Example feed" }],
"hreflang": [{ "language": "en", "url": "https://example.com/en/article" }],
"language": "en",
"charset": "utf-8",
"author": "Jane Doe",
"publisher": "Example",
"publishedTime": "2026-08-01T09:00:00Z",
"modifiedTime": "2026-08-20T12:00:00Z",
"robots": "index,follow",
"themeColor": "#ffffff",
"twitterCard": "summary_large_image",
"openGraph": { "title": "Example article", "type": "article" },
"twitter": { "card": "summary_large_image" },
"schemaTypes": ["Article", "Organization"],
"jsonLd": [{ "@context": "https://schema.org", "@type": "Article" }],
"fetchedAt": "2026-08-25T09:00:00.000Z"
}

Unreachable URLs, timeouts, and non-success HTTP responses produce ok: false records with an error message and a machine-readable errorCode: BLOCKED, RATE_LIMITED, NOT_FOUND, HTTP_ERROR, TIMEOUT, DNS, CONNECTION, TLS, REDIRECT, INVALID_URL, PRIVATE_ADDRESS, NOT_HTML, NO_METADATA or NETWORK. Those diagnostic records are not charged as successful link previews.

When a site answers with a typical bot-protection response (401, 403, 429, 503 or an empty 202), the Actor immediately retries with browser-like request profiles before giving up. A site that does not answer one client within requestTimeoutSecs is tried with the next one, within the same overall time budget. Pages that only redirect with a meta refresh (common for short links) are followed automatically, and links to private or local network addresses are refused immediately.

Large-batch guidance

The defaults (50 parallel requests, at most 10 per website) suit most large lists. Results are stored in batches, so throughput scales with concurrency; for very large mixed-domain lists try maxConcurrency 100. Lower maxConcurrencyPerDomain when a single site rate-limits you. If Apify migrates a long run to another server, the run resumes where it stopped instead of fetching and charging URLs again. Use maxItems while testing and set Apify's per-run maximum charge to control spend. Because results stream into the dataset continuously, a slow URL or a stopped run does not discard already completed previews.

Common use cases

  • Link unfurling for chat, comments, CMS, CRM, and bookmarking apps.
  • Content and feed enrichment for AI agents, RAG pipelines, newsletters, and databases.
  • OpenGraph, Twitter Card, canonical, hreflang, and JSON-LD audits.
  • Metadata snapshots before and after site migrations.
  • Article author/date extraction and schema.org inventory across large URL lists.

API and exports

Run the Actor from Apify Console, API, JavaScript/Python clients, schedules, webhooks, Make, Zapier, n8n, or MCP. Download the dataset as JSON, CSV, Excel, XML, RSS, or HTML using Apify's standard dataset exports.

Real-time API (Standby)

For instant single-link unfurls without waiting for a run to start, call the Standby endpoint with your Apify token:

curl -H "Authorization: Bearer $APIFY_TOKEN" \
"https://technicaldost--link-preview-api.apify.actor/?url=https://github.com"
curl -X POST -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \
-d '{"urls": ["https://github.com", "https://www.apify.com"]}' \
"https://technicaldost--link-preview-api.apify.actor/"

A single ?url= returns one preview object; ?urls=a,b, repeated url parameters, or a POST body return { "results": [...] }. Every input option can be passed as a query parameter or in the POST body. Up to 100 URLs per request; use a normal run for larger batches. Billing is the same: one result event per successful preview.

FAQ

Does it require an API key? No third-party API key is required. API calls to Apify use your normal Apify token.

Does it render JavaScript? No. It reads server-delivered HTML, where sites normally expose preview metadata. Pages that create metadata only after client-side JavaScript runs may return incomplete fields.

Is there a URL limit? The Actor imposes no arbitrary URL-count cap. Real limits come from the platform, input and dataset sizes, target sites, your run settings, and your spending limit.

Is there a timeout? The published Actor has no fixed overall run timeout. Each individual request has a configurable timeout so one unresponsive site cannot block a large job indefinitely.

What happens when the run spending limit is reached? The Actor stops scheduling new work. Successful results are saved and charged atomically, so it does not deliver successful paid output beyond the available run budget.

Pricing

Pay per successful link preview, plus the small start event shown on the Pricing tab. Failed URLs stay free. Always check the live Pricing tab for the current rate before starting a large run.

  1. Open Link Preview API on Apify Store and click Try for free.
  2. Fill in the input (the form is prefilled with a working example) and click Start.
  3. Watch results appear in the Output tab, then download them as JSON, CSV, Excel or HTML, or read them through the API.
  4. Optional: save the input as a task and add a schedule to run it automatically, or connect it to your tools with integrations and webhooks.

Give Claude, ChatGPT, Cursor, VS Code or any MCP client this Actor as a tool through the hosted Apify MCP server. The agent sees the input fields with descriptions and example values, runs the Actor, and reads the results.

MCP server URL (this Actor only):

https://mcp.apify.com/?tools=technicaldost/link-preview-api

Claude Code:

$claude mcp add --transport http apify "https://mcp.apify.com/?tools=technicaldost/link-preview-api" --header "Authorization: Bearer YOUR_APIFY_TOKEN"

Cursor, VS Code, Claude Desktop and other clients (mcp.json or the client's MCP settings):

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com/?tools=technicaldost/link-preview-api",
"headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
}
}
}

Clients that support sign-in (such as Claude.ai connectors) can use the URL without a token and log in to Apify instead. Get your token in Apify Console → Settings → API & Integrations, or generate a ready config for your client at mcp.apify.com. In the agent the tool is named technicaldost--link-preview-api; ask it, for example, to "run Link Preview API with {"urls": ["https://www.apify.com", "https://github.com"], "maxItems": 0, "maxConcurrency": 10, "requestTimeoutSecs": 20, "maxRetries": 1, "includeJsonLd": true,".

AI agents without an Apify account can also run and pay for this Actor per request with x402 agentic payments.

Run the Actor and get its results in one call (replace YOUR_APIFY_TOKEN):

curl -X POST "https://api.apify.com/v2/acts/technicaldost~link-preview-api/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://www.apify.com", "https://github.com"], "maxItems": 0, "maxConcurrency": 10, "requestTimeoutSecs": 20, "maxRetries": 1, "includeJsonLd": true, "includeRawTags": false}'

Python (pip install apify-client):

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("technicaldost/link-preview-api").call(run_input={"urls": ["https://www.apify.com", "https://github.com"], "maxItems": 0, "maxConcurrency": 10, "requestTimeoutSecs": 20, "maxRetries": 1, "includeJsonLd": true, "includeRawTags": false})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item)

JavaScript / TypeScript (npm install apify-client):

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('technicaldost/link-preview-api').call({"urls": ["https://www.apify.com", "https://github.com"], "maxItems": 0, "maxConcurrency": 10, "requestTimeoutSecs": 20, "maxRetries": 1, "includeJsonLd": true, "includeRawTags": false});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Long runs: start them with POST /v2/acts/technicaldost~link-preview-api/runs and fetch the dataset when the run finishes, or receive a webhook.