# Link Preview & OpenGraph Metadata API (`webintel/link-preview`) Actor

Fast HTTP-only API that turns URLs into compact link-preview objects with OpenGraph, Twitter, favicon, canonical, image and optional oEmbed metadata.

- **URL**: https://apify.com/webintel/link-preview.md
- **Developed by:** [Deepak Ganesh](https://apify.com/webintel) (community)
- **Categories:** Developer tools, AI, SEO tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 previews

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Link Preview & OpenGraph Metadata API

![Link Preview & OpenGraph Metadata API](https://api.apify.com/v2/key-value-stores/21SBwDwdNtlnapIdO/records/link-preview.png?v=6d9aca59)

Turn any public URL into a compact, chat-ready link preview object.

- Fetches pages with a fast HTTP-only Cheerio crawler (no browser overhead).
- Accepts full URLs, plain domains, and `{ "url": "..." }` API objects.
- Extracts OpenGraph, Twitter Cards, canonical URL, best favicon, theme color, language, author, publish time, keywords, video, and optional oEmbed JSON.
- Failed, blocked, invalid, or DNS-error URLs are returned with `success=false` and are not charged.

### Use cases

- Chat app and social link unfurling
- AI agent browsing context and source cards
- CRM, enrichment, bookmarking, and content ingestion pipelines
- Batch validation of OpenGraph/Twitter metadata
- Lightweight preview API before a heavier crawl

### Input

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `urls` | array | required | URLs or plain domains. String list in the UI; API also accepts objects like `{ "url": "https://example.com" }`. |
| `fetchOembed` | boolean | `false` | Fetch advertised `<link type="application/json+oembed">` endpoints and include parsed `oembed` JSON when available. |
| `maxConcurrency` | integer | `20` | Number of pages fetched in parallel (1-100). |
| `requestTimeoutSecs` | integer | `30` | Per-page timeout before retrying (5-120 seconds). |
| `maxRetries` | integer | `2` | Retries for transient fetch errors (0-5). |
| `proxyConfiguration` | object | `{ "useApifyProxy": false }` | Optional proxy settings. |

Example input:

```json
{
  "urls": ["apify.com", { "url": "https://github.com/apify/crawlee" }, "https://example.invalid"],
  "fetchOembed": true
}
```

### Output JSON example

This example is trimmed from a real run:

```json
{
  "inputUrl": "apify.com",
  "finalUrl": "https://apify.com/",
  "domain": "apify.com",
  "statusCode": 200,
  "success": true,
  "error": null,
  "title": "Apify: Marketplace of ready-to-run tools for AI",
  "description": "Thousands of tools to automate your business. Get real-time web data, track competitors, generate leads, and integrate your apps and AI agents.",
  "siteName": "Apify",
  "type": "website",
  "image": "https://apify.com/og-image?title=Thousands+of+tools%0Afor+your+AI",
  "imageWidth": 1200,
  "imageHeight": 630,
  "imageAlt": "Thousands of tools for your AI",
  "favicon": "https://apify.com/apple-icon.png?apple-icon.1qabm0kj8blk6.png?dpl=648527a422",
  "themeColor": "#020202",
  "canonicalUrl": "https://apify.com/",
  "language": "en",
  "author": "@apify",
  "publishedTime": null,
  "video": null,
  "oembedEndpoint": null,
  "twitterCard": "summary_large_image",
  "keywords": ["tools for AI", "AI agents", "web scraper", "web crawler", "scraping", "data extraction", "API"],
  "openGraph": {
    "title": "Apify: Marketplace of ready-to-run tools for AI",
    "site_name": "Apify",
    "type": "website",
    "image": "https://apify.com/og-image?title=Thousands+of+tools%0Afor+your+AI"
  },
  "twitter": {
    "card": "summary_large_image",
    "creator": "@apify",
    "title": "Apify: Marketplace of ready-to-run tools for AI"
  },
  "previewedAt": "2026-10-06T16:39:43.534Z"
}
```

### Pricing

| Event | Price | Charged when |
| --- | ---: | --- |
| Preview (`url-previewed`) | $1.00 / 1,000 previews | A URL is fetched successfully and a preview item is stored. |

Invalid URLs, DNS errors, blocked pages, and HTTP status codes 400 or higher are included in the dataset with `success=false` but are free.

### FAQ

#### Does it run a browser?

No. The Actor is HTTP-only and uses CheerioCrawler for speed and low cost.

#### Which title or image wins?

Title priority is `og:title`, then `twitter:title`, then `<title>`. Image priority is `og:image`, then `twitter:image`, then the first large page image.

#### Can it fetch oEmbed?

Yes. Set `fetchOembed` to `true`; invalid or unavailable oEmbed responses are ignored instead of failing the URL.

#### Are redirects followed?

Yes. `finalUrl` contains the loaded URL after redirects.

#### Are failed URLs charged?

No. Only successful preview items are pushed with the `url-previewed` pay-per-event charge.

### Changelog

#### 0.1

- Initial release with OpenGraph, Twitter Card, favicon, canonical, oEmbed, and failure-safe pay-per-event billing.

# Actor input Schema

## `urls` (type: `array`):

URLs or plain domains to preview, one per line. Objects like {"url": "https://example.com"} are also accepted via API. Duplicates are removed.

## `fetchOembed` (type: `boolean`):

When a page advertises an application/json+oembed endpoint, fetch it and include the parsed oEmbed object. Invalid or unavailable oEmbed responses are ignored.

## `maxConcurrency` (type: `integer`):

Maximum number of pages fetched in parallel.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for a page to respond before retrying.

## `maxRetries` (type: `integer`):

How many times to retry pages that fail to load.

## `proxyConfiguration` (type: `object`):

Optional. Most public pages work without a proxy. Use Apify Proxy only if many sites block you.

## Actor input object example

```json
{
  "urls": [
    "https://apify.com",
    "github.com",
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "fetchOembed": false,
  "maxConcurrency": 20,
  "requestTimeoutSecs": 30,
  "maxRetries": 2,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All link preview results (JSON). Each item includes finalUrl, statusCode, title, description, image, favicon, canonicalUrl, oEmbed, raw OpenGraph/Twitter maps and error details for failures.

## `metadata` (type: `string`):

Compact metadata table with canonical URL, language, author, published time, theme color and keywords.

## `raw` (type: `string`):

Raw OpenGraph and Twitter meta tag maps plus oEmbed endpoint/result when available.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        "https://apify.com",
        "github.com",
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("webintel/link-preview").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "urls": [
        "https://apify.com",
        "github.com",
        "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("webintel/link-preview").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    "https://apify.com",
    "github.com",
    "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call webintel/link-preview --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,webintel/link-preview"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/6WdCHgbFCnpqVsbT4/builds/MrwkPtfVerUdqaoW4/openapi.json
