Codegea

Desarrollo

Desarrollo de software a medidaSistemas, plataformas e integraciones hechas a la medida de tu operaciónSitios corporativosProfesional, rápido y pensado para generar confianzaTiendas onlineCatálogo, pagos y envíos listos para vender las 24 horasWooCommerceTiendas WooCommerce rápidas, con pagos y factura de cada paísLanding pagesUna página enfocada en un solo objetivo: convertir visitantes en clientesApps móvilesApps iOS y Android a medida que ponen tu negocio en el bolsillo de tus clientes

Integración y CMS

Integraciones CMSWordPress, Strapi, Directus y Arc XP conectados a todo tu ecosistemaArc XPSoporte, implementación e integraciones para la plataforma de mediosMigracionesMigra tu sitio, plataforma o base de datos sin perder nada

Crecimiento e infraestructura

Automatización con IALa tecnología hace lo repetitivo y tu equipo se enfoca en lo que importaSEO on-pageQue Google te encuentre y te recomiende: optimización técnica y de contenidoServidores y hostingServidores rápidos y seguros, monitoreados 24/7
RetainerTu equipo dev, por mesDesde 20h al mes. Cuota fija.
Un cotizador con IA para cotizar servicios en minutosCotizaciones profesionales en minutos, con seguimiento de proyectos, vendedores y pagos en un solo lugar.Ver el caso

Por tipo

EcommerceTiendas y catálogosSitios corporativosMarca y captaciónPlataformas y appsSoftware a medida

Explorar

Todos los proyectosCasos y resultadosClientesQuién confía en nosotrosRetainerEquipo dev mensual

Blog

Todos los artículosGuías y opiniónBoletínUn correo al mesContactoRespondemos en 24h

Últimos artículos

Así está construido codegea.com: Next.js, Payload, Turso y R2CMS · 2026-10-20Cloudflare Workers: qué son y cuándo conviene usarlosNode.js · 2026-10-19Live Preview en Payload con Next.jsCMS · 2026-10-19
BoletínÚnete a nuestro boletínNotas prácticas de web, SEO e IA.
ServiciosDesarrollo de software a medidaSitios corporativosTiendas onlineWooCommerceLanding pagesApps móvilesIntegraciones CMSArc XPMigracionesAutomatización con IASEO on-pageServidores y hostingTu equipo dev, por mes
ProyectosCotizaciones profesionales en minutos, con seguimiento de proyectos, vendedores y pagos en un solo lugar.EcommerceSitios corporativosPlataformas y appsTodos los proyectosClientesRetainer
Retainer
BlogTodos los artículosBoletínContactoAsí está construido codegea.com: Next.js, Payload, Turso y R2Cloudflare Workers: qué son y cuándo conviene usarlosLive Preview en Payload con Next.jsÚnete a nuestro boletín
ESEN
Hablemos

Web

Cómo generar imágenes para compartir (OG) con código

Generar la imagen que se ve al compartir un enlace sin abrir un editor de diseño: next/og, fuentes de marca y un script que crea una por artículo y por idioma.

Derian Pinto · Founder & Full Stack Developer2026-10-183 min

Cuando compartes un enlace en WhatsApp, LinkedIn o X, la red muestra una imagen. Si no la defines, muestra algo al azar o nada. Hacerlas a mano para cada artículo es un trabajo que nadie mantiene. Nosotros las generamos con código: una por artículo y por idioma, con el titular dentro y la marca.

Esa imagen es la og:image de la página. Ya no se muestra dentro del artículo, donde repetía el título que está justo encima, pero sigue siendo lo que ven quienes comparten el enlace.

Las herramientas

  • next/og: la clase ImageResponse, que convierte un árbol de elementos de React en una imagen. Por debajo usa Satori.
  • sharp: para convertir esa imagen a WebP y comprimirla.
  • Un script que recorre los artículos y escribe los archivos.

Se podría usar el archivo especial opengraph-image de Next.js, que genera la imagen al pedirla. Elegimos un script por una razón práctica: así la imagen es un archivo, se sube a la biblioteca de medios del CMS y se puede reutilizar como meta.image, sin cálculo en cada petición.

Paso 1: el diseño es un componente

La portada es un componente de React con estilos en línea. Una versión mínima:

function Cover({ title }: { title: string }) {
  return (
    <div
      style={{
        width: '100%',
        height: '100%',
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'space-between',
        padding: '80px 96px',
        background: '#0B0F1A',
        color: '#EEF1F7',
      }}
    >
      <span style={{ fontFamily: 'Mono', fontSize: 28 }}>codegea</span>
      <div style={{ fontFamily: 'Sans', fontWeight: 500, fontSize: 112 }}>{title}</div>
    </div>
  );
}

Satori entiende un subconjunto de CSS: maquetación con flexbox, sin cuadrícula ni muchas propiedades modernas. Si algo no se ve, casi siempre es porque falta un display: 'flex'.

Paso 2: las fuentes

Satori no usa las fuentes del sistema: hay que pasarle los archivos. Nosotros descargamos las tres de marca una vez y las guardamos en una carpeta de caché:

const fonts = await loadFonts(CACHE);
// [{ name: 'Sans', data, weight: 500 }, { name: 'Serif', … }, { name: 'Mono', … }]

Luego se las das a ImageResponse en la opción fonts y las usas por su nombre en fontFamily.

Paso 3: de componente a archivo

const res = new ImageResponse(<Cover title={title} />, {
  width: 1600,
  height: 900,
  fonts,
});
const png = Buffer.from(await res.arrayBuffer());
await sharp(png).webp({ quality: 84 }).toFile(`covers/${slug}.${locale}.webp`);

Un detalle: Satori genera un PNG, que pesa bastante. Pasarlo por sharp a WebP lo deja en una fracción del tamaño. Nosotros usamos 1600×900; para las redes se recomienda un formato apaisado de proporción cercana a 1,91:1 (por ejemplo, 1200×630). Si prefieres ese formato, cambia las dimensiones.

Paso 4: el titular con una palabra destacada

Los titulares del sitio marcan una palabra con asteriscos para mostrarla en cursiva serif: Cómo generar *imágenes para compartir* con código. Una función separa el texto en palabras normales y destacadas, y el componente aplica otro estilo a las segundas:

{words(title).map((w, i) => (
  <span key={i} style={w.em ? { fontFamily: 'Serif', fontStyle: 'italic', color: '#5C7CF5' } : {}}>
    {w.text}
  </span>
))}

Paso 5: una por artículo y por idioma

El script lee el frontmatter de cada artículo, toma coverTitle (o title si no hay), calcula los minutos de lectura del cuerpo y genera la imagen de cada idioma. Después escribe la ruta del archivo en el propio artículo:

pnpm covers                # solo las que no tienen portada
pnpm covers mi-articulo    # regenera una, en es y en
pnpm covers --force        # todas

Como cada imagen lleva el titular dentro, hay una por idioma; no sirve la misma para el artículo en español y en inglés.

Lo que aprendimos

  • El texto largo se corta. Ajustamos el tamaño de letra según cuántos caracteres tiene el titular. Sin eso, un título largo se sale del cuadro.
  • Prueba la imagen en las redes. Cada red guarda en caché la imagen anterior; para ver el cambio tienes que pedirles que vuelvan a leer el enlace con sus herramientas de depuración.
  • No metas fotos de terceros ni logos ajenos. Una imagen de marca con tipografía es suficiente y evita problemas de derechos.

Si quieres ver cómo se conectan con el resto del sitio, mira así está construido codegea.com, y para revisar el resto del SEO de tus páginas, títulos y meta descriptions que suben el CTR.

¿Compartir este artículo?LinkedInWhatsAppX

Escrito por

Derian Pinto

Founder & Full Stack Developer

Fundador de Codegea. Desarrolla sitios, tiendas y plataformas a medida, e integra y da soporte a Arc XP para medios.

Únete a nuestro boletín

Un correo con novedades y notas prácticas de web, SEO e IA. Sin spam, y te das de baja cuando quieras.

¿Montamos tu proyecto?

¿Necesitas ayuda? Chatea con nosotros