A friend launched a product page on a Tuesday, posted the link to Twitter on Wednesday, and watched the card come up blank. No title, no description, a broken image icon where the hero shot should have been. Three hundred retweets later, the URL still looked unclicked. He spent Thursday morning in a panic pasting the link into Slack, WhatsApp, and LinkedIn to confirm the same blank card everywhere, convinced the site was broken. The site was fine. The <head> was missing tags. The open graph preview is what every platform reads before a human ever does, and his was empty.
This is the debugging guide I wish I’d had handy that morning: which tags matter, what breaks them, and the order to check things in when a card comes up wrong.
Why previews break
When you paste a URL into Twitter, Slack, LinkedIn, iMessage, or Discord, that platform’s crawler fetches the page, reads the <head>, and renders a card from what it finds. The crawler is not a browser. It does not run JavaScript in most cases, it does not wait for your SPA to hydrate, and it does not parse your beautifully designed hero section. It reads HTML. If the tags are missing, relative, or pointing at a redirect, you get a blank card or a stale one.
The cards also get cached. Once Facebook has fetched your URL and built a preview, it will not re-fetch for roughly 30 days, even if you fix the tags. Twitter caches aggressively too. So a broken card on launch day is not a five-minute fix; it is a fix plus a cache invalidation plus a re-check. That is why you debug previews before you ship the link, not after.
The OG tags that matter
Open Graph is a protocol from Facebook, now governed by ogp.me. A platform-compliant page declares a small set of <meta> tags in its <head>, and the crawler reads them. The minimum useful set:
<meta property="og:title" content="Acme — Stripe-powered invoicing for freelancers" />
<meta property="og:description" content="Send invoices in under a minute. Track payments, send reminders, and reconcile with your bank automatically." />
<meta property="og:image" content="https://acme.com/og/invoices.png" />
<meta property="og:url" content="https://acme.com/invoices" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Acme" />
That is the floor. og:title is the headline of the card. og:description is the one or two lines under it. og:image is the thumbnail. og:url is the canonical URL you want the platform to treat as authoritative, which matters when the same content is reachable from multiple paths. og:type is almost always website for marketing pages; article is for blog posts and news, and article unlocks extra tags like article:published_time and article:author.
One tag that gets skipped and shouldn’t: og:site_name. It lets the platform render “from Acme” beside the card, which helps recognition when the card is screenshotted and reposted without context.
Image dimensions and aspect ratios
The image is where most previews fall apart. Each platform has its own aspect ratio and its own minimum size, and an image that works on one will crop awkwardly on another.
For Open Graph consumers (Facebook, LinkedIn, Slack, most others), the safe target is 1200×630 pixels, a 1.91:1 ratio. Below 1200×600 you risk tiny thumbnails; below 200×200 some platforms refuse to render the image at all. Keep the file under 8 MB and prefer PNG or JPEG.
Twitter’s summary_large_image card uses a slightly different ratio: 1200×600, a clean 2:1. If you only have one asset, design it on a 1200×630 canvas and keep the top and bottom 15 pixels as safe padding so Twitter’s crop does not cut anything important.
Two image rules that bite people:
- The
og:imageURL must be absolute and https. A path like/static/og/cover.pngrenders on your site but resolves to nothing inside the crawler.http://URLs get downgraded or rejected by several platforms. - Declare dimensions when you can.
og:image:widthandog:image:heightlet the crawler lay the card out before the image downloads, avoiding layout jumps:
<meta property="og:image" content="https://acme.com/og/invoices.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="Screenshot of the Acme invoicing dashboard" />
Twitter Card types and the OG relationship
Twitter runs its own protocol on top of OG. You declare a card type with twitter:card, then either let the twitter: tags fall back to your og: tags or override them per platform.
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Acme — Stripe-powered invoicing for freelancers" />
<meta name="twitter:description" content="Send invoices in under a minute." />
<meta name="twitter:image" content="https://acme.com/og/invoices.png" />
The summary card is a small square thumbnail with text beside it, used for links where the image is incidental. The summary_large_image card is the big below-the-fold image, used when the image is the headline. Pick one and commit; do not mix them per page without reason.
The relationship between the two namespaces is documented in X’s Card docs: if twitter:title, twitter:description, or twitter:image are missing, Twitter falls back to the matching og: value. So the practical approach is to ship a complete OG set, add twitter:card on top, and only write the twitter: overrides when you need Twitter to differ from everyone else.
Common bugs
After years of debugging these cards, the same handful of mistakes account for almost every broken preview.
Relative image URLs. <meta property="og:image" content="/og/cover.png"> works in a browser, because the browser has a base URL. The crawler does not. It will request literally /og/cover.png against nothing, fail, and render a card with no image. Always prefix the full origin.
http image URLs. Even if your site redirects http to https, the crawler often follows the redirect into a cache failure. Serve the image on https from the start, and put the https URL directly in the tag.
Missing dimensions. Without og:image:width and og:image:height, some crawlers download the image to learn its size before rendering the card. On a slow CDN this doubles the preview’s time to first paint, and on a flaky connection the card may render with a blank area where the image would go.
Multiple conflicting og:image tags. CMSes and SEO plugins sometimes emit two or three og:image tags, one from the post thumbnail and one from a site-wide default. Crawlers pick one, often the wrong one. Search your rendered HTML for og:image and confirm there is exactly one (or a deliberate ordered list if you intend to provide multiple fallbacks).
Aggressive platform caching. Facebook’s Sharing Debugger caches a preview for about 30 days. Fixing the tags does not refresh the card on its own. You have to paste the URL into the debugger and click “Scrape Again” to force a re-fetch. X’s old Card Validator at cards-dev.twitter.com/validator is no longer maintained and no longer renders working previews, so for Twitter/X cards use the Open Graph Preview tool or a third-party validator to sanity-check the rendered tags.
The debug workflow
Run this in order whenever a card comes up wrong, and ideally once before every launch.
Start with the Open Graph Preview tool. Paste your URL. It fetches the page the same way a crawler does, parses the <head>, and shows you exactly which tags it found and what the rendered card will look like. This catches 80 percent of issues in under a minute: missing tags, relative URLs, broken images. If the preview here is correct, the bug is downstream in the platform cache, not your page.
If the OG tags look right but the platform still shows a stale card, go to Facebook’s Sharing Debugger. Paste the URL. The debugger reports every tag it found, warnings for missing or malformed values, and the rendered preview as Facebook sees it. Click “Scrape Again” until the preview matches what you expect; that action is what flushes the 30-day cache.
For Twitter/X specifically, note that X’s official Card Validator at cards-dev.twitter.com/validator has been deprecated and no longer renders working previews (it shows “No information is available for this page”). To sanity-check a card before sharing, re-run the URL through the Open Graph Preview tool or a third-party validator; those read the same <head> tags X’s crawler reads. If the tags look right there but the card still renders wrong in the timeline, it is a per-user cache issue that resolves itself within hours.
One more pass worth doing: run the page through the Meta Tag Checker to confirm the <head> is coherent end to end. This catches conflicts between OG tags and the canonical link, duplicate tags emitted by a plugin, and description or title lengths that will truncate badly.
FAQ
Why is my Open Graph image not showing up on Facebook?
The URL is almost certainly relative, http, or redirected. Facebook’s crawler needs an absolute https URL that returns a 200 with an image content type. Check the rendered og:image tag in your page source, paste the URL into the Sharing Debugger, and click “Scrape Again” to clear the 30-day cache after fixing the tag.
Do I need both og: and twitter: tags?
You need the OG set, plus twitter:card. Twitter falls back to og:title, og:description, and og:image when the matching twitter: tags are absent, so a complete OG set plus a single twitter:card declaration is usually enough. Add explicit twitter: overrides only when Twitter should render something different from the other platforms.
What size should an Open Graph image be?
1200×630 pixels covers Facebook, LinkedIn, Slack, and most other OG consumers. Twitter’s summary_large_image card prefers 1200×600. Design on a 1200×630 canvas and keep the top and bottom 15 pixels as safe area so Twitter’s tighter crop does not cut anything important.
How often do platforms re-fetch my page?
Facebook caches for about 30 days and only re-fetches when you force it via the Sharing Debugger’s “Scrape Again” button. Twitter re-fetches when you submit in the Card Validator and again when a new user shares the link. Slack and Discord re-fetch on each share. For everything else, assume stale and force a refresh manually.
Fix it before users see it
A blank link preview costs you the click. Open your page in the Open Graph Preview tool right now, read the tags it returns, and fix whatever is missing or malformed before you share the URL anywhere.