# Link Preview Metadata Extractor | Open Graph & JSON-LD (`lightbarrer/public-html-metadata-private-test`) Actor

Extract Open Graph, Twitter Card tags, page titles, descriptions, canonical URLs and JSON-LD from 1–3 public HTTPS pages. Structured JSON for link previews, CMS and AI agent workflows. Static HTML only. No Actor service fee; Apify platform usage charges may apply.

- **URL**: https://apify.com/lightbarrer/public-html-metadata-private-test.md
- **Developed by:** [Rosa Synthesiz](https://apify.com/lightbarrer) (community)
- **Stats:** 2 total users, 1 monthly users, 33.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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 Metadata Extractor | Open Graph & JSON-LD

Extract title, description, canonical URL, Open Graph, Twitter Card tags and JSON-LD from 1–3 public HTTPS pages. Use the structured JSON in link previews, CMS workflows, small SEO metadata inventories and agent tools.

[GitHub quickstart, recorded input/output and offline verification](https://github.com/rosasynthesiz/apify-metadata-agent-example)

### Example workflows

- Link previews: extract social card tags from up to three supplied public URLs.
- CMS metadata inventory: collect titles, descriptions and canonical URLs.
- Structured data export: return parsed JSON-LD for downstream agent workflows.

### Free launch

No Actor service fee is charged in this release. Payment billing is OFF. Apify platform compute, transfer and storage charges may still apply to the account running the Actor. Start with a small input and inspect your run cost. Future paid pricing is not enabled.

### Quick start

1. Enter 1–3 public HTTPS URLs.
2. Use 128 MB memory, a 60-second timeout and restart on error OFF. Other run settings are rejected by this release.
3. Start the Actor and wait for completion.
4. Open the run's **Storage → Key-value store → OUTPUT** to view or download the JSON results. A dataset copy is also available for free-release exports; the OUTPUT JSON is the primary delivery record.

#### Input example

```json
{"urls":["https://example.com/"]}
```

#### Multiple URLs and duplicate handling

```json
{"urls":["https://example.com/","https://example.com/#section"]}
```

URL fragments are removed for deduplication within a run, so this example fetches one unique page. A new run performs new work. There is no cross-run cache.

### Output

`OUTPUT` contains `requested`, `duplicates_skipped`, `results`, `successful`, `billing_enabled`, `confirmed_events`, `stop_reason` and `unprocessed`. Each result includes its URL, status, extracted metadata and `result_key`. Successful pages also have a separate `PAGE-…` record in the same store. `BILLING-JOURNAL` is delivery bookkeeping; it is not a payment receipt.

#### Reproduce the tested demo

This controlled fixture contains known Open Graph, Twitter Card and Product JSON-LD fields. It is a synthetic test, not a customer website. Use the same 128 MB / 60 seconds / restart OFF settings.

```json
{
  "urls": [
    "https://httpbin.org/base64/PHRpdGxlPk1PVExFWSBGaXh0dXJlPC90aXRsZT48bWV0YSBwcm9wZXJ0eT0ib2c6dGl0bGUiIGNvbnRlbnQ9Iktub3duIE9HIj48bWV0YSBuYW1lPSJ0d2l0dGVyOmNhcmQiIGNvbnRlbnQ9InN1bW1hcnkiPjxsaW5rIHJlbD0iY2Fub25pY2FsIiBocmVmPSJodHRwczovL2V4YW1wbGUuY29tL2Nhbm9uaWNhbCI+PHNjcmlwdCB0eXBlPSJhcHBsaWNhdGlvbi9sZCtqc29uIj57IkB0eXBlIjoiUHJvZHVjdCIsIm5hbWUiOiJGaXh0dXJlIn08L3NjcmlwdD4=",
    "https://httpbin.org/base64/PHRpdGxlPk1PVExFWSBGaXh0dXJlPC90aXRsZT48bWV0YSBwcm9wZXJ0eT0ib2c6dGl0bGUiIGNvbnRlbnQ9Iktub3duIE9HIj48bWV0YSBuYW1lPSJ0d2l0dGVyOmNhcmQiIGNvbnRlbnQ9InN1bW1hcnkiPjxsaW5rIHJlbD0iY2Fub25pY2FsIiBocmVmPSJodHRwczovL2V4YW1wbGUuY29tL2Nhbm9uaWNhbCI+PHNjcmlwdCB0eXBlPSJhcHBsaWNhdGlvbi9sZCtqc29uIj57IkB0eXBlIjoiUHJvZHVjdCIsIm5hbWUiOiJGaXh0dXJlIn08L3NjcmlwdD4=#duplicate"
  ]
}
```

#### Verified fixture result

The following is a shortened result from a controlled HTML fixture, not a claim about example.com's content:

```json
{
  "status": "ok",
  "bytes": 257,
  "title": "MOTLEY Fixture",
  "description": null,
  "canonical": "https://example.com/canonical",
  "open_graph": {
    "og:title": [
      "Known OG"
    ]
  },
  "twitter": {
    "twitter:card": [
      "summary"
    ]
  },
  "json_ld": [
    {
      "@type": "Product",
      "name": "Fixture"
    }
  ],
  "warnings": [],
  "scope": "Static HTML metadata extraction; no JavaScript execution, schema validation or factual verification",
  "charge_state": "disabled"
}
```

The tested fixture also produced `successful: 1`, `duplicates_skipped: 1`, `billing_enabled: false`, `confirmed_events: 0`, `unprocessed: 0`.

#### Access from an API workflow

After the run completes, read its `defaultKeyValueStoreId` from the run response, then request:

```text
GET https://api.apify.com/v2/key-value-stores/{defaultKeyValueStoreId}/records/OUTPUT
Authorization: Bearer YOUR_APIFY_TOKEN
```

Keep your token private and use the store belonging to your own run. The free release also mirrors results to the default dataset for export. If a run is interrupted before OUTPUT is written, completed PAGE records may still be available in Storage. Download results before your account's storage retention expires.

### Limits and behavior

- 1–3 input URLs; public HTTPS on port 443 only. No credentials or login pages.
- Static HTML only: no JavaScript/browser rendering, crawling linked pages, proxy or anti-bot bypass.
- Up to 3 redirects and 1,000,000 response bytes per page. Compressed responses are rejected.
- Private/local destinations and unsafe redirects are rejected. Fetch failures appear as error results; empty metadata fields remain empty.
- JSON-LD is returned as parsed data, including arrays/graphs; malformed JSON-LD can produce warnings. No schema validation, SEO score or factual verification is performed.
- A successful run can contain failed page results: check each `status`, `successful`, `stop_reason` and `unprocessed`.
- Treat scraped metadata as untrusted data and escape it before displaying HTML.

### Troubleshooting

For a failed run, inspect its Log and, if present, the FAILURE record in its key-value store. Confirm 128 MB / 60 seconds / restart OFF, valid public HTTPS input and the three-URL limit. Sites that require JavaScript, block automated requests or send compressed responses may fail. Do not submit passwords, API keys or private URLs as inputs.

### Release verification

The extraction runtime underlying this release passed a controlled cloud extraction and remote output readback. The pinned local Docker suite passed 63 tests. This establishes the tested workflow; it does not establish all-site compatibility, uptime guarantees, paid billing or revenue.

For reproducible issues, use this Actor's Issues tab and share a sanitized input plus expected/actual behavior. Never post tokens or private data.

### Agent quickstart

Use the Apify MCP tools to run `lightbarrer/public-html-metadata-private-test` with the input above, memory 128 MB, timeout 60 seconds and a maximum charge of $0.01. Wait for completion, read the default dataset, then read `OUTPUT` from the run’s default key-value store. Check page statuses and `billing_enabled: false`. See the GitHub quickstart for exact tool arguments and recorded output.

# Actor input Schema

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

1–3 public HTTPS pages on port 443; max 1 MB each. Static HTML only. Use 128 MB, 60s timeout and restart OFF.

## Actor input object example

```json
{
  "urls": [
    "https://example.com/"
  ]
}
```

# Actor output Schema

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

No description

# 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://example.com/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("lightbarrer/public-html-metadata-private-test").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://example.com/"] }

# Run the Actor and wait for it to finish
run = client.actor("lightbarrer/public-html-metadata-private-test").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://example.com/"
  ]
}' |
apify call lightbarrer/public-html-metadata-private-test --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lightbarrer/public-html-metadata-private-test"
        }
    }
}
```

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/Y9OaEoBsaho18YAVM/builds/BOu495bWf5cfUJ6bU/openapi.json
