og:image: Nail the 1200x630 or Lose the Click
You know the failure mode: you paste a link into Slack or iMessage and the preview comes up as a grey box with a chopped-off URL and no image. That’s a broken og:image. It’s one of those things that’s invisible until the exact moment it’s embarrassing.
The fix is almost always the same handful of meta tags plus one specific image size. This is the checklist I run on every site before a link goes out, and the mistakes I keep seeing.
The number: 1200 x 630
Ratio is 1.91:1, and 1200x630 is the smallest size that stays crisp on retina and works everywhere. Go below 600x315 and Facebook/LinkedIn drop you to a tiny thumbnail instead of the big card.
The tags that actually matter
<meta property="og:image" content="https://example.com/og/launch.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:title" content="Spring Launch: 40% Faster Onboarding" />
<meta property="og:url" content="https://example.com/spring-launch" />
<meta name="twitter:card" content="summary_large_image" />
Three ways people shoot themselves in the foot, every single time:
property, notname. Open Graph usesproperty=. Get it wrong and the tag does nothing, silently.- Absolute
https://URL. A relative/og/launch.pngworks in your browser and dies in every unfurler. This is the #1 bug. - Declare width + height. It makes the card render instantly on the first share instead of flashing a blank box while the scraper re-measures. The first share is usually the one that gets seen, so you want it right immediately.
And twitter:card = summary_large_image is what gets you the big banner on X instead of a sad little square.
Design for the crop, not for Figma
Everyone eats the same 1200x630, but they crop differently, and WhatsApp/iMessage centre-crop hard. So: keep your logo, headline and CTA inside a centred ~1080x540 safe zone. Treat the outer edge as bleed that might vanish.
And make the text BIG. That 28px headline that looks fine in your design tool is mush when Slack renders the card at 360px wide. If it’s not legible at thumbnail size, it’s not legible.
PNG for text/logos, JPG for photos. No SVG, no WebP (scrapers choke). Keep it under ~1MB or WhatsApp may just refuse to fetch it.
The trap that actually ruins launch day: caching
Platforms scrape once and cache for days. So the classic disaster: you ship a placeholder, it gets shared internally, the bad card gets cached, and your big external announcement shows garbage to everyone with no refresh button.
The fix is discipline: get the image right before the URL is ever shared. Then force a re-scrape:
- Facebook/WhatsApp → Sharing Debugger, hit “Scrape Again”
- LinkedIn → Post Inspector
- Slack → no tool; slap a
?v=2on the URL to force a fresh unfurl
One more marketing gotcha: UTM params don’t change the card: same page, same image. Want a different card per channel? You need a different page.
Doing it at scale
Hand-cropping a card per landing page doesn’t scale. Generate them: @vercel/og (satori) turns JSX into a 1200x630 PNG at the edge, Cloudinary stamps text over a base image via URL params, and for a static site you pre-render one PNG per page at build time. Unique on-brand card, zero manual design, never a grey box again.
Ship-check
- Exactly 1200x630
-
og:imageis an absolutehttps://URL - width + height declared,
twitter:card=summary_large_image - logo/headline/CTA inside the centred safe zone, text legible at thumbnail size
- PNG/JPG, under ~1MB
- re-scraped fresh in the FB Debugger before the first real share
Six checks, none of them hard, and skipping any one is how you end up with the grey box. To create problemz for solutions, right? This one’s trivial once you know the number. 1200x630.