Link Unfurl and Open Graph Preview Validator
Pricing
Pay per usage
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
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
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:
- Fetches the page HTML with that platform's bot user agent.
- Follows redirects, up to 5 hops. It rejects any hop that points to a private or reserved network address.
- Reads the
og:title,og:description,og:image,og:type, andtwitter:cardmeta tags. - If
requireImageis true, it fetches theog:imageURL with a ranged GET. It reads only the image header, not the full file, to get the width and height. - Compares the image aspect ratio and minimum size against the platform's rule.
- 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
| Field | Type | Default | Notes |
|---|---|---|---|
urls | array of string | ["https://example.com"] | Public HTTP(S) URLs. Max 1000. |
platforms | array of enum | all six | slack, discord, x, facebook, linkedin, imessage. |
requireImage | boolean | true | Fail a check when og:image is missing or unreachable. |
expectedTitlePattern | string (regex) | "" (none) | Optional. og:title must match this pattern. |
followRedirects | boolean | true | Follow redirects, up to 5 hops. |
Output
One record per URL per platform, written to the default dataset:
url,platform,botUserAgentUsedhttpStatus,redirectChainogTitle,ogDescription,ogImage,ogType,twitterCardPresentmissingTagsimageStatus,imageContentType,imageBytes,imageWidth,imageHeight,aspectRatioverdict: one ofPASS,NO_CARD,MISSING_TAG,IMAGE_UNREACHABLE,IMAGE_WRONG_RATIO,SPA_SHELLreasonCodeandfailingRule: 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:imagefetches by URL within a run.
Local development
This project uses uv, pytest, and ruff.
uv syncuv run pytestuv run ruff check .
To run the Actor locally against the bundled fixture:
mkdir -p apify_storage/key_value_stores/defaultcp .actor/default_input.json apify_storage/key_value_stores/default/INPUT.jsonAPIFY_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.jsonon a schedule and after a reported preview failure. - Apple does not publish an iMessage crawler spec. The
imessagerule 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.