Link Unfurl and Open Graph Preview Validator avatar

Link Unfurl and Open Graph Preview Validator

Pricing

Pay per usage

Go to Apify Store
Link Unfurl and Open Graph Preview Validator

Link Unfurl and Open Graph Preview Validator

Validate Open Graph and social-preview cards for public URLs across Slack, Discord, X, Facebook, LinkedIn, and iMessage without a browser.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

kingii98

kingii98

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

4 days ago

Last modified

Share

This Actor checks if a URL produces a correct link preview card. It fetches each URL with the bot user agent of a chosen platform, reads the Open Graph and Twitter Card meta tags, and checks the preview image. It gives a PASS or FAIL verdict for each URL and platform pair.

Use this Actor as a release gate. Run it after every deploy. Run it again on a schedule, because a working card can break after a CDN cache change or a route change, with no code change to warn you.

What it checks

For each URL and each selected platform, the Actor:

  1. Fetches the page HTML with that platform's bot user agent.
  2. Follows redirects, up to 5 hops. It rejects any hop that points to a private or reserved network address.
  3. Reads the og:title, og:description, og:image, og:type, and twitter:card meta tags.
  4. If requireImage is true, it fetches the og:image URL with a ranged GET. It reads only the image header, not the full file, to get the width and height.
  5. Compares the image aspect ratio and minimum size against the platform's rule.
  6. Writes one output record with a verdict, a reason code, and the exact failing rule.

Platform rules live in a versioned config file inside the Actor (src/og_unf/platform_rules.json). Each rule lists its public source, or states that the source is unofficial.

Input

FieldTypeDefaultNotes
urlsarray of string["https://example.com"]Public HTTP(S) URLs. Max 1000.
platformsarray of enumall sixslack, discord, x, facebook, linkedin, imessage.
requireImagebooleantrueFail a check when og:image is missing or unreachable.
expectedTitlePatternstring (regex)"" (none)Optional. og:title must match this pattern.
followRedirectsbooleantrueFollow redirects, up to 5 hops.

Output

One record per URL per platform, written to the default dataset:

  • url, platform, botUserAgentUsed
  • httpStatus, redirectChain
  • ogTitle, ogDescription, ogImage, ogType, twitterCardPresent
  • missingTags
  • imageStatus, imageContentType, imageBytes, imageWidth, imageHeight, aspectRatio
  • verdict: one of PASS, NO_CARD, MISSING_TAG, IMAGE_UNREACHABLE, IMAGE_WRONG_RATIO, SPA_SHELL
  • reasonCode and failingRule: the exact rule that failed

A run summary goes to the default key-value store under the key SUMMARY. It has pass and fail counts per platform, and a gateResult of PASS or FAIL for use in continuous integration.

Limits and safety

  • HTTP(S) only. No browser rendering.
  • The Actor rejects private and reserved URL targets (loopback, private ranges, link-local, multicast, and similar), including on redirect hops. This stops the Actor from being used to probe internal services.
  • HTML body reads stop at 2 MB.
  • Image reads use a ranged GET and stop at 64 KB, with a 300 KB fallback cap if a server ignores the Range header.
  • Redirects stop at 5 hops.
  • Requests use a 15-second timeout.
  • At most 5 requests run at the same time.
  • The Actor deduplicates og:image fetches by URL within a run.

Local development

This project uses uv, pytest, and ruff.

uv sync
uv run pytest
uv run ruff check .

To run the Actor locally against the bundled fixture:

mkdir -p apify_storage/key_value_stores/default
cp .actor/default_input.json apify_storage/key_value_stores/default/INPUT.json
APIFY_LOCAL_STORAGE_DIR=apify_storage uv run python -m og_unf

Output records appear under apify_storage/datasets/default/. The summary appears under apify_storage/key_value_stores/default/SUMMARY.

Known limits

  • Platform card rules change over time. Review src/og_unf/platform_rules.json on a schedule and after a reported preview failure.
  • Apple does not publish an iMessage crawler spec. The imessage rule reuses the common Open Graph baseline with a wider tolerance and is marked unofficial in the config file.
  • Some sites serve different HTML to known preview bots on purpose. The Actor reports what it received. It does not treat this as an error.