Guide

iMessage link preview: Open Graph for Apple Messages

When someone pastes a URL in Messages, Apple may show a rich link — title, snippet, and image — instead of a bare blue string. That card is Open Graph–based. If og:image is missing, unreachable, or the wrong kind of file, the preview often collapses to a plain URL. Twitter Card tags alone will not save it.

CardScope reconstructs the iMessage shell from the same tags Apple’s rich-link crawler cares about. It is a diagnostic preview, not a screenshot of Messages.app on a phone.

iMessageog · rich link
Northline Roasters — Lot 19
A washed Ethiopian lot, roasted in Portland. Ships on Tuesdays.
northline.example
Without og:imageplain URL
https://northline.example/lots/19
No image — Messages often shows little more than the link.
northline.example

Same page, two outcomes: with a public og:image you get a rich bubble; without it the card often never forms. CardScope’s iMessage shell is rebuilt from tags, not from a live Messages session.

What Apple Messages typically needs

Rich links lean on Open Graph, with the document title and meta description as fallbacks. In practice you want:

twitter:card and other Twitter tags do not drive the iMessage shell the way they do on X or Discord. Ship OG for Messages; add Twitter tags for X separately. See LinkedIn vs X and Slack vs Discord for those clients.

Why a “good” page still looks blank in Messages

Three failure modes show up again and again:

  1. No usable image. The tag is missing, the URL redirects to HTML, the host blocks Apple’s fetch, or the file is too small / wrong MIME type.
  2. Wrong final URL. A redirect chain lands on a page without OG, or a mobile vs desktop variant strips tags.
  3. Stale cache. You fixed the tags; Messages still shows yesterday’s card (or no card). Live HTML can be correct while the rich-link cache is not.

View-source in your browser proves what you got with cookies and your user-agent. Apple’s crawler is different. A checker that fetches from the edge and shows the iMessage shell from those tags closes that gap without claiming pixel-perfect Messages.app rendering.

Tags that matter for iMessage

Tag / signal Role in Messages Practical check
og:title Primary title Specific, not just the brand
og:description Supporting text Present and matches the page
og:image (+ width/height) Rich-link image Absolute https, public, useful size
og:url / canonical Identity / cache key Stable permalink
<title> / meta description Fallback Present even if OG is incomplete
twitter:card Not the iMessage driver Still set for X; do not rely on it here

A minimal set for a rich link

If you only set six things for Messages, set these:

<meta property="og:title" content="A specific title, not the brand name">
<meta property="og:description" content="One sentence that matches the page.">
<meta property="og:image" content="https://example.com/og.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:url" content="https://example.com/permalink">

Keep important text away from the extreme edges of the image. Messages crops; a title only in a corner can disappear.

How to verify

  1. Paste the public permalink into CardScope. It fetches from the edge, reads Open Graph (and Twitter) tags in memory, and discards the HTML.
  2. Open the iMessage shell. You should see a title and, when tags allow, an image. If the shell collapses, start with og:image reachability.
  3. Compare Slack and Discord on the same check if you share there too — they are not identical to Messages (Slack vs Discord guide).
  4. Fix the live page, then recheck the same permalink. If CardScope is current but a phone still shows an old or empty link, treat that as Apple-side cache, not as “the tags are still wrong.”

Check a URL on CardScope

Paste the permalink. You get the iMessage shell beside X, LinkedIn, Slack, and Discord, plus the tag table and a fix checklist. Three free checks per day per IP, no account. Pro is $19 once if you want unlimited checks. We parse HTML in memory and discard it — rate limits store a hash of your IP for 48 hours, not the page.

Try a URL