---
name: "social_preview_metadata"
description: "Make a shared link preview well on every platform: set the Open Graph and X Card tags a page needs, size the preview image to the per platform specs, keep title and description inside published limits, and check the page with a tested validator before the link goes out. Use when a link preview is broken, missing, cropped, or showing the wrong image or title, when launching a page that will be shared, or when adding share metadata to a template."
---

# Social Preview Metadata

## Purpose

Control what a link looks like when someone pastes it into Facebook, X, LinkedIn, Slack, Discord, WhatsApp, or any other app that builds a preview card. The card comes from meta tags in the page head. When the tags are missing or wrong, each platform guesses, caches its guess, and shows that guess to everyone who shares the link next.

This skill covers the tag set, the image specs per platform, the text limits, a validator that checks a page before it ships, and the cache refresh steps that make a fix actually appear. Search ranking is a different job. These tags do not move a page in Google results. They decide whether a shared link gets clicked.

## Workflow

### 1. Start from the page, not the post

- Work on the destination page or its template. A preview cannot be fixed from the social post, the scheduling tool, or the share button.
- Decide the preview before writing tags: one title, one description, one image, and the canonical URL the shares should build credit on.
- Give every page its own title, description, and image where the page earns shares on its own. A single site wide image is the fallback for pages nobody shares directly, not the plan for articles, products, or launch pages.

### 2. Ship the complete tag set

Put this block in the head, in the HTML the server sends. Tags added later by page scripts do not exist for crawlers.

```html
<meta property="og:title" content="Link Previews That Survive Every Feed">
<meta property="og:type" content="article">
<meta property="og:url" content="https://example.com/guides/link-previews/">
<meta property="og:description" content="Set the tags once, size the image right, and check the card before the link goes out.">
<meta property="og:site_name" content="Example Guides">
<meta property="og:image" content="https://example.com/images/link-previews-1200x630.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="A link preview card on a phone, title and image visible">
<meta name="twitter:card" content="summary_large_image">
<meta name="theme-color" content="#1463d8">
```

Rules behind the block, from the Open Graph protocol at ogp.me:

- The protocol requires four properties on every page: og:title, og:type, og:image, and og:url. og:description and og:site_name are optional in the protocol and required in practice, because every large preview shows the description.
- og:type is website for a home or landing page and article for an article. Article pages can add article:published_time and article:author.
- og:url is the canonical URL, with no tracking parameters. Platforms key their cache and their share counts on it. If the page also sends a canonical link tag, the two values must match.
- Structured properties go directly after the tag they describe. og:image:width, og:image:height, and og:image:alt belong to the og:image line above them.
- If a tag appears twice, the first one wins. Site templates that print a default og:image before the page level tag silently override the page. Check the rendered head, not the template intent.
- twitter:card is the only X tag most pages need. X falls back to the og title, description, and image for anything the twitter tags leave out. Add twitter:title, twitter:description, or twitter:image only when X should show something different from the other platforms.
- theme-color is optional. Discord uses it for the coloured bar on its embed.

### 3. Size the image to the specs, and design for the crops

Read references/platform-specs.md for the full table. The working rules:

- Ship one image at 1200 by 630 pixels, ratio 1.91 to 1, JPG or PNG, at an absolute https address. That size is Facebook's recommended size, matches LinkedIn's 1200 by 627 crop, and passes on X with a small crop toward its 2 to 1 card shape.
- Respect the floors and caps: under 600 by 315 Facebook drops to a small thumbnail, under 200 by 200 it will not use the image, and under 300 by 157 X silently downgrades a large card to a small one. Caps are 5 MB on X and 8 MB on Facebook. A working target under 1 MB keeps every crawler fast, and it is a target, not a platform limit.
- Keep the headline, logo, and subject in the centre of the canvas. Platforms crop the same file three ways: wide at 1.91 to 1, wider at 2 to 1 on X, and a centre square in several chat clients. Before exporting, check the centre square crop, 630 by 630 from the middle of the file. If the square crop loses the point, move the subject instead of shrinking text.
- Write any text on the image large and plain. Previews render small on phones, and fine detail and thin type disappear.
- Use JPG for photos and PNG for flat graphics with text. WEBP support varies by crawler, AVIF is worse, and SVG is not supported by X cards at all.
- Set og:image:width and og:image:height to the real size of the file you ship. Wrong numbers are worse than none, and the validator fails a mismatch.

### 4. Keep the text inside the limits that cut

- Title: 70 characters or fewer when X matters, because X card titles cap at 70. LinkedIn shows up to 150. A title that fits 70 fits everywhere, and it survives mobile truncation better too.
- Description: one to two sentences, as the protocol puts it, and 200 characters or fewer, because X card descriptions cap at 200. Say what the page gives the reader. Do not repeat the title.
- Image alt: one plain sentence describing what is in the image. It is a description for assistive tools, not a caption and not a second headline.

### 5. Run the validator before the link goes out

The validator parses a page, resolves the effective preview through the fallback chain (twitter tags, then og tags, then plain HTML), and checks required tags, absolute https URLs, length limits, declared image size and ratio, card type, and, with a local image file, the real pixel size and file size against the declared tags.

```bash
python3 scripts/validate_preview.py page.html
python3 scripts/validate_preview.py page.html --image images/card-1200x630.png
python3 scripts/validate_preview.py --url https://example.com/guides/link-previews/
python3 scripts/validate_preview.py page.html --json
```

Worked results from the test run that ships with this skill:

- A complete page with a real 1200 by 630 PNG: PASS, exit code 0, effective preview shows the og title, description, and image, card summary_large_image.
- A page missing og:type and og:url, with a relative SVG og:image and no twitter:card: FAIL, exit code 1, five failing checks, each named with its fix.
- Good tags paired with a 200 by 100 image file: FAIL on declared vs real size and on the X large card minimum of 300 by 157.
- A live run against https://ogp.me/ itself passes with warnings. The spec site uses a 300 by 300 logo image and no twitter:card, which is a fair reminder that even good pages ship small previews when nobody did this job on purpose.

Treat a FAIL as a stop. Fix the tags or the image and run it again. Warnings can ship when the tradeoff is deliberate, for example a title over 70 characters on a page that will only ever be shared on LinkedIn, and the decision belongs in the report.

### 6. Check the real debuggers, then refresh the caches

The validator reads the page. Only the platform tools show what the platform kept.

- Facebook and Messenger: Sharing Debugger at developers.facebook.com/tools/debug. Read every warning. Inferred property means the real tag was missing and Facebook guessed. After a fix, use Scrape Again. Nothing updates until the cache is refreshed or expires.
- LinkedIn: Post Inspector at linkedin.com/post-inspector. Inspecting the URL shows the preview LinkedIn holds and forces a refresh. Without it, a fix can stay hidden behind a cache that help summaries put at about 7 days.
- X: there is no validator tool any more. It was retired and no replacement shipped. Paste the link into the post composer and read the card it renders. To force a fresh fetch, test a variant of the URL with a changed query string, then post the clean canonical URL.
- Discord and Slack: paste the link into a test channel or a private test space. For Discord, confirm the large image appears. If it shows a thumbnail, twitter:card is the first thing to check.
- One limit to state plainly in any report: a cache refresh changes new shares. A post that already went out with the wrong card keeps that card. On Facebook the working fix for a live post is to delete it and publish it again after the refresh.

### 7. Fix broken previews by symptom

Work references/fixes.md. It covers the seven cases that account for nearly every report: no card at all, wrong image, fixed tags with a stale preview, big card on Facebook and small card on X and Discord, cropped headlines, declared and real image sizes disagreeing, and a preview that fails on one surface because the page or image is walled off from that crawler.

## Output Contract

Deliver, for each page or template handled:

- The tag block as shipped, or a diff of the tags added and changed.
- The validator output for the final page, and for the image file when one was supplied, with the exit result stated.
- The effective preview the validator resolved: card type, title, description, and image URL.
- One line per platform debugger actually checked, with what it showed, and whether a cache refresh was run.
- Any warning left standing, with the reason it was accepted.
- For a fix job, the symptom, the cause found, and the check that proved the fix.

## Operating Rules

- Never invent a platform spec. Use references/platform-specs.md, which separates published figures from working practice. If a platform has changed a layout since the check date on that file, recheck the platform documentation and the debugger before quoting a number.
- Never report a preview as fixed on validator output alone. The validator proves the page is right. A debugger or a test post proves the platform shows it.
- Never change og:url on a live page to force a refresh. It splits share counts and cached credit onto a new URL. Refresh the cache instead, and use query string variants only for testing.
- Serve the page and the image in public, over https, with no login, and do not block the crawler user agents at a CDN or firewall. A crawler that cannot fetch the page builds its preview from nothing.
- Keep tags in the server sent HTML. If the stack renders tags with client side code only, move the share tags into the server template or the static head. This is the single most common cause of previews that work in a browser test and fail in a real share.
- One page, one og:image as the default. Multiple images are valid in the protocol, and the first wins, so extra tags are a source of wrong image bugs, not a feature to use casually.
