Overview
The Open Graph image is the unit of social distribution. Slack, Discord, X, LinkedIn, iMessage, and most LLM chat surfaces render the OG image when a URL is pasted. A page without a tuned OG image is invisible in feeds and unshareable in practice. Generate one per page, not one per site.
Ship 1200x630, keep aspect at 2:1, never below 600x315
The default Open Graph image is 1200 by 630 pixels. Most platforms downscale; few upscale.
- Default: 1200x630 (2:1).
- Minimum: 600x315. Anything smaller renders as a thumbnail or gets dropped.
- Maximum file size: 8 MB per the spec, but keep under 1 MB to avoid platform-level skips.
- Format: PNG for type, JPG for photography, WebP only as a secondary asset (some scrapers still miss it).
Declare dimensions and type so the scraper does not have to fetch the file to measure it:
<meta property="og:image" content="https://example.com/og/seo-technical.png" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="Technical SEO. The pre-publish checklist." />
<meta name="twitter:card" content="summary_large_image" />Generate one image per page, not one for the whole site
A single sitewide OG image collapses every share into a brand placeholder. Per-page generation lifts CTR in feeds by a measurable amount.
- Next.js: use the App Router
opengraph-image.tsxconvention orgenerateImageMetadatafor per-route variants. - Anywhere on Vercel:
@vercel/ogrenders JSX to PNG at the edge. - Framework-agnostic: Satori renders JSX to SVG; pair with
resvgto rasterize. - Static sites: pre-generate at build time and write to
public/og/<slug>.png.
Drive each image from the page’s frontmatter (title, summary, category) so the image cannot drift from the page.
Design the template for one-glance readability
The image is rendered at 200 pixels wide on a phone home screen. Treat that as the design target, not 1200.
- Title at 60 to 80 pixels tall, two lines maximum, ellipsize beyond that.
- One-line context underneath: category, date, or domain.
- Brand mark in a corner; do not center it.
- Contrast ratio of at least 7:1 between text and background.
- No decorative imagery behind the title unless it darkens to 30% opacity.
- One typeface, two weights. Three weights starts to look like a slide deck.
Match the visual system to the canonical site brand so a card in a feed reads as your domain at a glance.
Use absolute URLs in og:image
Scrapers fetch the meta tag in isolation; a relative path resolves against the scraper’s origin, which is wrong. Always:
<meta property="og:image" content="https://example.com/og/seo-technical.png" />Pair the absolute URL with the canonical declared on the same page (see technical). The canonical and the og:url must match, or some platforms strip the card.
Bust the cache on every regeneration
Facebook, X, LinkedIn, and Slack each cache OG metadata aggressively. A regenerated image at the same URL will not surface until the cache expires (days to weeks).
- Append a content hash to the filename or query string:
og/seo-technical.png?v=8f3a. - Update the
og:imageURL in the HTML on the same deploy. - Re-scrape proactively in the Facebook Sharing Debugger, the X Card validator, and the LinkedIn Post Inspector.
Plan for a one-cycle delay on platforms that have no manual refresh.
Debug with the platform validators, in this order
Different platforms parse different subsets of the spec. Validate against all three before declaring a card “done.”
- Meta Sharing Debugger (
https://developers.facebook.com/tools/debug/). - X Card Validator (
https://cards-dev.x.com/validator). - LinkedIn Post Inspector (
https://www.linkedin.com/post-inspector/).
If the image renders correctly on these three, Slack, Discord, and iMessage will follow.