Skip to main content
Back to BlogSEO Tips

How to Make a Twitter Card (the Fetch Button That Doesn't Fetch, the JSON That Drops Your iPad, and the Validator Link That's Been Dead for Years)

Make Twitter Card meta tags with the generator — and learn why the Fetch button copies your hostname and gives up, why JSON export drops iPad fields and player streams, why image validation fails on images Twitter would display fine, and why the validator link points to a page Twitter retired.

The Toolbox TeamAugust 14, 20267 min read

Paste a URL. Hit Fetch. Get an apology.

You open the Twitter Card Generator, paste https://example.com/page into "Extract from URL," click Fetch. You expect it to pull your <head> and fill title, description, image. Instead it pops an alert — "Due to browser security restrictions, please manually check ${url}... use browser DevTools (F12 > Elements)" — and copies your hostname into Site and your URL into the URL field. That's the entire fetch. The button reads Fetch; the card reads Extract from URL. It does neither. Browsers block cross-origin reads, so the tool declines to try.

The generator assembles <meta name="twitter:*"> tags from fields you fill by hand. Draft tags here; extract elsewhere.

Four card types, four shapes

The Card Type picker offers summary, summary_large_image, app, and player:

Type Image Extra fields
summary thumbnail (1:1) none
summary_large_image large (2:1) none
app none iPhone/iPad/Google Play name, ID, URL
player video frame player URL (HTTPS), width, height, stream

Switching type hides a section but keeps your values in state, so switching back restores them.

Image validation uses CORS, and Twitter doesn't

Type an image URL and click Validate. The tool builds new Image(), sets crossOrigin = 'anonymous', and loads it. If the server doesn't return Access-Control-Allow-Origin, the image fires onerror and validation reports "Could not validate image." Your image is probably fine — Twitter's crawler fetches server-side and ignores CORS. The tool fails on images that will display perfectly in the feed. Treat a red "Could not validate" as "I couldn't check it," not "Twitter rejects it."

When it loads, it checks: minimum dimensions (120×120 for summary, 300×157 for large image), max 4096×4096, 5 MB, and aspect ratio within 0.3 of 1:1 or 2:1. App and player fall back to the large-image requirements. Uploads (JPG, PNG, WebP, GIF) validate from a DataURL and always load.

Your uploaded image becomes [YOUR_IMAGE_URL]

Upload an image and the preview shows it; the generated HTML does not. When uploadedImagePreview is set, generateTagsForData substitutes the literal [YOUR_IMAGE_URL] — the data URL is too large for a meta tag and wouldn't work for Twitter's crawler. The output reads <meta name="twitter:image" content="[YOUR_IMAGE_URL]" />. Host the image and replace the placeholder before deploy.

JSON export is lossy

HTML and JSON are built by two separate functions, and JSON drops fields HTML includes. For an app card, HTML emits iPhone, iPad, and Google Play name/id/url (nine tags). JSON emits only iPhone and Google Play name/id — iPad and every app:url gone. For a player card, HTML includes twitter:player:stream; JSON omits it. twitter:url never appears in JSON. Prefer HTML; if you must use JSON, hand-check the app and player sections.

Titles with a double quote break the tag

The generator interpolates your title straight into content="${data.title}" with no escaping. A title like She said "yes" — here's how produces <meta name="twitter:title" content="She said "yes" — here's how" /> — the attribute closes early at the inner " and the rest dangles as invalid HTML. Same for description, site, creator, alt, and every app/player field. Strip double quotes, or swap for &quot; after copy.

Two places link to https://cards-dev.twitter.com/validator — the Preview tab note and the final "Test your card" card. Twitter retired that validator years ago; the URL goes nowhere useful. There's no official replacement. To preview, drop the URL in a tweet draft (don't post) and watch it render. The in-app preview is an approximation — a 1.91:1 box, a square thumbnail — not Twitter's real rendering.

Limits and where the badge turns

Title caps at 70 (TITLE_LIMIT); description at 200 (DESC_LIMIT). The bar turns yellow at 60 / 180, red at 70 / 200. Twitter truncates in-feed around those numbers, but the visible cut is shorter. Alt caps at 420, matching Twitter's spec.

Gotchas

  • Multi-page export drops your uploads. exportAllMultiPages calls generateTagsForData(p.data, null)null means "no uploaded image," so exported tags use the image URL field (likely empty), not your upload. Host and paste the URL before saving the page.
  • No persistence. No localStorage. Refresh clears the form and every saved page card. Copy before you reload.
  • twitter:url is unofficial for summary cards; the crawler uses og:url or the canonical. Harmless, but don't rely on it.

Summary

  • The Fetch button doesn't fetch — it copies your hostname and URL, then alerts you to DevTools. Cross-origin reads are blocked, so the tool doesn't try. Draft tags here; extract elsewhere.
  • Image validation uses CORS and fails on images Twitter's server-side crawler would display fine. A red "Could not validate" means "I couldn't check it," not "Twitter rejects it."
  • Uploaded images become [YOUR_IMAGE_URL] — host the file and replace the placeholder before deploy.
  • JSON export is lossy: no iPad app fields, no app:url, no player:stream, no twitter:url. HTML retains all.
  • No content escaping — a double quote in your title closes the attribute early. Strip quotes or swap for &quot;.
  • The Card Validator link is dead. Preview in a tweet draft. Build at Twitter Card Generator; pair with Open Graph Generator and Meta Tag Generator. Related: Meta Tag Extractor, Schema Markup Generator.