OG Image Generator
EditorCheckerBlogPricing

OG Image Generator

Free online tool to create beautiful Open Graph images for your content. No signup required.

Links

  • OG Image Generator
  • OG Checker
© 2026 OG Image Generator. All rights reserved.
PrivacyTerms
Back to Blog

Mastodon Link Preview Not Working? What Its Crawler Reads

Nov 6, 2026·12 min read

A blank link card on Mastodon is almost never an image problem. Mastodon only saves a preview card when the fetcher found a title or an embeddable player in your HTML. Ship a flawless 1200 × 630 og:image with no og:title and it throws the whole card away. That one guard clause explains more dead cards than every dimension argument combined.

I read Mastodon's own fetcher source on November 6, 2026 — the LinkDetailsExtractor and FetchLinkCardService classes, main branch, version 5.0.0-beta.1 — then tested what the code implies against live data: 100 preview cards pulled from five public instances and 41 pages re-fetched to compare what each card stores against what each page currently serves. Several popular fixes turn out to be wrong.

Mastodon Reads Your JSON-LD Before Your Open Graph Tags

Title and description come from structured data first. The extractor walks every application/ld+json block on the page, keeps the first one typed NewsArticle or WebPage, and uses its headline. og:title is only the fallback, and the literal <title> element is the fallback after that.

Our sample proved it rather than suggesting it. Sixteen of 41 pages shipped NewsArticle or WebPage JSON-LD, 14 of those declared a headline, and all 14 cards stored that headline exactly. Twelve also matched og:title, because most CMS templates write the same string into both places. The two that diverged are the reason this matters.

  • The Guardian wrote Electoral politics can be fun! What turned voters against Trump? into its JSON-LD headline and the same sentence plus | First Dog on the Moon into og:title. The card showed the clean JSON-LD version.
  • The Verge used curly quotes in JSON-LD — winding down wrapped in single curly marks — and straight double quotes in og:title. The card reproduced the curly version character for character.

Descriptions behave the same way, and the difference is bigger. Ten pages published a JSON-LD description; all ten cards matched it. Only seven of those ten also matched og:description. At theverge.com the og:description is a three-word teaser ("Will Enough be enough?") while the JSON-LD description is a full sentence about the phone — the card carries the paragraph, not the teaser. On aljazeera.com the card kept the JSON-LD curly apostrophe that the og:description had flattened into a straight one.

Real talk: this is the debugging step nobody does. You edit og:title in your CMS, repost the link three times, and the card keeps the old wording, so you conclude Mastodon is broken. Check the JSON-LD block first. If your theme prints the post title into headline and a SEO plugin rewrites og:title, the JSON-LD wins and your edits are invisible.

Four Silent Drops That Produce A Bare URL

The fetcher bails out in four places, and none of them produce an error anyone can see.

  • No title, no card. The save call is save_with_optional_image! unless title.blank? and html.blank?. A card needs a title or an iframe, never just an image.
  • Media on the post kills it. The service returns early when the status already has a preview card, has attached media, or is a quote post. Attach a screenshot next to your link and the card disappears completely — post the URL as plain text instead.
  • First URL only. The URL list ends in .first, so a post with three links builds one card, for the leftmost link. Hashtag and mention links are skipped entirely.
  • 200 plus text/html or nothing. A 202, a JSON response, or a PDF produces no card at all, even though a PDF carries its own metadata. Mastodon follows redirects and stores the card under the final destination URL.

Two tag rules trip people up. First, the image comes from og:image and nowhere else — there is zero twitter:image fallback. Twenty-six of our 41 pages shipped twitter:image, and not one of those tags fed a card. Relative og:image values do work, since the fetcher resolves them against your URL, but only http and https survive, and the strings null and undefined are treated as empty.

Second, video is a different pipeline. A card becomes a video player only when twitter:player exists, and the player dimensions come from twitter:player:width and twitter:player:height. og:video is ignored. None of our 41 news pages declared a player, so every card came back as a plain link.

Your 1200 × 630 Image Is Stored At 230,400 Pixels

Mastodon rehosts your image and resizes it. The attachment style is pinned to pixels: 230_400 — a 640 × 360 budget — and GIFs get converted to JPEG at quality 90. Anything over 8 MB is rejected, and only jpeg, png, gif and webp are accepted.

The 100 cards we pulled agree with the source. Ninety-six of them landed within one percent of 230,400 pixels: the most common sizes were 662 × 348 (29 cards), 665 × 346 (12) and 640 × 360 (11), with the largest at 230,594. Aspect ratio survived the resize, resolution did not. A 1200-wide canvas reaches the timeline at roughly 660 wide, which means the 24 px caption you carefully fitted is now about 13 px of mush. Draw card text at 56 px or larger and it survives.

Every one of the 100 cards also carried a blurhash, so Mastodon generates its own placeholder from your image. Nothing on your side to add. The rehosted files sit on each instance's own media host, under /cache/preview_cards/images/, which means deleting the source image later does not change any card already built.

There Is No Debugger, So Here Is What To Query

Bluesky hands you cardyb.bsky.app. Facebook has the Sharing Debugger. Mastodon has no anonymous endpoint that takes a URL and returns a card, so every guide that promises one is describing a different platform.

Two public API routes still work without a token, and I used both. GET /api/v1/trends/links?limit=20 returned twenty finished cards on mastodon.social, mastodon.online, fosstodon.org, hachyderm.io and mstdn.social — that is the 100-card sample. And /api/v1/accounts/<id>/statuses exposes the card object attached to any public post, which is the fastest way to see what your own link produced.

Know what the trends route hides. A card only appears there when it passes appropriate_for_trends?: link type, article link type, title, description, image and provider name all present. That is why our 100 cards looked suspiciously flawless — it is a success-only view, and cards missing a description or a provider name never reach it. Diagnose from a status object, not from trends.

The 100 cards covered 43 unique URLs, 57 of them duplicated across instances. On the 28 URLs that appeared on two or more servers, titles and descriptions matched with zero divergence. Same tags in, same card out — so a card that renders badly for you renders badly for everyone.

One URL, One Card, Two Weeks, Whole Server

Cards are cached per URL, per instance, and shared by every user on that instance. The fetcher looks for an existing row keyed on the URL, and refetches only when that row is older than two weeks or its image is missing.

Both halves of that rule have consequences. Your broken card is what every user on that server sees for fourteen days, and there is no purge button. The exception is the lever: if the card has no image, the next post of the same URL refetches immediately, so a card stuck without a picture heals faster than one stuck with a bad title.

Staleness is visible in the wild once you look for it. theguardian.com's live blog URL carried the card headline "Global stocks tumble as AI panic grips markets after Democrats' midterm success" while the page currently serves "US tech stocks recovering on Wall Street after worst day in 19 months" — the same URL, rewritten between fetch and now. A TechCrunch card still reads "Meta's warns that election backlash..." while the live page has since fixed that typo to "Meta warns...". Cards also outlive crawler access: ft.com answered us with a 403, telegraph.co.uk with a 402 and nytimes.com with a 403, and all three still had complete cards, because the fetch that built them happened when the door was open.

One more layer people miss: the card travels. Mastodon includes the preview card in the ActivityPub attachments of the note, so remote servers display the card the author's server fetched rather than re-scraping your page. A bad card is not a local annoyance; on a thread that crosses a dozen instances it is the same bad card twelve times.

Mastodon Against The Other Two Networks We Measured

Behaviour Mastodon Bluesky Threads
Public test endpointNone; use status.card or trends/linkscardyb.bsky.app, anonymousNone; crawler UA only
Title priorityJSON-LD headline, then og:title, then title tagog:title, falls back to title tagog:title
Image sourceog:image onlyog:image onlyog:image
Image treatmentRehosted, capped at 230,400 pxByte-proxied, size cap not seenProxied, 200 px floor
Cache windowTwo weeks per URL per instanceService-side, shortCrawler cache, refreshed on share

Symptom, Cause, Fix

What you see Why What to change
Bare URL, image is fineNo og:title and no JSON-LD headlineAdd og:title, keep it under 70 characters
Card shows an old headlinePer-URL cache up to two weeksWait it out, or post a fresh URL variant
Card vanished after attaching a screenshotMedia on the status blocks card fetchPost the link in its own status
Blurry or unreadable card artStored at 230,400 px, not 1200 × 630Type 56 px and up in a 1200-wide canvas
Card points at the wrong URLCross-host canonical or og:url is discardedKeep canonical on the same host
Second link in the post has no cardOnly the first URL is fetchedSplit into separate posts
Card has no site nameprovider name comes from JSON-LD publisher, then og:site_nameAdd og:site_name and stop stuffing the brand into og:title

Two smaller rules worth knowing while you are in the head. Canonical beats og:url, and a canonical pointing at a different host is thrown out entirely, after which the card falls back to the URL you posted. And the site name shown above the headline comes from the JSON-LD publisher name when it exists, otherwise og:site_name. theguardian.com shows "The Guardian" from its publisher block while its og:site_name reads "the Guardian" — the card follows the JSON-LD. If you want author attribution on the card, fediverse:creator is the tag for it; two of 41 pages used it, and the one we traced pointed at a real Mastodon handle.

One Line

Mastodon builds its card from your structured data first and your Open Graph tags second, refuses to save a card without a title, and keeps whatever it built for two weeks per URL per instance. Fix the JSON-LD headline, keep og:image absolute and bold, and accept that a repair can take fourteen days to appear unless the card has no image at all.

Paste your URL into the free OG checker to see every property a scraper can read from your server HTML — og:title, og:image, canonical, and the structured data Mastodon reads first. Build the image itself at ogimgen.com in about thirty seconds, at 1200 × 630 with text big enough to survive the downscale. Related: the Bluesky card-service breakdown shows the network that hands you a public endpoint, the Threads crawler study covers the network with no debugger at all, the og:image:alt guide explains the alt text only 22% of our cards carried, and the OG image size guide covers the dimensions every platform crops differently.

MastodonLink PreviewOpen Graph

Create your OG image now

Free, no signup, instant download. 5 templates to choose from.

Open Generator →

Related Articles

Threads Link Preview Not Working? What Meta's Crawler Sees

Nov 4, 2026

Bluesky Link Preview: How Its Card Service Reads OG Tags

Nov 3, 2026

og:locale: The Tag 43 of 74 Image Pages Skip (91 Measured)

Nov 2, 2026