Menu
Sign up

X (Twitter) card not showing the image: nine causes, reproduced and diagnosed

Why an X (Twitter) link shows no image or a small one: nine causes we reproduced on test pages, how each looks in curl and in our validator, and the fix.

Published November 8, 2026 · 6 min read

You share a link on X and the card has no picture — or a small square where a wide image should be. X does not tell you why. The card is built by X's crawler, Twitterbot, which downloads your page, reads its tags and downloads the image; anything that stops one of those three steps leaves the card empty. This page goes through the nine causes we see most, each reproduced on a small test site on 2026-11-08, with what it looks like in curl and in our X card validator, and how to fix it.

What we did and did not test. We served nine variants of one page (Node.js) and fetched each as Twitterbot with curl 8 from a second process, then ran each page's HTML through the parser our validator uses and each image's measured size and type through its X checks (the validator itself only fetches public sites, so the test pages could not be pasted into it). We did not post the test pages on X — they were not public — so what X itself displays comes from X's own documentation: its card troubleshooting guide (archived; the live page now redirects) and the card markup reference (archived too).

What we measured

Cause Page status for Twitterbot What curl shows What our validator reports
1. No twitter:card 200 og:image present, no twitter:card warning: missing twitter:card
2. Relative og:image 200 og:image=/img/ok.png error: relative image URL
3. Tags added by JavaScript 200 tags only inside a <script> string error: no og:image (and no title)
4. robots.txt disallows Twitterbot 200 page fetched fine — robots.txt is a rule the crawler follows, not a block nothing on the page itself; check robots.txt
5. Bot protection blocks Twitterbot 403 "Access denied", no tags — our validator uses its own user agent, so it saw the page normally
6. Image over 5 MB 200, image 200 image/png, 5,762,138 bytes error: file too large, 5.5 MB over X's 5 MB
7. SVG image 200, image 200 image/svg+xml error: format SVG, X takes JPG, PNG, WebP, GIF
8. Image URL returns HTML 200, image 200 text/html, 33 bytes the image is not an image
9. Everything correct 200, image 200 image/png no issues

The last row matters as much as the others: when every check passes and the card is still wrong, you are looking at X's cache (below).

The causes, one by one

1. No twitter:card — small square or no card

X's markup reference: "If an og:type, og:title and og:description exist in the markup but twitter:card is absent, then a summary card may be rendered" — the small square card, not the wide one. The image, title and description fall back to their og: tags, but the card type does not. Fix: add <meta name="twitter:card" content="summary_large_image"> to the page's <head>.

2. A relative image URL

<meta property="og:image" content="/img/card.png"> works in a browser and fails in crawlers, which do not resolve it against your domain. Use the full address: https://example.com/img/card.png. Our validator flags this as an error.

3. Tags added by JavaScript

Twitterbot reads the HTML your server sends and does not run scripts. In our test the tags were inserted by a script after load: a plain grep on the HTML still "found" them inside the script's text, while a real HTML parser — the one in our validator — found no og:image at all. That is how this cause hides: view source looks fine at a glance. Fix: render the tags on the server or at build time (every framework has a way; see our framework guides).

4. robots.txt disallows Twitterbot

User-agent: Twitterbot
Disallow: /blog/

A rule like this does not stop curl — our test page came back 200 — but X's troubleshooting guide names a robots.txt that blocks Twitter as a reason a card does not show. Check yours at https://example.com/robots.txt, and remember that a broad Disallow: / under User-agent: * covers Twitterbot too unless it has its own section.

5. Bot protection, firewall or .htaccess

The cause our validator cannot see from the outside: some firewalls and bot-protection modes answer crawlers differently from browsers. Our test server returned 403 to the Twitterbot/1.0 user agent and 200 to everyone else — including our validator, which identifies itself by its own name. X's guide also mentions Apache .htaccess deny rules against its IP ranges and CMS settings that block crawlers. Test with Twitterbot's user agent:

curl -s -A "Twitterbot/1.0" -o page.html -w "%{http_code}\n" https://example.com/post

A 403, a 503 or a page that says "checking your browser" means the crawler is turned away. Allow Twitterbot in the firewall's bot settings, or in the plugin that blocks it.

6. The image is too large

X's guide: "The web crawler will typically download up to 5MB images", and the markup reference says images "must be less than 5MB in size". Our 5.76 MB test image was flagged by the validator as over the limit. Social images rarely need more than a few hundred KB: 1200×630 as JPEG, or PNG for flat graphics, is plenty.

7. SVG (or another format X does not take)

X's markup reference: "JPG, PNG, WEBP and GIF formats are supported. Only the first frame of an animated GIF will be used. SVG is not supported." Our validator reported "format SVG" against X's JPG, PNG, WebP and GIF. Export a PNG or JPEG of the same design.

8. The image URL does not return an image

A missing file served as a 200 page, a login page, or a redirect to the home page: the image URL "works" but returns HTML. Ours returned text/html, 33 bytes. Check the image itself:

curl -s -A "Twitterbot/1.0" -o /dev/null -w "%{http_code} %{content_type} %{size_download}\n" https://example.com/img/card.png

You want 200, image/png or image/jpeg, and a size under 5 MB.

9. Everything is right — X's cache

X's guide: the crawler "re-indexes the meta information on your tag roughly every seven days". If the page was shared before you fixed it, X keeps showing the old card. There is no refresh button: share a URL X has not seen (add ?v=2), and give a changed image a new file name so no cache holds the old one under the same address.

A three-step check

  1. Paste the URL into our X card validator. It reads the tags with a real HTML parser and checks the image's size and format against X's limits: causes 1, 2, 3, 6, 7 and 8.
  2. Run the two curl commands above with -A "Twitterbot/1.0". They catch causes 4 and 5, which depend on who is asking.
  3. Paste the link into the X composer (do not post). If the validator and curl are clean but the draft shows an old card, it is the cache.

For every other platform — Facebook, LinkedIn, Slack, WhatsApp — the same causes apply with different crawlers and limits; our OG image debugging guide covers them, and the Twitter card guide lists every twitter: tag.

Once the card shows, it still needs a good picture for each page. Shareglint renders one from an HTML template and the page's title — as a JPEG or PNG well under X's limits, at an absolute HTTPS URL that bots can fetch — either through the API or with a signed URL in the page's og:image tag (signed image URLs). The free plan covers 100 images a month.

FAQ

Why is my Twitter card not showing an image?

Most often X's crawler (Twitterbot) cannot see the tags or fetch the image: the og:image URL is relative, the tags are added by JavaScript, Twitterbot is blocked by robots.txt or bot protection, or the image is over 5 MB or an SVG. If everything is correct, X may still show its cached card from up to about seven days ago.

Why does X show a small square image instead of a large one?

The page has no twitter:card tag, or it is set to summary. Add <meta name="twitter:card" content="summary_large_image"> to get the wide card. Our checker reports a missing twitter:card as a warning.

How do I see what Twitterbot sees?

Fetch the page with Twitterbot's user agent: curl -s -A "Twitterbot/1.0" -o page.html -w "%{http_code}" https://example.com/post. A 403 or a challenge page means bot protection blocks it; then check the og:image URL the same way and look at the status, content type and size.

How do I refresh an X card after fixing it?

There is no refresh button. X's troubleshooting guide says the crawler re-reads a page's tags roughly every seven days. To see the fix sooner, share a URL X has not seen, for example with ?v=2, and give a changed image a new file name.