Ir para o conteúdo

Ocorrências de varredura: registro de códigos ​

Cada problema informado pela varredura Pro usa um código estável de Rankbeam\Seo\Pro\Scanning\IssueRegistry. Os scanners criam ocorrências por IssueRegistry::make(), que aplica a gravidade e o campo definidos e rejeita códigos não registrados. Painéis, exportações e a pontuação Pro podem usar esses códigos em vez de interpretar mensagens. O seo:audit gratuito usa seu próprio registro Core, com cobertura menor e alguns códigos hreflang diferentes.

Cada código define:

  • id: string estável salva em seo_scan_issues.issue_type.
  • severity: critical, warning ou notice, fixa por código. Gravidades diferentes exigem códigos separados.
  • field: campo de seo_meta afetado, ou page para ocorrências da página.
  • execution class: o que a verificação precisa para executar.
  • evidence: chaves presentes no array context da ocorrência.

Classes de execução ​

Cada verificação pertence a uma destas três classes:

ClasseRequisitosQuem executa
metadataModelo e resolvedor Core, sem buscar a páginaPageScanner; o seo:audit gratuito cobre parte dessas verificações
renderedHTML servido, por requisição interna ao kernel ou busca externaUrlScanner
networkBusca externa para verificar outro alvo, como uma canonical que aponta para outra páginaUrlScanner, sempre pelo SsrfGuard

A auditoria gratuita dentro da aplicação não cobre toda a varredura Pro: apenas as verificações metadata dispensam a renderização da página. O Pro também busca HTML e verifica destinos pela rede. Filtre o registro com IssueRegistry::byClass(IssueRegistry::EXEC_METADATA).

Códigos de metadados ​

Detectados por PageScanner a partir do modelo e do resolvedor. missing_title, missing_description e os códigos de tamanho também são emitidos pela varredura de URL, medindo o <head> servido, com o mesmo significado.

CódigoGravidadeCampoEvidênciaSignificado
missing_titlecriticaltitle—Sem título nem fallback calculável.
missing_descriptionwarningdescription—Sem meta description nem fallback calculável.
missing_og_imagenoticeog_image—Sem imagem Open Graph nem fallback calculável.
missing_focus_keywordnoticefocus_keywords—Nenhuma palavra-chave de foco definida.
duplicate_titlewarningtitletitle, duplicate_urlsTítulo repetido em outras páginas do mesmo locale.
duplicate_descriptionwarningdescriptiondescription, duplicate_urlsDescrição repetida em outras páginas do mesmo locale.
title_too_longwarningtitlelength, max, scriptTítulo resolvido acima da recomendação da escrita: 60 para latina, cerca de 30 para CJK.
title_too_shortnoticetitlelength, min, scriptTítulo resolvido abaixo do mínimo: 30 para latina, cerca de 15 para CJK.
description_too_longwarningdescriptionlength, max, scriptDescrição resolvida acima da recomendação: 160 / cerca de 80.
description_too_shortnoticedescriptionlength, min, scriptDescrição resolvida abaixo do mínimo: 70 / cerca de 35.
robots_conflict_indexingcriticalrobotsrobotsDiretiva robots contém index e noindex.
robots_conflict_followingwarningrobotsrobotsDiretiva robots contém follow e nofollow.
noindex_warningwarningrobotsrobots, canonical, page_url, shipping_signalPágina com canonical autorreferente e noindex: heurística para revisão, não prova de que deve ser indexada. Emitida em varreduras de modelo e URL.
invalid_canonicalcriticalcanonicalcanonicalCanonical não é uma URL válida.
cross_domain_canonicalwarningcanonicalcanonical, page_urlCanonical aponta para outro servidor.
shared_canonicalnoticecanonicalcanonicalVárias páginas declaram a mesma canonical.
insecure_canonicalwarningcanonicalcanonicalCanonical http:// em um site https.
hreflang_invalid_codewarningalternatesinvalid_codesAlternativa hreflang não usa x-default nem um código BCP-47 válido.
hreflang_missing_self_referencewarningalternateslocale, page_urlHá alternativas, mas nenhuma representa o locale da própria página.
hreflang_duplicate_codewarningalternatesduplicate_codesO mesmo código hreflang aponta para mais de uma URL, criando um grupo ambíguo.
hreflang_missing_x_defaultnoticealternateslanguagesGrupo hreflang multilíngue sem fallback x-default.
aeo_missing_authornoticeschema—Artigo nos dados estruturados sem entidade de autor, deixando a autoria implícita.
aeo_article_missing_datenoticeschema—Artigo nos dados estruturados sem data de publicação ou modificação.

Os limites vêm da política por escrita do Core, usada desde o Pro 2.33: 60/160 para texto latino e cerca de 30/80 para CJK, contados em grafemas como no editor. Os mínimos recomendados são 30/70 para escrita latina e aproximadamente metade para CJK. A chave script identifica a faixa aplicada. O tamanho é medido no valor resolvido, incluindo fallback e sufixo de título.

Os códigos hreflang_* validam as alternativas declaradas pelo resolvedor: códigos inválidos ou repetidos, falta de autorreferência e ausência de x-default em grupos multilíngues. Só executam quando há alternativas. A reciprocidade entre páginas não é verificada por esses metadados; a verificação opcional de rede abaixo busca a outra página.

Os códigos aeo_* avaliam sinais de organização para respostas (AEO) no grafo JSON-LD. Só são emitidos quando há dados de artigo, como Article, BlogPosting ou NewsArticle, sem author ou sem datePublished/dateModified. Páginas sem artigo não recebem esses avisos. A opção seo-pro.scan.checks.aeo, ativada por padrão, controla as verificações, também presentes no seo:audit gratuito.

missing_focus_keyword depende da ativação do recurso

O aviso só aparece quando o fluxo de palavras-chave do Core está ativado por seo.keywords.enabled, cujo padrão é false. Desativado, a ausência de palavra-chave não gera aviso. Varredura Pro, seo:audit e editor Filament leem a mesma opção.

Códigos de HTML renderizado ​

UrlScanner analisa o HTML servido. Para o mesmo servidor, usa uma requisição ao kernel dentro do processo, sem tráfego externo; para destinos externos, faz uma busca protegida.

CódigoGravidadeCampoEvidênciaSignificado
http_errorcriticalpagestatusURL respondeu com status 4xx ou 5xx.
empty_responsecriticalpage—URL retornou corpo vazio.
missing_canonicalnoticecanonical—Nenhum <link rel="canonical"> no head renderizado.
noindex_pagenoticerobotsrobotsPágina noindex, informativo. Se também tiver canonical autorreferente, usa noindex_warning, que afeta a pontuação.
missing_h1noticepage—Nenhum título <h1>.
multiple_h1noticepagecountMais de um <h1>, informativo.
missing_image_altwarningpagecount, total, sampleImagens do conteúdo sem atributo alt. alt="" explícito indica imagem decorativa e não gera aviso.
thin_contentnoticepageword_count, threshold, segmenterTexto abaixo da contagem configurada. Usa o tokenizador do checklist: limites de palavras para escritas com espaços e dicionário ICU, segmenter: intl com ext-intl, para chinês, japonês e tailandês.
mixed_contentwarningpagecount, sampleRecursos http:// em página https.
html_lang_missingnoticepage—<html lang> ausente ou vazio; tecnologias assistivas podem selecionar uma voz inadequada.
html_lang_invalidnoticepagedeclaredlang não é uma tag BCP-47 válida, como english, en_US ou jp.
html_lang_mismatchwarningpagedeclared, declared_script, detected_scriptEscrita do texto visível não corresponde à do idioma declarado, como lang="en" em japonês. Requer pelo menos 40 letras; não tenta distinguir idiomas que compartilham a escrita latina.

Códigos de rede ​

UrlScanner executa essas verificações somente com as opções correspondentes ativadas: seo-pro.scan.url_checks.check_canonical_target para canonicals e check_hreflang_reciprocity para alternativas. Toda busca passa pelo SsrfGuard, com protocolos e servidores permitidos, rejeição de IPs privados e limites de tempo e tamanho. Redirecionamentos não são seguidos, permitindo identificar destinos que redirecionam. Canonicals e alternativas autorreferentes são ignoradas porque a própria página já foi buscada.

CódigoGravidadeCampoEvidênciaSignificado
blocked_urlnoticepagereasonSsrfGuard recusou o alvo antes de qualquer requisição HTTP.
canonical_target_brokencriticalcanonicalcanonical, statusDestino da canonical retorna erro HTTP.
canonical_target_redirectwarningcanonicalcanonical, status, locationCanonical aponta para redirecionamento; revise para usar a URL final.
canonical_target_noindexwarningcanonicalcanonicalDestino da canonical está marcado como noindex.
canonical_target_blockednoticecanonicalcanonical, reasonDestino não pôde ser verificado por bloqueio ou falha de resolução.
hreflang_not_reciprocalwarningalternateshreflang, href, statusAlternativa declarada não declara o link de volta. O par pode ser ignorado, mas isso não torna a tradução não indexável por si só.
hreflang_target_unverifiednoticealternateshreflang, href, reasonAlternativa não pôde ser buscada por bloqueio, erro, redirecionamento ou limite de tamanho. Reciprocidade não verificada; ausência de evidência não é defeito confirmado.

A reciprocidade busca no máximo hreflang_max_alternates alvos por página, 10 por padrão, incluindo x-default e ignorando duplicatas e a própria página. Os códigos de metadados verificam a lista declarada; esta verificação precisa consultar o outro destino.

Todos os caminhos de rede reutilizam o SsrfGuard. Consulte SECURITY.md para o modelo de ameaças e a limitação residual de TOCTOU.

Como os códigos alimentam a pontuação ​

A pontuação Pro parte de 100 e desconta penalidades fixas por ocorrência pontuada, com pesos por gravidade. Algumas ficam fora: missing_focus_keyword, consultiva; noindex_page e multiple_h1, informativas; blocked_url, canonical_target_blocked e hreflang_target_unverified, que indicam impossibilidade de verificar; e os sinais consultivos hreflang_*, html_lang_* e aeo_*. A referência de pontuação lista todos os códigos incluídos e suas penalidades.

Ciclo de vida das ocorrências ​

A varredura reconcilia ocorrências, preservando seu histórico. A identidade combina o alvo — scannable_type e scannable_id para modelos, ou url para rotas e sitemaps — com issue_type. Cada código é emitido no máximo uma vez por alvo em cada análise. Casos com várias instâncias, como missing_image_alt, mixed_content e hreflang_*, são agrupados em uma linha com count ou sample.

Para cada alvo analisado:

  • uma ocorrência sem linha anterior é criada como open, com detected_at;
  • uma ocorrência que já está aberta recebe evidências atualizadas, preservando o primeiro detected_at;
  • uma ocorrência aberta não encontrada por uma verificação concluída passa a fixed, com resolved_at; a linha permanece no histórico;
  • uma ocorrência fixed que reaparece é reaberta na mesma linha, com novo detected_at;
  • uma ocorrência marcada pelo usuário como ignored permanece intacta.
EstadoSignificadoDefinido por
openPresente atualmente.Varredura, ao detectar ou confirmar novamente
fixedExistia, mas não foi encontrada novamente.Varredura automática seguinte que conclui a verificação sem encontrá-la
ignoredSilenciada pelo usuário; fora das contagens abertas e da pontuação.Ação Ignore do painel

O histórico permite que o relatório com sua marca apresente contagens de ocorrências corrigidas e novas por período, em vez de apenas comparar duas fotografias do estado. Painel, seo-pro:scan-status e pontuação filtram open, sem contar linhas fixed. Ocorrências corrigidas são atribuídas à execução que as resolveu e seguem a retenção das varreduras.

Configuração ​

php
// config/seo-pro.php → 'scan'
'url_checks' => [
    'enabled' => true,
    'crawl_external' => false,             // fetch external URL targets (guarded)
    'check_canonical_target' => false,     // EXEC_NETWORK canonical validation (guarded)
    'check_hreflang_reciprocity' => false, // EXEC_NETWORK hreflang link-back crawl (guarded)
    'hreflang_max_alternates' => 10,       // targets fetched per page by that crawl
],
'checks' => [
    'length' => true,            // title/description length (metadata + rendered)
    'rendered_content' => true,  // H1 / alt / thin content / mixed content / html lang
],
'content' => [
    'min_word_count' => 200,     // thin_content threshold
    'evidence_sample' => 5,      // max example URLs stored per issue
],

Buscas protegidas usam seo-pro.http.max_response_bytes, 2 MB por padrão. A varredura do mesmo servidor dentro do processo não tem esse limite.

Compatibilidade: renomeação de códigos ​

O antigo robots_conflict, que tinha duas gravidades, foi dividido para manter uma gravidade por código:

Código antigoCódigo novoGravidade
robots_conflict (index + noindex)robots_conflict_indexingcritical
robots_conflict (follow + nofollow)robots_conflict_followingwarning

Atualize filtros e dados que dependem de robots_conflict para os dois códigos novos.

rankbeam/laravel-seo é distribuído sob a licença MIT.