You ship a new page. Someone shares it on Slack. Instead of a rich preview card, they see... nothing. Or worse — the wrong image, a truncated title, and a description pulled from your cookie banner.
Open Graph tags control how your pages look when shared. Get them wrong and your links look broken. Get them right and every share becomes a mini billboard.
This guide covers everything: what each tag does, the mistakes I see on most sites, and how to debug them.
What is Open Graph?
Open Graph (OG) is a protocol created by Facebook in 2010. It lets you define how a URL appears when shared on social platforms, chat apps, and anywhere that generates link previews.
When someone pastes your URL in Slack, Discord, Twitter, LinkedIn, iMessage, or WhatsApp, those platforms fetch your page and look for OG tags in the <head>. If they find them, they render a rich preview card. If not, they guess — and guessing rarely goes well.
The Essential Tags
og:title
<meta property="og:title" content="How to Deploy a Node.js App to Production" />
This is the headline of your preview card. Keep it under 60 characters or it gets truncated.
Common mistake: Using the same <title> tag that includes your site name. Your HTML title might be "How to Deploy Node.js | MyBlog" but your og:title should just be "How to Deploy a Node.js App to Production" — the site name goes in og:site_name.
og:description
<meta property="og:description" content="A step-by-step guide to deploying Node.js apps with zero downtime, covering PM2, Nginx, and SSL setup." />
Aim for 120-160 characters. This is your elevator pitch.
Common mistake: Leaving this empty and letting platforms pull text from your page. They'll grab the first text they find — which might be your nav menu, cookie consent, or footer.
og:image
<meta property="og:image" content="https://example.com/images/deploy-guide-og.png" />
This is the most important tag. A link preview without an image gets significantly less engagement.
Rules:
-
Must be an absolute URL (not
/images/og.png) - Recommended size: 1200x630px (1.91:1 ratio)
- Minimum: 600x315px
- Max file size: ~5MB (but keep it under 1MB for fast loading)
- Use PNG or JPG (some platforms don't support WebP in OG images)
Common mistakes:
- Using a relative URL — platforms can't resolve
/images/og.png - Using your logo as the OG image — it looks tiny and generic in a preview card
- Using an image that's too small — Facebook requires at least 200x200px
- Using a CDN URL that requires authentication or returns 403
og:url
<meta property="og:url" content="https://example.com/blog/deploy-nodejs" />
The canonical URL for this page. Use this to consolidate shares across different URL variations (with/without trailing slash, with tracking params, etc.).
og:type
<meta property="og:type" content="article" />
Common values:
-
website— for homepages and general pages -
article— for blog posts and news -
product— for e-commerce -
profile— for user profiles
Most sites should use website for the homepage and article for blog posts.
og:site_name
<meta property="og:site_name" content="MyBlog" />
Your brand name. Shown as secondary text in preview cards.
Twitter Card Tags
Twitter (X) uses its own meta tags, but falls back to OG tags if Twitter-specific ones are missing.
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="How to Deploy a Node.js App" />
<meta name="twitter:description" content="Step-by-step guide with PM2, Nginx, and SSL." />
<meta name="twitter:image" content="https://example.com/images/deploy-guide-og.png" />
The twitter:card value matters:
-
summary— small square image on the left, text on the right -
summary_large_image— large image on top, text below (this is what you usually want)
Pro tip: If you set OG tags, you only need to add twitter:card. Twitter will use your OG title, description, and image as fallbacks.
<!-- Minimum Twitter setup if you already have OG tags -->
<meta name="twitter:card" content="summary_large_image" />
The Complete Template
Copy this into every page and fill in the values:
<!-- Open Graph -->
<meta property="og:title" content="Page Title Here" />
<meta property="og:description" content="A concise description under 160 chars." />
<meta property="og:image" content="https://example.com/images/page-og.png" />
<meta property="og:url" content="https://example.com/page" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="YourSiteName" />
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image" />
<!-- Standard HTML (don't skip these) -->
<title>Page Title Here | YourSiteName</title>
<meta name="description" content="A concise description under 160 chars." />
<link rel="canonical" href="https://example.com/page" />
How Each Platform Parses Your Tags
Different platforms handle OG tags differently:
| Platform | Reads OG? | Reads Twitter Cards? | Image Size | Cache Duration |
|---|---|---|---|---|
| Yes | No | 1200x630 | ~24 hours | |
| Twitter/X | Fallback | Yes (preferred) | 1200x628 | ~7 days |
| Yes | No | 1200x627 | ~7 days | |
| Slack | Yes | Fallback | 1200x630 | Varies |
| Discord | Yes | Fallback | Any | ~minutes |
| iMessage | Yes | No | 1200x630 | ~24 hours |
| Yes | No | 600x315+ | ~24 hours | |
| Telegram | Yes | No | Any | ~minutes |
Key takeaway: If you set OG tags + twitter:card, you're covered everywhere.
Common Mistakes I See on Production Sites
1. Missing og:image
About 30-40% of pages I've tested have no og:image. Their links show up as plain text blocks in chat apps. Adding an image can increase click-through rates by 2-3x.
2. Relative image URLs
<!-- WRONG -->
<meta property="og:image" content="/images/og.png" />
<!-- RIGHT -->
<meta property="og:image" content="https://example.com/images/og.png" />
When Facebook's crawler sees /images/og.png, it doesn't know your domain. Always use absolute URLs.
3. Using the site logo as og:image
Your 200x200 logo looks terrible as a preview card image. Create a proper 1200x630 image for each page, or at least have a good default.
4. Description pulled from page content
If you don't set og:description, platforms will grab whatever text they find first. I've seen previews showing:
- Cookie consent banners
- Navigation menus
- "Loading..." placeholder text
- JavaScript error messages
5. Not testing after deployment
You deploy a new page, someone shares it, and the preview is broken. Always test your OG tags before announcing a launch.
How to Test Your OG Tags
Official Debuggers
- Facebook: Sharing Debugger — paste URL, see preview, clear cache
- Twitter: Card Validator — preview your Twitter card
- LinkedIn: Post Inspector — check LinkedIn previews
API-Based Testing
If you need to check OG tags programmatically (e.g., in a CI pipeline or monitoring tool), you can use a metadata extraction API:
# Example: extract OG tags from any URL
curl "https://linkpeek-api.linkpeek.workers.dev/v1/demo?url=https://github.com"
This returns the parsed title, description, image, and favicon — useful for verifying your tags are correct without opening each platform's debugger manually.
Browser Extensions
- Open Graph Preview (Chrome) — see OG tags on any page
- Meta SEO Inspector — shows all meta tags in a panel
DIY with curl
curl -s https://example.com | grep -i 'og:' | head -10
Quick and dirty, but works for a spot check.
OG Tags for SPAs (React, Next.js, Vue)
Single-page apps are the #1 source of broken OG tags. Here's why: crawlers don't execute JavaScript. If your OG tags are set client-side, crawlers see an empty <head>.
Solutions
Next.js — use the built-in <Head> component or Metadata API:
// app/page.tsx (App Router)
export const metadata = {
openGraph: {
title: 'My Page',
description: 'Page description',
images: ['https://example.com/og.png'],
},
};
Nuxt.js — use useHead:
useHead({
meta: [
{ property: 'og:title', content: 'My Page' },
{ property: 'og:image', content: 'https://example.com/og.png' },
],
});
Plain React SPA — you need SSR or prerendering. Options:
- Use
react-helmetwith a prerendering service - Switch to Next.js or Remix
- Use a serverless function to serve the HTML shell with OG tags
Dynamic OG Images
The best OG images are generated dynamically — they include the page title, author, date, or other dynamic content.
Popular approaches:
-
Vercel OG (
@vercel/og) — generates images at the edge using JSX - Satori — converts HTML/CSS to SVG (what Vercel OG uses under the hood)
- Puppeteer/Playwright — screenshot an HTML template
- Canvas API — programmatic image generation
Example with Vercel OG:
import { ImageResponse } from '@vercel/og';
export async function GET(request) {
const { searchParams } = new URL(request.url);
const title = searchParams.get('title') || 'My Site';
return new ImageResponse(
<div style={{ fontSize: 48, background: 'white', width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
{title}
</div>,
{ width: 1200, height: 630 }
);
}
Checklist
Before shipping any page:
- [ ]
og:titleset and under 60 characters - [ ]
og:descriptionset and 120-160 characters - [ ]
og:imageis an absolute URL, 1200x630px, under 1MB - [ ]
og:urlmatches your canonical URL - [ ]
og:typeis set (websiteorarticle) - [ ]
twitter:cardis set tosummary_large_image - [ ] Tested on Facebook Sharing Debugger
- [ ] Standard
<title>and<meta description>also set - [ ] OG tags are server-rendered (not client-side only)
If you found this useful, I write about web dev and APIs regularly. Follow for more.
Top comments (0)