Open Graph Protocol Explained, With a Tag Checker

The Open Graph protocol is the meta tag standard that controls link previews. See the required tags, how crawlers read them and a tested checker.

By Simon Chiu · Updated

The Open Graph protocol is a set of <meta property="og:..."> tags in a page's <head> that tells social networks, chat apps and other link consumers what the page is, so they can show it as a rich preview card.

Facebook published the protocol in 2010 at ogp.me. Today most link consumers read it: LinkedIn, Slack, Discord, iMessage, WhatsApp, Mastodon and many search and AI tools. X reads its own Twitter card tags first and falls back to Open Graph. This entry belongs to the screenshot and rendering glossary.

A plain explanation

A web page is written for people. A preview card needs a small, structured summary of it: a title, a type, a canonical URL and one image. Open Graph is the agreed place to put that summary. Without it, each platform guesses from the <title> and the first image it finds, and the guess is often wrong.

Tag Required What it holds
og:title yes The title for the card, without the site name suffix
og:type yes website, article, profile, video.movie and others
og:image yes Absolute URL of the preview image (see OG image)
og:url yes The canonical URL that shares and likes should count against
og:description no One or two sentences for the card body
og:site_name no The name of the whole site
og:locale no Language and territory, for example en_US

Some properties have structured children. og:image accepts og:image:width, og:image:height, og:image:type, og:image:secure_url and og:image:alt. A type can bring its own namespace: article:published_time and article:author apply when og:type is article.

How a crawler reads it

Link is shared Crawler GETs HTML(no JavaScript) Reads og:* tags,GETs og:image Card cachedand shown No tags found: guess from <title> and body image too big or 403: card without image
What happens between a paste and a preview card. The crawler sees only what your server sends on the first request.

Three facts follow from that flow. The tags must be in the server response, not added by JavaScript. The image URL must be public and absolute. And the platform keeps its copy, so a fix can take time to show unless the platform offers a re-scrape tool.

How to check and use it in Puppeteer, Playwright and RenderScreenshot

Playwright: list the tags and fail on missing ones. The script exits with code 1 when a required tag is missing, so it works as a CI check. It also flags name="og:...", a common typo.

import { chromium } from 'playwright';

const url = process.argv[2] ?? 'https://example.com';
const REQUIRED = ['og:title', 'og:type', 'og:image', 'og:url'];

const browser = await chromium.launch();
try {
  const page = await browser.newPage();
  await page.goto(url, { waitUntil: 'domcontentloaded' });
  const tags = await page.$$eval('meta[property]', (metas) =>
    metas.map((m) => [m.getAttribute('property'), m.getAttribute('content')]));
  const og = tags.filter(([p]) => p.startsWith('og:'));
  console.table(og);
  const missing = REQUIRED.filter((p) => !og.some(([k]) => k === p));
  if (missing.length) {
    console.error('missing:', missing.join(', '));
    process.exitCode = 1;
  }
  const misnamed = await page.$$eval('meta[name^="og:"]', (m) => m.map((x) => x.getAttribute('name')));
  if (misnamed.length) console.warn('uses name= instead of property=:', misnamed.join(', '));
} finally {
  await browser.close();
}

Against https://example.com it printed missing: og:title, og:type, og:image, og:url, because that page has no Open Graph tags. Against our test page with a name="og:description" tag, it listed seven tags and warned about the misnamed one.

Puppeteer: find tags that only JavaScript adds. This compares the raw HTML, which is what crawlers see, with the DOM after scripts ran.

import puppeteer from 'puppeteer';

const url = process.argv[2] ?? 'https://example.com';
const ogFrom = (html) => [...html.matchAll(/<meta[^>]+property=["'](og:[^"']+)["']/gi)].map((m) => m[1]);

const raw = await (await fetch(url, { headers: { 'user-agent': 'og-check/1.0' } })).text();
const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();
  await page.goto(url, { waitUntil: 'networkidle0' });
  const rendered = ogFrom(await page.content());
  const rawTags = ogFrom(raw);
  console.log('in raw HTML:', rawTags.join(', ') || 'none');
  const jsOnly = rendered.filter((p) => !rawTags.includes(p));
  if (jsOnly.length) console.warn('added by JavaScript, invisible to most crawlers:', jsOnly.join(', '));
} finally {
  await browser.close();
}

On a test page that inserts og:image with a script, it reported added by JavaScript, invisible to most crawlers: og:image.

RenderScreenshot: produce the og:image value. The protocol needs an image URL. A GET /v1/screenshot URL with preset=og_card returns a 1200 x 630 PNG, so it can be the tag's content. In public HTML, use a signed URL so the page does not expose an API key.

<meta property="og:image"
      content="https://api.renderscreenshot.com/v1/screenshot?url=https%3A%2F%2Fexample.com%2Fblog%2Fmy-post&preset=og_card&key_id=rs_pub_...&expires=...&signature=...">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">

Tested on 2026-10-15 with Node 22.18, Playwright 1.64.1 and Puppeteer 24.43.1 (run in headless shell mode), against example.com and a local test page. The signed URL above is a pattern; build real ones with the signed URL guide.

Common mistakes

  • name instead of property. Write property="og:title".
  • Tags that differ per request. If og:url changes with tracking parameters, shares are split across many URLs. Point it at the canonical URL.
  • Duplicate tags. Two og:image tags are valid (they form an array), but two og:title tags make the result depend on the parser.
  • Tags in the body. Some frameworks render meta tags late. Check the first response with curl.

To see what a platform will show for your URL, use the link preview checker. If the card has no image, the OG image not showing guide walks through each cause. To render card images on request, get a free API key.

Frequently asked questions

Which Open Graph tags are required?
The protocol requires four - og:title, og:type, og:image and og:url. og:description and og:site_name are optional but most platforms show them.
Should Open Graph tags use name or property?
Use property, for example <meta property="og:title" content="...">. The protocol is built on RDFa, which uses the property attribute. Some parsers accept name, but you should not depend on it.
Do link preview crawlers run JavaScript?
Most do not. They read the HTML your server returns. Tags that a client-side script inserts after load are often missed.

Related in this topic

Try RenderScreenshot free

150 free credits every month, no credit card required.