Skip to content

X Cards schema

Built-in id: x:cards:1.0

Published at: https://hawkeyexl.github.io/manni/schemas/x-cards/1.0.json

The twitter:* meta tags that decide how a link renders when someone shares it on X. It is the companion to ogp:article:1.0, on the same <meta> channel and through the same extractor. The two normally ship together, which is why a site with Open Graph tags and no card tags is the usual half-finished state.

It is one of the metadata vocabularies.

Run it beside ogp:article:1.0 on the pages you publish with social cards:

manni.config.yaml
meta:
overrides:
- files: "site/**/*.html"
schemas:
- ogp:article:1.0
- x:cards:1.0
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@exampledocs" />
<meta name="twitter:title" content="Validate document metadata in CI" />
<meta name="twitter:description" content="Fail the build when frontmatter is missing." />
<meta name="twitter:image" content="https://example.com/img/card.png" />
FieldTypeNotes
twitter:cardsummary | summary_large_image | app | playerRequired.
twitter:site, twitter:creatorstringA handle, with or without the @.
twitter:site:id, twitter:creator:idstring | integerNumeric account ids.
twitter:titlestring70 characters.
twitter:descriptionstring200 characters.
twitter:imagestringAn HTTPS URL.
twitter:image:altstring420 characters.
twitter:player, twitter:player:streamstringHTTPS URLs. Player cards.
twitter:player:width, twitter:player:heightstring | integerPixels.
twitter:app:*stringName, id, and URL per platform, plus twitter:app:country.

Every other tag on the card has an Open Graph fallback: X reads og:title, og:description and og:image when the twitter: equivalents are absent. A page carrying good Open Graph tags and no twitter:title is correct, so requiring one here would fail it.

twitter:card is the exception. It has no fallback, and X will not infer a card type from Open Graph alone. Without it no card renders at all, however complete the rest of the markup is. That is the whole of what this schema insists on.

The length caps are real limits rather than style advice: X truncates past them. And twitter:image must be HTTPS, because an image served over plain HTTP is dropped and the card renders without it.

Allowed. Open Graph tags and any other key sit beside the card tags.

---
"twitter:card": summary_large_image
"twitter:site": "@exampledocs"
"twitter:image": https://example.com/img/card.png
---

An image URL over plain HTTP fails, because X drops it:

✗ docs/share.md
/twitter:image must match pattern "^https://" (line 3) [x:cards:1.0]