Cuando compartes un enlace en Facebook, Twitter, LinkedIn, Discord o Slack, la tarjeta de vista previa enriquecida que aparece está impulsada por las meta tags Open Graph (OG) y las tags Twitter Card. Configurarlas correctamente significa más clics y una apariencia más profesional. Esta referencia completa cubre cada tag, cada requisito de plataforma y cada error común.
Genera meta tags perfectas con nuestro generador gratuito →
Tags Open Graph Esenciales
El protocolo Open Graph fue creado por Facebook en 2010 y ahora es adoptado por casi todas las plataformas sociales.
og:title
El título de tu página en la tarjeta de compartir. Mantenlo bajo 60 caracteres.
<meta property="og:title" content="How to Build a REST API with Node.js in 2026" />og:description
Un resumen del contenido mostrado bajo el título. Apunta a 120-160 caracteres.
<meta property="og:description" content="Step-by-step guide to building a production-ready REST API with Node.js, Express, and TypeScript. Includes auth, validation, and deployment." />og:image
La imagen en la tarjeta de compartir. El tag más impactante — las publicaciones con imagen obtienen 2-3x más engagement. Debe ser una URL absoluta.
<meta property="og:image" content="https://example.com/images/rest-api-guide-og.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="REST API with Node.js — Complete Guide" />
<meta property="og:image:type" content="image/png" />og:url
La URL canónica de la página.
<meta property="og:url" content="https://example.com/blog/rest-api-nodejs" />og:type
El tipo de contenido. Valores comunes: website, article, product, profile.
<!-- For a general page -->
<meta property="og:type" content="website" />
<!-- For a blog post / article -->
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2026-02-10T08:00:00Z" />
<meta property="article:author" content="https://example.com/about" />
<meta property="article:section" content="Technology" />
<meta property="article:tag" content="Node.js" />
<meta property="article:tag" content="REST API" />Tags Open Graph Adicionales
Más allá de lo básico, estos tags ofrecen control más fino sobre cómo se muestra tu contenido:
<!-- Site name — shown above the title on Facebook -->
<meta property="og:site_name" content="DevToolBox" />
<!-- Locale — language_TERRITORY format -->
<meta property="og:locale" content="en_US" />
<meta property="og:locale:alternate" content="fr_FR" />
<meta property="og:locale:alternate" content="de_DE" />
<meta property="og:locale:alternate" content="es_ES" />
<meta property="og:locale:alternate" content="ja_JP" />
<!-- Video (for og:type = video.*) -->
<meta property="og:video" content="https://example.com/video.mp4" />
<meta property="og:video:width" content="1280" />
<meta property="og:video:height" content="720" />
<meta property="og:video:type" content="video/mp4" />
<!-- Audio -->
<meta property="og:audio" content="https://example.com/podcast-ep1.mp3" />
<meta property="og:audio:type" content="audio/mpeg" />Tags Twitter Card
Twitter (ahora X) soporta su propio sistema de tarjetas con cuatro tipos. Twitter recurre a las tags OG si faltan las tags específicas de Twitter.
Tipos de Twitter Card
| Tipo de tarjeta | Descripción | Caso de uso |
|---|---|---|
| summary | Imagen cuadrada pequeña con título y descripción | Posts de blog, páginas generales |
| summary_large_image | Imagen grande sobre título y descripción | Contenido visual |
| player | Reproductor de video/audio integrado en el tweet | Hosting de video, podcasts |
| app | Tarjeta de descarga directa de aplicación | Promoción App Store / Google Play |
<!-- Summary Card (small image) -->
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@yourusername" />
<meta name="twitter:creator" content="@authorname" />
<meta name="twitter:title" content="How to Build a REST API with Node.js" />
<meta name="twitter:description" content="Complete guide with auth, validation, and deployment." />
<meta name="twitter:image" content="https://example.com/images/rest-api-square.png" />
<meta name="twitter:image:alt" content="REST API Guide illustration" />
<!-- Summary Card with Large Image -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@yourusername" />
<meta name="twitter:title" content="How to Build a REST API with Node.js" />
<meta name="twitter:description" content="Complete guide with auth, validation, and deployment." />
<meta name="twitter:image" content="https://example.com/images/rest-api-wide.png" />
<!-- Player Card (video/audio) -->
<meta name="twitter:card" content="player" />
<meta name="twitter:player" content="https://example.com/embed/video123" />
<meta name="twitter:player:width" content="1280" />
<meta name="twitter:player:height" content="720" />
<!-- App Card -->
<meta name="twitter:card" content="app" />
<meta name="twitter:app:id:iphone" content="123456789" />
<meta name="twitter:app:id:googleplay" content="com.example.app" />
<meta name="twitter:app:name:iphone" content="My App" />
<meta name="twitter:app:name:googleplay" content="My App" />Requisitos de Imagen por Plataforma
Cada plataforma tiene diferentes requisitos de tamaño de imagen:
| Plataforma | Tamaño recomendado | Tamaño mínimo | Tamaño máx. | Relación aspecto | Formatos |
|---|---|---|---|---|---|
| 1200 x 630 | 600 x 315 | 8 MB | 1.91:1 | JPG, PNG, GIF, WebP | |
| Twitter (summary) | 144 x 144 | 144 x 144 | 5 MB | 1:1 | JPG, PNG, GIF, WebP |
| Twitter (large image) | 1200 x 675 | 300 x 157 | 5 MB | 2:1 / 16:9 | JPG, PNG, GIF, WebP |
| 1200 x 627 | 200 x 200 | 5 MB | 1.91:1 | JPG, PNG | |
| Discord | 1200 x 630 | 256 x 256 | 8 MB | 1.91:1 | JPG, PNG, GIF |
| 1200 x 630 | 300 x 200 | 5 MB | 1.91:1 | JPG, PNG | |
| Slack | 1200 x 630 | 250 x 250 | 5 MB | 1.91:1 | JPG, PNG, GIF |
| Telegram | 1200 x 630 | 200 x 200 | 5 MB | 1.91:1 | JPG, PNG |
| 1000 x 1500 | 600 x 600 | 10 MB | 2:3 | JPG, PNG | |
| iMessage | 1200 x 630 | 300 x 300 | 5 MB | 1.91:1 | JPG, PNG |
Ejemplo Completo de Marcado HTML
Aquí hay un head HTML listo para producción con todas las tags OG y Twitter Card:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Primary Meta Tags -->
<title>How to Build a REST API with Node.js in 2026</title>
<meta name="description" content="Step-by-step guide to building a production-ready REST API with Node.js, Express, and TypeScript." />
<link rel="canonical" href="https://example.com/blog/rest-api-nodejs" />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="article" />
<meta property="og:url" content="https://example.com/blog/rest-api-nodejs" />
<meta property="og:title" content="How to Build a REST API with Node.js in 2026" />
<meta property="og:description" content="Step-by-step guide to building a production-ready REST API with Node.js, Express, and TypeScript." />
<meta property="og:image" content="https://example.com/images/rest-api-og.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="REST API with Node.js guide banner" />
<meta property="og:site_name" content="My Dev Blog" />
<meta property="og:locale" content="en_US" />
<!-- Article-specific OG tags -->
<meta property="article:published_time" content="2026-02-10T08:00:00Z" />
<meta property="article:modified_time" content="2026-02-10T12:00:00Z" />
<meta property="article:author" content="https://example.com/about" />
<meta property="article:section" content="Web Development" />
<meta property="article:tag" content="Node.js" />
<meta property="article:tag" content="REST API" />
<meta property="article:tag" content="TypeScript" />
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@yourusername" />
<meta name="twitter:creator" content="@authorname" />
<meta name="twitter:title" content="How to Build a REST API with Node.js in 2026" />
<meta name="twitter:description" content="Step-by-step guide to building a production-ready REST API." />
<meta name="twitter:image" content="https://example.com/images/rest-api-twitter.png" />
<meta name="twitter:image:alt" content="REST API with Node.js guide banner" />
</head>
<body>
<!-- Page content -->
</body>
</html>Ejemplos por Framework
Los frameworks modernos proporcionan APIs integradas para gestionar meta tags:
Next.js (App Router — Metadata API)
// app/blog/[slug]/page.tsx
import { Metadata } from 'next';
type Props = { params: { slug: string } };
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
alternates: {
canonical: `https://example.com/blog/${params.slug}`,
},
openGraph: {
type: 'article',
title: post.title,
description: post.excerpt,
url: `https://example.com/blog/${params.slug}`,
siteName: 'My Dev Blog',
locale: 'en_US',
images: [
{
url: post.ogImage, // Must be absolute URL
width: 1200,
height: 630,
alt: post.title,
},
],
publishedTime: post.date,
authors: [post.author],
tags: post.tags,
},
twitter: {
card: 'summary_large_image',
site: '@yourusername',
creator: '@authorname',
title: post.title,
description: post.excerpt,
images: [
{
url: post.twitterImage, // Can differ from OG image
alt: post.title,
},
],
},
};
}
export default function BlogPost({ params }: Props) {
// Page component...
}Nuxt 3 (useSeoMeta)
<!-- pages/blog/[slug].vue -->
<script setup lang="ts">
const route = useRoute();
const { data: post } = await useFetch(`/api/posts/${route.params.slug}`);
useSeoMeta({
title: post.value.title,
description: post.value.excerpt,
ogType: 'article',
ogTitle: post.value.title,
ogDescription: post.value.excerpt,
ogUrl: `https://example.com/blog/${route.params.slug}`,
ogImage: post.value.ogImage,
ogImageWidth: 1200,
ogImageHeight: 630,
ogImageAlt: post.value.title,
ogSiteName: 'My Dev Blog',
ogLocale: 'en_US',
articlePublishedTime: post.value.date,
articleAuthor: post.value.author,
articleTag: post.value.tags,
twitterCard: 'summary_large_image',
twitterSite: '@yourusername',
twitterCreator: '@authorname',
twitterTitle: post.value.title,
twitterDescription: post.value.excerpt,
twitterImage: post.value.twitterImage,
twitterImageAlt: post.value.title,
});
</script>
<template>
<article>
<!-- Page content -->
</article>
</template>HTML Estático
<!-- For static HTML sites, simply add meta tags in <head> -->
<!-- You can automate this with a build tool or templating engine -->
<!-- Example with Eleventy (11ty) Nunjucks template -->
<head>
<title>{{ title }}</title>
<meta name="description" content="{{ description }}" />
<meta property="og:type" content="{% if layout == 'post' %}article{% else %}website{% endif %}" />
<meta property="og:title" content="{{ title }}" />
<meta property="og:description" content="{{ description }}" />
<meta property="og:image" content="{{ site.url }}{{ ogImage }}" />
<meta property="og:url" content="{{ site.url }}{{ page.url }}" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="{{ title }}" />
<meta name="twitter:description" content="{{ description }}" />
<meta name="twitter:image" content="{{ site.url }}{{ ogImage }}" />
</head>
<!-- Example with Hugo -->
<!-- layouts/partials/head.html -->
<meta property="og:title" content="{{ .Title }}" />
<meta property="og:description" content="{{ .Description }}" />
<meta property="og:image" content="{{ .Params.ogImage | absURL }}" />
<meta property="og:url" content="{{ .Permalink }}" />
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="{{ .Title }}" />
<meta name="twitter:image" content="{{ .Params.ogImage | absURL }}" />Errores Comunes y Soluciones
Los problemas más frecuentes con las meta tags sociales:
| # | Error | Problema | Solución |
|---|---|---|---|
| 1 | Relative image URLs | og:image="/images/og.png" — platforms cannot resolve relative paths | Always use absolute URLs: og:image="https://example.com/images/og.png" |
| 2 | Missing image dimensions | Facebook may not display the image on first share without width/height | Always include og:image:width and og:image:height tags |
| 3 | HTTP instead of HTTPS | Many platforms reject or warn about non-HTTPS image URLs | Serve all OG images over HTTPS. Use protocol-relative URLs as last resort |
| 4 | Not handling cache | Platforms cache previews for hours/days; updating tags has no immediate effect | Use platform debug tools to force refresh. Append ?v=2 for cache-busting |
| 5 | Same tags on every page | Every page shows the same preview card — confusing and poor CTR | Generate unique og:title, og:description, og:image per page |
| 6 | Missing twitter:card tag | Twitter will not render any card at all without this tag | Always include <meta name="twitter:card" content="summary_large_image" /> |
| 7 | Image too large (>8MB) | Facebook silently fails; Twitter shows no image | Optimize images: compress to <1MB, use JPEG for photos, PNG for graphics |
| 8 | Wrong image aspect ratio | Image gets cropped awkwardly — text cut off, faces cropped | Use 1200x630 (1.91:1) for OG, 1200x675 (16:9) for Twitter large image |
| 9 | Duplicate og:image tags | Unpredictable behavior — platform may pick the wrong image | Use only one og:image tag per page (or intentionally provide multiple with primary first) |
| 10 | Forgetting og:url | Shares from different URLs (www vs non-www, query params) counted separately | Set og:url to the canonical URL to consolidate share counts |
Herramientas de Prueba y Depuración
Siempre valida tus meta tags antes de publicar. Cada plataforma cachea las vistas previas agresivamente.
| Herramienta | Plataforma | URL | Notas |
|---|---|---|---|
| Facebook Sharing Debugger | Facebook / Meta | developers.facebook.com/tools/debug/ | Shows all OG tags, image preview, and errors. Click "Scrape Again" to refresh cache. |
| Twitter Card Validator | Twitter / X | cards-dev.twitter.com/validator | Preview your Twitter Card. Validates tag structure. Requires Twitter login. |
| LinkedIn Post Inspector | linkedin.com/post-inspector/ | Validates OG tags for LinkedIn. Click "Inspect" to refresh cached preview. | |
| OpenGraph.xyz | Universal | opengraph.xyz | Preview how your URL appears on Facebook, Twitter, LinkedIn, Discord simultaneously. |
| Metatags.io | Universal | metatags.io | Real-time preview editor. Edit tags and see Facebook/Twitter/Google previews instantly. |
| Social Share Preview (VS Code) | Development | VS Code Extension | Preview OG tags directly in your IDE without deploying. |
| Ngrok / Cloudflare Tunnel | Development | ngrok.com | Expose localhost to test with real platform validators during development. |
Imágenes OG Dinámicas
Generar imágenes sociales únicas por página aumenta dramáticamente la tasa de clics.
Por Qué Importan las Imágenes OG Dinámicas
Sitios como GitHub, Vercel y DEV.to generan imágenes OG por página.
<!-- Instead of this (same image for every page): -->
<meta property="og:image" content="https://example.com/default-og.png" />
<!-- Generate this (unique per page): -->
<meta property="og:image" content="https://example.com/api/og?title=How+to+Build+a+REST+API" />Generación con @vercel/og
// app/api/og/route.tsx — Next.js Edge Route Handler
import { ImageResponse } from 'next/og';
import { NextRequest } from 'next/server';
export const runtime = 'edge';
export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url);
const title = searchParams.get('title') || 'Default Title';
const description = searchParams.get('desc') || '';
return new ImageResponse(
(
<div
style={{
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
padding: '60px 80px',
background: 'linear-gradient(135deg, #0f172a 0%, #1e293b 100%)',
fontFamily: 'Inter, sans-serif',
}}
>
<div style={{
fontSize: 56,
fontWeight: 800,
color: '#f8fafc',
lineHeight: 1.2,
marginBottom: 20,
}}>
{title}
</div>
{description && (
<div style={{
fontSize: 24,
color: '#94a3b8',
lineHeight: 1.5,
}}>
{description}
</div>
)}
<div style={{
display: 'flex',
alignItems: 'center',
marginTop: 'auto',
fontSize: 20,
color: '#64748b',
}}>
example.com
</div>
</div>
),
{
width: 1200,
height: 630,
}
);
}
// Usage in metadata:
// openGraph: { images: [`/api/og?title=${encodeURIComponent(post.title)}`] }Generación con Node Canvas
// scripts/generate-og-images.ts — Build-time generation
import { createCanvas, registerFont } from 'canvas';
import fs from 'fs';
import path from 'path';
registerFont('fonts/Inter-Bold.ttf', { family: 'Inter', weight: 'bold' });
interface OGConfig {
title: string;
slug: string;
theme?: string;
}
function generateOGImage(config: OGConfig): Buffer {
const { title, theme = '#0f172a' } = config;
const width = 1200;
const height = 630;
const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');
// Background gradient
const gradient = ctx.createLinearGradient(0, 0, width, height);
gradient.addColorStop(0, theme);
gradient.addColorStop(1, '#1e293b');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
// Title text
ctx.fillStyle = '#f8fafc';
ctx.font = 'bold 52px Inter';
const words = title.split(' ');
let line = '';
let y = 240;
for (const word of words) {
const test = line + word + ' ';
if (ctx.measureText(test).width > 1040) {
ctx.fillText(line.trim(), 80, y);
line = word + ' ';
y += 70;
} else {
line = test;
}
}
ctx.fillText(line.trim(), 80, y);
// Site name
ctx.fillStyle = '#64748b';
ctx.font = 'bold 24px Inter';
ctx.fillText('example.com', 80, 560);
return canvas.toBuffer('image/png');
}
// Generate for all posts
const posts: OGConfig[] = [
{ title: 'How to Build a REST API with Node.js', slug: 'rest-api-nodejs' },
{ title: 'TypeScript Generics Explained', slug: 'typescript-generics' },
];
for (const post of posts) {
const buffer = generateOGImage(post);
const outPath = path.join('public', 'og', `${post.slug}.png`);
fs.mkdirSync(path.dirname(outPath), { recursive: true });
fs.writeFileSync(outPath, buffer);
console.log(`Generated: ${outPath}`);
}Usando Transformaciones URL de Cloudinary
// Using Cloudinary URL-based image transformations
// No server-side code needed — just construct the URL
function getCloudinaryOGImage(title: string): string {
const cloudName = 'your-cloud-name';
const baseImage = 'og-template.png'; // Upload a background template first
// URL-encode the title
const encodedTitle = encodeURIComponent(title);
// Cloudinary text overlay transformation
return [
`https://res.cloudinary.com/${cloudName}/image/upload`,
// Resize to OG dimensions
'w_1200,h_630,c_fill',
// Add text overlay
`l_text:Inter_52_bold:${encodedTitle}`,
'co_rgb:f8fafc', // Text color
'g_west', // Left-align
'x_80,y_-40', // Position
'w_1040,c_fit', // Max text width
// Base image
baseImage,
].join('/');
}
// Usage:
// <meta property="og:image"
// content={getCloudinaryOGImage('How to Build a REST API with Node.js')} />
// Result URL looks like:
// https://res.cloudinary.com/your-cloud-name/image/upload/
// w_1200,h_630,c_fill/
// l_text:Inter_52_bold:How%20to%20Build%20a%20REST%20API/
// co_rgb:f8fafc,g_west,x_80,y_-40,w_1040,c_fit/
// og-template.pngPreguntas Frecuentes
¿Cuál es la diferencia entre Open Graph y Twitter Card?
Open Graph fue creado por Facebook y es el estándar universal usado por Facebook, LinkedIn, Discord, Slack, WhatsApp, etc. Twitter Cards es el sistema propietario de Twitter/X. Twitter recurre a tags OG si faltan las tags de Twitter.
¿Necesito ambos tipos de tags?
Técnicamente no — Twitter lee las tags OG como respaldo. Pero la mejor práctica es incluir ambos ya que twitter:card no tiene equivalente OG y es necesario para que Twitter muestre una tarjeta.
¿Por qué no aparece mi imagen OG al compartir?
Causas más comunes: URL relativa en lugar de absoluta, URL de imagen devuelve 404, archivo demasiado grande, plataforma ha cacheado versión anterior, tags og:image:width y og:image:height faltantes.
¿Cuál es el tamaño ideal de imagen OG?
El tamaño recomendado es 1200 x 630 píxeles con relación de aspecto 1.91:1.
¿Cómo forzar la actualización de la vista previa OG?
Cada plataforma tiene su propia herramienta: Facebook Sharing Debugger, Twitter Card Validator, LinkedIn Post Inspector.
¿Puedo usar imágenes diferentes para Facebook y Twitter?
Sí. Configura la imagen de Facebook con og:image y la de Twitter con twitter:image. Twitter prefiere twitter:image cuando ambas están presentes.