Twitter Card Meta Tags: The Complete Implementation Guide
X (still Twitter under the hood) reads its own twitter:* meta tags before it touches your Open Graph tags. Get them right and a shared link unfurls into a full-width image card; get them wrong (or omit twitter:card) and you get a bare blue link or a cramped thumbnail. This post covers exactly the Twitter Card layer: the card types, the tags each needs, how X falls back to Open Graph, and why a card sometimes refuses to render.
This sits on top of your Open Graph tags, not instead of them. If you haven't set those, start with the Open Graph meta tags guide; for image specs both layers share, see OG image size & format best practices.
One detail that catches everyone: name=, not property=
Open Graph uses property=. Twitter Cards use name=. Mixing them up is the most common reason a card silently fails validation:
<!-- Open Graph -->
<meta property="og:title" content="...">
<!-- Twitter Card: note name=, not property= -->
<meta name="twitter:card" content="summary_large_image">
summary vs summary_large_image
There are four card types, but two cover almost everything:
| twitter:card | Renders as | Use for |
|---|---|---|
| summary | Small square thumbnail beside the text | Utility pages, link lists, content without a strong hero image |
| summary_large_image | Full-width image above the title and description | Articles, marketing, anything with a 1.91:1 image |
| player | Inline audio/video player | Media you host with an embeddable HTTPS iframe |
| app | Native install/open prompt | iOS/Android app pages |
If you have a decent 1200 × 630 image, use summary_large_image; it takes far more feed real estate and pulls more clicks. Reserve summary for pages where a big image would be noise.
The minimum that works
Because X falls back to Open Graph (more on that below), the true minimum is a single line: declare the card type and let your existing og: tags fill the rest:
<meta name="twitter:card" content="summary_large_image">
That's genuinely enough if your og:title, og:description, and og:image are already in place. The card type is the one thing OG can't supply, so it's the one tag X needs from you.
The full set, when you want control
Add twitter:* tags only where you want X to differ from the rest of your social previews: a punchier headline, a different image, attribution:
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="A punchier headline for X">
<meta name="twitter:description" content="Up to ~200 chars; X truncates the visible part.">
<meta name="twitter:image" content="https://seotest.app/og/post.jpg">
<meta name="twitter:image:alt" content="Diagram of the four Twitter Card types">
<meta name="twitter:site" content="@seotest_app">
<meta name="twitter:creator" content="@author_handle">
twitter:siteis the publisher account (your brand), shown as attribution on the card.twitter:creatoris the individual author. Both take an@handle, not a URL.twitter:image:altis accessibility text for the card image.
How the Open Graph fallback actually works
X resolves each field by checking the twitter:* tag first, then falling back to its Open Graph counterpart:
| X uses | Falls back to |
|---|---|
| twitter:title | og:title |
| twitter:description | og:description |
| twitter:image | og:image |
There is no Open Graph equivalent of twitter:card, twitter:site, or twitter:creator; those have nothing to fall back to, so if you want them, you set them. This is why the practical advice is: ship full Open Graph tags for every platform, then add just twitter:card (plus site/creator if you want attribution) for X. Duplicating every field into twitter:* is only worth it when X needs different copy.
Why a card may not render
When a link posts as a plain URL with no preview, it's almost always one of these:
- No
twitter:cardand weak OG fallback. Without a card type and without usableog:image, X has nothing to build a large card from. - Image over HTTP. X requires HTTPS; an HTTP
twitter:image/og:imageis dropped. - Image too small.
summary_large_imagewants at least 600 × 314; smaller may downgrade to a small card or not unfurl. - Image not publicly fetchable. Behind a login, hotlink protection, or blocked for bots, so X's crawler can't
GETit. - Tags injected client-side. X's crawler reads the initial server-rendered HTML. If your meta tags are added by JavaScript after load, the crawler never sees them. Render them server-side.
- Stale cache. X caches by URL. After fixing tags, post the URL once (or in a draft) to trigger a re-crawl; the corrected card appears on the next fetch.
X's crawler, briefly
The bot that fetches your page identifies itself in the user agent (historically Twitterbot). It reads the raw HTML response and does not execute your JavaScript, so anything a framework injects after hydration is invisible to it. That's the single biggest gotcha on SPA-style sites: the tags exist in the browser DOM but not in the server response. Verify against the served HTML, not your dev tools.
Verify before you post
Check the tags a crawler actually receives, not what your framework renders client-side. Paste the URL into our OG Checker to see the resolved twitter:* and og:* values from the live response, then render the card with Social Preview to confirm summary_large_image looks right. Catching a client-side-only tag or an HTTP image here beats finding out from a flat link in your launch tweet. For how the same link renders on Facebook, LinkedIn, Slack, and Discord, see Open Graph and SEO impact.
Frequently Asked Questions
Do I still need Twitter Card tags if I already have Open Graph?
You only need twitter:card. X falls back to og:title, og:description, and og:image, but there's no OG equivalent for the card type; without it, X may not build a large card. Add other twitter:* tags only to override OG content on X specifically.
Why is my Twitter Card not showing?
Most often: a missing twitter:card, an image served over HTTP instead of HTTPS, an image under 600 × 314, tags injected client-side that the crawler can't see, or a stale cache. Re-post the URL to force a re-crawl after fixing.
What's the difference between twitter:site and twitter:creator?
twitter:site is the publishing account (your brand's @handle); twitter:creator is the individual author's @handle. Both are optional and shown as attribution. They take handles, not URLs.
Why do Twitter Cards use name= instead of property=?
Open Graph is an RDFa vocabulary that requires property=; Twitter Cards are plain meta tags that use name=. Using property= on twitter:* tags causes them to be ignored. Keep them straight in your <head>.
Do I need a separate image for the Twitter Card?
No. Reuse your 1200 × 630 Open Graph image with twitter:card set to summary_large_image. Only set a distinct twitter:image if you want a different visual on X.