Open Graph is a set of <meta> tags in a page’s <head> that tells other services what the page is: its title, an image, a canonical URL and a type. The Open Graph protocol was created at Facebook and is based on RDFa, which is why the tags use a property attribute instead of name. Today the same tags drive the link cards on Facebook and Instagram, the fallback for X cards, Slack unfurls, LINE chat previews and the thumbnails on Hatena Bookmark. Each of those services reads a different subset, caches it for a different time, and documents its limits in a different place.
This guide goes through the protocol itself, then what each platform says it reads, and ends with the output of ZeroTool’s Meta Tag Generator so you can compare a generated block with the rules.
The four required properties
The protocol names four properties that every page needs. The definitions below are quoted from ogp.me:
| Property | ogp.me definition | Example |
|---|---|---|
og:title | The title of your object as it should appear within the graph | Rotating API keys without downtime |
og:type | The type of your object; other properties may be required depending on the type | article |
og:image | An image URL which should represent your object | https://example.com/og/rotate-api-keys.png |
og:url | The canonical URL of your object that will be used as its permanent ID in the graph | https://example.com/blog/rotate-api-keys/ |
The optional properties ogp.me recommends are og:description (“a one to two sentence description”), og:site_name, og:locale (format language_TERRITORY, default en_US), og:locale:alternate, og:determiner, og:audio and og:video. A page with no og:type is treated as website, which ogp.me states for any non-marked-up page and Facebook repeats as its default.
The value types matter more than they look. ogp.me defines a URL as “all valid URLs that utilize the http:// or https:// protocols”, so og:image must be absolute: /og/post.png is not a valid value, whatever a browser would do with it in an <img>. Integers are 32-bit, and dates such as article:published_time are ISO 8601.
The article type adds its own namespace: article:published_time, article:modified_time, article:expiration_time, article:author (an array of profiles), article:section and article:tag. Other global types are book, profile, website and the music.* and video.* verticals.
Structured properties and arrays
Some properties take extra metadata after a colon. For og:image the protocol defines og:image:url (identical to og:image), og:image:secure_url (an alternate URL if the page requires HTTPS), og:image:type, og:image:width, og:image:height and og:image:alt. On og:image:alt the spec is direct: “If the page specifies an og:image it should specify og:image:alt.”
Repeating a tag makes an array, and order is the whole syntax. ogp.me says “the first tag (from top to bottom) is given preference during conflicts”, and a structured property belongs to the most recent root tag before it. This block, taken from the spec, describes three images: the first is 300×300, the second has no size, and only the third is 1000 pixels tall.
<meta property="og:image" content="https://example.com/rock.jpg" />
<meta property="og:image:width" content="300" />
<meta property="og:image:height" content="300" />
<meta property="og:image" content="https://example.com/rock2.jpg" />
<meta property="og:image" content="https://example.com/rock3.jpg" />
<meta property="og:image:height" content="1000" />
Two consequences follow. Put the image you want shown first, and never emit og:image:width before its og:image, because a width with no preceding root attaches to nothing.
What each platform reads
The table below lists only what each platform documents. Where a platform has removed its documentation, the archived copy is linked.
| Platform | Tags it reads | Image rules | Cache | Robots |
|---|---|---|---|---|
| Facebook, Instagram, Messenger (webmasters guide, crawler, images) | og:url, og:title, og:description, og:image, og:type, og:locale, fb:app_id; OG tags must appear within the first 1 MB of the page | Minimum 200×200, at most 8 MB, at least 1200×630 recommended, aspect ratio close to 1.91:1; og:image:type one of image/jpeg, image/gif, image/png | Images are cached by URL; a replaced image needs a new URL | FacebookExternalHit may bypass robots.txt for security or integrity checks |
| X (markup, large image card, getting started) | twitter:* first, then falls back to og:title, og:description, og:image, og:image:alt; without twitter:card, a summary card may be rendered from og:type, og:title and og:description | summary_large_image: 2:1, 300×157 to 4096×4096, under 5 MB, JPG, PNG, WEBP or GIF (first frame only), no SVG; summary: 1:1, minimum 144×144 | 7 days after the link is posted | Twitterbot respects robots.txt; a blocked page shows no card |
| Slack (robots) | oEmbed, Twitter Card and Open Graph tags; fetches as little of the page as it can with Range requests | Fetches the referenced image to check it | About 30 minutes, shared across Slack | Does not honor robots.txt |
| LINE (FAQ) | Only og:title, og:description, og:image; falls back to <title>, the meta description or body text | Not documented | Not documented | Not documented |
| Google Search (title links, site names) | og:title is one of nine sources for the title link; og:site_name is considered for the site name, after WebSite structured data | Not documented for Open Graph | Changes show after a recrawl, “a few days to a few weeks” | — |
As of 2 October 2026 the X card pages on developer.x.com redirect to the X API overview, so the links above point to the Internet Archive copies of January and February 2026. The same markup page caps twitter:title at 70 characters and twitter:description at 200, and says either twitter:site or twitter:site:id is required.
Facebook gives one more requirement that is easy to miss: the server must support gzip and deflate encodings, and the crawl must finish “within a few seconds”.
og:url and the canonical link do different jobs
Facebook’s guide defines og:url as “the undecorated URL, without session variables, user identifying parameters, or counters” and says likes and shares aggregate at that URL. A page reachable as /post/, /post and /post/?utm_source=newsletter collects its shares in one place only if all three serve the same og:url.
<link rel="canonical"> is for search engines. Google’s canonicalization guide calls it “a strong signal that the specified URL should become canonical”, which is still a signal and not a command. The two tags usually carry the same URL, but they are separate tags read by separate systems, and a page needs both.
A generated block, line by line
These are the values entered into the Meta Tag Generator for a blog post, with Schema.org @type set to Article and the viewport checkbox cleared:
<title>Rotating API keys without downtime</title>
<meta name="description" content="A four-step rotation plan: issue a second key, deploy readers, switch writers, revoke the old key.">
<link rel="canonical" href="https://example.com/blog/rotate-api-keys/">
<meta name="author" content="Jane Doe">
<meta name="robots" content="index, follow">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="article">
<meta property="og:title" content="Rotating API keys without downtime">
<meta property="og:description" content="A four-step rotation plan: issue a second key, deploy readers, switch writers, revoke the old key.">
<meta property="og:url" content="https://example.com/blog/rotate-api-keys/">
<meta property="og:site_name" content="Example Engineering">
<meta property="og:image" content="https://example.com/og/rotate-api-keys.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Two API keys overlapping during a rotation window">
<meta property="og:locale" content="en_US">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@exampleeng">
<meta name="twitter:title" content="Rotating API keys without downtime">
<meta name="twitter:description" content="A four-step rotation plan: issue a second key, deploy readers, switch writers, revoke the old key.">
<meta name="twitter:image" content="https://example.com/og/rotate-api-keys.png">
<!-- Schema.org JSON-LD -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"name": "Rotating API keys without downtime",
"description": "A four-step rotation plan: issue a second key, deploy readers, switch writers, revoke the old key.",
"url": "https://example.com/blog/rotate-api-keys/",
"image": "https://example.com/og/rotate-api-keys.png",
"author": {
"@type": "Person",
"name": "Jane Doe"
}
}
</script>
What the generator does with each field, read from its source:
- The Canonical URL field is written twice, as
<link rel="canonical">and asog:url. Leave it empty and both lines disappear, which drops one of the four required OG properties. - The Title field fills
<title>,og:titleandtwitter:titlewith the same text. Facebook asks for anog:title“without any branding such as your site name”, so if your<title>ends in| Site Name, edit theog:titleline after copying. og:image:width,og:image:heightandog:image:altare written only when an image URL is present, and always afterog:image, which keeps them attached to the right root.twitter:imagerepeatsog:imageunless you enter a separate Twitter image. Because X falls back to the OG tags anyway, the duplicatetwitter:title,twitter:descriptionandtwitter:imagelines are optional.twitter:cardis the line that matters: without it X may render only a summary card, never the large image.<meta name="robots">is always written. Google’s robots meta tag documentation does not listindexorfollowas rules; its default rule,all, means no restrictions. The line changes nothing until you picknoindexornofollow.- JSON-LD uses
name, notheadline. Google’s Article documentation has no required properties but recommendsheadline,image,datePublished,dateModifiedandauthor, so addheadlineand the dates by hand for an article. The generator writes<in JSON-LD as\u003c, so a title containing</script>cannot end the script element early. - The title and description counters (60 and 160) count JavaScript string length. Google’s snippet documentation says there is no length limit and the snippet “is truncated in Google Search results as needed, typically to fit the device width”, so treat the counters as a rough guide, not a rule.
With only a title and an image entered, the block shrinks to this. og:type defaults to website, and og:url is missing:
<title>Rotating API keys without downtime</title>
<meta name="robots" content="index, follow">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:title" content="Rotating API keys without downtime">
<meta property="og:image" content="https://example.com/og/rotate-api-keys.png">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Rotating API keys without downtime">
<meta name="twitter:image" content="https://example.com/og/rotate-api-keys.png">
The preview tabs (Google, Facebook, Twitter, Discord) are drawings made by the tool from your input. They are not the platforms’ renderers, and to draw them your browser loads the image URL you typed, so that image’s host sees the request. The tags themselves are not sent anywhere.
Checking what a crawler receives
Facebook’s crawler page gives a command that imitates its request, including the Range header and the user agent. Running it against this site and listing the tag names shows exactly what the crawler gets:
curl -s --compressed -H "Range: bytes=0-524288" -H "Connection: close" \
-A "facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)" \
"https://zerotool.dev/tools/meta-tag-generator/" \
| grep -oE '(property|name)="(og|twitter):[a-z_:]+"'
property="og:site_name"
property="og:title"
property="og:description"
property="og:url"
property="og:image"
property="og:type"
name="twitter:card"
name="twitter:title"
name="twitter:description"
name="twitter:image"
The four required properties are there. og:image:width, og:image:height and og:image:alt are not, which means Facebook has to download the image before it can render the first share (its images page lists the dimension tags as one of three ways to avoid that). The same check is worth running on staging before a launch, because it shows problems that a browser hides: a login wall in front of the crawler, a CDN that blocks unknown user agents, or tags injected by JavaScript after the HTML arrives.
Changing a preview after it has been shared
Every platform in the table caches, and each one clears differently:
- Facebook: run the URL through the Sharing Debugger or the Graph API to scrape it again. Images are cached by image URL, so a new image needs a new URL; keep the old file, because older posts still reference it. Updating the page does not change previews in shares that already exist.
- X: the cache lasts 7 days after the link is posted, according to the archived getting-started guide.
- Slack: responses are cached for about 30 minutes.
- LINE: the FAQ says neither how long previews are cached nor how to clear them.
Mistakes that break previews
- Relative image URLs. ogp.me’s URL type requires
http://orhttps://. - SVG images. X says SVG is not supported, and Facebook’s
og:image:typeallows only JPEG, GIF and PNG. - Tags added by client-side JavaScript. The crawler documents describe fetching response bytes: Facebook reads the first 1 MB, and Slack fetches “as little of the page as it can”. None of them says it runs page scripts, so put the tags in the HTML the server sends.
- A robots.txt rule that blocks the page or the image. X shows no card and no thumbnail. Slack ignores robots.txt, so the same page can unfurl in Slack and not on X.
- A wrong
og:url. A template that leaves the home page URL inog:urlsends every article’s shares to the home page, because shares aggregate atog:url. - Dimension tags that disagree with the file. The width and height are there so the crawler can lay out the card before it downloads the image; wrong numbers make it lay out the wrong shape.
Sources
- The Open Graph protocol
- Meta: A Guide to Sharing for Webmasters, Meta Web Crawlers, Images in Link Shares
- X Cards markup, summary card with large image and getting started (archived copies linked in the table)
- Slack Robots
- LINE Developers FAQ: How are URL previews generated in chats?
- Google Search Central: title links, site names, meta descriptions, Article structured data
Related tools: Favicon Generator for the icons referenced from the same <head>, Robots.txt Generator for the crawl rules that decide whether X can fetch the card, and URL Parser to check that og:url has no tracking parameters.