Fábrica OG

Úsala en tu sitio

Tres formas, de menos a más trabajo. Las tres usan las mismas 32 plantillas y el mismo motor.

1

En el editor

Para una imagen suelta

Eliges una plantilla, escribes y descargas el PNG para subirlo a tu página o a tu CMS.

Gratis, sin cuenta

Abrir el editor
Recomendado2

En tu build

Para todas tus páginas

Un comando lee el título de cada página al construir tu sitio y dibuja su imagen. Sin servidor.

Gratis, en tu hosting de siempre

Ver el comando
3

Por URL

Para sistemas que generan páginas solas

Montas tu copia en un VPS, Docker o Cloudflare y la imagen sale de una dirección.

Lo que cueste tu servidor

Montar mi API

¿Cómo genero una imagen para cada página de mi sitio?

Con el comando, después de construir tu sitio. Lee el <title> de cada página, dibuja su imagen y, si la página no tiene og:image, le agrega las etiquetas. Es lo que hace gabrielneuman.com en cada build.

npm i -D github:gneuman/fabrica-ogimage
npx fabrica-ogimage dist --url https://tusitio.com --plantilla articulo --marca "Acme"

Funciona con cualquier generador que deje HTML en una carpeta: Astro, Next en modo estático, Hugo, Eleventy, Jekyll. En Netlify, Vercel o Cloudflare Pages lo agregas al final del comando de build:

npm run build && npx fabrica-ogimage dist --url https://tusitio.com
OpciónQué hace
--urlURL pública de tu sitio. Con ella, a las páginas sin og:image se les agregan las etiquetas.
--plantillaCuál usar: marca, articulo, titular, emoji, icono, perfil, boton, captura, telefono, ciudad, cita, cifra, versus, evento, duelo, cohort, miniatura, escaparate, tweet, ruta, lista, entrevista, ceoagentico, ceoportada, ceopromo, alianza, caja, recibo, podcast, contactos, equipo, precio. Por defecto, marca.
--marcaTexto que se quita del título: "Precios | Acme" queda en "Precios".
--autor, --sitio, --fotoIguales en todas las imágenes.
--fondo, --texto, --acentoTus colores, sin #.
--carpetaDónde quedan las imágenes dentro del build. Por defecto, og.

Si una página ya declara un og:image de tu sitio dentro de /og/, el comando dibuja la imagen en esa ruta y no toca el HTML.

¿Y si mi sitio es Astro?

Usa la integración: corre lo mismo al terminar cada build y toma la URL de tu astro.config.

import fabricaOg from 'fabrica-ogimage/astro'

export default defineConfig({
  site: 'https://tusitio.com',
  integrations: [fabricaOg({ plantilla: 'marca', marca: 'Acme', fijos: { sitio: 'tusitio.com' } })],
})

¿Cómo monto la API por URL en mi servidor?

La API sirve cuando las páginas se crean solas y no hay un build donde correr el comando: una tienda, un CMS, una app. La imagen sale de una dirección que pegas en tu og:image:

<meta property="og:image" content="https://tu-dominio.com/og/articulo?titulo=Mi%20primer%20post&autor=Ana%20L%C3%B3pez&acento=3b5bdb" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />

Cada dirección se dibuja una vez y se guarda; la segunda petición sale de la caché. Elige dónde correrla:

La más barata si ya tienes servidor

Un VPS con Docker

Sin límite de CPU por petición: pagas el servidor y nada más. Yo uso Hostinger; el plan más chico (KVM 1) alcanza para la API.

git clone https://github.com/gneuman/fabrica-ogimage
cd fabrica-ogimage
docker build -t fabrica-og .
docker run -d --restart unless-stopped -p 3000:3000 \
  -v fabrica-og-cache:/app/.cache fabrica-og

Ponle tu dominio con HTTPS (Caddy, Nginx o el proxy gratis de Cloudflare). Con el proxy de Cloudflare, además, la plantilla ciudad detecta el país.

El de Hostinger es mi link de afiliado: si contratas por ahí gano una comisión, sin costo extra para ti.

Sin administrar servidor

Cloudflare Workers

Un clic copia el repo a tu GitHub, lo conecta a tu cuenta y lo publica. Detecta ciudad y país solo.

Deploy to Cloudflare

Necesita Workers Paid (5 USD al mes): dibujar una imagen usa de 20 a 500 milisegundos de CPU y el plan gratis da 10 por petición. La caché de un año hace que cada URL se dibuje una sola vez.

¿Solo quieres el sitio y el editor, como este? Pon API_OG=off en las variables del Worker y todo corre en el plan gratis.

Conectas el repo y listo

Render, Railway o Fly.io

Conectas tu copia del repo, detectan el Dockerfile y la publican con HTTPS. Revisa el plan de cada uno: los gratis suelen apagar el servidor cuando no tiene tráfico y la primera imagen tarda más.

Si ya tienes Node

Node, sin Docker

En cualquier servidor con Node 22:

npx -p github:gneuman/fabrica-ogimage fabrica-ogimage-servidor

Escucha en el puerto 3000 (PORT) y guarda la caché en .cache/og hasta 500 MB (CACHE_MAX_MB).

¿Qué parámetros acepta cada plantilla?

Los colores van sin # (acento=3b5bdb) y los espacios como %20. El editor de cada plantilla te arma la dirección.

Ver los 31 parámetros
ParámetroQué cambiaEn qué plantillas
tituloTítuloPon *entre asteriscos* lo que va en color de acento.marca, articulo, titular, emoji, icono, boton, captura, telefono, ciudad, cita, cifra, versus, evento, duelo, cohort, miniatura, escaparate, tweet, ruta, lista, entrevista, ceoagentico, ceopromo, alianza, caja, podcast, contactos, equipo, precio
subSubtítulomarca, titular, icono, perfil, telefono, ciudad, cita, cifra, duelo, cohort, escaparate, entrevista, ceoagentico, ceoportada, alianza, caja, recibo, podcast, contactos, equipo, precio
extractoExtractoarticulo, alianza, caja, precio
autorAutor o nombremarca, articulo, perfil, ciudad, cita, tweet, entrevista, ceoagentico, ceopromo, alianza, caja, podcast
sitioSitiomarca, articulo, perfil, captura, cifra, cohort, lista, entrevista, ceoagentico, ceopromo, alianza, caja, podcast, precio
botonTexto del botóntitular, boton, evento, miniatura, alianza, precio
fotoFoto (URL)marca, articulo, perfil, cita, miniatura, escaparate, tweet, ruta, entrevista, ceoagentico, ceopromo, alianza, podcast, contactos, equipo
imagenCaptura (URL)captura, telefono, ciudad, miniatura, escaparate, tweet
foto2Foto del anfitrión (URL)ceoagentico, ceoportada, ceopromo, contactos
anfitrionAnfitriónceoagentico, ceoportada, ceopromo
emojiEmojiemoji, boton
iconoÍcono de LucideEl nombre en lucide.dev, p. ej. rocket, workflow, bot.icono, escaparate
icono2Segundo ícono de LucideEl de la derecha, sobre fondo blanco. P. ej. github, bot.escaparate
fondoFondomarca, articulo, titular, emoji, icono, perfil, boton, captura, telefono, ciudad, cita, cifra, versus, evento, duelo, cohort, miniatura, escaparate, tweet, ruta, lista, entrevista, ceoagentico, ceoportada, ceopromo, alianza, caja, recibo, podcast, contactos, equipo, precio
textoTextomarca, articulo, titular, emoji, icono, perfil, boton, captura, telefono, ciudad, cita, cifra, versus, evento, duelo, cohort, miniatura, escaparate, tweet, ruta, lista, entrevista, ceoagentico, ceoportada, ceopromo, alianza, caja, recibo, podcast, contactos, equipo, precio
acentoAcentomarca, articulo, titular, emoji, icono, perfil, boton, captura, telefono, ciudad, cita, cifra, versus, evento, duelo, cohort, miniatura, escaparate, tweet, ruta, lista, entrevista, ceoagentico, ceoportada, ceopromo, alianza, caja, recibo, podcast, contactos, equipo, precio
ciudadCiudadVacío: la de quien ve la imagen. En el título usa {ciudad} y {pais}.ciudad
paisPaís (código de 2 letras)MX, CO, AR, ES… Vacío: el de quien ve la imagen.ciudad
cifraCifracifra, recibo, precio
izquierdaOpción de la izquierdaEn duelo: Nombre | > comando | ✓ paso | ✓ paso.versus, duelo
derechaOpción de la derecha (resaltada)versus, duelo
fechaFechaDía y mes, p. ej. 29 OCT.evento, duelo, cohort, ceopromo, precio
lugarLugar u horarioevento, duelo
logoLogo (URL)Sin logo sale el sitio en texto.alianza, caja
pilaresPilaresHasta 3, separados con |: ícono de Lucide: texto. P. ej. truck: Monitoreo de flotas.alianza
totalTotalVacío: la cifra.recibo
productoProductoEl nombre en la caja; *entre asteriscos* va en el acento.caja
lemaLemaUna o dos frases cortas debajo del nombre.caja
resumenResumenMayúsculas espaciadas bajo la raya; *entre asteriscos* va en el acento.caja
etiquetasEtiquetasHasta 4, separadas con |.caja
puntosPuntosDe 2 a 4, separados con |.cohort, ruta, lista, ceopromo, caja, recibo, contactos, equipo, precio

¿Cómo funciona la imagen por país y ciudad?

La plantilla ciudad pone la bandera y la ciudad en la imagen. Cada dato sale de la URL o, si no viene, de la conexión de quien pide la imagen.

ParámetroSi viene en la URLSi no viene
paisCódigo de 2 letras (ISO 3166): MX, CO, ES. Pone la bandera y el nombre en español.El país de la conexión, según Cloudflare.
ciudadEl texto tal cual: Monterrey.La ciudad de la conexión, según Cloudflare. A veces no la sabe; entonces queda el país.
titulo, subAceptan {ciudad} y {pais}, que se cambian por los valores de arriba.
imagenFoto de fondo, con un velo oscuro encima.Degradado de fondo a acento, o una foto de la ciudad si en Cloudflare pones el secreto UNSPLASH_KEY.

Con los dos datos fijos, la imagen es igual para todos y se guarda un año:

https://tu-dominio.com/og/ciudad?titulo=Taller%20presencial%20en%20%7Bciudad%7D&ciudad=Monterrey&pais=MX

Sin ellos, cambia según quién la pide:

https://tu-dominio.com/og/ciudad?titulo=Hola%20desde%20%7Bpais%7D

En Cloudflare Workers la ubicación sale sola. En el servidor de Node o Docker sale de las cabeceras CF-IPCountry y CF-IPCity, que llegan cuando tu dominio pasa por el proxy de Cloudflare; sin él, pásalas en la URL. Las imágenes por ubicación se guardan aparte y salen con Cache-Control: private, max-age=3600, para que ninguna caché intermedia le muestre a un visitante la ciudad de otro.

Antes de usarla en un link: cuando compartes una página, la imagen OG la pide el servidor de WhatsApp, LinkedIn, X o Facebook, no la persona. Ese servidor casi siempre está en Estados Unidos, así que con detección automática la tarjeta saldría con la ciudad del servidor. En un og:image, fija ciudad y pais. La detección automática sirve en imágenes que carga la persona: dentro de una página, en una landing o en el editor de esta fábrica.

Para tu propio código, GET /api/ubicacion/ devuelve {"pais":"MX","region":"…","ciudad":"…"}. No dibuja nada, así que en Cloudflare corre en el plan gratis.

¿Cuánto cuesta?

El código es abierto (licencia MIT) y está en GitHub. El editor, la galería y el comando son gratis. La API cuesta lo que cueste el servidor donde la montes: un VPS que ya tengas, el plan de Render o Railway, o Workers Paid en Cloudflare (5 USD al mes, con 30 millones de milisegundos de CPU y 10 millones de peticiones incluidos).