Exporte tarefas com guias detalhados ou copie um prompt pronto para Cursor/Codex corrigir o site.
Pré-visualizar checklist
# GEO Score — Checklist dev
- **Domínio:** https://example.com
- **Pergunta/dor:**
- **Score:** 10/100 (red)
- **Audit:** cb8459bd-08da-4fce-a750-fbe3bf1bf005 · 2026-10-05
## Tarefas (por impacto)
- [ ] **`P1-RENDER`** · CRITICAL — Conteúdo depende fortemente de JavaScript
- HTML cru = 18.5% do texto renderizado (limiar 20%)
- Texto visível sem JS: 171 caracteres
- Texto visível com JS: 926 caracteres
- Sem JS (início): "Example Domain This domain is for use in documentation examples without needing permission. This is not a service; avoid relying on it for testing and monitoring purposes."
- Com JS (início): "Example Domain This domain is for use in documentation examples without needing permission. This is not a service; avoid relying on it for testing and monitoring purposes. هذا النط"
- Ação: Adicione SSR/SSG ou pre-render para crawlers que não executam JS.
- **Guia:**
- Confirme o stack (Next.js, Nuxt, React SPA, WordPress, Webflow, etc.).
- Meça: o HTML inicial da home deve conter texto principal visível sem executar JS.
- Escolha uma estratégia: SSR/SSG (preferido), pre-render estático, ou renderização híbrida das rotas públicas.
- Garanta que `<title>`, `<h1>` e parágrafos introdutórios existam no HTML servido ao crawler.
- Re-teste: ratio texto cru vs renderizado deve ser ≥20%.
- **Snippets:**
- Next.js App Router — forçar SSR na página:
```
// app/page.tsx
export const dynamic = 'force-dynamic' // ou use SSG com generateStaticParams
export default function HomePage() {
return (
<>
<h1>Título principal</h1>
<p>Descrição do produto visível no HTML inicial.</p>
</>
)
}
```
- Nuxt 3 — SSG/SSR (default em rotas de marketing):
```
// pages/index.vue — evite ClientOnly para conteúdo principal
<template>
<h1>{{ title }}</h1>
<p>{{ intro }}</p>
</template>
```
- Meta tag fallback (não substitui SSR, só mitiga):
```
<noscript>
<h1>Título</h1>
<p>Resumo do produto para crawlers sem JavaScript.</p>
</noscript>
```
- **Pronto quando:**
- View Source da home mostra H1 e texto principal sem depender de JS
- Audit P1-RENDER passa (≥20% do texto renderizado no HTML cru)
- **Notas:**
- Se o audit indicou headless indisponível, configure Playwright no worker antes de re-testar.
- [ ] **`P2-JSONLD`** · CRITICAL — JSON-LD ausente
- Nenhum bloco JSON-LD em https://example.com/
- Busca: <script type="application/ld+json"> — 0 ocorrências
- URL analisada: https://example.com/
- Ação: Adicione JSON-LD (Organization, Product/SoftwareApplication, FAQPage).
- **Guia:**
- Adicione pelo menos um bloco `<script type="application/ld+json">` na home (ou layout global).
- Inclua `Organization` ou `SoftwareApplication`/`Product` com name, url, description, logo.
- Valide JSON (vírgulas, aspas) — JSON inválido é pior que ausência.
- Opcional: adicione `WebSite` com `potentialAction` SearchAction se houver busca.
- **Snippets:**
- Organization + SoftwareApplication:
```
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"name": "Nome da Marca",
"url": "https://example.com",
"logo": "https://example.com/logo.png"
},
{
"@type": "SoftwareApplication",
"name": "Nome do Produto",
"applicationCategory": "BusinessApplication",
"operatingSystem": "Web",
"description": "O que o produto faz em uma frase.",
"url": "https://example.com"
}
]
}
</script>
```
- **Pronto quando:**
- ≥1 bloco JSON-LD válido no HTML da home
- Audit P2-JSONLD passa
- [ ] **`P1-ROBOTS-EXISTS`** · HIGH — robots.txt ausente ou inacessível
- GET https://example.com/robots.txt → HTTP 404
- URL testada: https://example.com/robots.txt
- Ação: Publique um robots.txt em /robots.txt referenciando o sitemap e permitindo crawlers de IA.
- **Guia:**
- Crie o arquivo `public/robots.txt` (ou equivalente na raiz do site servido em `/robots.txt`).
- Permita crawlers públicos e bots de IA nas páginas de marketing (home, produto, blog, docs).
- Adicione a linha `Sitemap:` apontando para o sitemap canônico (HTTPS).
- Faça deploy e valide com `curl -I https://seudominio/robots.txt` → HTTP 200.
- **Snippets:**
- robots.txt mínimo:
```
User-agent: *
Allow: /
User-agent: GPTBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: PerplexityBot
Allow: /
Sitemap: https://example.com/sitemap.xml
```
- **Pronto quando:**
- GET /robots.txt retorna HTTP 200 com conteúdo text/plain
- Audit P1-ROBOTS-EXISTS passa
- [ ] **`P1-SITEMAP`** · HIGH — sitemap.xml ausente ou vazio
- sitemap → HTTP 404, 0 URL(s)
- Testado: https://example.com/sitemap.xml
- Ação: Publique um sitemap.xml com as URLs canônicas do site.
- **Guia:**
- Gere um `sitemap.xml` com URLs canônicas HTTPS (home, produto, principais landings, blog).
- Configure o CMS/framework para atualizar o sitemap ao publicar páginas.
- Referencie o sitemap no `robots.txt` (linha `Sitemap:`).
- Submeta o sitemap no Google Search Console (opcional, mas recomendado).
- **Snippets:**
- sitemap.xml mínimo:
```
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://example.com/</loc>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://example.com/pricing</loc>
</url>
</urlset>
```
- **Pronto quando:**
- GET /sitemap.xml → HTTP 200 com ≥1 URL
- Audit P1-SITEMAP passa
- [ ] **`P1-LLMS-TXT`** · MEDIUM — llms.txt ausente
- GET https://example.com/llms.txt → HTTP 404
- URL testada: https://example.com/llms.txt
- Raiz = mapa; detalhes por página = Markdown linkado (não um arquivo único gigante)
- Declare rel=alternate / describedby nas páginas importantes
- Ação: Crie /llms.txt na raiz (índice leve: o que é, FAQ, links). Se o conteúdo varia por página, publique .md por URL e liste no índice — ver guia do finding.
- **Guia:**
- Crie `/llms.txt` na raiz (ex.: `public/llms.txt`) — obrigatório para o GEO Score e ponto de entrada dos agentes.
- Trate a raiz como **índice leve**: H1 com o nome, blockquote com o que é / para quem, seções curtas (problema, público, FAQ) e uma lista de links Markdown para páginas-chave.
- Se o site tem conteúdo distinto por página/seção: **não** cole tudo num único arquivo gigante. Publique Markdown por URL importante (ex.: `/precos.md`, `/produto/x.md`) ou `llms.txt` por escopo (ex.: `/docs/llms.txt`).
- No `/llms.txt` raiz, liste esses arquivos: `- [Preços](https://seudominio/precos.md): planos e condições`.
- Na HTML de cada página importante, declare descoberta: `<link rel="alternate" type="text/markdown" href="…">` e/ou `<link rel="describedby" href="/llms.txt">` (ou o llms do escopo). Alternativa: header HTTP `Link`.
- Mantenha o HTML da página rico (H1, abertura, FAQ) — busca grounded (Perplexity etc.) ainda cita HTML; llms.txt/MD reforçam contexto, não substituem a página.
- Faça deploy e valide: `curl https://seudominio/llms.txt` e os `.md` linkados.
- **Snippets:**
- llms.txt raiz (índice + links):
```
# Nome do Produto / Marca
> Descrição direta em 1–2 frases: o que é, para quem, principal benefício.
## O que resolve
- Problema 1
- Problema 2
## Para quem é
- Público A
- Público B
## Perguntas frequentes
### O que é [produto]?
Resposta direta.
## Docs e páginas (Markdown)
- [Home](https://example.com/): visão geral
- [Preços](https://example.com/precos.md): planos e condições
- [Produto X](https://example.com/produtos/x.md): para quem é e diferencial
- [FAQ](https://example.com/faq.md): objeções comuns
## Links HTML
- Site: https://example.com
- Contato: https://example.com/contato
```
- Markdown por página (ex.: /precos.md):
```
# Preços — Nome do Produto
> Planos para [público]. Sem cartão no trial.
## Planos
- Starter: …
- Pro: …
## Perguntas frequentes
### Tem teste grátis?
Sim, X dias.
```
- Descoberta no HTML / header:
```
<!-- no <head> da página /precos -->
<link rel="alternate" type="text/markdown" href="https://example.com/precos.md" />
<link rel="describedby" href="https://example.com/llms.txt" />
# ou HTTP:
# Link: </precos.md>; rel="alternate"; type="text/markdown", </llms.txt>; rel="describedby"
```
- **Pronto quando:**
- GET /llms.txt → HTTP 200 com conteúdo Markdown
- Arquivo tem título H1, pelo menos 2 seções H2 e ≥100 palavras
- Audit P1-LLMS-TXT passa
- (Recomendado) Páginas-chave têm .md ou llms de escopo linkados a partir da raiz
- **Notas:**
- Padrão llmstxt.org: raiz = mapa; conteúdo específico = links / subpaths; o mais específico cobre o escopo.
- LLMs preferem Markdown limpo sob demanda. Arquivo único enorme estoura contexto e é pior que índice + pedaços.
- O audit v1 só valida /llms.txt na home — MD por página não sobe a nota, mas melhora citação correta.
- Opcional: /llms-full.txt com texto concatenado para agentes que pedem contexto completo (manutenção mais cara).
- [ ] **`P1-LINK-HEADERS`** · MEDIUM — Headers HTTP Link (RFC 8288) ausentes
- GET https://example.com/ sem header Link — agentes não descobrem llms.txt, sitemap ou API pelo HTTP
- Não confundir com <link> no HTML (canonical no <head> não conta). O check lê o header HTTP Link.
- Formato: Link: </llms.txt>; rel="describedby"; type="text/markdown"
- Nenhum header Link na resposta da home
- Ação: Adicione headers Link na home apontando para /llms.txt, sitemap e, se houver API, /.well-known/api-catalog.
- **Guia:**
- Confirme que o check é o header HTTP `Link`, não a tag HTML `<link rel="canonical">`.
- Na home, envie pelo menos um `Link` apontando para recursos que agentes devem descobrir: `/llms.txt`, `/sitemap.xml`, docs de API se existirem.
- Em hosting estático: `_headers` (Netlify/Cloudflare Pages), `nitro.routeRules`, ou config do CDN/nginx.
- Valide: `curl -sI https://seudominio.com/ | findstr /i Link` (Windows) ou `curl -sI … | grep -i ^link`.
- **Snippets:**
- Headers HTTP (RFC 8288):
```
Link: </llms.txt>; rel="describedby"; type="text/markdown"
Link: </sitemap.xml>; rel="index"
Link: </.well-known/api-catalog>; rel="api-catalog"
```
- Nuxt — nitro.routeRules:
```
nitro: {
routeRules: {
'/': {
headers: {
Link: '</llms.txt>; rel="describedby"; type="text/markdown", </sitemap.xml>; rel="index"',
},
},
},
},
```
- Cloudflare Pages / Netlify — public/_headers:
```
/
Link: </llms.txt>; rel="describedby"; type="text/markdown"
Link: </sitemap.xml>; rel="index"
```
- **Pronto quando:**
- GET / inclui header Link com rel de descoberta (describedby, index, api-catalog ou service-doc)
- Audit P1-LINK-HEADERS passa
- **Notas:**
- Verificado pelo isitagentready.com (Discoverability).
- Landing sem API: describedby → llms.txt + index → sitemap já basta. api-catalog só se houver catálogo RFC 9727.
- [ ] **`P2-H1`** · MEDIUM — H1 ausente
- 0 elemento(s) <h1> em https://example.com/
- Nenhum <h1> encontrado no HTML da home
- Ação: Use exatamente um H1 descritivo por página.
- **Guia:**
- Se a evidência mencionar SPA / HTML cru vazio / P1-RENDER: não “adicione H1 no design” — ative SSR/SSG primeiro para o H1 ir no HTML inicial.
- Confirme no View Source (não só no DevTools Elements) se existe exatamente um `<h1>`.
- Se o HTML já tem conteúdo e há 0 ou >1 H1: escolha UM H1 principal (hero) e converta extras em `<h2>`.
- Evite H1 no header global + hero ao mesmo tempo.
- **Snippets:**
- Estrutura correta (após SSR):
```
<main>
<h1>Título principal da página</h1>
<h2>Seção secundária (antes era H1 duplicado)</h2>
</main>
```
- Nuxt — garantir HTML no servidor:
```
// nuxt.config — marketing precisa de HTML inicial
export default defineNuxtConfig({
ssr: true, // ou nitro.preset: 'static' + generate
})
```
- **Pronto quando:**
- View Source mostra exatamente 1 <h1>
- Audit P2-H1 passa
- **Notas:**
- H1 só no DOM após JS não conta para crawlers/LLMs que não executam JavaScript.
- Use os textos da evidência se houver múltiplos H1 no HTML cru.
- [ ] **`P2-HEADINGS`** · MEDIUM — Nenhum heading no HTML cru
- Sequência de níveis:
- Nenhum heading (H1–H6) no HTML da home
- Ação: Inclua headings semânticos (H1 → H2 → H3) no HTML da página.
- **Guia:**
- Se a evidência indicar shell SPA / HTML cru vazio: priorize P1-RENDER (SSR/SSG). Hierarquia no Vue não aparece no HTML cru.
- Com HTML inicial populado: revise o outline (H1 → H2 → H3).
- Corrija saltos (ex.: H1 → H3) inserindo H2 ou rebaixando níveis.
- Não use headings só por estilo — ajuste CSS em vez de pular níveis.
- Prefira H2/H3 como perguntas em conteúdo FAQ-style.
- **Pronto quando:**
- View Source tem headings; sequência sem saltos >1 nível
- Audit P2-HEADINGS passa
- **Notas:**
- Sem SSR, “corrigir hierarquia” no componente não muda o que o GEO Score ou bots de IA leem.
- [ ] **`P2-OPENING`** · MEDIUM — Abertura pouco extratível
- Primeiros parágrafos não definem o produto claramente
- Parágrafo 1 (156 chars): "This domain is for use in documentation examples without needing permission. This is not a service; avoid relying on it…"
- Ação: Defina o produto de forma direta nos 2 primeiros parágrafos ("X é uma ferramenta de Y que Z").
- **Guia:**
- Se a evidência indicar SPA / HTML cru sem <p>: ative SSR/SSG primeiro (P1-RENDER) — reescrever copy no Hero.vue não coloca texto no HTML inicial.
- Com HTML populado: reescreva os 2 primeiros parágrafos acima da dobra.
- Primeira frase: "[Marca] é [categoria] que [benefício principal]."
- Segunda frase: público-alvo ou diferencial concreto.
- Evite abrir só com slogans ou CTAs.
- **Snippets:**
- Modelo de abertura:
```
<p>Acme é uma plataforma de gestão de tempo para equipes remotas que integra timesheet, aprovações e relatórios em um só lugar.</p>
<p>Indicada para agências e consultorias B2B que cobram por hora e usam Slack no dia a dia.</p>
```
- **Pronto quando:**
- View Source mostra parágrafo de abertura >50 chars com definição clara
- Audit P2-OPENING passa
- **Notas:**
- GEO mede o HTML cru. Texto só após JS = abertura “ausente” para crawlers.
- [ ] **`P2-CANONICAL`** · MEDIUM — URL canônica (<link rel="canonical">) ausente
- Nenhum <link rel="canonical"> encontrado em https://example.com/
- Página analisada: https://example.com/
- O canonical evita conteúdo duplicado e ajuda motores de IA a identificar a URL autoritativa.
- Ação: Adicione <link rel="canonical" href="https://seudominio.com/"> no <head> de cada página.
- **Guia:**
- Adicione `<link rel="canonical" href="URL_CANÔNICA">` no `<head>` de cada página.
- A URL deve ser absoluta (https://), apontar para a versão preferida da página.
- Para Nuxt: use `useHead({ link: [{ rel: "canonical", href: url }] })` ou configure no `nuxt.config`.
- Para Next.js: use `<Head><link rel="canonical" href={url} /></Head>` ou metadata API.
- **Snippets:**
- HTML direto:
```
<link rel="canonical" href="https://example.com/" />
```
- Nuxt 3 (nuxt.config.js — head global):
```
head: {
link: [
{ rel: 'canonical', href: 'https://example.com/' }
]
}
```
- **Pronto quando:**
- <link rel="canonical"> presente no HTML com URL HTTPS válida
- Audit P2-CANONICAL passa
- [ ] **`P2-META`** · MEDIUM — Metadados incompletos
- title, meta description ou og:title ausentes ou muito curtos
- title (14 chars): "Example Domain"
- meta description: (ausente)
- og:title: (ausente)
- Ação: Preencha title, meta description e og:title com texto descritivo (>10 chars).
- **Guia:**
- Preencha `<title>` único e descritivo (marca + proposta de valor, ~50–60 chars).
- Adicione `<meta name="description">` com benefício claro (~120–160 chars).
- Configure `<meta property="og:title">` (pode espelhar title ou ser mais marketing).
- Opcional: `og:description` e `og:image` para compartilhamento.
- **Snippets:**
- Meta tags mínimas:
```
<title>Acme — Gestão de tempo para equipes remotas</title>
<meta name="description" content="Controle horas, aprovações e relatórios. Integração com Slack. Teste grátis.">
<meta property="og:title" content="Acme — Gestão de tempo para equipes remotas">
```
- **Pronto quando:**
- title, meta description e og:title presentes com >10 caracteres cada
- Audit P2-META passa
- **Notas:**
- Compare com os valores ausentes/curtos listados na evidência do audit.
- [ ] **`P1-AI-TXT`** · LOW — Content Signals (ai.txt) ausente
- GET https://example.com/.well-known/ai.txt → HTTP 404
- URL testada: https://example.com/.well-known/ai.txt
- Declarar política aumenta confiança de agentes e pode melhorar indexação em motores que respeitam Content Signals.
- Ação: Crie /.well-known/ai.txt declarando sua política de uso por IA (treino, busca, inferência).
- **Guia:**
- Crie o diretório `public/.well-known/` se não existir.
- Crie o arquivo `ai.txt` declarando sua política de uso do conteúdo para IA.
- Deploy e valide com `curl https://seudominio/.well-known/ai.txt`.
- **Snippets:**
- ai.txt mínimo (permite busca e inferência, nega treino):
```
# AI Usage Policy — https://seudominio.com
# Baseado no padrão Content Signals (isitagentready.com)
Allow: search
Allow: inference
Disallow: training
```
- ai.txt permissivo (permite tudo):
```
# AI Usage Policy
Allow: search
Allow: inference
Allow: training
```
- **Pronto quando:**
- GET /.well-known/ai.txt → HTTP 200
- Arquivo declara pelo menos Allow: search e Allow: inference
- Audit P1-AI-TXT passa
- **Notas:**
- Content Signals é verificado pelo Cloudflare isitagentready.com e está se tornando padrão.
- Negar treino mas permitir search/inference é o padrão mais seguro para a maioria dos sites.
- [ ] **`P1-MARKDOWN`** · LOW — Servidor não serve Markdown por negociação de conteúdo
- Requisição com Accept: text/markdown não retornou text/markdown
- LLMs preferem Markdown limpo a HTML — menos tokens, menos ruído.
- Para Nuxt/Next.js: adicione um endpoint /api/content ou middleware de content negotiation.
- Para sites estáticos: serve /llms.txt já cobre a maioria dos casos práticos.
- Ação: Configure o servidor/framework para responder com Markdown quando solicitado via Accept: text/markdown.
- **Guia:**
- Avalie se faz sentido para seu stack — sites estáticos já têm /llms.txt como alternativa mais simples.
- Para Nuxt/Next.js: adicione middleware que, quando `Accept: text/markdown` for enviado, sirva uma versão Markdown da página.
- Para sites estáticos: garanta que /llms.txt esteja rico — é o equivalente prático.
- **Snippets:**
- Nuxt server middleware (server/middleware/markdown.ts):
```
export default defineEventHandler(async (event) => {
const accept = getHeader(event, 'accept') ?? ''
if (!accept.includes('text/markdown')) return
// Redireciona para versão Markdown equivalente
const url = getRequestURL(event)
if (url.pathname === '/') {
setHeader(event, 'content-type', 'text/markdown; charset=utf-8')
// retorne o conteúdo Markdown da home
return '# Worklift\n\nDescrição Markdown da home...'
}
})
```
- **Pronto quando:**
- GET / com Accept: text/markdown retorna Content-Type: text/markdown
- Audit P1-MARKDOWN passa
- **Notas:**
- Este check tem impacto prático menor que llms.txt — priorize os outros primeiro.
## Prompt para code agent (todos os findings)
Copie o bloco abaixo para Cursor/Codex:
```
Você está corrigindo múltiplos problemas de GEO (Generative Engine Optimization) em um site.
Trabalhe por ordem de severidade. Mudanças mínimas, estilo consistente.
## Contexto
- Domínio: https://example.com
- Pergunta/dor:
- Score atual: 10/100
- Audit ID: cb8459bd-08da-4fce-a750-fbe3bf1bf005
## 13 finding(s) a tratar
---
### 1. P1-RENDER — Conteúdo depende fortemente de JavaScript (critical)
HTML cru = 18.5% do texto renderizado (limiar 20%)
Detalhes coletados:
- Texto visível sem JS: 171 caracteres
- Texto visível com JS: 926 caracteres
- Sem JS (início): "Example Domain This domain is for use in documentation examples without needing permission. This is not a service; avoid relying on it for testing and monitoring purposes."
- Com JS (início): "Example Domain This domain is for use in documentation examples without needing permission. This is not a service; avoid relying on it for testing and monitoring purposes. هذا النط"
**Ação resumida:** Adicione SSR/SSG ou pre-render para crawlers que não executam JS.
## Passos
1. Confirme o stack (Next.js, Nuxt, React SPA, WordPress, Webflow, etc.).
2. Meça: o HTML inicial da home deve conter texto principal visível sem executar JS.
3. Escolha uma estratégia: SSR/SSG (preferido), pre-render estático, ou renderização híbrida das rotas públicas.
4. Garanta que `<title>`, `<h1>` e parágrafos introdutórios existam no HTML servido ao crawler.
5. Re-teste: ratio texto cru vs renderizado deve ser ≥20%.
## Snippets (adapte ao stack do projeto)
### Next.js App Router — forçar SSR na página
```
// app/page.tsx
export const dynamic = 'force-dynamic' // ou use SSG com generateStaticParams
export default function HomePage() {
return (
<>
<h1>Título principal</h1>
<p>Descrição do produto visível no HTML inicial.</p>
</>
)
}
```
### Nuxt 3 — SSG/SSR (default em rotas de marketing)
```
// pages/index.vue — evite ClientOnly para conteúdo principal
<template>
<h1>{{ title }}</h1>
<p>{{ intro }}</p>
</template>
```
### Meta tag fallback (não substitui SSR, só mitiga)
```
<noscript>
<h1>Título</h1>
<p>Resumo do produto para crawlers sem JavaScript.</p>
</noscript>
```
## Definition of done
- View Source da home mostra H1 e texto principal sem depender de JS
- Audit P1-RENDER passa (≥20% do texto renderizado no HTML cru)
## Notas
- Se o audit indicou headless indisponível, configure Playwright no worker antes de re-testar.
---
### 2. P2-JSONLD — JSON-LD ausente (critical)
Nenhum bloco JSON-LD em https://example.com/
Detalhes coletados:
- Busca: <script type="application/ld+json"> — 0 ocorrências
- URL analisada: https://example.com/
**Ação resumida:** Adicione JSON-LD (Organization, Product/SoftwareApplication, FAQPage).
## Passos
1. Adicione pelo menos um bloco `<script type="application/ld+json">` na home (ou layout global).
2. Inclua `Organization` ou `SoftwareApplication`/`Product` com name, url, description, logo.
3. Valide JSON (vírgulas, aspas) — JSON inválido é pior que ausência.
4. Opcional: adicione `WebSite` com `potentialAction` SearchAction se houver busca.
## Snippets (adapte ao stack do projeto)
### Organization + SoftwareApplication
```
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"name": "Nome da Marca",
"url": "https://example.com",
"logo": "https://example.com/logo.png"
},
{
"@type": "SoftwareApplication",
"name": "Nome do Produto",
"applicationCategory": "BusinessApplication",
"operatingSystem": "Web",
"description": "O que o produto faz em uma frase.",
"url": "https://example.com"
}
]
}
</script>
```
## Definition of done
- ≥1 bloco JSON-LD válido no HTML da home
- Audit P2-JSONLD passa
---
### 3. P1-ROBOTS-EXISTS — robots.txt ausente ou inacessível (high)
GET https://example.com/robots.txt → HTTP 404
Detalhes coletados:
- URL testada: https://example.com/robots.txt
**Ação resumida:** Publique um robots.txt em /robots.txt referenciando o sitemap e permitindo crawlers de IA.
## Passos
1. Crie o arquivo `public/robots.txt` (ou equivalente na raiz do site servido em `/robots.txt`).
2. Permita crawlers públicos e bots de IA nas páginas de marketing (home, produto, blog, docs).
3. Adicione a linha `Sitemap:` apontando para o sitemap canônico (HTTPS).
4. Faça deploy e valide com `curl -I https://seudominio/robots.txt` → HTTP 200.
## Snippets (adapte ao stack do projeto)
### robots.txt mínimo
```
User-agent: *
Allow: /
User-agent: GPTBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: PerplexityBot
Allow: /
Sitemap: https://example.com/sitemap.xml
```
## Definition of done
- GET /robots.txt retorna HTTP 200 com conteúdo text/plain
- Audit P1-ROBOTS-EXISTS passa
---
### 4. P1-SITEMAP — sitemap.xml ausente ou vazio (high)
sitemap → HTTP 404, 0 URL(s)
Detalhes coletados:
- Testado: https://example.com/sitemap.xml
**Ação resumida:** Publique um sitemap.xml com as URLs canônicas do site.
## Passos
1. Gere um `sitemap.xml` com URLs canônicas HTTPS (home, produto, principais landings, blog).
2. Configure o CMS/framework para atualizar o sitemap ao publicar páginas.
3. Referencie o sitemap no `robots.txt` (linha `Sitemap:`).
4. Submeta o sitemap no Google Search Console (opcional, mas recomendado).
## Snippets (adapte ao stack do projeto)
### sitemap.xml mínimo
```
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://example.com/</loc>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://example.com/pricing</loc>
</url>
</urlset>
```
## Definition of done
- GET /sitemap.xml → HTTP 200 com ≥1 URL
- Audit P1-SITEMAP passa
---
### 5. P1-LLMS-TXT — llms.txt ausente (medium)
GET https://example.com/llms.txt → HTTP 404
Detalhes coletados:
- URL testada: https://example.com/llms.txt
- Raiz = mapa; detalhes por página = Markdown linkado (não um arquivo único gigante)
- Declare rel=alternate / describedby nas páginas importantes
**Ação resumida:** Crie /llms.txt na raiz (índice leve: o que é, FAQ, links). Se o conteúdo varia por página, publique .md por URL e liste no índice — ver guia do finding.
## Passos
1. Crie `/llms.txt` na raiz (ex.: `public/llms.txt`) — obrigatório para o GEO Score e ponto de entrada dos agentes.
2. Trate a raiz como **índice leve**: H1 com o nome, blockquote com o que é / para quem, seções curtas (problema, público, FAQ) e uma lista de links Markdown para páginas-chave.
3. Se o site tem conteúdo distinto por página/seção: **não** cole tudo num único arquivo gigante. Publique Markdown por URL importante (ex.: `/precos.md`, `/produto/x.md`) ou `llms.txt` por escopo (ex.: `/docs/llms.txt`).
4. No `/llms.txt` raiz, liste esses arquivos: `- [Preços](https://seudominio/precos.md): planos e condições`.
5. Na HTML de cada página importante, declare descoberta: `<link rel="alternate" type="text/markdown" href="…">` e/ou `<link rel="describedby" href="/llms.txt">` (ou o llms do escopo). Alternativa: header HTTP `Link`.
6. Mantenha o HTML da página rico (H1, abertura, FAQ) — busca grounded (Perplexity etc.) ainda cita HTML; llms.txt/MD reforçam contexto, não substituem a página.
7. Faça deploy e valide: `curl https://seudominio/llms.txt` e os `.md` linkados.
## Snippets (adapte ao stack do projeto)
### llms.txt raiz (índice + links)
```
# Nome do Produto / Marca
> Descrição direta em 1–2 frases: o que é, para quem, principal benefício.
## O que resolve
- Problema 1
- Problema 2
## Para quem é
- Público A
- Público B
## Perguntas frequentes
### O que é [produto]?
Resposta direta.
## Docs e páginas (Markdown)
- [Home](https://example.com/): visão geral
- [Preços](https://example.com/precos.md): planos e condições
- [Produto X](https://example.com/produtos/x.md): para quem é e diferencial
- [FAQ](https://example.com/faq.md): objeções comuns
## Links HTML
- Site: https://example.com
- Contato: https://example.com/contato
```
### Markdown por página (ex.: /precos.md)
```
# Preços — Nome do Produto
> Planos para [público]. Sem cartão no trial.
## Planos
- Starter: …
- Pro: …
## Perguntas frequentes
### Tem teste grátis?
Sim, X dias.
```
### Descoberta no HTML / header
```
<!-- no <head> da página /precos -->
<link rel="alternate" type="text/markdown" href="https://example.com/precos.md" />
<link rel="describedby" href="https://example.com/llms.txt" />
# ou HTTP:
# Link: </precos.md>; rel="alternate"; type="text/markdown", </llms.txt>; rel="describedby"
```
## Definition of done
- GET /llms.txt → HTTP 200 com conteúdo Markdown
- Arquivo tem título H1, pelo menos 2 seções H2 e ≥100 palavras
- Audit P1-LLMS-TXT passa
- (Recomendado) Páginas-chave têm .md ou llms de escopo linkados a partir da raiz
## Notas
- Padrão llmstxt.org: raiz = mapa; conteúdo específico = links / subpaths; o mais específico cobre o escopo.
- LLMs preferem Markdown limpo sob demanda. Arquivo único enorme estoura contexto e é pior que índice + pedaços.
- O audit v1 só valida /llms.txt na home — MD por página não sobe a nota, mas melhora citação correta.
- Opcional: /llms-full.txt com texto concatenado para agentes que pedem contexto completo (manutenção mais cara).
---
### 6. P1-LINK-HEADERS — Headers HTTP Link (RFC 8288) ausentes (medium)
GET https://example.com/ sem header Link — agentes não descobrem llms.txt, sitemap ou API pelo HTTP
Detalhes coletados:
- Não confundir com <link> no HTML (canonical no <head> não conta). O check lê o header HTTP Link.
- Formato: Link: </llms.txt>; rel="describedby"; type="text/markdown"
- Nenhum header Link na resposta da home
**Ação resumida:** Adicione headers Link na home apontando para /llms.txt, sitemap e, se houver API, /.well-known/api-catalog.
## Passos
1. Confirme que o check é o header HTTP `Link`, não a tag HTML `<link rel="canonical">`.
2. Na home, envie pelo menos um `Link` apontando para recursos que agentes devem descobrir: `/llms.txt`, `/sitemap.xml`, docs de API se existirem.
3. Em hosting estático: `_headers` (Netlify/Cloudflare Pages), `nitro.routeRules`, ou config do CDN/nginx.
4. Valide: `curl -sI https://seudominio.com/ | findstr /i Link` (Windows) ou `curl -sI … | grep -i ^link`.
## Snippets (adapte ao stack do projeto)
### Headers HTTP (RFC 8288)
```
Link: </llms.txt>; rel="describedby"; type="text/markdown"
Link: </sitemap.xml>; rel="index"
Link: </.well-known/api-catalog>; rel="api-catalog"
```
### Nuxt — nitro.routeRules
```
nitro: {
routeRules: {
'/': {
headers: {
Link: '</llms.txt>; rel="describedby"; type="text/markdown", </sitemap.xml>; rel="index"',
},
},
},
},
```
### Cloudflare Pages / Netlify — public/_headers
```
/
Link: </llms.txt>; rel="describedby"; type="text/markdown"
Link: </sitemap.xml>; rel="index"
```
## Definition of done
- GET / inclui header Link com rel de descoberta (describedby, index, api-catalog ou service-doc)
- Audit P1-LINK-HEADERS passa
## Notas
- Verificado pelo isitagentready.com (Discoverability).
- Landing sem API: describedby → llms.txt + index → sitemap já basta. api-catalog só se houver catálogo RFC 9727.
---
### 7. P2-H1 — H1 ausente (medium)
0 elemento(s) <h1> em https://example.com/
Detalhes coletados:
- Nenhum <h1> encontrado no HTML da home
**Ação resumida:** Use exatamente um H1 descritivo por página.
## Passos
1. Se a evidência mencionar SPA / HTML cru vazio / P1-RENDER: não “adicione H1 no design” — ative SSR/SSG primeiro para o H1 ir no HTML inicial.
2. Confirme no View Source (não só no DevTools Elements) se existe exatamente um `<h1>`.
3. Se o HTML já tem conteúdo e há 0 ou >1 H1: escolha UM H1 principal (hero) e converta extras em `<h2>`.
4. Evite H1 no header global + hero ao mesmo tempo.
## Snippets (adapte ao stack do projeto)
### Estrutura correta (após SSR)
```
<main>
<h1>Título principal da página</h1>
<h2>Seção secundária (antes era H1 duplicado)</h2>
</main>
```
### Nuxt — garantir HTML no servidor
```
// nuxt.config — marketing precisa de HTML inicial
export default defineNuxtConfig({
ssr: true, // ou nitro.preset: 'static' + generate
})
```
## Definition of done
- View Source mostra exatamente 1 <h1>
- Audit P2-H1 passa
## Notas
- H1 só no DOM após JS não conta para crawlers/LLMs que não executam JavaScript.
- Use os textos da evidência se houver múltiplos H1 no HTML cru.
---
### 8. P2-HEADINGS — Nenhum heading no HTML cru (medium)
Sequência de níveis:
Detalhes coletados:
- Nenhum heading (H1–H6) no HTML da home
**Ação resumida:** Inclua headings semânticos (H1 → H2 → H3) no HTML da página.
## Passos
1. Se a evidência indicar shell SPA / HTML cru vazio: priorize P1-RENDER (SSR/SSG). Hierarquia no Vue não aparece no HTML cru.
2. Com HTML inicial populado: revise o outline (H1 → H2 → H3).
3. Corrija saltos (ex.: H1 → H3) inserindo H2 ou rebaixando níveis.
4. Não use headings só por estilo — ajuste CSS em vez de pular níveis.
5. Prefira H2/H3 como perguntas em conteúdo FAQ-style.
## Definition of done
- View Source tem headings; sequência sem saltos >1 nível
- Audit P2-HEADINGS passa
## Notas
- Sem SSR, “corrigir hierarquia” no componente não muda o que o GEO Score ou bots de IA leem.
---
### 9. P2-OPENING — Abertura pouco extratível (medium)
Primeiros parágrafos não definem o produto claramente
Detalhes coletados:
- Parágrafo 1 (156 chars): "This domain is for use in documentation examples without needing permission. This is not a service; avoid relying on it…"
**Ação resumida:** Defina o produto de forma direta nos 2 primeiros parágrafos ("X é uma ferramenta de Y que Z").
## Passos
1. Se a evidência indicar SPA / HTML cru sem <p>: ative SSR/SSG primeiro (P1-RENDER) — reescrever copy no Hero.vue não coloca texto no HTML inicial.
2. Com HTML populado: reescreva os 2 primeiros parágrafos acima da dobra.
3. Primeira frase: "[Marca] é [categoria] que [benefício principal]."
4. Segunda frase: público-alvo ou diferencial concreto.
5. Evite abrir só com slogans ou CTAs.
## Snippets (adapte ao stack do projeto)
### Modelo de abertura
```
<p>Acme é uma plataforma de gestão de tempo para equipes remotas que integra timesheet, aprovações e relatórios em um só lugar.</p>
<p>Indicada para agências e consultorias B2B que cobram por hora e usam Slack no dia a dia.</p>
```
## Definition of done
- View Source mostra parágrafo de abertura >50 chars com definição clara
- Audit P2-OPENING passa
## Notas
- GEO mede o HTML cru. Texto só após JS = abertura “ausente” para crawlers.
---
### 10. P2-CANONICAL — URL canônica (<link rel="canonical">) ausente (medium)
Nenhum <link rel="canonical"> encontrado em https://example.com/
Detalhes coletados:
- Página analisada: https://example.com/
- O canonical evita conteúdo duplicado e ajuda motores de IA a identificar a URL autoritativa.
**Ação resumida:** Adicione <link rel="canonical" href="https://seudominio.com/"> no <head> de cada página.
## Passos
1. Adicione `<link rel="canonical" href="URL_CANÔNICA">` no `<head>` de cada página.
2. A URL deve ser absoluta (https://), apontar para a versão preferida da página.
3. Para Nuxt: use `useHead({ link: [{ rel: "canonical", href: url }] })` ou configure no `nuxt.config`.
4. Para Next.js: use `<Head><link rel="canonical" href={url} /></Head>` ou metadata API.
## Snippets (adapte ao stack do projeto)
### HTML direto
```
<link rel="canonical" href="https://example.com/" />
```
### Nuxt 3 (nuxt.config.js — head global)
```
head: {
link: [
{ rel: 'canonical', href: 'https://example.com/' }
]
}
```
## Definition of done
- <link rel="canonical"> presente no HTML com URL HTTPS válida
- Audit P2-CANONICAL passa
---
### 11. P2-META — Metadados incompletos (medium)
title, meta description ou og:title ausentes ou muito curtos
Detalhes coletados:
- title (14 chars): "Example Domain"
- meta description: (ausente)
- og:title: (ausente)
**Ação resumida:** Preencha title, meta description e og:title com texto descritivo (>10 chars).
## Passos
1. Preencha `<title>` único e descritivo (marca + proposta de valor, ~50–60 chars).
2. Adicione `<meta name="description">` com benefício claro (~120–160 chars).
3. Configure `<meta property="og:title">` (pode espelhar title ou ser mais marketing).
4. Opcional: `og:description` e `og:image` para compartilhamento.
## Snippets (adapte ao stack do projeto)
### Meta tags mínimas
```
<title>Acme — Gestão de tempo para equipes remotas</title>
<meta name="description" content="Controle horas, aprovações e relatórios. Integração com Slack. Teste grátis.">
<meta property="og:title" content="Acme — Gestão de tempo para equipes remotas">
```
## Definition of done
- title, meta description e og:title presentes com >10 caracteres cada
- Audit P2-META passa
## Notas
- Compare com os valores ausentes/curtos listados na evidência do audit.
---
### 12. P1-AI-TXT — Content Signals (ai.txt) ausente (low)
GET https://example.com/.well-known/ai.txt → HTTP 404
Detalhes coletados:
- URL testada: https://example.com/.well-known/ai.txt
- Declarar política aumenta confiança de agentes e pode melhorar indexação em motores que respeitam Content Signals.
**Ação resumida:** Crie /.well-known/ai.txt declarando sua política de uso por IA (treino, busca, inferência).
## Passos
1. Crie o diretório `public/.well-known/` se não existir.
2. Crie o arquivo `ai.txt` declarando sua política de uso do conteúdo para IA.
3. Deploy e valide com `curl https://seudominio/.well-known/ai.txt`.
## Snippets (adapte ao stack do projeto)
### ai.txt mínimo (permite busca e inferência, nega treino)
```
# AI Usage Policy — https://seudominio.com
# Baseado no padrão Content Signals (isitagentready.com)
Allow: search
Allow: inference
Disallow: training
```
### ai.txt permissivo (permite tudo)
```
# AI Usage Policy
Allow: search
Allow: inference
Allow: training
```
## Definition of done
- GET /.well-known/ai.txt → HTTP 200
- Arquivo declara pelo menos Allow: search e Allow: inference
- Audit P1-AI-TXT passa
## Notas
- Content Signals é verificado pelo Cloudflare isitagentready.com e está se tornando padrão.
- Negar treino mas permitir search/inference é o padrão mais seguro para a maioria dos sites.
---
### 13. P1-MARKDOWN — Servidor não serve Markdown por negociação de conteúdo (low)
Requisição com Accept: text/markdown não retornou text/markdown
Detalhes coletados:
- LLMs preferem Markdown limpo a HTML — menos tokens, menos ruído.
- Para Nuxt/Next.js: adicione um endpoint /api/content ou middleware de content negotiation.
- Para sites estáticos: serve /llms.txt já cobre a maioria dos casos práticos.
**Ação resumida:** Configure o servidor/framework para responder com Markdown quando solicitado via Accept: text/markdown.
## Passos
1. Avalie se faz sentido para seu stack — sites estáticos já têm /llms.txt como alternativa mais simples.
2. Para Nuxt/Next.js: adicione middleware que, quando `Accept: text/markdown` for enviado, sirva uma versão Markdown da página.
3. Para sites estáticos: garanta que /llms.txt esteja rico — é o equivalente prático.
## Snippets (adapte ao stack do projeto)
### Nuxt server middleware (server/middleware/markdown.ts)
```
export default defineEventHandler(async (event) => {
const accept = getHeader(event, 'accept') ?? ''
if (!accept.includes('text/markdown')) return
// Redireciona para versão Markdown equivalente
const url = getRequestURL(event)
if (url.pathname === '/') {
setHeader(event, 'content-type', 'text/markdown; charset=utf-8')
// retorne o conteúdo Markdown da home
return '# Worklift\n\nDescrição Markdown da home...'
}
})
```
## Definition of done
- GET / com Accept: text/markdown retorna Content-Type: text/markdown
- Audit P1-MARKDOWN passa
## Notas
- Este check tem impacto prático menor que llms.txt — priorize os outros primeiro.
---
## Instruções finais
- Corrija na ordem listada (critical → high → medium → low).
- Um commit ou PR por tema (robots/sitemap, HTML/headings, JSON-LD) se fizer sentido.
- Ao terminar, liste cada finding e se o critério de pronto foi atendido.
```
---
_Gerado por GEO Score_