# Website Metadata Extractor: Open Graph, Twitter Card & SEO Tags (`larkmoor/website-metadata-extractor`) Actor

Get the title, meta description, canonical, Open Graph and Twitter Card tags, favicon, language, hreflang, RSS feeds, schema.org JSON-LD types and quick SEO checks for any list of URLs. One clean row per page. $1 per 1,000 URLs, no start fee.

- **URL**: https://apify.com/larkmoor/website-metadata-extractor.md
- **Developed by:** [Larkmoor Data](https://apify.com/larkmoor) (community)
- **Categories:** SEO tools, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.85 / 1,000 url analyzeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Website Metadata Extractor: Open Graph, Twitter Card & SEO Tags

Give it a list of URLs and get one clean row per page with everything a link preview, an SEO audit or a data pipeline needs: title, meta description, canonical URL, Open Graph tags (og:title, og:description, og:image, og:type, og:site_name), Twitter Card tags, favicon and Apple touch icon, page language, robots meta and X-Robots-Tag, hreflang alternates, RSS/Atom feeds, schema.org JSON-LD types (and the raw JSON-LD if you want it), H1s, heading counts, images without alt text and a short list of SEO issues.

No browser, no login: it reads the public HTML of each page, respects robots.txt and is fast and cheap.

### What you can use it for

- **Link previews**: build rich cards (title, description, image, favicon) for any URL in your app, newsletter or CRM
- **Quick SEO audits**: check thousands of pages for missing titles, long descriptions, missing og:image, missing canonical, several H1s or a noindex tag
- **Social sharing QA**: make sure every page you share has the right Open Graph and Twitter Card image before a campaign
- **Data enrichment**: turn a list of company websites into site name, description, logo/icon, language and social image
- **Structured data checks**: see which pages carry Product, Article, Organization, FAQPage, BreadcrumbList or Recipe JSON-LD
- **Migration checks**: confirm canonicals, hreflang and robots tags after a redesign or domain move

### Why this one

- **$1 per 1,000 URLs**, $0.001 per run start. The best-known metadata actor charges about five times as much.
- **All the tags in one row**: Open Graph, Twitter Card, icons, canonical, hreflang, feeds and JSON-LD together
- **SEO issues spelled out** in plain words on every row, ready to filter in a spreadsheet
- **Polite and safe**: honours robots.txt by default, one request per page, clear error column when a site refuses automated access
- **Fast**: up to 20 pages in parallel, 256 MB memory

### Input

| Field | What it does |
|---|---|
| `urls` | Page URLs or bare domains, one per line |
| `includeJsonLd` | Add the page's raw schema.org JSON-LD blocks |
| `respectRobotsTxt` | Skip URLs disallowed by robots.txt (default on) |
| `skipFailed` | Leave out pages that could not be fetched, so you pay only for successes |
| `concurrency` | Pages fetched at the same time (default 8) |
| `maxResults` | Hard cap on URLs processed |

Example:

```json
{
  "urls": ["https://www.apple.com", "https://github.com", "https://www.python.org/about/"],
  "includeJsonLd": false
}
```

### Output

```json
{
  "url": "https://www.python.org/about/",
  "finalUrl": "https://www.python.org/about/",
  "status": 200,
  "title": "About Python™ | Python.org",
  "titleLength": 26,
  "description": "The official home of the Python Programming Language",
  "canonical": null,
  "language": "en",
  "ogTitle": "About Python™",
  "ogImage": "https://www.python.org/static/opengraph-icon-200x200.png",
  "ogType": "website",
  "ogSiteName": "Python.org",
  "twitterCard": null,
  "favicon": "https://www.python.org/static/favicon.ico",
  "appleTouchIcon": "https://www.python.org/static/apple-touch-icon-144x144-precomposed.png",
  "feeds": ["https://www.python.org/blogs/feed/"],
  "hreflang": [],
  "jsonLdTypes": ["WebSite", "SearchAction"],
  "h1": ["About"],
  "headingCounts": {"h1": 1, "h2": 4},
  "images": 3,
  "imagesWithoutAlt": 1,
  "issues": ["missing canonical"]
}
```

Other columns: `descriptionLength`, `robotsMeta`, `xRobotsTag`, `ogDescription`, `ogUrl`, `ogLocale`, `twitterSite`, `twitterTitle`, `twitterImage`, `themeColor`, `author`, `publishedTime`, `modifiedTime`, `keywords`, `generator`, `viewport`, and `jsonLd` when asked for. A page that could not be read has an `error` column (for example `HTTP 403 (site blocked automated access)` or `blocked by robots.txt`).

### How much does it cost?

**$1.00 per 1,000 URLs** on the Free plan plus **$0.001 per run**, with automatic discounts on paid Apify plans. Platform compute is included. Turn on `skipFailed` to pay only for pages that returned metadata.

Worked examples:

- **Link previews for 200 URLs** a day from your app: **$0.20 a day**
- **SEO check of a 5,000-page sitemap**: **$5.00**
- **Enrich 1,000 company homepages** with site name, description and icon: **$1.00**

### FAQ

**Is this legal?**
It reads the same public HTML any browser or social network preview bot reads, one request per page, and skips anything robots.txt disallows. No logins, no paywalls, no personal data.

**Why did some sites return an error?**
A few large sites refuse automated requests (HTTP 403 or a bot check). They appear with an `error` column instead of wrong data, and with `skipFailed` on they cost nothing.

**Does it run JavaScript?**
No. Open Graph, Twitter Card, canonical and JSON-LD tags are almost always in the server HTML because social networks and search engines need them there. Pages that build their tags only in the browser will show them as missing.

**Can I crawl a whole site?**
Give it the URLs. To get every URL of a site first, run a sitemap extractor and pass its output here.

**What counts as an SEO issue?**
Missing title, title over 60 characters, missing meta description, description over 160 characters, missing og:title, missing og:image, missing canonical, no H1 or more than one H1, and a noindex robots tag.

### Tips

- **Feeding a sitemap**: run a sitemap URL extractor first, then pass its `url` column here to audit every page of a site in one go.
- **Monitoring**: schedule a weekly run on your key landing pages and send rows whose `issues` list is not empty to Slack, so a broken social image or an accidental noindex is caught the same week.
- **Clean previews**: prefer `ogImage` for the card image, fall back to `twitterImage`, then `appleTouchIcon`; use `ogSiteName` or the domain as the source label.
- **Large lists**: keep `concurrency` at 8 to 12; lists that mix many different sites finish fastest.

### Integrations

Works with Google Sheets, Slack, Zapier, Make, Airtable, webhooks, the Apify API and the Python and JavaScript clients. Download as JSON, CSV, Excel, XML or HTML.

### Changelog

- **2026-10-20** — First release: title, description, canonical, Open Graph, Twitter Card, icons, language, robots, hreflang, feeds, JSON-LD types and raw JSON-LD, headings, image alt count and SEO issues.

# Actor input Schema

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

Page URLs (or bare domains). One per line.

## `includeJsonLd` (type: `boolean`):

Adds the page's full schema.org JSON-LD blocks (products, articles, organization, breadcrumbs, FAQ...).

## `respectRobotsTxt` (type: `boolean`):

Skip URLs the site's robots.txt disallows.

## `skipFailed` (type: `boolean`):

Leave out URLs that could not be fetched, so you pay only for pages that returned metadata. Default: off (failed URLs appear with an error column).

## `concurrency` (type: `integer`):

Pages fetched at the same time (spread across sites).

## `maxResults` (type: `integer`):

Hard cap on URLs processed.

## Actor input object example

```json
{
  "urls": [
    "https://www.apple.com",
    "https://github.com",
    "https://www.nytimes.com"
  ],
  "includeJsonLd": false,
  "respectRobotsTxt": true,
  "skipFailed": false,
  "concurrency": 8,
  "maxResults": 1000
}
```

# Actor output Schema

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

All results as JSON items in the run's default dataset (also downloadable as CSV/Excel from the dataset).

# 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://www.apple.com",
        "https://github.com",
        "https://www.nytimes.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("larkmoor/website-metadata-extractor").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://www.apple.com",
        "https://github.com",
        "https://www.nytimes.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("larkmoor/website-metadata-extractor").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://www.apple.com",
    "https://github.com",
    "https://www.nytimes.com"
  ]
}' |
apify call larkmoor/website-metadata-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,larkmoor/website-metadata-extractor"
        }
    }
}
```

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/onRETWivtRQ41p1Aj/builds/FvE9dtKXaJCMlVkga/openapi.json
