You share a link on X (Twitter) and get a small text card with a grey placeholder instead of a large image preview. X needs both Twitter Card tags and a reachable image file. Missing twitter:card, a wrong card type, or a broken twitter:image URL are the usual causes.
Short answer
Set twitter:card to summary_large_image, add twitter:image with an absolute HTTPS URL, and include matching og:image as a fallback. Validate at cards-dev.twitter.com/validator, then wait for X's cache to refresh. If the image still fails, check file size, dimensions, and whether your server blocks X's crawler.
How X chooses card layout
X supports several card types. The one that controls image size is twitter:card:
| Card type | Result |
|---|---|
summary_large_image | Large image on top, text below (what most sites want) |
summary | Small square thumbnail on the left |
player | Video/audio embed |
app | App download card |
If twitter:card is missing, X defaults to summary (small thumbnail). If the image also fails to load, you get a text-only card with a placeholder icon.
Required tags for a large image card:
<meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="Your Page Title"><meta name="twitter:description" content="Short description."><meta name="twitter:image" content="https://example.com/og.jpg">Also include Open Graph tags. X falls back to og:image when Twitter tags are incomplete. Details: Open Graph vs Twitter Card.
Step 1: Confirm tags are in server HTML
X's crawler (Twitterbot) reads the initial HTML response. It does not execute JavaScript.
- View page source.
- Search for
twitter:cardandtwitter:image. - Confirm
twitter:cardsayssummary_large_image, notsummary.
If tags appear only in DevTools after page load, move them to server-rendered output (SSR, generateMetadata in Next.js, or static HTML).
Step 2: Test the image URL
Open your twitter:image (or og:image) URL in a browser:
- Must return HTTP 200
- Must use HTTPS
- Must not require login
- Must not redirect to an HTML page
- Recommended: 1200 × 630 px, under 5 MB
A dynamic OG image endpoint (like /opengraph-image) can fail if it is slow, returns HTML errors, or blocks bots. A static .jpg or .png on your CDN is more reliable.
Step 3: Validate and refresh X's cache
- Go to cards-dev.twitter.com/validator.
- Paste your URL and click Preview card.
- Check for warnings or errors.
- Click preview again after fixing issues.
X caches card data aggressively. One validation does not always update live tweets immediately. Allow 15-30 minutes, then test with a new tweet.
Unlike Facebook, X does not have a "scrape again" button beyond re-running the validator.
Why you see a small card instead of large image
twitter:card set to summary
Change to summary_large_image. This is the most common fix.
Image too small
Images under 300 × 157 px may not render in large card format. Use 1200 × 630 px.
Only og:image, no Twitter tags
Usually works, but explicit twitter:card and twitter:image are safer. Some CMS setups output OG but not Twitter tags.
twitter:image different from og:image
If twitter:image points to a broken URL but og:image works, X may use the broken one. Align both to the same working URL.
Dynamic image route fails for bots
Next.js opengraph-image.tsx routes can timeout or return 404 to crawlers. Test the image URL directly. Consider a static fallback image.
Server issues that block Twitterbot
robots.txt
Allow Twitterbot:
User-agent: Twitterbot
Allow: /
Firewall / bot protection
Whitelist Twitterbot in Cloudflare or WAF rules. Aggressive bot challenges block image fetches.
SSL or redirect problems
Expired certificates and long redirect chains cause fetch failures. Point tags to the final HTTPS URL.
X cache vs. broken image
| Situation | What you see | Fix |
|---|---|---|
| Never showed image | Placeholder from first failed fetch | Fix tags and image URL, re-validate |
| Showed image before, old one now | Cached card from previous scrape | Re-validate, wait, tweet again |
| Large card became small card | twitter:card changed to summary | Set summary_large_image |
| Works in validator, not in tweet | Cache lag | Wait 30 min, post fresh URL with ?x=1 |
For general missing image fixes across platforms, see How to Fix a Missing OG Image.
Image specs for X (2026)
| Property | Value |
|---|---|
| Recommended size | 1200 × 630 px (1.91:1) |
| Minimum for large card | 300 × 157 px |
| Formats | JPG, PNG, WEBP, GIF (no animated GIF in cards) |
| Max file size | 5 MB |
| URL | Absolute HTTPS |
FAQ
Does X use Open Graph or Twitter Card tags?
Both. Twitter Card tags take priority. og:image is the fallback.
Why does my card work on Facebook but not X?
Separate crawlers and caches. Fix Twitter tags independently and validate on X.
Do I need twitter:site for the image to show?
No. twitter:site links to your account but is not required for image cards.
Can I use the same image for all platforms?
Yes. A 1200 × 630 JPG works for X, Facebook, LinkedIn, and WhatsApp.
Why is my Next.js opengraph-image not picked up?
The route must be publicly accessible, return an image content-type, and respond within X's timeout. Test the URL in an incognito tab.
Does deleting a tweet clear the card cache?
No. X caches by URL. Change the URL query string or wait for cache expiry after fixing tags.
Bottom line
A missing image on X starts with twitter:card set to summary_large_image and a working twitter:image URL in server HTML. Validate in the Card Validator, fix bot access and image specs, then test a fresh tweet. Facebook fixes alone will not solve X-specific card issues.