# 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.

URL: https://codegea.com/generar-imagenes-para-compartir-og-con-codigo
Web · 2026-10-18 · Derian Pinto

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:

```ts
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é:

```ts
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

```ts
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:

```ts
{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:

```bash
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](/asi-esta-construido-codegea-nextjs-payload-turso-r2), y para revisar el resto del SEO de tus páginas, [títulos y meta descriptions que suben el CTR](/titulos-y-meta-descriptions-que-suben-el-ctr).
