DEV Community

eatyou eatyou
eatyou eatyou

Posted on

The Complete Guide to Open Graph Tags — What Most Developers Get Wrong

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" />
Enter fullscreen mode Exit fullscreen mode

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." />
Enter fullscreen mode Exit fullscreen mode

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" />
Enter fullscreen mode Exit fullscreen mode

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:

  1. Using a relative URL — platforms can't resolve /images/og.png
  2. Using your logo as the OG image — it looks tiny and generic in a preview card
  3. Using an image that's too small — Facebook requires at least 200x200px
  4. Using a CDN URL that requires authentication or returns 403

og:url

<meta property="og:url" content="https://example.com/blog/deploy-nodejs" />
Enter fullscreen mode Exit fullscreen mode

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" />
Enter fullscreen mode Exit fullscreen mode

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" />
Enter fullscreen mode Exit fullscreen mode

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" />
Enter fullscreen mode Exit fullscreen mode

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" />
Enter fullscreen mode Exit fullscreen mode

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" />
Enter fullscreen mode Exit fullscreen mode

How Each Platform Parses Your Tags

Different platforms handle OG tags differently:

Platform Reads OG? Reads Twitter Cards? Image Size Cache Duration
Facebook Yes No 1200x630 ~24 hours
Twitter/X Fallback Yes (preferred) 1200x628 ~7 days
LinkedIn Yes No 1200x627 ~7 days
Slack Yes Fallback 1200x630 Varies
Discord Yes Fallback Any ~minutes
iMessage Yes No 1200x630 ~24 hours
WhatsApp 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" />
Enter fullscreen mode Exit fullscreen mode

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

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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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'],
  },
};
Enter fullscreen mode Exit fullscreen mode

Nuxt.js — use useHead:

useHead({
  meta: [
    { property: 'og:title', content: 'My Page' },
    { property: 'og:image', content: 'https://example.com/og.png' },
  ],
});
Enter fullscreen mode Exit fullscreen mode

Plain React SPA — you need SSR or prerendering. Options:

  • Use react-helmet with 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 }
  );
}
Enter fullscreen mode Exit fullscreen mode

Checklist

Before shipping any page:

  • [ ] og:title set and under 60 characters
  • [ ] og:description set and 120-160 characters
  • [ ] og:image is an absolute URL, 1200x630px, under 1MB
  • [ ] og:url matches your canonical URL
  • [ ] og:type is set (website or article)
  • [ ] twitter:card is set to summary_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)