Social Share Preview — Complete Developer Guide to OG Tags
Table of Contents
Social share preview cards look simple from the outside — an image, a title, a description. But implementing them correctly across frameworks, handling dynamic routes, testing without a live URL, and debugging when platforms ignore your tags requires knowing a few non-obvious things that the documentation rarely explains clearly.
This is the developer-focused guide to Open Graph tags: what they are, how to implement them in modern frameworks, how to test them at every stage of development, and how to debug the edge cases.
The Minimum Viable OG Tag Set
Every page that might be shared on social media needs these six tags in the <head> element:
<meta property="og:title" content="Page Title" />
<meta property="og:description" content="Description under 155 characters." />
<meta property="og:image" content="https://yourdomain.com/og-image.jpg" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:url" content="https://yourdomain.com/page/" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
The og:image:width and og:image:height tags are technically optional but practically important. Without them, Facebook fetches and decodes the image to determine its dimensions before deciding which card format to use. Declaring the dimensions means Facebook can make that decision immediately, resulting in more consistent card display especially on first share.
For article pages, use og:type article
Set og:type to "article" for blog posts and news articles. For everything else, "website" is the correct value. Article type enables additional OG properties like article:published_time and article:author that some platforms display in the preview.
Implementing OG Tags in Next.js
Next.js provides framework-level metadata APIs that generate OG tags server-side — making them visible to platform scrapers without requiring JavaScript execution.
App Router (Next.js 13+) — metadata export
// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
images: [{ url: post.ogImage, width: 1200, height: 630 }],
url: "https://yourdomain.com/blog/" + params.slug + "/",
type: "article",
},
twitter: { card: "summary_large_image" },
};
}
Pages Router — next/head
import Head from "next/head";
export default function BlogPost({ post }) {
return (
<>
<Head>
<meta property="og:title" content={post.title} />
<meta property="og:description" content={post.excerpt} />
<meta property="og:image" content={post.ogImage} />
<meta name="twitter:card" content="summary_large_image" />
</Head>
{/* page content */}
</>
);
}
Both approaches render tags server-side. The tags are in the HTML before it reaches the browser, so platform scrapers see them without executing JavaScript.
Sell Custom Apparel — We Handle Printing & Free ShippingDynamic OG Images — Generating Images Per Page
Static og:images work for a homepage or simple landing page. For content-heavy sites (blogs, product pages, documentation), generating a unique og:image per page dramatically improves social share engagement.
Next.js og:image generation with next/og
Next.js has a built-in image generation API using the ImageResponse component:
// app/blog/[slug]/opengraph-image.tsx
import { ImageResponse } from "next/og";
export const runtime = "edge";
export const size = { width: 1200, height: 630 };
export default async function Image({ params }) {
const post = await getPost(params.slug);
return new ImageResponse(
<div style={{ background: "#0d1117", width: "100%", height: "100%",
display: "flex", alignItems: "center", padding: 60 }}>
<h1 style={{ color: "white", fontSize: 48 }}>{post.title}</h1>
</div>
);
}
This generates a unique 1200x630 image for each blog post using JSX. The image is served from /blog/[slug]/opengraph-image and automatically linked in the og:image tag by Next.js. For high-traffic sites, add caching headers to avoid regenerating the image on every request.
Alternative: pre-generate with a script
For static sites or non-Next.js setups, you can pre-generate og:images during the build step using a headless browser (Puppeteer or Playwright) to screenshot an HTML template with the post data injected. This produces images you host as static files and reference with absolute URLs in og:image.
Testing OG Tags at Every Development Stage
Different stages of development require different testing approaches.
Local development — HTML paste
During local development, use the HTML paste method. Open your local page, view source, copy, paste into the OG checker. This tests tag structure and content without needing a live URL. Works for localhost:3000, localhost:8080, any local port.
Staging — URL check
If your staging server is publicly accessible, you can use URL-based checks in the OG checker and platform debug tools. Test representative pages from each template type. Confirm og:image URLs resolve correctly on the staging domain.
Production — platform debug tools
After deploying, run through the platform debug checklist for your most important pages:
- HTML paste check — confirm tags are present and correct in the served HTML
- Facebook Sharing Debugger — confirm Facebook's scraper sees the correct tags
- LinkedIn Post Inspector — confirm LinkedIn sees the correct tags
- Twitter Cards Validator — confirm Twitter card type and image
Automated testing
For larger projects, add an automated OG tag check to your CI pipeline. A Playwright or Puppeteer test can fetch key pages, parse the head section, and assert that og:title, og:description, og:image, and twitter:card are all present and not empty. Run this on deploy to catch regressions before they go live.
Debugging Invisible OG Tags
The most confusing OG tag situation is when tags look correct in the browser but platform scrapers cannot see them.
The JavaScript rendering problem
Most platform scrapers do not execute JavaScript. If your OG tags are injected by a client-side library (react-helmet running in the browser, for example), the tags only exist in the DOM after JavaScript runs — and they are absent from the server-rendered HTML that scrapers see.
Test for this: press Ctrl+U to view page source. If the OG tags do not appear in view-source but they do appear in the browser DevTools Elements panel, they are JavaScript-injected and invisible to scrapers.
The fix: server-side rendering
Move meta tag generation to the server. Every major framework has a server-side mechanism: Next.js metadata export or next/head, Nuxt useHead in setup context, SvelteKit svelte:head in layouts, Astro frontmatter, Remix meta function.
CSP and image fetch failures
If your Content Security Policy blocks external fetches or image loading from certain origins, platform scrapers may hit CSP errors when trying to fetch og:image. The og:image must be served from a URL that is accessible to any HTTP client without authentication or CSP restrictions.
robots.txt blocking the scraper
If your robots.txt blocks all bots (User-agent: * Disallow: /), platform scrapers respect this and will not fetch your pages. For pages you want shared on social media, ensure robots.txt allows access. You can block Googlebot for specific paths while still allowing social platform scrapers.
Try It Free — No Signup Required
Runs 100% in your browser. No data is collected, stored, or sent anywhere.
Open Free OG Tag CheckerFrequently Asked Questions
Should og:title be the same as the HTML title tag?
They do not have to match, and in many cases a slight difference is intentional. The title tag is optimized for SEO — it often includes the brand name at the end and keywords at the front. The og:title is optimized for social sharing — it can be more conversational or curiosity-driving without keyword stuffing. Using different values for each is valid. If you use the same value for both, that is fine too.
What is the best way to handle OG tags for single-page applications that do not use SSR?
Options in order of effectiveness: (1) Switch to a framework with SSR or static generation support — Next.js, Nuxt, SvelteKit, Astro. (2) Use a prerendering service like Prerender.io that serves cached static HTML snapshots to bots while the SPA serves live users. (3) Use Cloudflare Workers or similar edge functions to serve a static HTML response with correct head tags to bot user-agents. Client-side meta injection alone is not sufficient for social preview tags.
Do I need to redeploy to update og:image on a page, or can I change the image URL in the tag without redeploying?
If your og:image URL points to an image on a CDN and you want to update the preview image, you can either (a) replace the image at the same URL on the CDN and use platform debug tools to force a re-scrape, or (b) update the og:image URL in your HTML to point to the new image path and deploy the HTML change. Option (a) requires no redeployment but platform cache may still show the old image. Option (b) requires a deploy but gives you a clean URL for the new image.

