A Twitter card is the preview X draws under a post that contains a link: an image, a title, a description and the domain. You choose its layout with one tag, <meta name="twitter:card" content="summary_large_image">; for the rest X reads its own twitter: tags or, when they are missing, your Open Graph tags. The large card wants a 2:1 image between 300×157 and 4096×4096 pixels, under 5 MB — in practice the same 1200×630 image every other platform uses.
Card types
X documents four card types (X cards markup, archived):
twitter:card |
What it shows | Use it for |
|---|---|---|
summary |
A small square image beside the title and description | Pages without a designed image; a logo or avatar |
summary_large_image |
A wide image across the card | Articles, products, anything with a 1200×630 og:image |
player |
An inline video or audio player in an iframe | Media you host, needs HTTPS and an approved player |
app |
An app with install links | Mobile apps in the App Store or Google Play |
The old Photo and Gallery cards were deprecated and are now drawn as summary_large_image (X docs, archived). If you are not sure, use summary_large_image.
Twitter card image size
summary_large_image |
summary |
|
|---|---|---|
| Aspect ratio | 2:1 | 1:1, cropped to a square |
| Minimum | 300×157 px | 144×144 px |
| Maximum | 4096×4096 px | 4096×4096 px |
| File size | under 5 MB | under 5 MB |
| Formats | JPG, PNG, WEBP, GIF (first frame only); no SVG | same |
Sources: X's summary card with large image and summary card pages. X's card documentation moved off developer.x.com, so these are the last archived copies.
Two practical consequences:
- 1200×630 is fine for X. It is 1.91:1, close to the 2:1 X asks for and inside its limits, and it meets Facebook, LinkedIn and WhatsApp too. Keep text away from the edges; the OG image size table shows each platform's crop.
- A wide image in a
summarycard is cut to a square from the middle. If your card shows a slice of a headline, the page is missingtwitter:cardor setssummary.
Every twitter: tag
| Tag | Falls back to | What it holds |
|---|---|---|
twitter:card |
— | The card type. Without it, if og:type, og:title and og:description exist, "a summary card may be rendered" |
twitter:title |
og:title |
Title, max 70 characters |
twitter:description |
og:description |
Description, max 200 characters |
twitter:image |
og:image |
Image URL; under 5 MB |
twitter:image:alt |
og:image:alt |
Image description for screen readers, max 420 characters |
twitter:site |
— | @username of the website |
twitter:site:id |
— | The same as a numeric user ID |
twitter:creator |
— | @username of the author |
twitter:creator:id |
— | The same as a numeric user ID |
twitter:player |
— | HTTPS URL of the player iframe (player card) |
twitter:player:width, twitter:player:height |
— | Iframe size in pixels |
twitter:player:stream |
— | URL of the raw video or audio stream |
twitter:app:name:iphone, :id:iphone, :url:iphone |
— | App card: name, App Store ID, custom URL scheme (also :ipad, :googleplay) |
The two X pages disagree on twitter:site: the markup reference says "Either twitter:site or twitter:site:id is required", the card pages mark it optional. Set it when you have an account to attribute the card to.
The minimal markup
If the page already has Open Graph tags, X needs one more line:
<meta property="og:title" content="How we cut our image pipeline to 900 ms">
<meta property="og:description" content="Moving rendering off the request path and caching by content hash.">
<meta property="og:image" content="https://example.com/og/image-pipeline.png">
<meta property="og:image:alt" content="Title card: How we cut our image pipeline to 900 ms">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@example">
Set twitter:title, twitter:description or twitter:image only when X should get something different from everyone else — a shorter title that fits 70 characters, or a 2:1 crop of a square image. Twitter Card tags use name=; Open Graph uses property= (ogp.me). Most parsers accept either, but following each spec avoids surprises with strict ones. The full list of og: properties is on the Open Graph reference.
How X fetches the card
X's crawler identifies itself as Twitterbot (for example Twitterbot/1.0). When a link is first posted it downloads the page, reads the tags from the HTML and downloads the image. What follows from that:
- The tags must be in the server's HTML. Twitterbot does not run your JavaScript. A React or Vue app that sets meta tags in the browser shows no card; render the tags on the server or at build time.
- Twitterbot must be allowed in. X's troubleshooting guide lists
robots.txtrules,.htaccessdeny lines, CMS settings and hosts blocking its IP ranges as the usual reasons a card is missing, and notes the crawler "will typically download up to 5MB images" (X troubleshooting, archived). Bot protection that serves a challenge page has the same effect. - HTTPS must work for an old client. The same guide asks for TLS 1.1 or newer and a correct certificate chain.
- Cards are cached. X re-crawls a page "roughly every seven days". There is no button to refresh it: to see a change sooner, share a URL X has not seen (add
?v=2) and give a new image a new file name.
Testing a card
The old Card Validator at cards-dev.x.com/validator now redirects to an X login (checked 2026-11-04). Three ways that work:
- The X composer. Paste the URL into a new post; the card appears in the draft. You do not need to publish.
- A validator that reads the tags. Our Twitter card validator fetches the page as a crawler, shows the card X would draw and the tag it used for each field, and flags a missing
twitter:card, a relative image URL or an image under the minimum. - curl. See exactly what Twitterbot receives:
curl -sL -A "Twitterbot/1.0" https://example.com/blog/post \
| grep -Eio '<meta[^>]+(og:|twitter:)[^>]+>'
If curl shows the tags and the image URL opens in a private window, the remaining suspects are bot protection and X's cache. The debugging guide goes through each cause on every platform.
Common mistakes
| Symptom | Cause | Fix |
|---|---|---|
| Small square thumbnail instead of a wide image | No twitter:card, or summary |
<meta name="twitter:card" content="summary_large_image"> |
| Headline cut off in the image | Wide image shown in a summary card, or text near the edges |
Use summary_large_image; keep text in the centre |
| No card at all | Twitterbot blocked, tags added by JavaScript, image over 5 MB or SVG | Check robots.txt and bot rules; render tags on the server; serve JPG/PNG |
| Old image after an update | X's ~7-day cache keyed by URL | New image file name; share a changed URL |
| Card works on Facebook, not X | Facebook re-scraped, X did not; or X blocked by a firewall rule | Wait or change the URL; allow Twitterbot |
One image for every card
The image is the part that takes work: every post needs its own, at 1200×630, with the title readable at phone size. Shareglint renders it from an HTML template and the page's title with one HTTP request — 153 built-in templates or your own HTML and CSS — and the same template renders in every size from one request (og 1200×630, square 1080×1080, portrait 1080×1350, story 1080×1920, pinterest 1000×1500, youtube 1280×720), so the card for X and LinkedIn, a square for Instagram and a tall pin for Pinterest come from one design. The free plan covers 100 images a month.