Open Graph Generator_

Build the Open Graph and Twitter card tags for a page, then see what six different platforms will each do with the image you gave them. They do not agree, and the disagreements are invisible until the link is already posted.

The same 1200×630 picture is a full-width card on Facebook, a small square on X if one tag is missing, and no image at all on WhatsApp if the file is over about 300 KB.

toolkit.codes/og-generator
What each platform will do with that image
PlatformCardWhy
Fill in a title and an image URL
UTF-8
Ready
100% LOCAL
Input
The title, description, canonical URL and image URL for one page, plus the image's dimensions and weight.
Output
The tag block, a per-platform verdict on the image, and a list of anything that will stop a card rendering.
Processing
Generated and judged in this tab. The image is never fetched — the numbers you type are what the verdicts are computed from.
Limits
It cannot see your image. Dimensions and file size are yours to supply, and the platform rules are applied to them; nothing here downloads a URL to check.
The one nobody expects
WhatsApp drops images much over 300 KB rather than resizing them, so a card that works everywhere else arrives there as plain text.

Six renderers, one set of tags

The card type has no fallback

Nearly every tag degrades gracefully: twitter:title falls back to og:title, which falls back to the document title. twitter:card does not, because Open Graph has nothing that expresses it. Leave it out and X renders a small square thumbnail no matter how wide and well-proportioned the image is — which is why so many otherwise-correct pages have a good card everywhere except there. It is one tag, it has one useful value for most pages, and it is the one this page will not let you forget.

LinkedIn has never read a Twitter tag

Several frameworks emit twitter:* by default and treat Open Graph as optional. LinkedIn reads Open Graph and nothing else, so those pages produce no preview there at all — not a degraded one, none. Slack and Discord sit in between: they prefer Open Graph and will fall back to Twitter tags, so they are the platforms least likely to reveal that your Open Graph block is missing.

A relative image URL yields nothing, anywhere

og:image must be absolute and begin with a scheme. A path like /card.png is valid HTML, passes every linter, renders correctly in your browser, and gives a scraper nothing it can fetch — because the scraper is not on your page and has no base URL to resolve against. This is the single commonest reason a link preview has no picture, it is silent, and it survives review because the markup looks right.

The first share is the one that sticks

Facebook caches what it scraped the first time a URL was shared, and there is no expiry to wait out — if the tags were not deployed yet, that empty card is what everyone sees until somebody re-scrapes it through the Sharing Debugger. LinkedIn holds on for about a week, Slack for around half an hour, Discord for hours, WhatsApp per device and effectively forever. Scraping a URL deliberately before announcing it is a thirty-second habit that prevents the one problem you cannot fix by editing the page.

Fill it in, read the table, then paste

  1. 01Enter the title, description and canonical URL. The description is what appears under the title on every card, and it is not your meta description unless you make it one.
  2. 02Give the absolute image URL, then its real dimensions and file size in kilobytes — those two numbers are what the table is computed from.
  3. 03Read the verdict column. A row saying "none" means that platform will render a text-only card, and the reason column says which number caused it.
  4. 04Fix anything in the panel underneath, copy the block into your head element, and scrape the URL once through the platform tools before you share it.

Where the disagreement bites

Fine everywhere, blank on WhatsApp

A 1200×630 PNG exported at full quality, 900 KB.

Five platforms
large card
WhatsApp
no image at all

A square logo as the card

A 400×400 brand mark used as og:image.

Result
thumbnail beside the text
Needs
600×315 for a large card

Twitter tags only

A framework default that never emitted Open Graph.

X
renders correctly
LinkedIn
renders nothing

A card that will not update

The tags shipped after the link was first posted.

Cause
the first scrape was cached
Fix
re-scrape, do not re-edit

What each platform reads, and how long it remembers

PlatformReadsCacheRefresh
Facebookog:*Until you clear it — there is no expiry you can wait outSharing Debugger
X (Twitter)twitter:*, og:* as fallbackAbout a weekNo public tool since the Card Validator was retired
LinkedInog:*Around 7 daysPost Inspector
Slackog:*, twitter:* as fallbackAbout 30 minutesRepost after the cache expires
Discordog:*, twitter:* as fallbackHours, not minutesAppend a query string to bust it
WhatsAppog:*Per device, effectively foreverNone

Slack and Discord fall back to Twitter tags, which makes them the platforms least likely to reveal that your Open Graph block is missing. Test on LinkedIn, which will not cover for you.

The fallback chain, tag by tag

FieldConsulted in orderWhat that means
Titletwitter:titleog:title<title>Every platform falls through to og:title, so twitter:title is redundant unless the two should genuinely differ.
Descriptiontwitter:descriptionog:descriptionmeta descriptionSame chain. A card showing text you do not recognise is usually the meta description at the end of it.
Imagetwitter:imageog:imageNo further fallback. With neither, some platforms pick an image from the page and others show none — and which one they pick is not something you control.
Card typetwitter:cardNO FALLBACK, and the reason large images render small on X. Nothing in Open Graph expresses it.
Site nameog:site_nameTwitter has no equivalent; twitter:site is an @handle, which is a different thing entirely.

Because title, description and image all fall through to Open Graph, the Twitter block generated here is one tag. Repeating the other three is four more places for the copy to drift out of sync.

Habits that make cards work first time

  • Export the card image at 1200×630 and keep it under 300 KB. That single pair of numbers is the only combination that gives a large card on all six platforms.
  • Always write the image URL absolute, with the scheme. A relative path is the commonest failure here and the hardest to spot, because everything about it looks correct.
  • Set twitter:card explicitly. It is the one tag with no fallback, and leaving it out is why a good image renders small.
  • Include og:image:width and og:image:height. They let a scraper lay the card out before it has fetched the picture, which is what makes the first share render properly.
  • Scrape the URL through the Sharing Debugger and Post Inspector before you announce it. Facebook caches the first scrape with no expiry, so the empty card from before deployment is otherwise permanent.
  • Use a versioned image filename when you change the picture. Cache-busting the URL is more reliable than asking six platforms to forget what they saw.

Where link previews go wrong

A relative og:image produces no picture anywhere

The scraper is not on your page and has nothing to resolve the path against. The markup validates, the browser renders it, and every platform silently falls back to a text-only card. Absolute URLs with the scheme, always.

The first scrape is cached before your tags exist

Share a URL while the tags are still on a branch and that empty card is what Facebook serves from then on. There is no expiry. The fix is the Sharing Debugger, and the habit is to scrape deliberately before announcing rather than after complaints.

File size is a hard limit, not a hint

WhatsApp drops images much over 300 KB and does not resize them. Facebook stops at 8 MB and X at 5 MB. A card that works in five places and fails in the sixth is almost always weight, and nothing in any validator tells you.

Twitter-only tags mean no LinkedIn card

LinkedIn reads Open Graph and ignores twitter:* entirely. Several frameworks ship Twitter tags by default, so a page can look correct on X and produce nothing at all on the platform where B2B links actually get shared.

The description is not your meta description

og:description is what appears under the title on the card, and it is read in a feed rather than in a search result. Reusing the SEO description gives you a sentence written to be truncated at 155 characters by a different renderer with different priorities.

What is emitted, and what is judged

Attribute names
og:* uses property and twitter:* uses name. That is the specifications rather than a preference — RDFa defines property, the card spec was written against name — and generators that emit name for everything are quietly wrong
Twitter block
One tag: twitter:card. Title, description and image all fall back to Open Graph, so repeating them is four more values that can drift apart from the ones above
Dimensions
og:image:width and og:image:height from the numbers you supply, so a scraper can lay out the card before fetching the image
Verdicts
Computed from the dimensions and file size you enter, against each platform's minimum, its large-card threshold and its weight ceiling
No image fetch
The URL is never loaded. The site's content policy permits images from its own origin only, so a preview would fail in production while working locally — and it would disclose an unpublished URL to a third party besides
Escaping
Quotes and angle brackets in every value are escaped as entities, because a stray quote in a title silently truncates the attribute and drops the rest of the tag
Scope
Cards only. The SEO block — title length against what Google truncates, robots directives, canonical — lives on the meta tag generator
Network
None from tool code. A test sweep calls every function this page uses with fetch and XMLHttpRequest replaced by stubs that throw, so a stray request fails the build instead of shipping. Disconnect from the network and the page still works.

Questions about Open Graph tags

What size should an Open Graph image be?

1200 by 630 pixels, and under about 300 KB. The dimensions clear every platform’s large-card threshold with room, and the weight is the only figure that keeps WhatsApp in the set — it drops heavier images rather than resizing them. Anything squarer than roughly 1.91:1 gets cropped, and the crop is from the top and bottom.

Why is my link preview not showing an image?

In order of how often it is the cause: the og:image URL is relative rather than absolute; the URL was scraped and cached before the tags were deployed; the file is over a platform’s weight limit; or the image is behind authentication so the scraper gets a login page. The table above catches the second and third from the numbers you enter.

Do I need Twitter tags if I already have Open Graph?

One of them. X falls back to og:title, og:description and og:image, so those three are redundant — but twitter:card has no Open Graph equivalent, and without it your image renders as a small square instead of a full-width card. That is the whole of what this page emits in the Twitter block.

How do I refresh a cached link preview?

Through each platform’s own tool, because none of them re-scrapes on its own. Facebook has the Sharing Debugger and LinkedIn the Post Inspector; X retired its Card Validator and offers nothing; Slack expires in about half an hour on its own; Discord responds to a changed query string. Changing the image filename is the one approach that works everywhere at once.

Does og:image work with a relative path?

No, anywhere. The scraper fetches your page from outside and has no base to resolve a relative reference against, so it finds no image and renders a text-only card. Nothing warns you: the HTML is valid, your browser shows the picture, and only the preview is wrong.

What is the difference between og:description and the meta description?

The renderer and the reader. og:description sits under the title on a social card in a feed; the meta description is a candidate snippet in a search result, which Google frequently rewrites anyway. They are different lengths, different audiences and different jobs — writing one and reusing it for the other is why so many cards read like search results.

Is anything I type here sent anywhere?

The work is JavaScript running in this tab. Every function it calls is covered by a test that stubs fetch and XMLHttpRequest to throw, so a request that slipped in would break the build rather than reach a server — and you can confirm it for yourself by disconnecting and carrying on.