Zum Inhalt springen

Scan-Befunde – die Registry der Befundcodes

Jedes vom Pro-Scan gemeldete Problem erhält einen stabilen Befundcode aus der zentralen Registry Rankbeam\Seo\Pro\Scanning\IssueRegistry. Scanner erfinden keine Codes während der Ausführung. Sie erzeugen Befunde über IssueRegistry::make(), das Schweregrad und Feld aus der Registry übernimmt und nicht definierte Codes ablehnt. Der folgende Katalog ist damit eine verlässliche Schnittstelle: Dashboards, Exporte und der Pro-Score werten Codes aus, statt Meldungstexte zu zerlegen. Das kostenlose seo:audit verwendet eine eigene Metadaten-Registry des Core-Pakets mit geringerem Prüfumfang und teilweise anderen hreflang-Codes.

Jeder Code enthält:

  • id: die stabile Zeichenfolge, die als seo_scan_issues.issue_type gespeichert wird.
  • severity: critical, warning oder notice, pro Code festgelegt. Statt den Schweregrad zu variieren, wird ein Code aufgeteilt.
  • field: das betroffene Feld von seo_meta oder page für Befunde auf Seitenebene.
  • execution class: die Voraussetzungen für die Prüfung; siehe unten.
  • evidence: die Schlüssel im Array context des Befunds.

Ausführungsklassen

Jede Prüfung gehört anhand ihrer Voraussetzungen zu genau einer von drei Klassen:

KlasseVoraussetzungAusführung
metadataModell und Core-Resolver, ohne SeitenabrufModell-Scan (PageScanner); das kostenlose seo:audit deckt einen Teil dieser Metadatenprüfungen ab
renderedAusgeliefertes HTML der Seite, über eine Kernel-Anfrage im Prozess oder einen externen AbrufURL-Scan (UrlScanner)
networkAusgehender Abruf zur Prüfung eines anderen Ziels, etwa einer abweichenden Canonical-URLURL-Scan, immer über den SsrfGuard

Deshalb deckt ein kostenloses Audit innerhalb des Prozesses nicht denselben Umfang ab wie ein vollständiger Pro-Scan. Nur die metadata-Codes lassen sich ohne Rendering einer Seite ermitteln. Die Pro-Pipeline ruft zusätzlich gerendertes HTML ab und prüft Canonical-Ziele über das Netzwerk. Mit IssueRegistry::byClass(IssueRegistry::EXEC_METADATA) kannst du die Registry nach Klasse filtern.

Metadaten-Codes

PageScanner ermittelt diese Befunde aus Modell und Resolver. missing_title, missing_description und die Längencodes werden auch vom Scan gerenderter URLs ausgegeben. Dort messen sie den ausgelieferten <head>; Codes und Bedeutung bleiben gleich.

CodeSchweregradFeldBelegeBedeutung
missing_titlecriticaltitleWeder ein Titel noch ein berechenbarer Fallback ist vorhanden.
missing_descriptionwarningdescriptionWeder eine Meta-Beschreibung noch ein berechenbarer Fallback ist vorhanden.
missing_og_imagenoticeog_imageWeder ein Open-Graph-Bild noch ein berechenbarer Fallback ist vorhanden.
missing_focus_keywordnoticefocus_keywordsKein Fokus-Keyword festgelegt.
duplicate_titlewarningtitletitle, duplicate_urlsAndere Seiten derselben Sprache verwenden denselben Titel.
duplicate_descriptionwarningdescriptiondescription, duplicate_urlsAndere Seiten derselben Sprache verwenden dieselbe Beschreibung.
title_too_longwarningtitlelength, max, scriptDer aufgelöste Titel überschreitet die Empfehlung für seine Schrift: 60 bei lateinischer Schrift, ungefähr 30 bei CJK.
title_too_shortnoticetitlelength, min, scriptDer aufgelöste Titel unterschreitet die Untergrenze für seine Schrift: 30 bei lateinischer Schrift, ungefähr 15 bei CJK.
description_too_longwarningdescriptionlength, max, scriptDie aufgelöste Beschreibung überschreitet die Empfehlung für ihre Schrift: 160 beziehungsweise ungefähr 80.
description_too_shortnoticedescriptionlength, min, scriptDie aufgelöste Beschreibung unterschreitet die Untergrenze für ihre Schrift: 70 beziehungsweise ungefähr 35.
robots_conflict_indexingcriticalrobotsrobotsDie Robots-Anweisung enthält sowohl index als auch noindex.
robots_conflict_followingwarningrobotsrobotsDie Robots-Anweisung enthält sowohl follow als auch nofollow.
noindex_warningwarningrobotsrobots, canonical, page_url, shipping_signalEine Seite mit Canonical-Verweis auf sich selbst ist auf noindex gesetzt. Das ist eine zu prüfende Heuristik, kein Beweis, dass die Seite indexiert werden muss. Wird sowohl bei Modell- als auch bei gerenderten URL-Scans ausgegeben.
invalid_canonicalcriticalcanonicalcanonicalDer Canonical-Wert ist keine gültige URL.
cross_domain_canonicalwarningcanonicalcanonical, page_urlDie Canonical-URL verweist auf einen anderen Host als die Seite.
shared_canonicalnoticecanonicalcanonicalMehrere Seiten geben dieselbe Canonical-URL an.
insecure_canonicalwarningcanonicalcanonicalEine HTTPS-Website verwendet eine Canonical-URL mit http://.
hreflang_invalid_codewarningalternatesinvalid_codesEine hreflang-Alternative verwendet weder x-default noch einen gültigen BCP-47-Sprachcode.
hreflang_missing_self_referencewarningalternateslocale, page_urlAlternativen sind angegeben, aber keine verweist auf die eigene Sprache der Seite; der hreflang-Selbstverweis fehlt.
hreflang_duplicate_codewarningalternatesduplicate_codesDerselbe hreflang-Code verweist auf mehrere URLs und macht die Zuordnung mehrdeutig.
hreflang_missing_x_defaultnoticealternateslanguagesEiner hreflang-Gruppe mit mehreren Sprachen fehlt der Fallback x-default.
aeo_missing_authornoticeschemaEin Artikel in den strukturierten Daten der Seite enthält keine Autorenentität; Urheberschaft beziehungsweise Herkunft sind im Schema nicht ausdrücklich angegeben.
aeo_article_missing_datenoticeschemaEin Artikel in den strukturierten Daten enthält kein Veröffentlichungs-/Änderungsdatum; der zeitliche Verlauf ist im Schema nicht ausdrücklich angegeben.

Die Längengrenzen stammen aus der schriftabhängigen Längenrichtlinie des Core-Pakets (Pro 2.33): 60/160 für lateinischen Text und ungefähr 30/80 für CJK. Gezählt werden Grapheme, damit Scan und Zeichenzähler des Editors dieselbe Grundlage verwenden. Die Untergrenzen – bei lateinischer Schrift 30 für Titel und 70 für Beschreibungen, bei CJK ungefähr die Hälfte – dienen dem Scan als Hinweis auf möglicherweise zu kurze Metadaten. Der Kontextschlüssel script nennt die verwendete Schriftgruppe. Gemessen werden aufgelöster Titel und aufgelöste Beschreibung, also die tatsächliche Ausgabe einschließlich Fallbacks und Titelsuffix.

Die Codes hreflang_* prüfen die von der Seite angegebenen hreflang-Alternativen aus alternates des Resolvers: ungültige oder doppelte Codes, einen fehlenden Selbstverweis und fehlendes x-default bei einer mehrsprachigen Gruppe. Sie laufen nur, wenn die Seite Alternativen angibt. Ob andere Seiten zurückverweisen, prüfen diese Metadatenprüfungen nicht. Dafür ruft die optionale Netzwerkprüfung weiter unten die andere Seite ab.

Die Codes aeo_* sind Signale für die Aufbereitung als Antwortquelle (AEO): Ist der Artikelinhalt in den strukturierten Daten nachvollziehbar beschrieben? Sie lesen den aufgelösten JSON-LD-Graphen und schlagen nur bei angegebenen Artikeltypen wie Article, BlogPosting oder NewsArticle an, wenn eine author-Entität für ausdrückliche Urheberschaft/Herkunft oder datePublished beziehungsweise dateModified für die zeitliche Einordnung fehlen. Seiten ohne Artikel erhalten diese Befunde nicht. Die Prüfungen hängen von seo-pro.scan.checks.aeo ab (standardmäßig aktiviert) und entsprechen dem kostenlosen seo:audit.

missing_focus_keyword hängt von einer Freigabe ab

Der Hinweis auf ein fehlendes Fokus-Keyword erscheint nur, wenn der Fokus-Keyword-Ablauf im Core-Paket aktiviert ist: seo.keywords.enabled, standardmäßig false. Bei deaktivierter Funktion meldet der Scan kein fehlendes Fokus-Keyword. Das kostenlose seo:audit und der Filament-Editor lesen denselben Core-Schalter. Scan, Audit und Editor verwenden damit eine einzige gemeinsame Freigabe.

Codes für gerendertes HTML

UrlScanner ermittelt diese Befunde aus dem ausgelieferten HTML. Ziele auf demselben Host werden über eine Kernel-Anfrage im Prozess ohne ausgehenden Netzwerkverkehr abgerufen; externe Ziele über einen geschützten Abruf.

CodeSchweregradFeldBelegeBedeutung
http_errorcriticalpagestatusDie URL antwortet mit einem Status 4xx oder 5xx.
empty_responsecriticalpageDie URL liefert einen leeren Antwortinhalt.
missing_canonicalnoticecanonicalIm gerenderten Head fehlt <link rel="canonical">.
noindex_pagenoticerobotsrobotsDie gerenderte Seite ist auf noindex gesetzt; rein informativ. Verweist ihre Canonical-URL zusätzlich auf sie selbst, wird stattdessen der bewertete Befund noindex_warning ausgegeben.
missing_h1noticepageKeine <h1>-Überschrift vorhanden.
multiple_h1noticepagecountMehr als eine <h1> vorhanden; rein informativ.
missing_image_altwarningpagecount, total, sampleInhaltsbilder haben kein alt-Attribut. Ein ausdrücklich leeres alt="" gilt als dekorativ und wird nicht gemeldet.
thin_contentnoticepageword_count, threshold, segmenterDer Haupttext unterschreitet die konfigurierte Wortzahl. Der Checklisten-Tokenizer verwendet Worttrennung für Schriften mit Leerzeichen und ICU-Wörterbuchsegmentierung für Chinesisch, Japanisch und Thai (segmenter: intl, benötigt ext-intl). Ein japanischer Artikel mit 400 Wörtern zählt dadurch nicht als ein einziges „Wort“.
mixed_contentwarningpagecount, sampleEine HTTPS-Seite bindet Unterressourcen über http:// ein.
html_lang_missingnoticepage<html lang> fehlt oder ist leer. Assistive Technik könnte eine ungeeignete Stimme wählen.
html_lang_invalidnoticepagedeclaredDer Wert von lang ist kein gültiges BCP-47-Tag, etwa english, en_US mit Unterstrich oder jp.
html_lang_mismatchwarningpagedeclared, declared_script, detected_scriptDie Schrift des sichtbaren Haupttexts passt nicht zur angegebenen Sprache, etwa lang="en" auf einer japanischen Seite oder lang="ru" bei lateinischer Schrift. Die Prüfung erkennt nur Schriftunterschiede; sie errät keine falsche Sprache innerhalb derselben Schrift. Mindestens 40 Buchstaben im Haupttext sind erforderlich.

Netzwerk-Codes

UrlScanner ermittelt diese Befunde nur bei aktivierter passender Option: seo-pro.scan.url_checks.check_canonical_target für Canonical-Ziele und check_hreflang_reciprocity für hreflang-Alternativen. Jeder Zielabruf läuft durch den SsrfGuard mit Schema-Allowlist, Host-Scope, Ablehnung privater IPs sowie Weiterleitungs-, Zeit- und Größenlimits. Weiterleitungen werden dabei nicht verfolgt, damit eine weiterleitende Canonical-URL sichtbar bleibt. Canonical- und Alternativverweise auf die Seite selbst werden übersprungen; die Seite wurde gerade bereits abgerufen.

CodeSchweregradFeldBelegeBedeutung
blocked_urlnoticepagereasonDer SsrfGuard hat ein Ziel vor jeder HTTP-Anfrage abgelehnt.
canonical_target_brokencriticalcanonicalcanonical, statusDie Canonical-URL verweist auf eine Seite mit HTTP-Fehler.
canonical_target_redirectwarningcanonicalcanonical, status, locationDie Canonical-URL verweist auf eine Weiterleitung. Verwende die endgültige URL.
canonical_target_noindexwarningcanonicalcanonicalDas Canonical-Ziel ist selbst auf noindex gesetzt.
canonical_target_blockednoticecanonicalcanonical, reasonDas Canonical-Ziel konnte nicht geprüft werden, etwa wegen Ablehnung durch den Guard oder fehlender Auflösbarkeit.
hreflang_not_reciprocalwarningalternateshreflang, href, statusEine angegebene Alternative verweist nicht auf die Ausgangsseite zurück. Das hreflang-Paar könnte ignoriert werden; dadurch allein wird die Übersetzung nicht unindexierbar.
hreflang_target_unverifiednoticealternateshreflang, href, reasonDie Alternative konnte nicht abgerufen werden, etwa wegen Guard-Ablehnung, Fehlerstatus, Weiterleitung oder überschrittenem Größenlimit. Der Rückverweis wurde deshalb nicht geprüft. Das ist ein fehlender Nachweis, kein festgestellter Fehler.

Die Rückverweisprüfung ruft pro Seite höchstens hreflang_max_alternates Ziele ab, standardmäßig 10, einschließlich x-default. Duplikate und die Seite selbst werden übersprungen. Die modellbezogenen Metadaten-Codes hreflang_* prüfen die angegebene Liste; diese zusätzliche Prüfung benötigt die andere Seite.

Alle hier beschriebenen Netzwerkpfade verwenden den gemeinsamen SsrfGuard. Das Bedrohungsmodell und die verbleibende TOCTOU-Einschränkung stehen in SECURITY.md.

Wie die Codes den Score beeinflussen

Der Pro-SEO-Score beginnt bei 100 und zieht für jeden bewerteten Befund einen festen, nach den oben genannten Schweregraden gewichteten Betrag ab. Die meisten Codes zählen; einige sind bewusst ausgeschlossen: missing_focus_keyword als redaktioneller Hinweis, noindex_page und multiple_h1 als Informationen sowie blocked_url, canonical_target_blocked und hreflang_target_unverified, weil eine nicht mögliche Prüfung keinen Fehler beweist. Auch hreflang_*, html_lang_* und aeo_* bleiben derzeit als beratende Signale außerhalb des Scores. Die Seite zur Bewertung enthält die vollständige Allowlist und den Abzug für jeden Code.

Lebenszyklus eines Befunds

Ein Befund ist mehr als eine Zeile, die nur während eines Problems existiert. Er hat einen Lebenszyklus. Ein Scan gleicht die Befunde eines Ziels ab, statt sie zu löschen und neu anzulegen. Jeder Befund hat eine stabile Identität: das Ziel (scannable_type und scannable_id bei Modellen oder url bei Routen-/Sitemap-Zielen) plus issue_type. Pro Ziel und Scan wird jeder Code höchstens einmal ausgegeben. Codes für mehrere betroffene Elemente wie missing_image_alt, mixed_content oder hreflang_* fassen diese in einer Zeile mit count beziehungsweise sample zusammen. Die Identität bleibt damit eindeutig.

Bei jedem Scan gilt für jedes Ziel:

  • Ein Befund ohne vorhandene Zeile wird als open mit detected_at angelegt.
  • Ein Befund, der zu einer bestehenden offenen Zeile passt, aktualisiert die Belege und behält das ursprüngliche detected_at. Der Zeitpunkt der ersten Feststellung wird nicht bei jedem Scan zurückgesetzt.
  • Ein offener Befund, den eine vollständig ausgeführte Prüfung nicht mehr findet, wird als fixed markiert und erhält resolved_at. Die Zeile bleibt erhalten; die Behebung wird dokumentiert.
  • Ein behobener Befund, der zurückkehrt, wird in derselben Zeile wieder geöffnet. Diese Regression erhält ein neues detected_at.
  • Ein im Dashboard durch einen Nutzer als ignored markierter Befund bleibt unverändert.
StatusBedeutungGesetzt durch
openDer Befund liegt aktuell vor.Scan bei einem neuen oder weiterhin festgestellten Problem
fixedDer Befund lag vor und wird nicht mehr gefunden.Automatisch beim nächsten Scan, der ihn nicht erneut feststellt
ignoredDurch einen Nutzer ausgeblendet; zählt weder zu offenen Befunden noch zum Score.Ignore-Aktion im Dashboard

Weil Behebungen gespeichert werden, kann der White-Label-Bericht tatsächlich gespeicherte neue und behobene Befunde eines Zeitraums zählen, statt nur zwei Berichts-Snapshots zu vergleichen. Dashboard, seo-pro:scan-status und Score filtern offene Befunde auf open. Gespeicherte fixed-Zeilen erhöhen diese Zahlen deshalb nicht. Behobene Zeilen werden dem Lauf zugeordnet, der sie aufgelöst hat, und nach der normalen Aufbewahrungsfrist für Scan-Läufe entfernt.

Konfiguration

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
],

Das Größenlimit für Antworten bei geschützten Abrufen ist seo-pro.http.max_response_bytes, standardmäßig 2 MB. Für Scans desselben Hosts innerhalb des Prozesses gilt dieses Limit nicht.

Kompatibilitätshinweis zur Umbenennung eines Befundcodes

Der bisherige einzelne Code robots_conflict, der zwei Schweregrade haben konnte, wurde aufgeteilt. Jeder Code entspricht jetzt genau einem Schweregrad:

Alter CodeNeuer CodeSchweregrad
robots_conflict (index + noindex)robots_conflict_indexingcritical
robots_conflict (follow + nofollow)robots_conflict_followingwarning

Wenn du robots_conflict gespeichert oder danach gefiltert hast, stelle auf die beiden neuen Codes um.

rankbeam/laravel-seo steht unter der MIT-Lizenz.