Create X/Twitter cards that look like images, not marketing banners. Use when asked to "create OG images", "set up X cards", "make social cards", or "twitter card without text".
90
86%
Does it follow best practices?
Impact
91%
1.78xAverage score across 6 eval scenarios
Passed
No findings from the security scan
Create X cards that look like images, not marketing banners. Let the visual be the content — X already shows your title and description in the card UI.
| Spec | Value | Why |
|---|---|---|
| Dimensions | 2400×1200 physical (1200×600 logical) | 2x for retina, 2:1 aspect ratio |
| Safe margins | 50-56px padding (at 1x) | X clips edges on mobile |
| URL format | /og/page.png not /og/page?format=png | X prefers explicit extensions |
| Colors | #FFFFFF primary, avoid subtle grays | Thumbnails are tiny |
X overlays og:title as white text on the image. Hide it with a zero-width space:
<meta property="og:title" content="​" />In JSX: content={"\u200B"}
Your page <title> stays descriptive for SEO — only og:title uses the trick.
<meta property="og:image" content="https://example.com/og/page.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="600" />
<meta property="og:title" content="​" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="https://example.com/og/page.png" />Use @vercel/og with 2x scale and safe margins:
import { ImageResponse } from '@vercel/og';
const OG_SCALE = 2;
export async function GET(request: Request) {
return new ImageResponse(
(
<div style={{
width: '100%',
height: '100%',
display: 'flex',
backgroundColor: '#0a0f1c',
padding: 100, // 50px * 2 for safe margins
}}>
{/* Your visual content here */}
</div>
),
{ width: 1200 * OG_SCALE, height: 600 * OG_SCALE }
);
}app.get('/og/:slug.png', async (req, res) => {
const image = new ImageResponse(/* ... */);
const buffer = await image.arrayBuffer();
res.setHeader('Content-Type', 'image/png');
res.setHeader('Cache-Control', 'public, max-age=86400');
res.send(Buffer.from(buffer));
});For per-page OG images, two approaches:
Generate when crawler requests the image:
/og/[slug].png → generates image on requestRisk: X crawlers timeout after ~5 seconds. Cold starts can exceed this, causing blank previews.
Generate and store image when content is created:
// On content creation
const imageBuffer = await generateOgImage(data);
await db.insert({ ogImageData: imageBuffer }); // Store as BYTEA
// On request - instant response
app.get('/og/:id.png', (req, res) => {
const { ogImageData } = await db.get(req.params.id);
res.setHeader('Content-Type', 'image/png');
res.send(ogImageData);
});Pre-generation ensures instant response for crawlers.
.png extension in URLog:titleBuilt for BondTerminal. See it in action: example X post.
2f57aec
Also appears in
since Feb 24, 2026
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.