Back to articles

Fügen Sie ein SEO-Audit in Ihre Deploy-Pipeline ein: API, Exit-Codes und CI-Rezepte

SEOReport Team·
apici-cdautomationgithub-actionstechnical-seodevops

Ein funktionierendes Rezept zur Audittierung Ihrer Seite aus CI: drei REST-Endpunkte, die Score-Felder, die ein Build-Gate lesen kann, und der Unterschied zwischen einer echten Regression und einem Infrastruktur-Fehler.

Die technischen Regressionen, die am meisten Sichtbarkeit kosten, sind in einem Code-Review unsichtbar. Ein Canonical-Tag, der auf den falschen Host zeigt, ein hreflang-Block, der seine Selbstreferenz verliert, ein Content‑Security‑Policy-Header, der aus einer Reverse‑Proxy-Konfiguration entfernt wurde, eine Route, die ihren Inhalt hinter Hydration verschiebt — jeder dieser Fälle kommt in einem Diff an, der gut aussieht und jeden Test besteht, den Sie haben. Sie tauchen Wochen später auf, in einem Traffic-Diagramm, lange nachdem der Commit, der sie verursacht hat, aus dem Blickfeld gerutscht ist. Die Lösung ist strukturell: führen Sie das Audit beim Deploy aus, nicht an dem Tag, an dem jemand sich erinnert. Jeder SEOReport-Bericht ist über REST verfügbar, die Antwort trägt einen numerischen Score-Block, und ein Shell-Skript kann diesen Block in einen Exit-Code umwandeln. Das ist der gesamte Mechanismus.

Vier Regressionstypen, die nur eine Maschine rechtzeitig erkennt

Die Prüfungen unseres Engines korrespondieren sauber mit den Fehlermodi, die menschliche Reviews überleben, und es lohnt sich, sie konkret zu benennen, denn sie sind das, was ein Gate tatsächlich schützt. Hreflang. Der Prüfsatz umfasst Selbstreferenz, Rücklinks, x-default Korrektheit, gut formatierte URLs, ob jedes alternative Ziel indexierbar ist, und ob das Ziel-Canonical übereinstimmt. Eine CMS-Migration, die URL Muster neu schreibt, kann Rücklinks in allen Sprachen gleichzeitig brechen, und keine Sprache sieht isoliert fehlerhaft aus. Canonicalisierung. Vorhandensein, Zielindexierbarkeit, umleitungsfreie Ziele und off‑site Canonicals. Die schlimmste Variante dieses Fehlers ist ein Staging-Canonical, der in Produktion ausgeliefert wird — eine Seite, die stillschweigend einen Host nominieren, den Sie nicht indexiert haben wollen. Sicherheitsheader. Content‑Security‑Policy, HSTS, Referrer‑Policy, X‑Frame‑Options, X‑Content‑Type‑Options und Permissions‑Policy. Diese leben in der Infrastruktur‑Konfiguration, nicht im Anwendungscode, was genau der Grund ist, warum sie bei einer Proxy- oder Edge‑Config‑Änderung verschwinden und niemand es bemerkt. Render‑Parity. Jedes Audit holt die Homepage zweimal — schlicht HTTP, dann ein echter Browser — und vergleicht Titel, H1s, Canonical, Meta‑Description, JSON‑LD und Body‑Text‑Volumen über die beiden. Als unsere veröffentlichten Render‑Parity‑Daten einen Urteil fällten, boten die meisten Seiten eine materiell dünnere Seite für alles, was HTML als geliefert ansah. Ein ssr: false in einer Konfigurationsdatei reicht aus, um eine Seite in diese Gruppe zu verschieben. Alle vier sind deterministisch, alle vier sind günstig zu prüfen, und alle vier sind die Art von Dingen, die eine Person nur untersucht, wenn sie bereits misstrauisch ist.

Drei Endpunkte und eine Schleife

Die API Oberfläche, die eine Pipeline benötigt, ist klein. Authentifizierung ist ein Bearer‑Token: erstellen Sie ein Konto, geben Sie einen Schlüssel vom Dashboard aus, und senden Sie ihn als Authorization: Bearer sr__live_your_api_key. Der gleiche Schlüssel öffnet REST und MCP; die vollständige Referenz befindet sich auf der Entwicklerseite.

graph TD A[Bereitstellung abgeschlossen] --> B["POST /api/v1/reports"] B --> C["GET /api/v1/reports/:id/ready"] C -->|"ready: false"| C C -->|"error.code present"| D[Infrastruktursignal, exit 75] C -->|"ready: true"| E["GET /api/v1/reports/:id"] E --> F{Score-Block innerhalb des Budgets?} F -->|Ja| G[exit 0] F -->|Nein| H[exit 1, Build schlägt fehl]

Einen Bericht einzureichen ist ein POST:

bash
JOB_ID=$(curl -sS -X POST https://seoreport.dev/api/v1/reports \
-H "Authorization: Bearer $SEOREPORT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "forceRerun": true}' \
| jq -r '.report.jobId')

Zwei Dinge über diesen Body sind speziell im CI wichtig. forceRerun existiert, weil der API ein vorhandenes Snapshot wiederverwendet, wenn eines verfügbar ist — sinnvoll für einen Benutzer, der einen Button klickt, aber falsch für ein Deploy-Gate, das sonst die vorherige Version bewerten würde. Die Antwort sagt Ihnen, was in submission.reusedSnapshot passiert ist. Erzwingte frische Läufe sind eine Funktion für zahlende Konten; ein Schlüssel ohne diese Berechtigung erhält ein 403 mit dem Grund, statt stillschweigend veraltete Daten zurückzugeben. Der Prüfungsumfang wird aus dem URL Pfad abgeleitet. Ein reiner Ursprung führt eine vollständige Site-Prüfung durch; ein URL mit Pfad prüft diese Seite isoliert. So kann ein Pipeline die Homepage bei jedem Deploy sperren und die spezifische Route, die geändert wurde, hinzufügen, ohne zusätzliche Parameter. Dann poll. GET /api/v1/reports/:id/ready ist der günstige Status-Endpunkt — er gibt ready, status, stage, pollAfterMs zurück, und wenn ein Lauf fehlschlägt, ein error Objekt:

bash
for _ in $(seq 1 60); do
READY=$(curl -sS -H "Authorization: Bearer $SEOREPORT_API_KEY" \
"https://seoreport.dev/api/v1/reports/$JOB_ID/ready")
CODE=$(echo "$READY" | jq -r '.error.code // empty')
if [ -n "$CODE" ]; then
echo "audit did not complete: $CODE"
exit 75
fi
[ "$(echo "$READY" | jq -r '.ready')" = "true" ] && break
sleep 5
done

Dieses exit 75 ist absichtlich, und es ist der Teil, den die meisten Integrationen falsch handhaben.

Unterscheide eine Regression von einem Lauf, der nie stattgefunden hat

error.code trägt einen maschinenlesbaren Grund und einen retryable booleschen Wert. DNS_FAILURE, CRAWLER_BLOCKED, REDIRECT_LOOP, TLS_ERROR, NO_CONTENT und STALE_ENGINE_VERSION sind als nicht wiederholbar gekennzeichnet, weil ein erneuter Versuch dieselbe Antwort liefert. Der Großteil dieser Liste beschreibt eine Bedingung auf der Seite, und mehrere Einträge – ein Weiterleitungs‑Loop, ein TLS‑Fehler, eine Bot‑Regel, die jetzt Crawler blockiert – sind echte Deploy‑Defekte, die einen Build‑Fehler rechtfertigen. Codes außerhalb dieses Satzes sind vorübergehend und rechtfertigen einen weiteren Versuch. Ein Gate, das „die Seite regressiert“ und „der Audit konnte nicht ausgeführt werden“ in denselben roten Build zusammenführt, wird innerhalb eines Monats deaktiviert. Halte sie in deinen Exit‑Codes getrennt: 1 für ein Urteil, das du vom Gate erzwingen lassen möchtest, 75 – der konventionelle EX_TEMPFAIL – für einen Lauf, der kein Urteil geliefert hat. Die meisten CI‑Systeme können so konfiguriert werden, dass sie den zweiten Lauf wiederholen und den ersten an einen Menschen weiterleiten.

Den Score‑Block lesen

Sobald ready wahr ist, gibt GET /api/v1/reports/:id das Bericht‑Objekt zurück. Der score Block ist der Teil, den ein Gate liest:

bash
REPORT=$(curl -sS -H "Authorization: Bearer $SEOREPORT_API_KEY" \
"https://seoreport.dev/api/v1/reports/$JOB_ID")
echo "$REPORT" | jq '.report.score
| {overall, totalChecks, passedChecks, failedChecks,
warnChecks, inconclusiveChecks, failingCriticalChecks}'

Drei dieser Felder tragen den Großteil des Signals. failingCriticalChecks ist die Anzahl der Fehler, die der Engine als kritisch eingestuft werden – die, die in der Lage sind, Seiten aus einem Index zu entfernen oder Inhalte vollständig vor einem Crawler zu verbergen. Für ein erstes Gate ist dies die einzige Zahl, die du brauchst, und > 0 ist ein verteidigungsfähiger Schwellenwert am ersten Tag. overall ist der zusammengesetzte Score, nützlich als Riegel: speichere den Wert des vorherigen Deploys und fehlschlage, wenn der neue um mehr als eine von dir gewählte Toleranz fällt. Dies fängt langsame Erosion ein, die kein einzelner Check erkennt. domainScores zerlegt den Score nach seo, ai, performance, security und brand, jeweils mit eigenen pass, fail und warn Zählungen. Pro‑Domain‑Boden erlauben es verschiedenen Teams, unterschiedliche Budgets zu besitzen – der Sicherheits‑Score ist ein sinnvoller Gate‑Parameter für jeden, der die Edge‑Konfiguration verwaltet, unabhängig davon, was das Content‑Team liefert. inconclusiveChecks verdient seine eigene Regel: gate niemals darauf. Ein Check meldet unentschlossen, wenn die Engine kein verteidigungsfähiges Urteil erreichen konnte, und behandelt das als Fehler, trainiert alle dazu, das Gate zu ignorieren. Der Score‑Block stammt aus dem freien Hero‑Bereich des Berichts, sodass ein Build‑Gate ihn lesen kann, ohne die vollständigen Ergebnisse zu entsperren. Wenn du die komplette Payload für die Archivierung brauchst, gibt GET /api/v1/reports/:id/result die vollständigen Ergebnisse für einen entsperrten Bericht zurück, und GET /api/v1/reports/:id/download?format=json liefert dasselbe Objekt als herunterladbares Artefakt – es lohnt sich, es dem Build anzuhängen, damit der Unterschied zwischen zwei Deploys später überprüfbar ist.

In ein Workflow einbinden

Nichts oben ist CI‑Vendor‑spezifisch. In GitHub Actions ist das gesamte Gate ein Schritt, der das Skript aufruft, das du bereits hast:

yaml
- name: SEO audit gate
env:
SEOREPORT_API_KEY: ${{ secrets.SEOREPORT_API_KEY }}
AUDIT_URL: https://example.com
run: ./scripts/seo-gate.sh

Wo seo-gate.sh einreicht, abstimmt und mit der Entscheidung endet:

bash
CRITICAL=$(echo "$REPORT" | jq -r '.report.score.failingCriticalChecks // 0')
SECURITY=$(echo "$REPORT" | jq -r \
'.report.score.domainScores[] | select(.domain == "security") | .score')
if [ "$CRITICAL" -gt 0 ]; then
echo "::error::$CRITICAL critical checks failing"
exit 1
fi
echo "clean — security domain at $SECURITY"

Führe es aus, nachdem die Bereitstellung abgeschlossen ist, anstatt gegen eine Vorschauumgebung. Eine Vorschau URL ist in der Regel hinter einer Basisauthentifizierung oder einer Bot-Herausforderung versteckt, und eine Prüfung, die die Seite nicht abrufen kann, meldet CRAWLER_BLOCKED statt einer Punktzahl. Nach der Bereitstellung gegen die echte Herkunft ist sowohl einfacher als auch näher an dem, was ein Crawler erlebt. Zwei benachbarte Formen sind es wert, bekannt zu sein. Wenn deine Orchestrierung bereits auf einer Scraping-Plattform läuft, führt unser Apify-Akteur dieselbe Engine nach einem Zeitplan aus, ohne diese Klebefolie. Und für Agenten authentifiziert derselbe Träger-Schlüssel eine MCP-Verbindung bei https://seoreport.dev/mcp, wo die Berichtswerkzeuge auf connect beworben werden — ein Agent, der einen Verkehrsabfall untersucht, kann die Prüfung durchführen und die Ergebnisse selbst lesen, was neben der REST Oberfläche auf der Entwicklerseite dokumentiert ist.

Was die Tür nicht abdeckt

Ein Bereitstellungstor beantwortet eine Frage: hat diese Veröffentlichung eine Regression eingeführt. Es bleibt still über alles, was sich ohne Bereitstellung ändert — ein ablaufendes Zertifikat, eine CDN Konfiguration, die in einem Dashboard bearbeitet wurde, ein Drittanbieter-Skript, das das Rendern blockiert, eine Migration eines Konkurrenten, die ändert, womit deine kanonische URL kollidiert. Die Überwachung pro Domain ist das immer‑an-Komplement zum Tor und liest aus demselben Konto und demselben Schlüssel, wie auf der Entwicklerseite beschrieben. Beginne mit der schmalen Version. Ein Endpunkt, ein Feld, failingCriticalChecks > 0, und ein ehrlicher exit 75, wenn die Prüfung überhaupt nicht ausgeführt werden konnte. Ein Tor, das zweimal im Jahr auslöst und beide Male vertrauenswürdig ist, ist mehr wert als ein umfassendes, das jeder gelernt hat zu überspringen.

Sehen Sie, wie Ihre Seite rankt

Get a free KI-powered SEO report with actionable findings and priority fixes for your website.

Keine Anmeldung erforderlich.