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:

Propertyogp.me definitionExample
og:titleThe title of your object as it should appear within the graphRotating API keys without downtime
og:typeThe type of your object; other properties may be required depending on the typearticle
og:imageAn image URL which should represent your objecthttps://example.com/og/rotate-api-keys.png
og:urlThe canonical URL of your object that will be used as its permanent ID in the graphhttps://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.

PlatformTags it readsImage rulesCacheRobots
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 pageMinimum 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/pngImages are cached by URL; a replaced image needs a new URLFacebookExternalHit 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:descriptionsummary_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×1447 days after the link is postedTwitterbot 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 requestsFetches the referenced image to check itAbout 30 minutes, shared across SlackDoes not honor robots.txt
LINE (FAQ)Only og:title, og:description, og:image; falls back to <title>, the meta description or body textNot documentedNot documentedNot 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 dataNot documented for Open GraphChanges 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”.

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 as og:url. Leave it empty and both lines disappear, which drops one of the four required OG properties.
  • The Title field fills <title>, og:title and twitter:title with the same text. Facebook asks for an og:title “without any branding such as your site name”, so if your <title> ends in | Site Name, edit the og:title line after copying.
  • og:image:width, og:image:height and og:image:alt are written only when an image URL is present, and always after og:image, which keeps them attached to the right root.
  • twitter:image repeats og:image unless you enter a separate Twitter image. Because X falls back to the OG tags anyway, the duplicate twitter:title, twitter:description and twitter:image lines are optional. twitter:card is 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 list index or follow as rules; its default rule, all, means no restrictions. The line changes nothing until you pick noindex or nofollow.
  • JSON-LD uses name, not headline. Google’s Article documentation has no required properties but recommends headline, image, datePublished, dateModified and author, so add headline and 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:// or https://.
  • SVG images. X says SVG is not supported, and Facebook’s og:image:type allows 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 in og:url sends every article’s shares to the home page, because shares aggregate at og: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

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.