Open Graph is the metadata protocol that turns a URL into a rich social card on Facebook, LinkedIn, X, Slack, Discord, WhatsApp, iMessage, Telegram, and every AI chat that unfurls links. Add four <meta property="og:..." /> tags to your <head> and a page goes from a naked blue hyperlink to a 1200×630 preview (see the Open Graph cheatsheet for a copy-paste tag block) with a title, description, and image. Open Graph was published by Facebook in 2010 and remains the de-facto standard in 2026: the ogp.me specification hasn't changed, but platform rendering rules, image size expectations, and the rise of LLM-powered link unfurling have reshaped the best practices around it.
Why Does Open Graph Matter?
Open Graph is the single highest-leverage change you can make to how your URLs perform outside your own site. The cost is four lines of HTML; the upside compounds across every channel a link can be shared in.
- Click-through rate. A rich preview card lifts CTR on shared links by roughly 30–40% over a naked URL. On a link that gets 10k social impressions, that is 3–4k extra visits per post.
- First impression for free traffic. Most visitors from LinkedIn, Slack, Reddit, Discord, iMessage, and X see your OG card before they ever see your site. It is your real homepage for 60–80% of social sessions.
- Brand consistency. Without OG tags, every platform guesses — a random image from your page, a truncated
<title>, or nothing at all. With OG tags, every platform shows the exact title, image, and description you chose. - AI and LLM citation. GPTBot, ClaudeBot, PerplexityBot, and Google's AI crawlers read
og:title,og:description, andarticle:modified_timewhen choosing which pages to surface in answers. Fresh, well-described pages get cited; stale or unlabeled ones get skipped. - Indirect SEO. OG is not a Google ranking signal, but the downstream effects are: more clicks from shares → more branded search → longer sessions → stronger authority signals for the pages Google does rank.
- Share consolidation. A canonical
og:urlmakes likes, shares, and reactions aggregate to one URL instead of fragmenting across UTM and tracking variants. - It is table stakes in 2026. Missing OG tags read as neglect — the social equivalent of a broken favicon. Competitors have them; readers notice when you don't.
What Is the Open Graph Protocol?
Open Graph (OG) is a set of <meta> tags placed inside the <head> of an HTML document. Each tag uses a property="og:*" attribute instead of the usual name="...", because Open Graph is an RDFa vocabulary — a structured way to attach semantic data to a page. When a platform fetches your URL, its crawler parses these tags and uses them to render a preview card.
<meta property="og:type" content="website" />
<meta property="og:url" content="https://env.dev/guides/opengraph" />
<meta property="og:title" content="Open Graph Protocol: Complete Guide" />
<meta property="og:description" content="How to use Open Graph meta tags in 2026." />
<meta property="og:image" content="https://env.dev/og/opengraph.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="Open Graph guide cover, 1200x630" />Two critical rules: tags must be server-rendered in the initial HTML — most social crawlers do not execute JavaScript, so client-side frameworks that inject meta tags with useEffect produce empty previews. And URLs must be absolute HTTPS: every major platform drops http:// images silently.
Which Open Graph Tags Are Required?
The spec defines four required properties. Everything else is optional but compounding — the more you add, the better every platform renders your card.
| Tag | Required? | Purpose | Notes |
|---|---|---|---|
| og:title | Yes | Preview headline | Keep ≤ 60 chars desktop, 40 mobile; no brand suffix |
| og:type | Yes | Content category | website, article, video.movie, music.song, profile, book |
| og:image | Yes | Preview image URL | Absolute HTTPS, JPG/PNG, 1200×630, ≤ 5 MB |
| og:url | Yes | Canonical URL | Strip query params; this is where shares aggregate |
| og:description | Recommended | Preview body | 2–4 sentences, ≤ 200 chars |
| og:site_name | Recommended | Site identity | Shown above the card on most platforms |
| og:locale | Optional | Primary language | e.g. en_US; add og:locale:alternate for others |
| og:image:width | Recommended | Image width in px | Lets crawlers render on first share |
| og:image:height | Recommended | Image height in px | Prevents async re-fetch delays |
| og:image:alt | Recommended | Image alt text | Screen readers + AI crawler context |
The og:type value unlocks an extra namespace of properties. For articles, add article:published_time, article:modified_time, article:author, and article:tag. These feed directly into LinkedIn's freshness signal and are read by LLM crawlers when citing content.
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2026-04-22T09:00:00Z" />
<meta property="article:modified_time" content="2026-04-22T09:00:00Z" />
<meta property="article:author" content="https://env.dev/about" />
<meta property="article:section" content="Web Standards" />
<meta property="article:tag" content="opengraph" />
<meta property="article:tag" content="seo" />What Are the Correct OG Image Dimensions in 2026?
One image at 1200×630 pixels (1.91:1) satisfies every major platform — Facebook, LinkedIn, Discord, Slack, WhatsApp, iMessage, and Telegram all render it cleanly. X/Twitter prefers 1200×675 (16:9) but crops 1200×630 with minimal loss. Going below 600×315 forces a fallback to the small summary card on most networks. For a per-platform breakdown of every aspect ratio, file format, and edge case, see the OG image sizes reference.
| Platform | Recommended size | Aspect ratio | Notes |
|---|---|---|---|
| 1200 × 630 | 1.91:1 | Minimum 600×315; max 8 MB | |
| 1200 × 627 | 1.91:1 | Cache lives ~7 days; hard to force refresh | |
| X / Twitter | 1200 × 675 | 16:9 | Works with 1200×630; falls back to og:image |
| Discord | 1200 × 630 | 1.91:1 | Max 8 MB; supports GIF and WebP |
| Slack | 1200 × 630 | 1.91:1 | Honors og:image:alt for screen readers |
| 1200 × 630 | 1.91:1 | ≤ 300 KB or it may be dropped on mobile | |
| iMessage | 1200 × 630 | 1.91:1 | Uses Apple Link Presentation; respects og:image |
| Telegram | 1200 × 630 | 1.91:1 | Caches aggressively; append ?v=2 to URL to bust |
File Format and Size Rules
- JPG or PNG — universally supported. PNG for logos and text, JPG for photos.
- WebP — works on Facebook, X, LinkedIn, Slack, Discord, but not on every older crawler. Safe as a primary, risky as the only format.
- AVIF — only Facebook renders it reliably in 2026. Don't use it as your og:image.
- GIF — shows the first frame as a static image on most platforms. Only Discord animates it.
- Target file size ≤ 300 KB for WhatsApp compatibility; hard limit is 8 MB on Facebook and Discord.
How Do X (Twitter) Cards Work With Open Graph?
X/Twitter runs its own Twitter Cards protocol, but the crawler falls back to Open Graph when a Twitter-specific tag is missing. That means you only need one extra tag to opt into the large image layout: twitter:card. Everything else can reuse your OG tags.
<!-- OpenGraph tags (shared with all other platforms) -->
<meta property="og:title" content="Open Graph Protocol: Complete Guide" />
<meta property="og:description" content="How to use Open Graph meta tags in 2026." />
<meta property="og:image" content="https://env.dev/og/opengraph.png" />
<meta property="og:url" content="https://env.dev/guides/opengraph" />
<!-- Twitter-specific additions -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@envdotdev" />
<meta name="twitter:creator" content="@envdotdev" />
<!-- twitter:title, twitter:description, twitter:image are all optional -->
<!-- If omitted, X will fall back to og:title / og:description / og:image -->Note the attribute difference: Twitter Cards use name="twitter:..." (standard HTML meta attribute), while Open Graph uses property="og:..." (RDFa). Both are valid HTML5 and both work in the same <head>.
| twitter:card value | Layout | When to use |
|---|---|---|
| summary | Small square thumbnail + text | Short posts, profile links |
| summary_large_image | Full-width 1.91:1 image + text | Blog posts, articles, marketing pages (default choice) |
| app | App Store / Play Store card | Mobile app landing pages |
| player | Embedded video / audio player | Video content with a playable stream |
How Do You Generate Dynamic OG Images?
A static site-wide image is fine for a landing page but looks amateur on a blog. Every blog post sharing the homepage image is one of the most visible signals of poor Open Graph implementation. Dynamic OG images — generated on demand per URL — are the 2026 default for any content site. The two common approaches:
1. Runtime image generation (JSX → PNG)
Vercel's @vercel/og library (bundled into next/og) uses Satori to render a JSX tree to SVG, then Resvg to rasterize to PNG — all inside an edge function. The output is cached at the CDN, so the second render is essentially free.
import { ImageResponse } from 'next/og';
export const runtime = 'edge';
export async function GET(req: Request, { params }: { params: { slug: string } }) {
const post = await getPost(params.slug);
return new ImageResponse(
(
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', height: '100%',
background: '#0b1020', color: 'white', padding: 80, justifyContent: 'space-between' }}>
<div style={{ fontSize: 72, fontWeight: 700, lineHeight: 1.1 }}>{post.title}</div>
<div style={{ fontSize: 28, opacity: 0.7 }}>env.dev · {post.date}</div>
</div>
),
{ width: 1200, height: 630 },
);
}Then point og:image at the route: <meta property="og:image" content="https://env.dev/og/my-post" />. Constraints: only flexbox layouts, max 500 KB bundle including fonts, and only .ttf / .otf / .woff fonts.
2. Build-time prerendering
For static sites, render images at build with Playwright or Satori and commit the PNGs. Zero runtime cost, but every content change triggers a rebuild. Works well when content volume is low or the build is already fast.
import satori from 'satori';
import { Resvg } from '@resvg/resvg-js';
import { writeFile } from 'node:fs/promises';
for (const post of await loadAllPosts()) {
const svg = await satori(
{ type: 'div', props: { style: { /* ... */ }, children: post.title } },
{ width: 1200, height: 630, fonts: [/* ttf buffer */] },
);
const png = new Resvg(svg).render().asPng();
await writeFile(`public/og/${post.slug}.png`, png);
}How Do Open Graph Tags Affect SEO?
Open Graph tags are not a direct Google ranking signal — Google uses its own <title>, <meta name="description">, and structured data. The SEO impact is indirect but measurable:
- Better previews lift click-through rate on shared links — industry benchmarks put the uplift at +30–40% vs. a naked URL.
- More clicks → more branded search volume and return visits → signals Google associates with authority.
- LinkedIn, Reddit, and Hacker News all strip tracking parameters differently. A canonical
og:urlmakes shares aggregate to one URL instead of fragmenting social proof across UTM variants. - AI crawlers (GPTBot, ClaudeBot, PerplexityBot) read
article:published_timeandog:descriptionwhen deciding whether to cite a page. Content older than three months without a refreshedarticle:modified_timesees meaningful AI citation drops.
Open Graph does not replace JSON-LD structured data. The two complement each other: OG drives the social card, Schema.org Article drives the Google rich result. Set both with matching titles, descriptions, and dates.
<meta property="og:title" content="Open Graph Protocol: Complete Guide" />
<meta property="og:description" content="How to use Open Graph meta tags in 2026." />
<meta property="article:published_time" content="2026-04-22T09:00:00Z" />
<meta property="article:modified_time" content="2026-04-22T09:00:00Z" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Open Graph Protocol: Complete Guide",
"description": "How to use Open Graph meta tags in 2026.",
"datePublished": "2026-04-22",
"dateModified": "2026-04-22",
"author": { "@type": "Organization", "name": "env.dev" }
}
</script>How Do You Debug and Monitor Open Graph Tags?
Every platform caches previews — typically 24–72 hours on Facebook, up to 7 days on LinkedIn, and indefinitely on Slack and Telegram until a user-side clear. Debugging means two things: inspecting what a crawler sees, and forcing a refresh after you change a tag. If your image is missing entirely after a deploy, walk through the "OG image not showing" checklist before blaming the cache.
Facebook Sharing Debugger
Parses your URL, shows the exact OG tags seen, and has a "Scrape Again" button that bumps the cache immediately.
developers.facebook.com/tools/debugLinkedIn Post Inspector
Previews the LinkedIn card. Hitting Inspect bumps the cache, but LinkedIn may still serve the old image for up to a week.
linkedin.com/post-inspectorX Card validator
Deprecated in 2023. Use opengraph.xyz, microlink.io, or a throwaway post in your drafts to preview.
opengraph.xyzSlack / Discord / WhatsApp
No official debugger. Send the URL to yourself in a private channel — but remember these platforms cache aggressively.
self-testcurl -A "facebookexternalhit"
See exactly what a crawler sees. Swap the user-agent for Twitterbot, LinkedInBot, Slackbot-LinkExpanding, WhatsApp, TelegramBot.
CLICache-buster query
Append ?v=2 to og:url and og:image when you genuinely change content — platforms treat new query strings as new URLs.
manual# Facebook
curl -sL -A "facebookexternalhit/1.1" https://env.dev/guides/opengraph \
| grep -Eo '<meta (property|name)="(og|twitter):[^"]+" content="[^"]+"'
# X / Twitter
curl -sL -A "Twitterbot/1.0" https://env.dev/guides/opengraph | grep 'twitter:'
# LinkedIn
curl -sL -A "LinkedInBot/1.0 (compatible; Mozilla/5.0; Apache-HttpClient +http://www.linkedin.com)" \
https://env.dev/guides/opengraph | grep 'og:'
# Slack
curl -sL -A "Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)" \
https://env.dev/guides/opengraph | grep 'og:'For production monitoring, snapshot your OG tags in a scheduled job and alert when og:image returns a non-200 or the tag shape drifts. A single missing tag on a popular page can cost thousands of impressions per day of social traffic.
Tools to Validate Your Setup
- opengraph.xyz — paste any URL and get a side-by-side preview of how it renders on Facebook, X, LinkedIn, Discord, Slack, and more. Useful for a quick sanity check before you ship.
What Are Common OG Mistakes and How to Fix Them?
| Mistake | Symptom | Fix |
|---|---|---|
| Tags injected by JS | Preview is blank or shows the fallback homepage card | Render tags in SSR/SSG initial HTML; never in useEffect |
| Relative image URL | No image in preview on any platform | Always use absolute https:// URL for og:image |
| Same og:image on every page | Homepage image appears on every blog post share | Generate dynamic images per URL (see section above) |
| Missing og:image:width / height | Image shows on second share but not first | Hardcode width/height so the crawler skips async parsing |
| Image > 300 KB | WhatsApp drops the preview entirely on mobile | Optimize to ≤ 300 KB; prefer JPG over PNG for photos |
| Cached old preview after edit | New title/image shows in HTML but not on Facebook | Use Sharing Debugger "Scrape Again" or append ?v=2 to og:url |
| Duplicate title/description tags | Random tag wins; preview is inconsistent across platforms | Keep one og:* tag per property; audit with curl or a debugger |
| Missing twitter:card | X shows a tiny summary card instead of the large image | Add <meta name="twitter:card" content="summary_large_image"> |
| og:url differs from canonical | Shares aggregate across multiple URLs; social counters fragment | og:url must equal <link rel="canonical"> |
| HTTP image instead of HTTPS | Preview image never renders on modern platforms | Serve OG images over HTTPS; no exceptions |
How Do Open Graph Tags Look in Different Frameworks?
Every modern meta-framework has a first-class API for OG tags — the key is that they render into the initial SSR HTML, not the client bundle.
// app/guides/opengraph/page.tsx
export const metadata = {
title: 'Open Graph Protocol: Complete Guide',
description: 'How to use Open Graph meta tags in 2026.',
openGraph: {
type: 'article',
url: 'https://env.dev/guides/opengraph',
title: 'Open Graph Protocol: Complete Guide',
description: 'How to use Open Graph meta tags in 2026.',
images: [{ url: 'https://env.dev/og/opengraph', width: 1200, height: 630, alt: 'Guide cover' }],
publishedTime: '2026-04-22T09:00:00Z',
modifiedTime: '2026-04-22T09:00:00Z',
},
twitter: { card: 'summary_large_image', site: '@envdotdev' },
};// apps/web/src/routes/guides/opengraph.tsx
export const Route = createFileRoute('/guides/opengraph')({
head: () => ({
meta: [
{ title: 'Open Graph Protocol: Complete Guide' },
{ name: 'description', content: 'How to use Open Graph meta tags in 2026.' },
{ property: 'og:type', content: 'article' },
{ property: 'og:url', content: 'https://env.dev/guides/opengraph' },
{ property: 'og:title', content: 'Open Graph Protocol: Complete Guide' },
{ property: 'og:description', content: 'How to use Open Graph meta tags in 2026.' },
{ property: 'og:image', content: 'https://env.dev/og/opengraph.png' },
{ property: 'og:image:width', content: '1200' },
{ property: 'og:image:height', content: '630' },
{ name: 'twitter:card', content: 'summary_large_image' },
],
}),
component: OpengraphRoute,
});---
// src/layouts/Base.astro
const { title, description, image = '/og/default.png', type = 'website' } = Astro.props;
const url = new URL(Astro.url.pathname, Astro.site).toString();
const ogImage = new URL(image, Astro.site).toString();
---
<head>
<title>{title}</title>
<meta name="description" content={description} />
<meta property="og:type" content={type} />
<meta property="og:url" content={url} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={ogImage} />
<meta name="twitter:card" content="summary_large_image" />
</head>References
- The Open Graph Protocol (ogp.me) — the original and canonical specification, including all og:type namespaces and structured properties
- Facebook Sharing for Webmasters — Meta's official guide to Open Graph tags, crawler behavior, and caching rules
- Facebook Sharing Debugger — inspect what Facebook's crawler sees and force a cache refresh with Scrape Again
- LinkedIn Post Inspector — preview and debug how your page renders when shared on LinkedIn
- X Cards markup reference — all twitter:card values, required fields, and Open Graph fallback behavior
- Vercel @vercel/og documentation — runtime OG image generation with JSX, ImageResponse, and edge caching
- Satori — JSX to SVG renderer — the engine behind @vercel/og; useful for build-time OG image generation
- Schema.org Article — the structured-data counterpart to og:type="article", used for Google rich results
- Ahrefs — Open Graph Meta Tags — practical tag-by-tag walkthrough with screenshots of real social previews
- Open Graph cheatsheet (env.dev) — every required and recommended tag in one printable reference
Generate a complete OG + Twitter Card tag block — including image dimensions, locale, and article metadata — with the env.dev meta-tag generator. Paste the output into your <head> and ship.