O que og-image-kit faz?
Objetivo: toda página pública deve ter uma imagem de compartilhamento de 1200×630 e as tags og:* / twitter:* corretas, e você deve verificá-las com scripts/check_og.py, não apenas escrevê-las.
Etapa 1 — Detectar a pilha
Olhe o repositório antes de escrever qualquer coisa:
| Sinal | Pilha | Vá para |
|---|---|---|
next no package.json e um diretório app/ (ou src/app/) | Next.js App Router | Etapa 2A |
next apenas com pages/ | Next.js Pages Router | Etapa 2C (estático) ou adicione /api/og com ImageResponse |
astro no package.json | Astro | Etapa 2B |
| HTML simples, Hugo, Jekyll, Vite SPA, qualquer outra coisa | Estático | Etapa 2C |
Também encontre: a URL base canônica do site (variável de ambiente como NEXT_PUBLIC_SITE_URL, site em astro.config.*), as cores da marca, o logotipo e a fonte em uso. Pergunte ao usuário apenas se nenhum puder ser encontrado.
Etapa 2A — Next.js App Router
- Certifique-se de que o layout raiz exporte
metadataBase(URLs OG devem ser absolutas):export const metadata = { metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000") } - Copie
assets/nextjs/opengraph-image.tsxparaapp/opengraph-image.tsx(padrão do site). EditeBRAND, cores e slogan. - Para rotas dinâmicas (posts de blog, produtos), copie-o no segmento de rota, por exemplo,
app/blog/[slug]/opengraph-image.tsx, e useassets/nextjs/dynamic-opengraph-image.tsx, que lêparamse carrega o título da sua fonte de dados. No Next.js 15+paramsé uma Promise — useawait. - Adicione
twitter-image.tsxapenas se o card do X precisar ser diferente; caso contrário, o Next.js reutiliza a imagem OG quando você definetwitter: { card: "summary_large_image" }nos metadados. - Texto por página: defina
titleedescriptionnosmetadata/generateMetadatade cada página. - Fontes personalizadas: carregue um TTF/OTF (não WOFF2) via
fetch(new URL("./Inter-Bold.ttf", import.meta.url))oureadFile. Texto CJK precisa de um arquivo de fonte CJK, caso contrário, renderiza como quadrados — faça um subconjunto para reduzir o tamanho.
Limites a respeitar (next/og / satori): apenas flexbox (sem grid), toda div com vários filhos precisa de
display: "flex", mantenha o bundle pequeno — a documentação do ImageResponse do Next.js lista um limite de 500 KB para
JSX + CSS + fontes + imagens. Fontes grandes também tornam a renderização lenta, portanto, faça subconjuntos.
Etapa 2B — Astro
Use assets/astro/og-endpoint.ts como src/pages/og/[...slug].png.ts. Ele renderiza um PNG por página em
tempo de build com satori + @resvg/resvg-js (npm i satori @resvg/resvg-js), e você o referencia a partir do seu layout:
<meta property="og:image" content={new URL(`/og/${slug}.png`, Astro.site)} />
Astro.site deve ser definido em astro.config.mjs. Arquivo de fonte: coloque um TTF em src/assets/fonts/.
Etapa 2C — Sites estáticos / qualquer outra coisa
Gere PNGs uma vez e os commite:
python3 scripts/generate_og.py --pages pages.json --out public/og --brand "Acme" --bg "#0f172a" --fg "#ffffff" --accent "#38bdf8"
pages.json é uma lista de {"slug": "pricing", "title": "...", "subtitle": "..."} (veja
assets/pages.example.json). Requer Pillow (pip install pillow). Passe --font path/to/font.ttf
para fontes da marca ou texto CJK (ex.: Noto Sans SC). Em seguida, adicione tags a cada página (modelo em
references/meta-tags.md).
Etapa 3 — Tags obrigatórias (toda página)
<meta property="og:title" content="Título da página" />
<meta property="og:description" content="Uma frase, ≤ ~160 caracteres" />
<meta property="og:image" content="https://exemplo.com/og/page.png" /> <!-- URL absoluta -->
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:url" content="https://exemplo.com/page" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
O Next.js gera estas a partir de metadata + opengraph-image.tsx; não escreva duplicatas manualmente.
Etapa 4 — Verificar (não pule)
Execute contra o site em execução (servidor de desenvolvimento, deploy de pré-visualização ou produção):
python3 scripts/check_og.py http://localhost:3000/ http://localhost:3000/pricing
python3 scripts/check_og.py --json https://exemplo.com/ # legível por máquina
Ele busca cada página, verifica as tags obrigatórias, se og:image é absoluta, acessível,
um content-type de imagem, ~1.91:1 e pelo menos 600 px de largura, e abaixo de 5 MB. Código de saída 1 em caso de erro.
Corrija tudo marcado como ERROR; itens WARN são recomendações.
Nota: as plataformas sociais armazenam prévias em cache. Após a correção, use o depurador da própria plataforma
(LinkedIn Post Inspector, Facebook Sharing Debugger) para re-raspar. O X não tem mais um validador público;
publique em um rascunho/DM para verificar. URLs localhost não podem ser raspadas por essas ferramentas — faça o deploy primeiro.
Regras de design para a imagem
- 1200×630, PNG, texto dentro de uma margem de segurança de ~60 px; título ≤ ~60 caracteres, máximo 3 linhas.
- Alto contraste; é mostrada pequena (~500 px de largura) nos feeds. Teste com zoom de 50%.
- Inclua nome/logotipo da marca; evite texto muito pequeno (< 28 px na largura de 1200).
- Veja
references/platform-specs.mdpara notas específicas de cada plataforma.
Concluído quando
- Toda página indexável retorna og:title, og:description, og:image (absoluta), twitter:card
-
check_og.pysai com código 0 para a página inicial e pelo menos uma página de cada tipo de rota - As imagens estão corretas (abra um PNG e observe)