Open Graph: como seu link fica bonito ao ser compartilhado
Cole o link de um post em qualquer mensageiro ou rede social e o resultado vai depender muito do que está escondido no <head> do HTML. Sem nenhuma instrução, o WhatsApp tenta adivinhar: pega a primeira imagem grande que encontra, ou nenhuma. Com as meta tags certas, o link vira um cartão completo, com imagem, título e descrição. Esse protocolo é o Open Graph.
O cartão no WhatsApp lê og:title, og:description e og:image direto do HTML.
A renderização muda entre plataformas, mas a fonte é a mesma — daí a importância de fornecer tags consistentes.
O protocolo em quatro tags
Open Graph foi criado pelo Facebook em 2010 e adotado por praticamente todas as plataformas. São meta tags simples no <head>:
<meta property="og:title" content="Context API no React" />
<meta property="og:description" content="Como compartilhar estado sem prop drilling." />
<meta property="og:image" content="https://seusite.com/blog/context-api/og.png" />
<meta property="og:url" content="https://seusite.com/blog/context-api" />Quando alguém compartilha um link, o crawler da plataforma faz uma requisição para a URL, lê essas tags e monta o preview. Título e descrição podem ser inferidos de <title> e <meta name="description"> se as variantes og: não existirem — mas a imagem não. Sem og:image, o cartão fica sem imagem ou pega qualquer imagem aleatória da página.
O tamanho recomendado é 1200 × 630 pixels. Vale também declarar og:image:width e og:image:height explicitamente: alguns crawlers usam esses valores para decidir o layout antes mesmo de baixar a imagem inteira, o que acelera o preview no primeiro paste.
ImageResponse no Next.js
O Next.js gera essas imagens por convenção: um arquivo chamado opengraph-image.tsx dentro de qualquer pasta de rota produz a imagem OG daquela rota — sem biblioteca externa, sem serviço de terceiros, sem nada no runtime.
import { ImageResponse } from 'next/og'
export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'
export default function OgImage() {
return new ImageResponse(
<div style={{ background: '#1e1e2e', width: '100%', height: '100%' }}>
<h1 style={{ color: 'white', fontSize: 80 }}>Meu Site</h1>
</div>,
{ ...size }
)
}O JSX passa por um renderizador baseado em Satori, não pelo browser. Isso significa um subconjunto bem específico do CSS: flexbox funciona, posicionamento absoluto funciona, mas grid completo não, pseudo-elementos não, e custom fonts precisam ser carregadas explicitamente. É o tipo de surpresa que melhor descobrir cedo do que tarde.
Imagens dinâmicas por post
O ganho real aparece quando a imagem reflete o conteúdo da página. Cada post do blog gera o próprio PNG com o título dele:
export default async function PostOgImage({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
const post = getPostBySlug(slug)
return new ImageResponse(
<div style={{ /* estilos do cartão */ }}>
<div style={{ fontSize: 64, fontWeight: 800 }}>
{post.title}
</div>
<div style={{ opacity: 0.6 }}>
Ana Laura · {post.tags.slice(0, 3).join(' · ')}
</div>
</div>,
{ width: 1200, height: 630 }
)
}getPostBySlug lê o .md correspondente e devolve os metadados; o componente compõe título e tags. Como o blog usa export estático, esses PNGs são gerados uma vez durante o next build e servidos depois como arquivos comuns.
O PNG resultante, 1200×630, com o título do post e a lista de tags.
As meta tags no HTML
Quando o opengraph-image.tsx existe, o Next.js injeta as tags relevantes em cada página automaticamente:
<meta property="og:image" content="/blog/context-api-react-sem-prop-drilling/opengraph-image" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:image" content="/blog/context-api-react-sem-prop-drilling/opengraph-image" />O Twitter (agora X) usa um namespace próprio (twitter:), mas o Next.js preenche os dois conjuntos a partir do mesmo arquivo. Não é preciso duplicar nada.