You spent hours building your project. You share it on Twitter. And the preview looks like... nothing. Just a plain URL.
Meanwhile, that random blog post has a beautiful card with an image, title, and description.
The difference? Open Graph tags.
What Are Open Graph Tags?
Open Graph (OG) tags are HTML meta tags that control how your page appears when shared on social media.
They live in the <head> of your HTML:
<head>
<meta property="og:title" content="My Awesome Project">
<meta property="og:description" content="A tool that does cool things">
<meta property="og:image" content="https://example.com/preview.png">
<meta property="og:url" content="https://example.com">
</head>
When someone shares your link, platforms like Twitter, Facebook, LinkedIn, Slack, and Discord read these tags and render a preview card.
Why Should You Care?
Links with previews get more clicks.
Which would you click?
Option A: https://example.com/some-long-path/page
Option B: [Beautiful card with image, title, and description]
Studies show rich previews can increase click-through rates by 2-3x.
The Essential Tags
Required Tags
<!-- Title: 60-70 characters max -->
<meta property="og:title" content="Your Page Title">
<!-- Description: 155-200 characters -->
<meta property="og:description" content="A compelling description of your page">
<!-- Image: 1200x630px recommended -->
<meta property="og:image" content="https://example.com/og-image.png">
<!-- Page URL -->
<meta property="og:url" content="https://example.com/page">
<!-- Content type -->
<meta property="og:type" content="website">
Twitter-Specific Tags
Twitter uses its own tags (but falls back to OG tags):
<!-- Card type: summary, summary_large_image, app, player -->
<meta name="twitter:card" content="summary_large_image">
<!-- Optional: Your Twitter handle -->
<meta name="twitter:site" content="@yourusername">
<!-- These can duplicate OG tags, or be Twitter-specific -->
<meta name="twitter:title" content="Your Title">
<meta name="twitter:description" content="Your description">
<meta name="twitter:image" content="https://example.com/twitter-image.png">
Image Requirements
Different platforms have different preferences:
| Platform | Recommended Size | Aspect Ratio |
|---|---|---|
| 1200 × 630 px | 1.91:1 | |
| 1200 × 600 px | 2:1 | |
| 1200 × 627 px | 1.91:1 | |
| Discord | 1200 × 630 px | 1.91:1 |
Safe bet: Use 1200 × 630 px — it works well everywhere.
Image Tips
- Use
.pngor.jpg(some platforms don't support.webpfor OG images) - Keep file size under 1MB
- Include your logo or branding
- Make text readable at small sizes
- Avoid text near edges (gets cropped on some platforms)
Complete Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Primary Meta Tags -->
<title>My Project - A Tool That Does Cool Things</title>
<meta name="description" content="A comprehensive description for search engines">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://myproject.com/">
<meta property="og:title" content="My Project - A Tool That Does Cool Things">
<meta property="og:description" content="A compelling description for social sharing">
<meta property="og:image" content="https://myproject.com/og-image.png">
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="https://myproject.com/">
<meta name="twitter:title" content="My Project - A Tool That Does Cool Things">
<meta name="twitter:description" content="A compelling description for social sharing">
<meta name="twitter:image" content="https://myproject.com/og-image.png">
</head>
<body>
<!-- Your content -->
</body>
</html>
Framework-Specific Implementation
Next.js (App Router)
// app/layout.js or app/page.js
export const metadata = {
title: 'My Project',
description: 'A tool that does cool things',
openGraph: {
title: 'My Project',
description: 'A tool that does cool things',
url: 'https://myproject.com',
siteName: 'My Project',
images: [
{
url: 'https://myproject.com/og-image.png',
width: 1200,
height: 630,
},
],
type: 'website',
},
twitter: {
card: 'summary_large_image',
title: 'My Project',
description: 'A tool that does cool things',
images: ['https://myproject.com/og-image.png'],
},
};
Nuxt 3
// nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
meta: [
{ property: 'og:title', content: 'My Project' },
{ property: 'og:description', content: 'A tool that does cool things' },
{ property: 'og:image', content: 'https://myproject.com/og-image.png' },
{ name: 'twitter:card', content: 'summary_large_image' },
],
},
},
});
Astro
---
// BaseHead.astro component
const { title, description, image } = Astro.props;
---
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={image} />
<meta name="twitter:card" content="summary_large_image" />
Testing Your Tags
Before sharing, always test:
Free Debuggers
- Facebook Sharing Debugger — developers.facebook.com/tools/debug/
- Twitter Card Validator — cards-dev.twitter.com/validator
- LinkedIn Post Inspector — linkedin.com/post-inspector/
- OpenGraph.xyz — Free preview for multiple platforms
Quick Generation
Don't want to write tags manually? Use a generator:
OGTags.site — Generate all the tags you need, preview how they'll look, and copy the HTML.
Common Mistakes
1. Relative Image URLs
<!-- ❌ Won't work -->
<meta property="og:image" content="/images/og.png">
<!-- ✅ Use absolute URLs -->
<meta property="og:image" content="https://example.com/images/og.png">
2. Missing Image Dimensions
Some platforms cache better with explicit dimensions:
<meta property="og:image" content="https://example.com/og.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
3. Not Handling Cache
Social platforms cache previews aggressively. After updating your tags:
- Use the Facebook debugger to force a re-scrape
- Add a version query param:
og-image.png?v=2 - Wait (Twitter can cache for up to 7 days)
4. Same Image for Everything
Create page-specific OG images when possible:
- Blog posts: Include the title on the image
- Products: Show the product
- Profiles: Show the user's avatar
Dynamic OG Images
For sites with many pages, generate images programmatically:
Vercel OG Image Generation
// app/api/og/route.js
import { ImageResponse } from 'next/og';
export async function GET(request) {
const { searchParams } = new URL(request.url);
const title = searchParams.get('title') || 'Default Title';
return new ImageResponse(
(
<div style={{ fontSize: 64, background: 'white' }}>
{title}
</div>
),
{ width: 1200, height: 630 }
);
}
Then use: https://yoursite.com/api/og?title=Your+Page+Title
Quick Checklist
Before launching:
- [ ]
og:title— Clear, compelling, under 70 chars - [ ]
og:description— Actionable, under 200 chars - [ ]
og:image— 1200×630px, absolute URL, under 1MB - [ ]
og:url— Canonical page URL - [ ]
twitter:card— Set tosummary_large_image - [ ] Tested on Facebook, Twitter, LinkedIn debuggers
- [ ] Image loads fast (use a CDN)
Wrapping Up
OG tags take 5 minutes to add but make every share of your project look professional. Don't let bad previews undersell your work.
Need help generating OG tags? ogtags.site — preview and generate all the meta tags you need.
Top comments (0)