Zum Inhalt springen
Doctor SEO

SEO mit KI: KI als Arbeitswerkzeug

Die drei Claude-Crawler und deine robots.txt

Zwei Messtage an einer einzigen Datei: die Türschwelle an der Kennung trat beide Male gleich auf, das Unterschieben einer Wartehinweis-Seite nicht. Dazu ein Skript, das aus deiner robots.txt abliest, welcher Block jedes der drei Claude-Tokens namentlich führt.

Aktualisiert am 7 Oktober 2026 32 Min. Lesezeit

Nach dieser Lektion belegst du an deiner eigenen robots.txt, welcher Block die Tokens ClaudeBot, Claude-User und Claude-SearchBot namentlich führt. Das Skript dafür steht unten vollständig, samt aller Dateien, an denen sich seine Ausgabe nachbauen lässt.

Die Zahl, an der dieses Thema hängt, steht in der Datei, mit der Anthropic die Überprüfung seiner Agenten anbietet: claude.com/crawling/bots.json führte am 20. September 2026 26 IPv4-Präfixe über Google Cloud, Azure und AWS – und zu keinem davon einen Agentennamen. Wer Logzeilen auf die drei Namen aufteilt, teilt nach einer Kennung auf, die sich der Client selbst gibt.

Eine Stufe tiefer liegt eine eigene Messung an /robots.txt von doctor-seo.net: Anfragen ohne User-Agent-Kopfzeile wurden an beiden Messtagen abgewiesen, HTTP 403, drei von drei – das Unterschieben einer Wartehinweis-Seite dagegen ließ sich nicht wiederholen.

Zwei Abgrenzungen vorweg. Die Crawler aller Anbieter nebeneinander behandelt GEO und AIO: SEO für KI-Suchmaschinen (Level 4); hier steht allein das Drei-Bot-Problem von Claude. Und die Frage, mit der die meisten Leser herkommen – sperren oder zulassen –, bleibt offen: es gibt die Evidenz jedes Lagers und die Lücke, die alle drei teilen, aber keine Empfehlung.

Was du lernst

  • Was zwei eigene Messtage an einer einzigen Datei belegen – und woran zwanzig Anfragen scheitern.
  • Was die drei Lager in der Sperrfrage vorlegen und was keinem von ihnen vorliegt.
  • Wie du aus deiner Datei abliest, welcher Block jedes der drei Tokens namentlich führt.
  • Weshalb jede Aufteilung deiner Logzeilen auf die drei Namen unverifiziert bleibt.
  • Warum drei erlaubende Blöcke die vom Stern verschlossenen Pfade öffnen würden, falls ein benannter Block die Sternregel wirklich ersetzt – belegt ist diese Lesart nicht.

Welcher Block welches Token führt – und woher diese Lesart kommt

Drei Tokens stehen in Anthropics Dokumentation, und für jedes verlangt sie einen eigenen User-agent:-Block: ClaudeBot, Claude-User, Claude-SearchBot. Der Hilfeartikel dazu ist Does Anthropic crawl data from the web, and how can site owners block the crawler? – die einzige Quelle dieser Lektion mit bestätigter URL. Ein absolutes Datum trägt sie nicht, nur eine Abstandsangabe, weshalb hier keines dabeisteht: die Seite, die die gültigen Tokens nennen soll, sagt nichts darüber, ob drei weiterhin die Zahl ist.

Zwei Begriffe. Eine robots.txt liegt in der Wurzel eines Hosts und hält fest, welche Pfade ein benanntes Programm anfragen darf; die User-Agent-Kennung schickt ein Client mit, verglichen wird davon nur das Token – ClaudeBot, nicht die Zeile drumherum. Anfragen, Indexierung und Ranking behandelt als drei Vorgänge SEO-Grundlagen: Level 0 des kostenlosen SEO-Kurses. Eine komplette Kennung von Anthropic findest du hier nicht, weil keine bestätigte vorliegt – in den Testdateien stehen synthetische Platzhalter um die dokumentierten Tokens.

Search Engine Land hielt am 25. Februar 2026 fest, dass eine Sperre für einen dieser Agenten die beiden anderen nicht erfasst – ohne Link, weil keine bestätigte URL vorliegt, und ohne Stichprobengröße, weil der Artikel keine angibt. Von dort kommt auch, dass IP-Sperren unzuverlässig sind.

Jetzt die Vorsicht, die hierher gehört. Die Mechanik dahinter heißt auf dieser Seite Substitutionslesart: ein Block, der einen Agenten nennt, ersetzt für ihn die Sternregel, statt sie zu ergänzen. Nahegelegt wird sie von der Forderung nach einem Block je Agent; eine Spezifikationsstelle dafür gibt der Quellenbestand dieses Kurses nicht her, und alles Weitere hier steht unter diesem Vorbehalt. Darum druckt das Skript unten aus, welcher Block welches Token führt, und keine Prognose über einen Agenten.

Daraus erklärt sich der Fehler, der Leser wirklich etwas kostet, und er sieht wie eine Höflichkeit aus: drei Blöcke mit Allow: /, damit eine Zustimmung aktenkundig wird. Zieht ein benannter Block seinen Agenten aus der Sternregel, endet damit jede Sperre, die dort für ihn stand – Warenkorb und Kundenkonto liegen für alle drei offen:

User-agent: *
Disallow: /warenkorb/
Disallow: /mein-konto/

User-agent: Claude-User
Allow: /

User-agent: ClaudeBot
Allow: /

User-agent: Claude-SearchBot
Allow: /

Die nachgezogene Fassung wiederholt jede Sternregel, die bleiben soll, in jedem benannten Block; wer alle drei aussperren will, setzt drei Blöcke mit je einem Disallow: /. Empfohlen wird keine Richtung:

User-agent: *
Disallow: /warenkorb/
Disallow: /mein-konto/

User-agent: Claude-User
Disallow: /warenkorb/
Disallow: /mein-konto/

User-agent: ClaudeBot
Disallow: /warenkorb/
Disallow: /mein-konto/

User-agent: Claude-SearchBot
Disallow: /warenkorb/
Disallow: /mein-konto/

Das Prüfskript: drei Dateien von der Platte, fünfzehn belegte Rückgabewerte

gruppenzuordnung.py baut aus drei Dateien eine Prüfakte: Abschnitt 1 nennt je Token ClaudeBot, Claude-User und Claude-SearchBot den Block, der es namentlich führt, Abschnitt 2 zählt die Logzeilen nach Kennung und Absenderlage. Einen Socket öffnet das Skript nie; die Netzdatei lädst du selbst herunter, damit nachvollziehbar bleibt, gegen welchen Stand geprüft wurde. Ein vierter Parameter deckelt wahlweise die gelesenen Logzeilen.

Der Ablauf ist zweigeteilt, und das ist Absicht: erst werden alle drei Dateien gelesen und abgenommen, dann entsteht die Akte, erst danach druckt etwas. Allein für die robots-Datei trennt die Abnahme fünf Fälle, weil sie fünf Reparaturen bedeuten – Kopfabzug, Markup-Seite, irgendein anderer erster Zeileninhalt, Datei ohne user-agent-Zeile und eine, die mitten in der Zeile aufhört. Keiner davon erscheint als Befund über deine Konfiguration.

Wert Wodurch er entsteht
0 Befund: alle drei Tokens werden namentlich geführt
2 Befund: mindestens ein Token wird nicht namentlich geführt
3 Parameterzahl weder drei noch vier
4 Eingabe ist keine lesbare reguläre Datei
5 Eingabe ist nicht in UTF-8 kodiert
6 Eingabe enthält nur Leerraum
7 robots-Datei beginnt mit einer HTTP-Statuszeile
8 robots-Datei beginnt mit Markup
9 erste Zeile ist kein Direktivenfeld und kein Kommentar
10 nirgends ein Feld user-agent
11 robots-Zeile ohne Doppelpunkt und ohne führendes #
12 Netzdatei liefert keine verwertbare Netzangabe
13 Logdatei liefert keine Zeile im Combined-Format
14 Limit ist keine positive Ganzzahl
15 unerwartete Ausnahme, kein Befund gedruckt
1 bleibt frei

Zwei Werte tragen Befunde, zwölf je einen Eingabefehler, einer fängt eine unerwartete Ausnahme auf – dieser 15er kommt in keinem der Läufe unten vor. Frei bleibt die 1, weil Python sie selbst setzt, wenn eine Ausnahme ungefangen durchfällt: läge dort auch ein Befund, wäre ein Absturz nicht von einem Ergebnis zu trennen. Und die 0 ist keine Freigabe – sie zählt Namen, nicht Regeln.

Drei bekannte Stolperstellen stehen im Code benannt. Ein Block ohne Direktive bleibt vom fehlenden getrennt und ein leer gesendetes Kennungsfeld von einem mit Strich, statt dass ein Vorgabewert beide Paare einzieht. Dekodiert wird ohne Ersatzzeichen, und dieser Zweig liegt neben dem Datei-Zweig, weil UnicodeDecodeError unter ValueError hängt und nicht unter OSError. Das Limit prüft bool vor der Zahl, denn ein Wahrheitswert ist in Python eine Ganzzahl.

#!/usr/bin/env python3
"""Baut aus drei Dateien auf der Platte eine Prüfakte und druckt sie in zwei
Abschnitten aus.

    python3 gruppenzuordnung.py <robots.txt> <zugriff.log> <netze.txt> [Limit]

Abschnitt 1 nennt je Token ClaudeBot, Claude-User und Claude-SearchBot den
Block, der es namentlich führt. Abschnitt 2 zählt die Logzeilen nach erklärtem
Token und nach Lage der Absenderadresse. Das Limit ist optional und deckelt die
Zahl der betrachteten nicht leeren Logzeilen.

Kein Socket, keine Netzanfrage, nur Standardbibliothek. Die Netzdatei lädst du
selbst herunter und legst sie ab; so bleibt nachvollziehbar, gegen welchen Stand
geprüft wurde.

Der Ablauf ist absichtlich zweigeteilt: erst werden alle drei Dateien gelesen
und vollständig abgenommen, dann entsteht die Akte, und erst danach druckt
irgendetwas. Eine beschädigte Eingabe kann so nicht als Befund über eine
Konfiguration erscheinen.

Was Abschnitt 1 liefert, ist eine Aussage über die Datei und keine darüber, was
ein Agent anschließend tut. Was Abschnitt 2 liefert, hängt an der Kennung, die
der Client selbst setzt; der Trailer unter jedem Lauf sagt das noch einmal.

Rückgabewerte, fünfzehn belegt: zwei Befunde, zwölf Eingabefehler mit je einer
Ursache und ein Auffangwert.
     0  Befund: alle drei Tokens werden namentlich geführt
     2  Befund: mindestens ein Token wird nicht namentlich geführt
     3  Parameterzahl weder drei noch vier
     4  Eingabe ist keine lesbare reguläre Datei
     5  Eingabe ist nicht in UTF-8 kodiert
     6  Eingabe enthält nur Leerraum
     7  robots-Datei beginnt mit einer HTTP-Statuszeile
     8  robots-Datei beginnt mit Markup
     9  robots-Datei beginnt mit etwas, das kein Direktivenfeld ist
    10  robots-Datei führt nirgends ein Feld user-agent
    11  robots-Zeile ohne Doppelpunkt und ohne führendes #
    12  Netzdatei liefert keine verwertbare Netzangabe
    13  Logdatei liefert keine Zeile im Combined-Format
    14  Limit ist keine positive Ganzzahl
    15  unerwartete Ausnahme, es wird kein Befund gedruckt
     1  bleibt frei: diesen Wert setzt Python selbst, wenn eine Ausnahme
        ungefangen durchfällt
"""
import os
import sys
import re
from ipaddress import ip_address, ip_network

TOKENS = ("ClaudeBot", "Claude-User", "Claude-SearchBot")

# Pro Token ein vorkompiliertes Muster. Die Klammern links und rechts halten
# Teiltreffer heraus, damit Claude-User nicht in Claude-UserX anspricht.
MUSTER = tuple((t, re.compile(r"(?<![\w-])" + re.escape(t) + r"(?![\w-])", re.I))
               for t in TOKENS)

COMBINED = re.compile(
    r'^(?P<absender>\S+)\s+\S+\s+\S+\s+\[(?P<zeit>[^\]]+)\]\s+'
    r'"(?P<anfrage>[^"]*)"\s+(?P<status>\d{3})\s+(?P<umfang>\S+)\s+'
    r'"(?P<verweis>[^"]*)"\s+"(?P<kennung>[^"]*)"\s*$'
)

AUFRUF = "gruppenzuordnung.py <robots.txt> <zugriff.log> <netze.txt> [Limit]"

NAMENTLICH, STERN, REGELFREI = "namentlich", "Sternregel", "regelfrei"


def abbruch(wert, satz):
    sys.stderr.write("EINGABE %d: %s\n" % (wert, satz))
    raise SystemExit(wert)


def argumente(argv):
    """Zerlegt die Kommandozeile in (drei Orte, Limit oder None).

    Das Limit geht durch isdigit und davor durch eine bool-Abfrage: ein
    Wahrheitswert ist in Python eine Ganzzahl, und wer diese Funktion aus einem
    eigenen Skript mit einem Schalter füttert, bekäme sonst True als Limit 1.
    """
    if len(argv) not in (3, 4):
        abbruch(3, "Parameterzahl weder drei noch vier. Aufruf: " + AUFRUF)
    limit = None
    if len(argv) == 4:
        rohwert = argv[3]
        tauglich = not isinstance(rohwert, bool) and str(rohwert).strip().isdigit()
        limit = int(str(rohwert).strip()) if tauglich else 0
        if limit < 1:
            abbruch(14, "Limit %r ist keine positive Ganzzahl" % (rohwert,))
    return tuple(argv[:3]), limit


def inhalt(ort):
    """Gibt den Text einer Eingabe zurück.

    Drei Ursachen, drei Werte. Der UTF-8-Zweig steht neben dem Datei-Zweig und
    nicht in ihm, weil UnicodeDecodeError unter ValueError hängt und nicht unter
    OSError. Ein Ersatzzeichen ist nicht erlaubt: es würde mitten in einem Token
    stehen und den Namensvergleich lautlos verschieben.
    """
    if not os.path.isfile(ort):
        abbruch(4, "%s ist keine lesbare reguläre Datei" % ort)
    try:
        with open(ort, "rb") as griff:
            rohbytes = griff.read()
    except OSError as grund:
        abbruch(4, "%s ist keine lesbare reguläre Datei: %s" % (ort, grund.strerror))
    try:
        text = rohbytes.decode("utf-8")
    except UnicodeDecodeError as grund:
        abbruch(5, "%s ist nicht in UTF-8 kodiert: Byte %d, %s"
                   % (ort, grund.start, grund.reason))
    if not text.strip():
        abbruch(6, "%s enthält nur Leerraum" % ort)
    return text


def erste_zeile(text):
    for roh in text.splitlines():
        if roh.strip():
            return roh.strip()
    return ""


def abnahme(orte, texte):
    """Nimmt alle drei Eingaben ab, bevor irgendetwas beurteilt wird.

    Die robots-Datei bekommt fünf eigene Werte, weil ein Statuszeilen-Abzug,
    eine Markup-Seite, irgendein anderer erster Zeileninhalt, eine fehlende
    user-agent-Zeile und ein Schnitt mitten in einer Zeile für den Leser fünf
    verschiedene Reparaturen bedeuten.
    """
    robots_ort, log_ort, netz_ort = orte
    robots, log, netze = texte

    kopf = erste_zeile(robots)
    if re.match(r"^HTTP/\d", kopf):
        abbruch(7, "%s beginnt mit einer HTTP-Statuszeile: %r — das ist ein "
                   "Kopfabzug und nicht die Datei" % (robots_ort, kopf[:60]))
    if kopf.startswith("<"):
        abbruch(8, "%s beginnt mit Markup: %r — ein HTTP 200 mit dem falschen "
                   "Inhaltstyp bleibt eine fremde Seite" % (robots_ort, kopf[:60]))
    if not re.match(r"^(#|[A-Za-z][A-Za-z-]*[ \t]*:)", kopf):
        abbruch(9, "%s beginnt mit %r — das ist kein Direktivenfeld und kein "
                   "Kommentar" % (robots_ort, kopf[:60]))
    if not re.search(r"(?im)^[ \t]*user-agent[ \t]*:", robots):
        abbruch(10, "%s führt nirgends ein Feld user-agent" % robots_ort)
    for nummer, roh in enumerate(robots.splitlines(), 1):
        zeile = roh.strip()
        if zeile and not zeile.startswith("#") and ":" not in zeile:
            abbruch(11, "%s Zeile %d ohne Doppelpunkt: %r — eine kaputte "
                        "Direktive, oder die Datei endet mitten in der Zeile"
                        % (robots_ort, nummer, zeile))

    if not netzadressen(netze):
        abbruch(12, "%s liefert keine verwertbare Netzangabe" % netz_ort)
    if not logpaare(log, None):
        abbruch(13, "%s liefert keine Zeile im Combined-Format" % log_ort)


def netzadressen(text):
    """Liest Netzangaben, eine je Zeile, und erträgt Anführungszeichen und
    Kommas aus einem JSON-Auszug.

    strict=True ist Absicht und nicht Strenge um ihrer selbst willen: damit
    fällt 198.51.100.13/24 heraus, also eine einzelne Adresse, die jemand mit
    der Maske ihres Blocks zusammengeschrieben hat. Dieselbe Prüfung fängt eine
    Zeile ab, der beim Kopieren die letzte Ziffer der Maske fehlt.
    """
    gelesen = []
    for roh in text.splitlines():
        zeile = roh.strip().strip('",[]{} ')
        if not zeile:
            continue
        try:
            gelesen.append(ip_network(zeile, strict=True))
        except ValueError:
            continue
    return gelesen


def logpaare(text, limit):
    """Liefert [(Absender, Kennung)] für die Zeilen im Combined-Format."""
    roh = [z for z in text.splitlines() if z.strip()]
    if limit is not None:
        roh = roh[:limit]
    paare = []
    for zeile in roh:
        treffer = COMBINED.match(zeile.strip())
        if treffer:
            paare.append((treffer.group("absender"), treffer.group("kennung")))
    return paare


def direktivenindex(text):
    """Baut einen flachen Index über die Datei.

    Rückgabe ist ein Paar: eine Liste von (Blocknummer, Feld, Wert) in
    Dateireihenfolge und eine Abbildung Name -> Blocknummer. Ein Block ohne
    Direktive taucht in der Abbildung auf und in der Liste nicht, womit
    'Block vorhanden, ohne Regel' und 'kein Block' zwei verschiedene Befunde
    bleiben, statt über einen Vorgabewert zur gleichen leeren Ausgabe zu werden.
    """
    felder, wohin = [], {}
    block, offen = 0, False
    for roh in text.splitlines():
        zeile = roh.split("#", 1)[0].strip()
        if ":" not in zeile:
            continue
        feld, _, wert = zeile.partition(":")
        feld, wert = feld.strip().lower(), wert.strip()
        if feld == "user-agent":
            if not offen:
                block += 1
                offen = True
            wohin.setdefault(wert.lower(), block)
        elif feld in ("allow", "disallow") and block:
            offen = False
            felder.append((block, feld, wert))
    return felder, wohin, block


def zuordnungstabelle(felder, wohin):
    """Berechnet die Zeilen von Abschnitt 1 für alle drei Tokens in einem Zug."""
    tabelle = []
    for token in TOKENS:
        block = wohin.get(token.lower())
        quelle = NAMENTLICH
        if block is None:
            block, quelle = wohin.get("*"), STERN
        if block is None:
            quelle = REGELFREI
        regeln = ["%s: %s" % (f.capitalize(), w) for b, f, w in felder if b == block]
        if block is None:
            text = "keine Direktive anwendbar"
        elif not regeln:
            text = "Block vorhanden, ohne Regel"
        else:
            text = "; ".join(regeln)
        tabelle.append((token, quelle, text))
    return tabelle


def adresslage(absender, netze):
    """Gibt eine Lagebezeichnung statt eines Wahrheitswerts zurück, damit eine
    unlesbare Adresse in Abschnitt 2 nicht stillschweigend als fremd gilt."""
    try:
        anschrift = ip_address(absender)
    except ValueError:
        return "unlesbar"
    for netz in netze:
        if anschrift in netz:
            return "geladen"
    return "fremd"


def kennungslage(kennung):
    """Ordnet ein Kennungsfeld einer von sechs Lagen zu. Leerstring und '-'
    bleiben getrennt: das eine deutet auf eine kaputte Zeile, das andere auf
    einen Client, der ausdrücklich nichts angibt."""
    if kennung == "":
        return "leer"
    if kennung.strip() == "-":
        return "ohne Angabe"
    for token, muster in MUSTER:
        if muster.search(kennung):
            return token
    return "fremder Client"


def verkehrsbild(paare, netze):
    """Zählt die Logzeilen über (Kennungslage, Adresslage) hinweg."""
    bild = {}
    for absender, kennung in paare:
        schluessel = (kennungslage(kennung), adresslage(absender, netze))
        bild[schluessel] = bild.get(schluessel, 0) + 1
    return bild


def summe(bild, kennung=None, lage=None):
    return sum(z for (k, l), z in bild.items()
               if (kennung is None or k == kennung) and (lage is None or l == lage))


def drucke(orte, limit):
    robots_ort, log_ort, netz_ort = orte
    texte = tuple(inhalt(o) for o in orte)
    abnahme(orte, texte)
    robots, log, netzText = texte

    netze = netzadressen(netzText)
    paare = logpaare(log, limit)
    felder, wohin, bloecke = direktivenindex(robots)
    tabelle = zuordnungstabelle(felder, wohin)

    print("== 1. Welcher Block führt welches Token ==")
    for token, quelle, regeltext in tabelle:
        print("   %-17s %-11s %s" % (token, quelle, regeltext))
    print("   Blöcke: %d | Netzangaben: %d | Direktiven: %d"
          % (bloecke, len(netze), len(felder)))

    bild = verkehrsbild(paare, netze)
    print()
    print("== 2. Logzeilen nach Kennung und Absenderlage ==")
    for token in TOKENS:
        print("   %-17s %2d erklärt | %2d aus geladenen Netzen | %2d von anderswo"
              % (token, summe(bild, kennung=token),
                 summe(bild, kennung=token, lage="geladen"),
                 summe(bild, kennung=token) - summe(bild, kennung=token, lage="geladen")))
    for lage, satz in (("ohne Angabe", "Kennungsfeld trägt nur einen Strich"),
                       ("leer", "Kennungsfeld leer gesendet"),
                       ("fremder Client", "Kennung nennt keines der drei Tokens")):
        print("   %-42s %2d" % (satz + ":", summe(bild, kennung=lage)))
    print("   Zeilen verwertet: %d" % len(paare))

    print()
    print("-- Was hier nicht geprüft wurde --")
    print("   Ob die drei Dateien ganz angekommen sind. Ein Schnitt genau auf")
    print("   einer Zeilengrenze ergibt wieder eine gültige, nur kürzere Datei.")
    print("   Ob irgendein Client eine der Zeilen aus Abschnitt 1 beachtet hat.")
    print("   Und die Hauptsache: welcher Agent gesendet hat. Die geladenen Netze")
    print("   führen keine Namen, darum endet ein Treffer beim Betreiber, und die")
    print("   Aufteilung in Abschnitt 2 hängt an einer Kennung, die der Client")
    print("   sich selbst gibt.")

    fehlend = [t for t, q, _ in tabelle if q != NAMENTLICH]
    print()
    if fehlend:
        print("NICHT NAMENTLICH: %s" % ", ".join(fehlend))
        print("Das ist der Stand der Datei. Was daraus folgen soll, entscheidest du.")
        return 2
    print("NAMENTLICH: alle drei Tokens stehen in dieser Datei mit eigenem Block.")
    print("Was in diesen Blöcken steht, zeigt Abschnitt 1 – gelesen hat es kein Agent.")
    return 0


def main(argv):
    try:
        orte, limit = argumente(argv)
        return drucke(orte, limit)
    except SystemExit as gewollt:
        raise gewollt
    except Exception as grund:
        sys.stderr.write("EINGABE 15: unerwartete Ausnahme %s (%s), kein Befund\n"
                         % (type(grund).__name__, grund))
        return 15


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))

Bienenhof Lindtal: die Testdateien und die Läufe daran

Bienenhof Lindtal ist ein erfundener Imkereibedarf-Shop; erfunden sind damit Pfade, Adressen und Kennungen, und Messwerte einer echten Website stehen in keiner dieser Dateien. Jede bekommt einen Block für sich und keine Namenszeile darüber, damit du sie unverändert speichern kannst; die Netze sind reservierte Dokumentationsbereiche. Nicht erfunden sind die 159 Bytes von doctor-seo.net und deren erste 20 Bytes. Zuerst der Fehlstand, bei dem allein ClaudeBot einen Block erhält:

User-agent: *
Disallow: /warenkorb/
Disallow: /mein-konto/
Allow: /produkte/

User-agent: ClaudeBot
Disallow: /

Dazu 8 Logzeilen im Combined-Format mit synthetischen Platzhaltern um die Tokens. 3 Zeilen nennen gar kein Claude-Token: eine mit einem Strich im Kennungsfeld, eine mit leer gesendetem Feld, eine mit einer Browserkennung.

192.0.2.24 - - [04/Oct/2026:05:12:41 +0000] "GET /produkte/smoker/ HTTP/1.1" 200 38114 "-" "synthetischer Platzhalter: ClaudeBot"
192.0.2.188 - - [04/Oct/2026:05:13:08 +0000] "GET /produkte/mittelwaende/ HTTP/1.1" 200 41002 "-" "synthetischer Platzhalter: ClaudeBot"
203.0.113.41 - - [04/Oct/2026:05:14:55 +0000] "GET /produkte/smoker/ HTTP/1.1" 200 38114 "-" "synthetischer Platzhalter: ClaudeBot"
198.51.100.13 - - [04/Oct/2026:05:16:02 +0000] "GET /robots.txt HTTP/1.1" 200 112 "-" "synthetischer Platzhalter: Claude-User"
198.51.100.72 - - [04/Oct/2026:05:17:19 +0000] "GET /sitemap_index.xml HTTP/1.1" 200 8817 "-" "synthetischer Platzhalter: Claude-SearchBot"
198.51.100.205 - - [04/Oct/2026:05:18:44 +0000] "GET /blog/imkern-im-oktober/ HTTP/1.1" 200 18110 "-" "-"
192.0.2.96 - - [04/Oct/2026:05:19:30 +0000] "GET /warenkorb/ HTTP/1.1" 200 7204 "-" ""
2001:db8::7f - - [04/Oct/2026:05:20:11 +0000] "GET / HTTP/1.1" 200 11480 "-" "synthetischer Platzhalter: Browserkennung"

Und zwei Dokumentationsnetze, das erste ein /25, damit die Maskenlänge mitzählt:

192.0.2.0/25
198.51.100.0/24
$ python3 gruppenzuordnung.py bienenhof-nur-claudebot.txt bienenhof-oktober.log netze-doku.txt
== 1. Welcher Block führt welches Token ==
   ClaudeBot         namentlich  Disallow: /
   Claude-User       Sternregel  Disallow: /warenkorb/; Disallow: /mein-konto/; Allow: /produkte/
   Claude-SearchBot  Sternregel  Disallow: /warenkorb/; Disallow: /mein-konto/; Allow: /produkte/
   Blöcke: 2 | Netzangaben: 2 | Direktiven: 4

== 2. Logzeilen nach Kennung und Absenderlage ==
   ClaudeBot          3 erklärt |  1 aus geladenen Netzen |  2 von anderswo
   Claude-User        1 erklärt |  1 aus geladenen Netzen |  0 von anderswo
   Claude-SearchBot   1 erklärt |  1 aus geladenen Netzen |  0 von anderswo
   Kennungsfeld trägt nur einen Strich:        1
   Kennungsfeld leer gesendet:                 1
   Kennung nennt keines der drei Tokens:       1
   Zeilen verwertet: 8

-- Was hier nicht geprüft wurde --
   Ob die drei Dateien ganz angekommen sind. Ein Schnitt genau auf
   einer Zeilengrenze ergibt wieder eine gültige, nur kürzere Datei.
   Ob irgendein Client eine der Zeilen aus Abschnitt 1 beachtet hat.
   Und die Hauptsache: welcher Agent gesendet hat. Die geladenen Netze
   führen keine Namen, darum endet ein Treffer beim Betreiber, und die
   Aufteilung in Abschnitt 2 hängt an einer Kennung, die der Client
   sich selbst gibt.

NICHT NAMENTLICH: Claude-User, Claude-SearchBot
Das ist der Stand der Datei. Was daraus folgen soll, entscheidest du.
# exit code 2

Abschnitt 1 ist eindeutig: ClaudeBot hat seinen Block mit Disallow: /, Claude-User und Claude-SearchBot hängen an der Sternregel, die nur Warenkorb und Kundenkonto verschließt – gemeint war Claude, geschrieben einer von drei.

Abschnitt 2 enthält die Falle, für die die Logdatei gebaut ist. ClaudeBot steht dreimal als erklärte Kennung, davon einmal aus einem geladenen Netz. Von den beiden übrigen Zeilen kommt die eine von 203.0.113.41, außerhalb jedes geladenen Bereichs, die andere von 192.0.2.188 – und 192.0.2.0/25 reicht nur bis .127. Wer die Maske für ein ganzes 192.0.2-Netz nimmt, verbucht sie als bestätigt.

Gegen bienenhof-drei-mal-offen.txt von oben zeigt sich, was der Rückgabewert allein nicht hergibt:

$ python3 gruppenzuordnung.py bienenhof-drei-mal-offen.txt bienenhof-oktober.log netze-doku.txt
== 1. Welcher Block führt welches Token ==
   ClaudeBot         namentlich  Allow: /
   Claude-User       namentlich  Allow: /
   Claude-SearchBot  namentlich  Allow: /
   Blöcke: 4 | Netzangaben: 2 | Direktiven: 5

== 2. Logzeilen nach Kennung und Absenderlage ==
   ClaudeBot          3 erklärt |  1 aus geladenen Netzen |  2 von anderswo
   Claude-User        1 erklärt |  1 aus geladenen Netzen |  0 von anderswo
   Claude-SearchBot   1 erklärt |  1 aus geladenen Netzen |  0 von anderswo
   Kennungsfeld trägt nur einen Strich:        1
   Kennungsfeld leer gesendet:                 1
   Kennung nennt keines der drei Tokens:       1
   Zeilen verwertet: 8

-- Was hier nicht geprüft wurde --
   Ob die drei Dateien ganz angekommen sind. Ein Schnitt genau auf
   einer Zeilengrenze ergibt wieder eine gültige, nur kürzere Datei.
   Ob irgendein Client eine der Zeilen aus Abschnitt 1 beachtet hat.
   Und die Hauptsache: welcher Agent gesendet hat. Die geladenen Netze
   führen keine Namen, darum endet ein Treffer beim Betreiber, und die
   Aufteilung in Abschnitt 2 hängt an einer Kennung, die der Client
   sich selbst gibt.

NAMENTLICH: alle drei Tokens stehen in dieser Datei mit eigenem Block.
Was in diesen Blöcken steht, zeigt Abschnitt 1 – gelesen hat es kein Agent.
# exit code 0

Der dritte Lauf nimmt die Datei dieses Hosts: 159 Bytes, eine Sternregel, vier geschlossene Pfadmuster, kein KI-Agent, ein Leerzeichen nach dem Stern, keines auf disallow:, kein Zeilenumbruch am Ende. Speichere sie mit CRLF-Zeilenenden – der Schnitt auf 20 Bytes hängt daran und bricht mit CRLF nach disa, mit reinen LF-Enden erst nach disal.

User-agent: * 
disallow:*/feed/*
disallow:*/?s=search_term_string
disallow:*/amp
disallow:*/search/*


sitemap: https://doctor-seo.net/sitemap_index.xml
$ python3 gruppenzuordnung.py doctor-seo-159.txt bienenhof-oktober.log netze-doku.txt
== 1. Welcher Block führt welches Token ==
   ClaudeBot         Sternregel  Disallow: */feed/*; Disallow: */?s=search_term_string; Disallow: */amp; Disallow: */search/*
   Claude-User       Sternregel  Disallow: */feed/*; Disallow: */?s=search_term_string; Disallow: */amp; Disallow: */search/*
   Claude-SearchBot  Sternregel  Disallow: */feed/*; Disallow: */?s=search_term_string; Disallow: */amp; Disallow: */search/*
   Blöcke: 1 | Netzangaben: 2 | Direktiven: 4

== 2. Logzeilen nach Kennung und Absenderlage ==
   ClaudeBot          3 erklärt |  1 aus geladenen Netzen |  2 von anderswo
   Claude-User        1 erklärt |  1 aus geladenen Netzen |  0 von anderswo
   Claude-SearchBot   1 erklärt |  1 aus geladenen Netzen |  0 von anderswo
   Kennungsfeld trägt nur einen Strich:        1
   Kennungsfeld leer gesendet:                 1
   Kennung nennt keines der drei Tokens:       1
   Zeilen verwertet: 8

-- Was hier nicht geprüft wurde --
   Ob die drei Dateien ganz angekommen sind. Ein Schnitt genau auf
   einer Zeilengrenze ergibt wieder eine gültige, nur kürzere Datei.
   Ob irgendein Client eine der Zeilen aus Abschnitt 1 beachtet hat.
   Und die Hauptsache: welcher Agent gesendet hat. Die geladenen Netze
   führen keine Namen, darum endet ein Treffer beim Betreiber, und die
   Aufteilung in Abschnitt 2 hängt an einer Kennung, die der Client
   sich selbst gibt.

NICHT NAMENTLICH: ClaudeBot, Claude-User, Claude-SearchBot
Das ist der Stand der Datei. Was daraus folgen soll, entscheidest du.
# exit code 2

Für die Bedienfehler kommen fünf Dateien hinzu – Kopfabzug der Edge, ihre Wartehinweis-Seite, eine robots-Datei ohne user-agent-Zeile, eine Netzzeile ohne letzte Maskenziffer, zwei Logzeilen in anderem Format:

HTTP/2 200
content-type: text/plain; charset=utf-8
cache-control: max-age=600
<!doctype html>
<html>
<head><title>Einen Moment bitte</title><meta charset="utf-8"></head>
<body><p id="pruefung">Die Anfrage wird gerade geprueft.</p></body>
</html>
Disallow: /warenkorb/
Sitemap: https://bienenhof-lindtal.example/sitemap.xml
192.0.2.0/2
[04/Oct/2026:05:12:41] GET /produkte/smoker/ 200 38114
[04/Oct/2026:05:13:08] GET /produkte/mittelwaende/ 200 41002

Drei weitere entstehen in der Sitzung, weil sie sich nicht abdrucken lassen: die leere, die mit einem Byte, das UTF-8 nicht kennt, und der Schnitt auf 20 Bytes. Einmal steht die Netzdatei im ersten Parameter – der Griff daneben:

$ python3 gruppenzuordnung.py bienenhof-nur-claudebot.txt bienenhof-oktober.log
EINGABE 3: Parameterzahl weder drei noch vier. Aufruf: gruppenzuordnung.py <robots.txt> <zugriff.log> <netze.txt> [Limit]
# exit code 3
$ python3 gruppenzuordnung.py bienenhof-nur-claudebot.txt bienenhof-oktober.log netze-doku.txt zwei
EINGABE 14: Limit 'zwei' ist keine positive Ganzzahl
# exit code 14
$ python3 gruppenzuordnung.py fehlt.txt bienenhof-oktober.log netze-doku.txt
EINGABE 4: fehlt.txt ist keine lesbare reguläre Datei
# exit code 4
$ python3 gruppenzuordnung.py . bienenhof-oktober.log netze-doku.txt
EINGABE 4: . ist keine lesbare reguläre Datei
# exit code 4
$ printf 'User-agent: *\ndisallow: /gl\366ckchen/\n' > bienenhof-latin1.txt
$ python3 gruppenzuordnung.py bienenhof-latin1.txt bienenhof-oktober.log netze-doku.txt
EINGABE 5: bienenhof-latin1.txt ist nicht in UTF-8 kodiert: Byte 27, invalid start byte
# exit code 5
$ : > nichts.txt
$ python3 gruppenzuordnung.py nichts.txt bienenhof-oktober.log netze-doku.txt
EINGABE 6: nichts.txt enthält nur Leerraum
# exit code 6
$ python3 gruppenzuordnung.py edge-statuszeile.txt bienenhof-oktober.log netze-doku.txt
EINGABE 7: edge-statuszeile.txt beginnt mit einer HTTP-Statuszeile: 'HTTP/2 200' — das ist ein Kopfabzug und nicht die Datei
# exit code 7
$ python3 gruppenzuordnung.py edge-wartehinweis.html bienenhof-oktober.log netze-doku.txt
EINGABE 8: edge-wartehinweis.html beginnt mit Markup: '<!doctype html>' — ein HTTP 200 mit dem falschen Inhaltstyp bleibt eine fremde Seite
# exit code 8
$ python3 gruppenzuordnung.py netze-doku.txt bienenhof-oktober.log netze-doku.txt
EINGABE 9: netze-doku.txt beginnt mit '192.0.2.0/25' — das ist kein Direktivenfeld und kein Kommentar
# exit code 9
$ python3 gruppenzuordnung.py bienenhof-nur-pfade.txt bienenhof-oktober.log netze-doku.txt
EINGABE 10: bienenhof-nur-pfade.txt führt nirgends ein Feld user-agent
# exit code 10
$ head -c 20 doctor-seo-159.txt > doctor-seo-20-byte.txt
$ python3 gruppenzuordnung.py doctor-seo-20-byte.txt bienenhof-oktober.log netze-doku.txt
EINGABE 11: doctor-seo-20-byte.txt Zeile 2 ohne Doppelpunkt: 'disa' — eine kaputte Direktive, oder die Datei endet mitten in der Zeile
# exit code 11
$ python3 gruppenzuordnung.py bienenhof-nur-claudebot.txt bienenhof-oktober.log netze-doku-halb.txt
EINGABE 12: netze-doku-halb.txt liefert keine verwertbare Netzangabe
# exit code 12
$ python3 gruppenzuordnung.py bienenhof-nur-claudebot.txt bienenhof-altformat.log netze-doku.txt
EINGABE 13: bienenhof-altformat.log liefert keine Zeile im Combined-Format
# exit code 13

Der Wert 11 ist der lehrreiche: die auf 20 Bytes geschnittene Datei endet als Eingabefehler, wo sie ohne die Abnahme mit 2 geendet und sich wie ein Befund über eine ganze Datei gelesen hätte. Wie so eine Prüfung monatlich eingeplant wird, zeigt Claude Code für technisches SEO.

Ein Adressabgleich reicht bis zum Betreiber

Ein Treffer in Anthropics veröffentlichter Netzliste weist den Betreiber des Netzes nach, aus dem eine Anfrage kam – und nie den Agenten, der sie gestellt hat. Für die Überprüfung seiner Agenten stellt Anthropic diese Liste unter claude.com/crawling/bots.json bereit: am 20. September 2026 gelesen, trug sie einen creationTime vom 18. August 2026 und 26 IPv4-Präfixe über Google Cloud, Azure und AWS. Mehr steht nicht darin: Bereiche, ein Zeitstempel, kein Name.

Eine IP-Adresse sagt, aus welchem Netz eine Anfrage kam. Welches Programm sie abschickte, steht in den Kopfzeilen – in dem, was der Absender über sich mitteilt. Darum ist der Adressabgleich die belastbarere Prüfung, und darum bleibt er auf halbem Weg stehen, sobald nach dem Agenten gefragt wird: gegen eine Liste ohne Namen lässt sich keine Kennung halten. Für ClaudeBot, Claude-User und Claude-SearchBot ist damit keine Anfragezahl je Agent verifiziert, egal wer sie ausweist.

Zwei Dokumente, zwei Lücken. Der Hilfeartikel Does Anthropic crawl data from the web, and how can site owners block the crawler? verlangt eine Konfiguration je Agent und trägt kein absolutes Datum dafür. Die Netzliste derselben Firma, mit der die Überprüfung angeboten wird, führt keine Agentennamen und keine getrennten Listen je Agent. Der Anweisung lässt sich folgen, ihre Einhaltung nicht nachrechnen.

Die Zahl 26 gilt für einen Lesetag: die Liste erneuert sich, was ihr creationTime anzeigt, und für diese Lektion war sie nicht erneut abrufbar – sie steht hier mit Datum und ohne Link.

Zwei Messtage an derselben URL, sechs Tage auseinander

Auf doctor-seo.net liefen am 30. September und am 6. Oktober 2026 je zwei Durchgänge mit zehn cache-gebusteten Anfragen an /robots.txt und drei Anfragen ohne Kennung – ein Host, dasselbe Verfahren an beiden Tagen. Zwei Verhaltensweisen traten auf, und nur eine davon wiederholte sich.

Durchgang Messtag Anfragen Was zurückkam
A – Kennung robots-check/1.0, Cache-Buster 6. Oktober 2026 10 10 von 10: HTTP 200, text/plain, 159 Bytes, ein Körper, SHA-256-Präfix 312e6b75a110
B – gleiche Anfrage, Minuten später 6. Oktober 2026 10 10 von 10, von A nicht zu unterscheiden
C – ohne User-Agent-Kopfzeile 6. Oktober 2026 3 HTTP 403, 3 von 3
A und B, gleiches Verfahren 30. September 2026 10 und 10 die Datei 6 von 10 und 7 von 10; sonst rund 12,3 KB text/html unter demselben 200, die Wartehinweis-Seite der Edge
C, gleiches Verfahren 30. September 2026 3 HTTP 403, 3 von 3

Die Wartehinweis-Seite trat am 30. September in einer Minderheit der Anfragen auf und am 6. Oktober in keiner; sie ist damit belegt, aber nicht verlässlich wiederholbar. Die Türschwelle an der Kennung verhielt sich umgekehrt und trat beide Male gleich auf, und das SHA-256-Präfix des ausgelieferten Körpers lautete an beiden Tagen 312e6b75a110.

Festliegen damit zwei Punkte: /robots.txt kann auf diesem Host unter einem HTTP 200 etwas anderes als die Datei zurückgeben, und eine Anfrage ohne User-Agent-Kopfzeile wird abgewiesen. Offen bleiben Rate, Ursache und Rhythmus – und was das Ausbleiben am 6. Oktober bedeutet, denn zwanzig Anfragen trennen nicht, ob ein Verhalten aufgehört hat oder diesmal nur nicht auftrat. Über Anthropics Agenten sagt die Messung nichts, weil keine Anfrage von ihnen stammte. Und ein text/plain besagt nicht, dass der Körper ganz ankam – eine abgeschnittene Datei mit plausiblem Typ zerlegt sich anstandslos, wogegen der Prüfsummenvergleich über mehrere Durchgänge hilft.

Die 403er sind dabei der Gegensatz zu jeder Textdatei im Kleinen: dort wurde abgewiesen, bevor eine Regel aus einer Datei überhaupt gelesen werden konnte, und das vermag keine Zeile in einer robots.txt. Die Langzeitbeobachtung solcher Antworten gehört zu Technisches SEO: Crawling, Indexierung, Ladezeit.

Drei Dinge, für die eine Disallow-Zeile nicht einsteht

Ein Block für ClaudeBot, Claude-User oder Claude-SearchBot ist eine Bitte an einen Client und kein Riegel: wer einen Abruf anhalten muss, braucht einen Fehlerstatus oder eine Authentifizierung.

Erstens steht eine Disallow-Zeile nicht für ein noindex: einen Abruf abzulehnen lässt jede Kopie unberührt, die schon angelegt ist. Zweitens steht sie nicht für eine Identität, was der Abschnitt über den Adressabgleich ausführt. Drittens hält sie als Adressliste nicht: die Netzliste erneuert sich, und eine im Juni gezogene Kopie sperrt im September Adressen, die längst außer Dienst sind, während neue durchkommen. Dass IP-Sperren unzuverlässig bleiben, hielt Search Engine Land am 25. Februar 2026 fest, ohne Stichprobengröße.

Vor der Sperrfrage liegt eine Vorfrage, die bei einem Anbieter schon offen ausgetragen wird. In seiner Dokumentationsüberarbeitung vom 9. Dezember 2025 – berichtet von PPC Land – strich OpenAI die Aussage, der nutzerausgelöste Abrufer halte sich an die robots.txt, und setzte dafür ein: „because these actions are initiated by a user, robots.txt rules may not apply“. Auf Deutsch: weil ein Nutzer die Handlung auslöste, greifen die Regeln womöglich nicht. Ob eine dauerhaft hinterlegte Beobachtungsanweisung noch als nutzerausgelöster Abruf durchgeht, bleibt in dieser Lektion unentschieden; eine Messung auf Logebene, welche Kennung eine solche Aufgabe mitschickt, hat niemand veröffentlicht. An dieser Frage hängt, ob ein Disallow gegen so einen Abrufer ein Hebel ist oder eine Absichtserklärung.

Die Entscheidung, die niemand gemessen hat

Für oder gegen eine Sperre liegt keine Messung vor; entscheiden wird es der Preis deiner Texte und die Konditionen, zu denen du sie abgibst. Die Zahlen, die in jeder Diskussion auftauchen, stammen aus der robots.txt-Momentaufnahme von Cloudflare Radar vom 31. August 2026 über die oberen rund 10.000 Domains, von denen etwa 4.000 Dateien zerlegt wurden.

Crawler Disallow-Zeilen Allow-Zeilen Verhältnis
ClaudeBot 619 259 2,39:1
GPTBot 696 299 2,33:1
OAI-SearchBot 250 266 0,94:1

Die Einteilung in trainierende und antwortende Agenten stammt von Cloudflare Radar und nicht von den Anbietern: ClaudeBot und GPTBot zählt die Momentaufnahme zum Training, OAI-SearchBot zur Beantwortung. Lager eins nimmt die Tabelle als Beschreibung dessen, was der Markt längst entschieden hat: trainierende Agenten werden zwei- bis dreimal häufiger ausgesperrt als zugelassen, der antwortende netto zugelassen, ablesbar an der 0,94:1. Lager zwei hält dagegen, dass in diesen Spalten Textzeilen stehen und weder Besucher noch Zitate noch Umsätze – gezählt werden Absichten, nicht Folgen. Lager drei will Trainingszugriff lizenzieren und hat Bewegung statt Messung vorzuweisen: Cloudflare stellte am 15. September 2026 seine Voreinstellungen um, ohne Zahlen zu Verbreitung oder Erlösen.

Dazu zwei Grenzen. Die erste gilt dem Material: 10.000 Domains sind ein Ausschnitt, gezählte Direktiven keine Wirkung. Die zweite trägt diese Seite bei. Die Verifikationslücke taugt für keines der Lager – für eine Sperre so wenig wie gegen eine –, aber sie zieht allen dreien eine Decke ein: wer eine Regel je Agent setzt, deren Wirkung sich keinem Agenten zuordnen lässt, kann hinterher weder Erfolg noch Fehlschlag belegen.

Diese Lektion empfiehlt daher weder zu sperren noch zuzulassen. Beenden könnte den Streit eine Untersuchung, die es nicht gibt: zwei vergleichbare Gruppen von Websites, eine sperrend, eine nicht, mit Zitaten und verwiesenem Verkehr auf beiden Seiten, über einen angegebenen Zeitraum und mit offengelegter Stichprobengröße. Solange sie aussteht, sind die Behauptung, eine Sperre nehme dich aus den KI-Antworten, und die Gegenbehauptung, sie koste nichts, dieselbe Vermutung in zwei Richtungen. Überprüfbar bleibt nur die eine Hälfte: ob deine Datei das sagt, was du gemeint hast. Auf welchem Weg Claude zu Webseiten kommt, behandelt Von Claude zitiert werden: die Brave-Abhängigkeit.

Häufige Fehler

  • Die Netzliste als Namensliste behandeln. Sie führt Bereiche und keine Agenten, also ist jede Aufteilung deiner Logzeilen auf die drei Namen damit eine Selbstauskunft der Clients. Die Korrektur: das Ergebnis als erklärten Verkehr ausweisen und getrennt benennen, was der Adressabgleich wirklich belegt – den Betreiber des Netzes, nicht den Agenten.
  • Die Maskenlänge aus dem Gedächtnis setzen. 192.0.2.0/25 deckt nicht, was 192.0.2.0/24 deckt, und die Liste erneuert sich obendrein. Die Korrektur: am Prüftag neu laden und die Zugehörigkeit von einer Bibliothek entscheiden lassen.
  • Nach dem Umbau nicht nachsehen. Drei Blöcke mit Allow: / enden mit Rückgabewert 0, und unter der Substitutionslesart – ein benannter Block ersetzt für seinen Agenten die Sternregel, zitierfähig belegt ist das nicht – stünde damit der Warenkorb offen; der Rückgabewert allein verrät davon nichts. Die Korrektur: nach jedem Eingriff Abschnitt 1 lesen, Zeile für Zeile, und jede Sternregel, die bleiben soll, in jedem benannten Block wiederholen.
  • Einen 200er für die Datei halten. Markup an /robots.txt zerlegt sich zu einer Datei ohne Regeln, was nach Entwarnung aussieht. Die Korrektur: Inhaltstyp und Bytezahl vor dem Zerlegen prüfen und jeden Eingabefehler als Abrufproblem behandeln, nicht als Befund.

Kurzfassung

  • Eigene Messung an /robots.txt von doctor-seo.net, je zwei Durchgänge mit zehn Anfragen und drei ohne Kennung an zwei Tagen: die Türschwelle an der Kennung trat beide Male gleich auf, 3 von 3 am 30. September und am 6. Oktober 2026; die Wartehinweis-Seite nicht – 6 von 10 und 7 von 10 am 30. September, kein Fall am 6. Oktober.
  • Zwanzig Anfragen trennen ein verschwundenes Verhalten nicht von einem diesmal ausgebliebenen; Rate, Ursache und Rhythmus bleiben offen, und über Anthropics Agenten sagt die Messung nichts, weil keine von ihnen stammte.
  • claude.com/crawling/bots.json trug am 20. September 2026 26 IPv4-Präfixe und einen creationTime vom 18. August 2026, zu keinem Bereich einen Namen – ein Treffer weist den Betreiber aus, und keine Anfragezahl je Agent ist damit verifiziert.
  • Ein benannter Block ersetzt für seinen Agenten die Sternregel. Diese Lesart legt Anthropics Forderung nach einem Block je Agent nahe, eine zitierfähige Spezifikationsstelle dafür gibt es nicht, und dass eine Sperre die beiden anderen Agenten nicht erfasst, hielt Search Engine Land am 25. Februar 2026 ohne Stichprobengröße fest. Der Hilfeartikel trägt kein absolutes Datum.
  • Rückgabewert 0 zählt Namen, nicht Regeln: dreimal Allow: / endet ebenso mit 0 und gäbe – unter der Substitutionslesart, nach der ein benannter Block die Sternregel ersetzt und für die keine Spezifikationsstelle zitierbar ist – den Warenkorb frei, den die Sternregel verschloss. Eine Disallow-Zeile steht weder für ein noindex noch für eine Identität, und als Adressliste hält sie nicht, weil die Netzliste sich erneuert.
  • Die Sperrfrage ist offen: Cloudflare Radars Momentaufnahme vom 31. August 2026 über rund 10.000 Domains und etwa 4.000 zerlegte Dateien zählt Direktiven und keine Folgen; vergleichbare Gruppen mit und ohne Sperre hat niemand erhoben.

Häufige Fragen

Das Skript endet mit 0 – ist meine robots.txt damit in Ordnung?

Nein. Der Rückgabewert 0 meldet, dass ClaudeBot, Claude-User und Claude-SearchBot je einen eigenen Block haben. Was darin steht, liest du in Abschnitt 1 der Ausgabe: der Lauf gegen bienenhof-drei-mal-offen.txt endet mit 0 und gibt drei Agenten den Warenkorb frei. Über deine Politik urteilt weder das Skript noch diese Lektion.

Wie oft muss ich die Netzliste neu herunterladen?

Vor jeder Prüfung. claude.com/crawling/bots.json trägt einen creationTime – am 20. September 2026 den 18. August 2026 –, und dieser Zeitstempel sagt gerade, dass die Datei neu erzeugt wird; die 26 Präfixe sind ein Stand und keine Konstante. Das Skript greift absichtlich nicht selbst zu, damit in deinen Unterlagen steht, gegen welche Fassung du geprüft hast.

Was mache ich mit Anfragen, die sich ClaudeBot nennen und aus keinem geladenen Netz kommen?

Abschnitt 2 führt sie als erklärt und von anderswo – im Lauf oben zwei von drei ClaudeBot-Zeilen. Daraus folgt kein SEO-Befund, sondern eine Serverentscheidung: Rate begrenzen, eine Prüfung verlangen oder stehen lassen. Dass eine Adresse außerhalb der geladenen Bereiche liegt, belegt dabei nicht, dass die Anfrage nicht von Anthropic kam – die Liste erneuert sich, und der Trailer jedes Laufs hält das fest.

Quellen

Wo (ohne Link) steht, ließ sich keine bestätigte URL prüfen; dann stehen Urheber und Datum.

  • Anthropic, Does Anthropic crawl data from the web, and how can site owners block the crawler? – dokumentiert die drei Agenten und das Sperren über robots.txt. Statt eines Datums trägt die Seite nur eine Abstandsangabe, weshalb hier keines steht.
  • Anthropic, claude.com/crawling/bots.json, gelesen am 20. September 2026: creationTime 18. August 2026, 26 IPv4-Präfixe über Google Cloud, Azure, AWS, keine Namen. (ohne Link)
  • Search Engine Land zu Anthropics Crawlern, 25. Februar 2026: eine Sperre erfasst die beiden anderen Agenten nicht, IP-Sperren bleiben unzuverlässig. Keine Stichprobengröße. (ohne Link)
  • Cloudflare Radar, robots.txt-Momentaufnahme vom 31. August 2026. Stichprobe: obere rund 10.000 Domains, davon etwa 4.000 zerlegte Dateien. Zahlen in der Tabelle oben; die Einteilung in Training und Beantwortung ist die von Cloudflare Radar, dessen Voreinstellungen am 15. September 2026 umgestellt wurden. (ohne Link)
  • PPC Land über OpenAIs Überarbeitung der Crawler-Dokumentation vom 9. Dezember 2025: statt der Aussage, der nutzerausgelöste Abrufer halte sich an die robots.txt, steht dort „because these actions are initiated by a user, robots.txt rules may not apply“. (ohne Link)
  • Eigene Messung. doctor-seo.net, 30. September und 6. Oktober 2026, ein Host, dasselbe Verfahren. Stichprobe je Messtag: zwei Durchgänge mit zehn cache-gebusteten GET-Anfragen an /robots.txt unter der Kennung robots-check/1.0 und drei Anfragen ohne User-Agent-Kopfzeile. Ergebnisse vollständig in der Tabelle oben; Rate, Ursache und Rhythmus sind nicht belegt.
  • Eigenes Material. gruppenzuordnung.py und die Testdateien stehen oben in voller Länge – Standardbibliothek allein, keine Netzanfrage, fünfzehn belegte Rückgabewerte. Die Läufe tragen kein Datum, weil ihre Ausgabe allein an den abgedruckten Dateien hängt. Erfunden sind die Dateien von Bienenhof Lindtal, nicht die 159 Bytes dieses Hosts.

Weiter im Kurs

In diesem Level liegen schon vor: Was Claude im SEO leisten kann – und was nicht, Claude Skills für SEO: installieren, nutzen, selbst schreiben, Im Brave-Index landen: das Web Discovery Project und Von Claude zitiert werden: die Brave-Abhängigkeit.