Skip to main content
SEO & Writing

Open Graph tags: fix your link previews before you share another URL

Paste your app's URL into Slack, Telegram, or X and the preview comes back wrong: random image, stale title, a description cut off mid-sentence. The page works fine. The problem is almost always the Open Graph tags — missing, malformed, or cached somewhere you didn't expect.

Here is how link previews actually work, which tags matter, and the mistakes that cause 90% of broken previews.

What crawlers actually read

When someone shares a URL, the platform's crawler fetches the HTML and looks for tags in the <head>:

  • og:title — the preview headline. Falls back to <title> if missing, which is often something like "Home | MyApp v2.3".
  • og:description — the preview text. Falls back to <meta name="description">.
  • og:image — the preview image. This is the one that most often breaks.
  • og:url — the canonical URL. Ignore it and Facebook may treat parameters as part of the page identity.
  • og:type — website for pages, article for posts with article:published_time.

Twitter still reads these as a fallback, but its own tags (twitter:card, twitter:title) override them. Set twitter:card to summary_large_image for anything you want to look good in X.

Size limits nobody checks

The tags have limits, and crawlers enforce them by truncation, not by error:

  • og:title — aim for under 60 characters. Longer titles get cut with an ellipsis.
  • og:description — under 160 characters. This is the same budget as a meta description, and for the same reason.
  • og:image — 1200×630 pixels is the safe standard. Anything smaller risks cropping; anything hugely larger wastes the user's time.
  • Image file size — keep it under 1 MB. Some crawlers skip images over ~5 MB entirely and render a preview with no image at all.

The image rule catches people constantly: a 3 MB PNG looks fine in your code, then Slack shows a text-only card. Export as JPEG or WebP at 1200×630 and you stop thinking about it.

Mistake 1: relative URLs in og:image

<meta property="og:image" content="/img/cover.jpg"> is not valid. Open Graph images must be absolute URLs, protocol and all: https://example.com/img/cover.jpg. Most crawlers will not resolve the relative path, so you get a title-only card even though the tag exists.

Mistake 2: forgetting the image dimensions

Add og:image:width and og:image:height. Without them, some platforms fetch the image just to measure it — slower previews, and a few rate-limit you for it. With them, the crawler knows the shape before downloading.

Mistake 3: testing your own share and seeing the old preview

Crawlers cache aggressively. Facebook's cache can hold a URL for days. You fix the tags, share again, see the old data, assume your fix failed. It didn't — you need to refresh the cache: Facebook has the Sharing Debugger with a "Scrape Again" button, and posting the URL with an unused query parameter (?v=2) sidesteps the cache on platforms that key on the full URL.

The same trap applies to previews rendered before your site had any OG tags. Some platforms won't re-crawl until you force it.

Mistake 4: dynamic pages with no server-side tags

If your app is a client-rendered SPA and you set OG tags with JavaScript, most crawlers will never see them. Slack, X, LinkedIn, and Telegram render little or no JS. The tags must exist in the raw HTML response.

Options, in order of effort: pre-render OG tags for routes that matter (blog posts, product pages), use a prerendering service, or ship static defaults plus per-route tags from the server. Don't try to fix previews from client code — you can't.

Mistake 5: one set of tags for every page

Pointing every route at the same og:image and title is the SPA default, and it kills click-through. When your changelog link shows the homepage hero image, people skip it. Per-route tags are boring config work, but they are the difference between a preview that says "your site" and one that says "this specific page".

How to check your tags in a minute

Two habits keep this from being a recurring fire:

  1. Inspect the rendered head. Before every release that touches routing or templates, dump the raw HTML (curl the URL, don't view source in the browser — the browser shows post-JS DOM) and read the OG block. An open graph checker does the same in one paste: it fetches the page and lists every OG and Twitter tag it found, so a missing og:image or a relative URL is visible immediately.
  2. Check the snippet, not just the tags. A tag can be present and still look bad: a 90-character title or a description with raw HTML entities. A serp preview shows the tag content the way a feed or search snippet will render it, which is what you actually want to judge. If you need fresh description text for a page, a meta description generator drafts text in the 120–160 character range you can reuse as og:description without a second editing pass.

If you fix tags often enough, batch it: for a site migration or a template change, checking every important route is easier with a script than by hand. Curl each URL, grep for og:, and diff the results. Any page missing og:image or pointing og:url at the wrong host is a bug you want to find before someone else shares the link.

A minimal working block

This is the whole list, in tag form: absolute image URL, correct type, dimensions set, card set for Twitter. Copy the shape and adjust per page:

<meta property="og:title" content="Deploy previews that don't look broken"> <meta property="og:description" content="Why your Slack previews show the wrong image — and the five fixes that cover 90% of cases."> <meta property="og:type" content="article"> <meta property="og:url" content="https://example.com/blog/og-tags"> <meta property="og:image" content="https://example.com/img/og/deploy-previews.jpg"> <meta property="og:image:width" content="1200"> <meta property="og:image:height" content="630"> <meta name="twitter:card" content="summary_large_image">

If a preview still renders wrong after this, the cause is almost always a cache — force a re-scrape instead of re-editing the tags.

Broken previews are invisible from inside your own browser, which is why they survive QA. Make checking them part of the release routine and they stop coming back.