Open Graph is the set of og: meta tags in a page's <head> that tells social networks and messaging apps what the page is: its title, type, canonical URL and image. Facebook published it in 2010 at ogp.me; today almost every link-preview crawler reads it — LinkedIn, Slack, Discord, WhatsApp, iMessage, Telegram, Mastodon — to draw the card you see when a link is shared. Four tags are required: og:title, og:type, og:image and og:url. This page lists every tag the protocol defines, with an example of each, plus the twitter: tags X reads on top.
A complete example
The set that works on every major platform, for a blog post:
<head prefix="og: https://ogp.me/ns# article: https://ogp.me/ns/article#">
<meta property="og:title" content="How we cut our image pipeline to 900 ms">
<meta property="og:type" content="article">
<meta property="og:url" content="https://example.com/blog/image-pipeline">
<meta property="og:image" content="https://example.com/og/image-pipeline.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Title card: How we cut our image pipeline to 900 ms">
<meta property="og:description" content="Moving rendering off the request path and caching by content hash.">
<meta property="og:site_name" content="Example Engineering">
<meta property="og:locale" content="en_US">
<meta property="article:published_time" content="2026-11-04T09:00:00Z">
<meta property="article:author" content="https://example.com/team/anna">
<meta name="twitter:card" content="summary_large_image">
</head>
The prefix attribute declares the namespaces (RDFa). Crawlers read the tags without it, but it is what the specification shows, and it does no harm.
The four required properties
| Tag | What it holds | Example |
|---|---|---|
og:title |
The title "as it should appear within the graph" — usually the page title without the site name | How we cut our image pipeline to 900 ms |
og:type |
The object type; website for most pages, article for posts (see types below) |
article |
og:image |
An absolute URL of the image that represents the page | https://example.com/og/post.png |
og:url |
The canonical URL, used as the object's permanent ID | https://example.com/blog/image-pipeline |
og:url matters more than it looks: platforms key their cache and their like/share counts on it. Point it at the canonical address, not the one with tracking parameters, or the same page collects several previews.
For og:image, the size that satisfies Facebook, LinkedIn, X and WhatsApp at once is 1200×630 pixels, JPEG or PNG under 600 KB — the per-platform size table has each platform's documented minimum, maximum and crop. Use an absolute https:// URL: relative paths are the most common reason an image does not show.
Optional properties
| Tag | What it holds | Example |
|---|---|---|
og:description |
A one- or two-sentence summary | Moving rendering off the request path… |
og:site_name |
The name of the whole site | Example Engineering |
og:locale |
The page language as language_TERRITORY; default en_US |
pl_PL |
og:locale:alternate |
Other languages the page exists in (an array) | de_DE |
og:determiner |
The word before the title in a sentence: a, an, the, "" or auto |
the |
og:video |
A video file URL that complements the page | https://example.com/clip.mp4 |
og:audio |
An audio file URL | https://example.com/episode.mp3 |
og:description is optional in the protocol, but LinkedIn and WhatsApp both list it among the tags a full preview needs. Treat it as required.
og:determiner is rarely used. It was meant for sentences like "Anna read the Hobbit" in activity feeds that no longer exist; nothing you share today shows it.
Structured properties of og:image, og:video and og:audio
A structured property adds detail to the tag above it:
| Tag | Meaning |
|---|---|
og:image:url |
Same as og:image |
og:image:secure_url |
An HTTPS URL, for pages that also serve the image over HTTP |
og:image:type |
MIME type, e.g. image/png |
og:image:width, og:image:height |
Size in pixels |
og:image:alt |
"A description of what is in the image (not a caption)" |
og:video:url, :secure_url, :type, :width, :height |
The same, for video |
og:audio:url, :secure_url, :type |
The same for audio (no size) |
Width and height are worth setting. Meta says they let Facebook "render the image immediately without having to asynchronously download and process it" (Meta image guide); without them the first share of a new link can come out with no image. og:image:alt is what screen readers announce on platforms that support it, and ogp.me says a page with og:image should set it.
Arrays: more than one value
Repeat a tag to give several values. The protocol's rule: "The first tag (from top to bottom) is given preference during conflicts", and structured properties belong to the root tag above them until the next root tag starts:
<meta property="og:image" content="https://example.com/og/wide.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image" content="https://example.com/og/square.png">
<meta property="og:image:width" content="1080">
<meta property="og:image:height" content="1080">
Here a platform that takes one image takes wide.png. Discord is the main reader that uses more: up to four og:image tags become a gallery (Discord link previews). Put the image you want everywhere first.
Object types (og:type)
Every page has a type. The global ones, each with its own namespace and extra properties:
og:type |
Extra properties |
|---|---|
website |
None. Any page without markup is treated as website. |
article |
article:published_time, article:modified_time, article:expiration_time (ISO 8601), article:author (profile URLs, array), article:section, article:tag (array) |
profile |
profile:first_name, profile:last_name, profile:username, profile:gender |
book |
book:author, book:isbn, book:release_date, book:tag |
music.song |
music:duration (seconds), music:album, music:album:disc, music:album:track, music:musician |
music.album |
music:song, music:song:disc, music:song:track, music:musician, music:release_date |
music.playlist, music.radio_station |
music:song…, music:creator |
video.movie |
video:actor, video:actor:role, video:director, video:writer, video:duration, video:release_date, video:tag |
video.episode |
as video.movie, plus video:series |
video.tv_show, video.other |
as video.movie |
ogp.me also lists payment.link, marked beta. In practice: website for home and product pages, article for anything with a publish date. Previews look the same either way; the type matters for parsers that read the extra properties.
Values have types too: Boolean (true, false, 1, 0), DateTime (ISO 8601), Enum, Float, Integer (32-bit), String and URL (http or https only).
The twitter: tags X reads
X has its own tags, Twitter Cards, and falls back to Open Graph for most of them (X cards markup, archived):
| Tag | Falls back to | Notes |
|---|---|---|
twitter:card |
— | summary, summary_large_image, app or player. Without it "a summary card may be rendered" — the small one |
twitter:title |
og:title |
Max 70 characters |
twitter:description |
og:description |
Max 200 characters |
twitter:image |
og:image |
Under 5 MB; JPG, PNG, WEBP, GIF (first frame); no SVG |
twitter:image:alt |
og:image:alt |
Max 420 characters |
twitter:site, twitter:creator |
— | @username of the site and of the author |
So the minimal addition to a page with Open Graph is one line, <meta name="twitter:card" content="summary_large_image">. Sizes, card types and the reasons a card does not show are on the Twitter card page.
Other tags crawlers read
fb:app_id— ties the page to a Facebook app for Insights. Optional; the Sharing Debugger warns when it is missing, which is not an error.theme-color— Discord uses it for the coloured bar beside the embed.<link rel="canonical">,<title>,<meta name="description">— fallbacks whenog:tags are missing.- oEmbed links — Slack and Discord prefer an oEmbed endpoint when the page advertises one.
Three rules crawlers enforce
- Tags must be in the HTML the server sends. Crawlers such as
facebookexternalhit,LinkedInBot,TwitterbotandSlackbotdo not wait for JavaScript. Tags injected by a single-page app after load are invisible to them; render them on the server or at build time. - URLs are absolute and fetchable. The image must answer
200to a bot without cookies, logins or bot protection, with an imageContent-Type. - Caches are keyed by URL. A changed image under the same URL keeps the old preview until the platform re-scrapes. Give a new image a new URL (
/og/post.png?v=2). The debugging guide lists each platform's refresh tool.
Check what a crawler reads
Read the tags the way a crawler does, without running JavaScript:
curl -sL -A "facebookexternalhit/1.1" https://example.com/blog/post \
| grep -Eio '<meta[^>]+(og:|twitter:)[^>]+>'
Or paste the URL into the OG checker, which shows the card on X, LinkedIn, Facebook, Slack and Discord and flags missing tags; the meta tag generator writes the whole set for you.
Making the og:image itself
The tags are the easy part; every page needs its own image. You can design one per page by hand, render them at build time, or have them rendered on request. With Shareglint one HTTP request turns an HTML template and the page's title into a 1200×630 PNG — 153 built-in templates, or your own HTML and CSS — and the free plan covers 100 images a month. What an OG image is and how each platform shows it covers the image side in detail.