Content-Signal w robots.txt nie dociera do crawlerów AI: nasz własny błąd

Content-Signal w robots.txt nie dociera do crawlerów AI: nasz własny błąd

Ostatnio zweryfikowano: 14 października 2026
12 min czytania
Przewodnik
500+ projektów WP
Techniczne SEO

Nasza rezerwacja praw do trenowania AI była napisana do nikogo. Linia Content-Signal: search=yes, ai-input=yes, ai-train=no stała w pliku robots.txt wppoland.com dokładnie raz, w grupie User-agent: *, a poniżej niej leżało dwadzieścia nazwanych grup crawlerów. Zgodnie z RFC 9309 żadna z tych dwudziestu grup nie dziedziczy niczego z grupy gwiazdki. GPTBot, ClaudeBot, PerplexityBot, Google-Extended i reszta listy czytały wyłącznie swoje własne sekcje, w których tej linii nie było.

Każdy crawler, którego zadaliśmy sobie trud nazwać ręcznie, był dokładnie tym, który nie mógł przeczytać tego, co dla niego napisaliśmy.

Piszemy o tym, bo to nasz plik i nasz błąd. Sprawdzaliśmy robots.txt pod kątem tego, czy nie blokuje czegoś przypadkiem, i nigdy pod kątem tego, czy deklaracja w ogóle trafia do adresata. To dwa różne pytania i tylko na pierwsze istnieje narzędzie, które na nie odpowiada.

#Przykład Content-Signal w robots.txt

Struktura wyglądała tak, jak wygląda w większości plików, które widzieliśmy: jedna ogólna grupa na górze, a pod nią lista nazwanych botów z rozszerzonymi regułami Allow dla endpointów maszynowych.

User-agent: *
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /
Disallow: /cdn-cgi/

Sitemap: https://wppoland.com/sitemap-index.xml
Agentmap: https://wppoland.com/.well-known/ai-catalog.json

User-agent: GPTBot
Allow: /
Allow: /llms.txt
Allow: /facts.json

User-agent: ClaudeBot
Allow: /

User-agent: PerplexityBot
Allow: /

Wygląda porządnie. Sygnał jest, nazwane grupy są, endpointy dla agentów są wypisane osobno. Problem polega na tym, że te dwie rzeczy nie mają ze sobą kontaktu. Kto czyta plik jak dokument, widzi politykę na górze i uprawnienia pod nią, i w głowie dopisuje między tymi częściami relację, o której parser nic nie wie.

Parser nie czyta dokumentów. Porównuje token z listą nazw, bierze zwycięski blok i odrzuca resztę pliku, zanim przeczyta choć jedną dyrektywę.

#Czy grupy w robots.txt dziedziczą reguły z gwiazdki

RFC 9309 opisuje dopasowanie grup w sposób, który łatwo przeczytać jako oczywisty, dopóki nie zestawi się go z własnym plikiem. Klient porównuje swój token produktu z nazwami w liniach User-agent, bez rozróżniania wielkości liter, i stosuje jedną grupę: tę, która go nazywa. Gwiazdka nie jest wzorcem najmniej szczegółowym, tylko zapasową: RFC 9309 sięga po nią wyłącznie wtedy, gdy żadna grupa nie wymienia klienta z nazwy. Gdy nazwana grupa istnieje, klient stosuje wyłącznie jej dyrektywy i grupa gwiazdki przestaje go dotyczyć w całości.

To ostatnie zdanie jest całym błędem. W specyfikacji brzmi oczywiście i przestaje takie być, gdy postawi się je obok pliku napisanego przez siebie, bo taki plik niesie w sobie intencję autora, a intencja jest niewidoczna dla jedynego czytelnika, który tu się liczy.

To nie jest wyjątek dla Content Signals. Ta sama zasada od zawsze obowiązuje Allow i Disallow i dokładnie dlatego plik, w którym ktoś dopisał Disallow: /wp-admin/ tylko do grupy gwiazdki, nie chroni niczego przed botem, który ma swoją sekcję niżej. Różnica jest taka, że przy Disallow konsekwencję widać: strona pojawia się w indeksie albo nie, a tydzień danych z indeksowania mówi, która z tych dwóch rzeczy zaszła. Przy Content-Signal nie widać nic. Deklaracja praw nie ma sprzężenia zwrotnego, więc może być błędna przez wiele miesięcy i wyglądać identycznie jak poprawna.

Content Signals to propozycja Cloudflare, a nie część RFC 9309. Cloudflare włącza tę politykę domyślnie w swoim zarządzanym pliku robots.txt. Ale mechanizm grup, w którym ta linia mieszka, jest w całości mechanizmem z RFC 9309, więc zasada jednej grupy obowiązuje ją tak samo jak wszystko inne w tym pliku. Nowa dyrektywa w starym kontenerze dziedziczy zasady kontenera, także te, o które nikt nie zapytał, dopisując ją.

#Co oznaczają search, ai-input i ai-train

Specyfikacja definiuje trzy sygnały, każdy z wartością yes albo no:

SygnałCzego dotyczy
searchbudowanie indeksu wyszukiwarki i zwracanie wyników, czyli odnośników i krótkich fragmentów
ai-inputpodawanie treści na wejście modelu AI w czasie odpowiadania, czyli RAG i ugruntowanie odpowiedzi
ai-traintrenowanie i dostrajanie modeli

Nasz zestaw search=yes, ai-input=yes, ai-train=no jest świadomym wyborem. Chcemy być cytowani w odpowiedziach generatywnych, bo to dziś jeden z kanałów, którym ktoś nas znajduje, i nie chcemy oddawać korpusu do treningu, bo wytrenowany model zabiera tekst bez drogi powrotnej do strony, z której pochodzi.

Powiedzieć tak pierwszemu i nie drugiemu to przyjąć, że ten sam crawler może wykonywać obie prace w różne dni, i zaufać, że odróżnia te dni. Brak sygnału oznacza coś innego niż no: według polityki Cloudflare operator strony ani nie udziela zgody, ani jej nie odmawia tą drogą. Cisza nie jest tu odmową i dlatego ta linia istnieje.

Żaden z tych sygnałów niczego nie blokuje. To linia tekstu w pliku, który klient może pobrać albo nie, przeczytać albo nie i uszanować albo nie. Serwer odpowiada na żądanie niezależnie od tego, co w tym pliku napisano. Blokowanie jest osobną warstwą, ocenianą przed aplikacją, i robi się je regułami WAF, limitami zapytań albo weryfikacją tożsamości bota, nie plikiem tekstowym. Ta warstwa kosztuje: działa przy każdym żądaniu, może pomylić się co do człowieka i trzeba ją utrzymywać w miarę, jak zmieniają się sygnały tożsamości.

Deklaracja nic nie kosztuje i niczego nie wymusza, co jest rozsądną wymianą, o ile wiesz, którą z tych dwóch rzeczy właśnie opublikowałeś. Sygnał ma wartość dokładnie taką, jak jednoznaczny komunikat wysłany pod właściwy adres. Nasz był jednoznaczny i wysłany pod zły.

#Jak sprawdzić Content-Signal w robots.txt

To zajmuje kilka sekund i działa na dowolnej domenie:

curl -s https://twojadomena.pl/robots.txt \
  | awk 'tolower($0) ~ /^user-agent:/ {ua++} tolower($0) ~ /^content-signal:/ {cs++} END {print "grupy User-agent: " ua "\nlinie Content-Signal: " cs}'

Jedno zastrzeżenie, zanim zadziałasz na podstawie wyniku: komenda liczy linie User-agent, a nie grupy, a ABNF z RFC 9309 dopuszcza kilka linii User-agent otwierających jedną grupę. Plik, który tak układa nazwy, zgłosi tu braki, których nie ma, i wtedy wiążąca jest lista z drugiej komendy, a nie arytmetyka z pierwszej.

Jeśli liczba grup jest większa od liczby sygnałów, to różnica mówi, ile grup nie widzi twojej rezerwacji. U nas wynik brzmiał dwadzieścia jeden do jednego.

Dokładniejszy wariant wypisuje nazwy grup, w których sygnału brakuje:

curl -s https://twojadomena.pl/robots.txt \
  | awk '/^[Uu]ser-agent:/ {if (name != "" && !sig) print "brak sygnalu: " name; name=$2; sig=0} /^[Cc]ontent-[Ss]ignal:/ {sig=1} END {if (name != "" && !sig) print "brak sygnalu: " name}'

Druga komenda jest tą, którą warto wpiąć w pipeline, bo jej wyjście jest listą do naprawienia, a nie liczbą do zinterpretowania.

#Gdzie wpisać Content-Signal w robots.txt

Poprawka jest nudna: powtórzyć linię Content-Signal w każdej grupie, której ma dotyczyć. Nie ma tu skrótu, formy skróconej ani dziedziczenia, które można włączyć.

User-agent: *
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /
Disallow: /cdn-cgi/

User-agent: GPTBot
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /
Allow: /llms.txt
Allow: /facts.json

User-agent: ClaudeBot
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /

User-agent: PerplexityBot
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /

Tę zmianę wdrożyliśmy 18 września 2026, w dniu publikacji tego wpisu. Sygnał stoi teraz w 18 grupach na 23, a pięć pominiętych to scrapery, które i tak mają u nas Disallow, a zgoda w ich grupie tylko zamąciłaby to, co im mówimy.

Przy okazji poprawki trzeba rozstrzygnąć jedną rzecz, której plik z powtórzoną linią nie rozstrzyga sam: czy ten sam zestaw sygnałów pasuje do każdej grupy. Dla crawlera indeksującego i dla crawlera zbierającego korpus treningowy odpowiedź jest inna, a plik z dwudziestoma identycznymi liniami sugeruje, że nikt się nad tym nie zastanawiał. Grupa, w której search=yes nie ma sensu, bo klient nie buduje indeksu, powinna mieć swój własny zapis, i dopiero przy jego pisaniu plik przestaje być kopią, a staje się polityką.

#Grupy Claude-User i Claude-SearchBot w robots.txt

Przy tej samej lekturze pliku wyszło, że mieliśmy samą grupę ClaudeBot, a nie mieliśmy dwóch pozostałych: Claude-User, obsługującej pobrania inicjowane przez użytkownika, i Claude-SearchBot, obsługującej ugruntowanie wyszukiwania. To trzy różne role i różne intencje po stronie klienta. Bot, który pobiera stronę, bo człowiek właśnie wkleił jej adres w rozmowie, robi coś innego niż bot budujący korpus, i sensownie jest odpowiedzieć mu czymś innym.

Efekt braku tych grup jest dokładnie ten sam co wyżej, tylko od drugiej strony: klient, który nie ma swojej sekcji, wraca do grupy gwiazdki. W naszym przypadku to akurat oznaczało, że Claude-User widział poprawny sygnał, bo w gwiazdce on był. Czyli w pliku, w którym sygnał nie docierał do dwudziestu nazwanych botów, docierał do tych nienazwanych. Dokładnie odwrotnie niż zamierzaliśmy, i to wynik tej samej zasady działającej dokładnie tak, jak ją zapisano.

#Dlaczego przegląd robots.txt nie wyłapuje tego błędu

Trzy powody, wszystkie strukturalne, żaden z nich to nieuwaga.

Plik robots.txt czyta się z góry na dół i sekcja ogólna wygląda na nadrzędną. Wcięcie w nią czegokolwiek uruchamia intuicję z CSS albo z konfiguracji serwera, gdzie ogólne ustawienie jest domyślne, a szczegółowe je nadpisuje. W RFC 9309 nie ma nadpisywania. Jest wybór jednej grupy i odrzucenie reszty pliku.

Drugi powód: nie ma narzędzia, które by to zgłosiło. Testery robots.txt sprawdzają, czy dany adres jest dozwolony dla danego bota, i o Content-Signal nie wiedzą nic, bo to nie jest dyrektywa z RFC. Linia przechodzi jako komentarz w oczach walidatora i jako polityka w oczach człowieka, a każde z tych odczytań jest osobno spójne.

Trzeci, i najważniejszy: deklaracja praw nie ma sygnału zwrotnego. Gdy błędnie postawisz Disallow, po tygodniu widzisz to w raporcie indeksowania. Gdy błędnie postawisz Content-Signal, nie dzieje się nic, co dałoby się zaobserwować, a brak zdarzenia wygląda identycznie w obu przypadkach. Tę klasę defektów trzeba znajdować przez czytanie pliku, nie przez patrzenie na skutki, i to trudno zaplanować, bo czytanie nie ma wyzwalacza.

#Zasięg dyrektyw Sitemap i Content-Signal w robots.txt

Jest w tym pliku rzecz, która wprost podpowiada złą intuicję. Obok grup User-agent robots.txt zna rekordy niezależne od grup, i Sitemap jest takim rekordem. W naszym pliku stoi on po grupie gwiazdki:

Sitemap: https://wppoland.com/sitemap-index.xml
Agentmap: https://wppoland.com/.well-known/ai-catalog.json

Sitemap obowiązuje cały plik niezależnie od tego, gdzie go postawisz i ile grup jest pod nim. Nikt nie powtarza go dwadzieścia razy i nikt nie musi. Człowiek, który wie, jak zachowuje się Sitemap, i który widzi Content-Signal postawione w tym samym rejonie pliku, dwa wiersze wyżej, ma pełne prawo założyć, że ta linia zachowuje się tak samo. Nie zachowuje się. Jedna jest rekordem globalnym, druga dyrektywą wewnątrz grupy, i nic w składni tego nie sygnalizuje. Obie to dwuczłonowa linia z dwukropkiem, postawiona obok siebie.

Praktyczny wniosek przy czytaniu cudzego pliku: wcięcie i kolejność nic nie znaczą, znaczy wyłącznie to, czy dana dyrektywa jest zdefiniowana jako grupowa. Allow, Disallow i Content-Signal są grupowe. Sitemap nie jest.

#Czy ai-train=no wiąże crawlery AI

Dwie rzeczy zostawiamy poza zakresem świadomie, bo nie są nasze.

Pierwsza to skutek prawny rezerwacji. Content Signals odwołuje się do rezerwacji praw wyrażonej w prawie autorskim i taki tekst rzeczywiście stoi w komentarzu na górze naszego pliku. Czy i kiedy ta rezerwacja jest skuteczna, rozstrzyga prawnik, a nie osoba edytująca robots.txt. Nasz jedyny wkład jest techniczny: jeśli deklaracja ma mieć jakikolwiek ciężar, to musi przynajmniej dotrzeć do klienta, do którego jest adresowana, a nasza nie docierała.

Druga to zachowanie konkretnych operatorów. Nie mierzyliśmy, który crawler czyta Content-Signal, który go respektuje i co robi z niespójnymi sygnałami w różnych grupach. Bez własnego pomiaru nie mamy tu nic do powiedzenia i nie zamierzamy powtarzać cudzych liczb. Poprawka, którą opisujemy, jest warta zrobienia niezależnie od tej wiedzy, bo naprawia plik, który mówi co innego, niż jego autor zamierzał, a to jest defekt sam w sobie.

#Automatyczny test robots.txt w pipeline CI

Sprawdzenie zasięgu sygnału jest jednorazową pracą na kilka minut, ale jego utrzymanie jednorazowe nie jest. Każda nowa grupa dopisana do pliku, a dopisuje się je regularnie, bo lista crawlerów AI rośnie z miesiąca na miesiąc, jest nową grupą bez sygnału, dopóki ktoś o nim nie pamięta. Dlatego druga z komend wyżej ma trafić do testów, a nie do notatki. Reguła, która sprawdza się sama, przeżyje; reguła zapisana w dokumencie przeżyje do następnej edycji pliku przez kogoś, kto tego dokumentu nie czytał.

Warto też pamiętać, o jakiej części ruchu tu mówimy. W naszym pomiarze z sierpnia 2026, opisanym we wpisie o ruchu botów na małej stronie, 72% żądań nie pochodziło z przeglądarki. Plik robots.txt jest jedynym miejscem, w którym w ogóle rozmawiamy z tą większością, i jedyną rzeczą, jaką ta większość o naszych warunkach wie. Jeśli zdanie w nim jest zaadresowane do złej grupy, to nie jest miękki błąd, tylko cisza.

Na tej poprawce nie zyskujemy w pierwszej kolejności my. Zyskuje osoba, która redaguje stronę i musi umieć odpowiedzieć, na co się na niej zgadza, prawnik, który doradza jej właścicielowi i potrzebuje jednoznacznej deklaracji do przeczytania, oraz każdy, kto jutro dopisze nową grupę crawlera i potrzebuje, żeby plik mówił to, co wygląda, że mówi.

#Lista kontrolna Content-Signal w robots.txt

  • Policz grupy User-agent i linie Content-Signal w swoim pliku. Jeśli liczby się nie zgadzają, różnica to grupy bez rezerwacji.
  • Powtórz linię w każdej grupie, której ma dotyczyć. Powtórzenie jest tu poprawną formą, nie duplikatem.
  • Zdecyduj świadomie, czy każda grupa dostaje ten sam zestaw sygnałów. Dwadzieścia identycznych linii to zwykle znak, że nikt nie decydował.
  • Sprawdź, czy masz osobne grupy dla ról tego samego dostawcy, na przykład dla pobrania inicjowanego przez użytkownika i dla zbierania korpusu.
  • Wepnij sprawdzenie w pipeline. Lista crawlerów rośnie i każda dopisana grupa startuje bez sygnału.
  • Nie opowiadaj sobie, że sygnał cokolwiek blokuje. Blokowanie to warstwa przed aplikacją, a to jest deklaracja.

Czytanie robots.txt grupa po grupie to też część audytu zgodności UE dla WordPressa: reguły crawlerów i deklaracje regionalne muszą zgadzać się z tym, co strona realnie serwuje.

Następny krok

Przekuj artykuł w realne wdrożenie

Pod tym wpisem dokładam linki, które domykają intencję użytkownika i prowadzą dalej w strukturze serwisu.

Chcesz wdrożyć ten temat na swojej stronie?

Jeśli zależy Ci na widoczności w Google i systemach AI, mogę przygotować architekturę treści, FAQ, schema i linkowanie pod GEO, AEO i SEO.

Powiązany klaster

Sprawdź inne usługi WordPress i bazę wiedzy

Wzmocnij swój biznes dzięki profesjonalnemu wsparciu technicznemu w kluczowych obszarach ekosystemu WordPress.

Czy crawler czyta grupę gwiazdki, jeśli ma własną grupę w robots.txt?#
Nie. RFC 9309 mówi, że klient stosuje jedną grupę, tę, która wymienia jego token produktu, a grupę gwiazdki traktuje jako zapasową, używaną tylko wtedy, gdy żadna grupa go nie nazywa. Nie ma dziedziczenia z grupy User-agent dla gwiazdki. Jeśli GPTBot ma własną sekcję, to grupa gwiazdki go nie dotyczy w ogóle.
Gdzie postawić linię Content-Signal, żeby faktycznie działała?#
W każdej grupie, której ma dotyczyć, osobno. Jedna linia w grupie gwiazdki obejmuje wyłącznie te roboty, które nie mają własnej sekcji. Powtórzenie jest tu poprawną formą zapisu, nie duplikacją do usunięcia.
Czy Content-Signal to część standardu robots.txt?#
Nie. Content Signals to propozycja Cloudflare, dodatkowa linia w pliku robots.txt. Dziedziczy jednak semantykę grup z RFC 9309, więc podlega tej samej zasadzie jednej grupy co Allow i Disallow.
Czy ai-train=no powstrzymuje trenowanie modelu na treści?#
Nie. To deklaracja, a nie mechanizm egzekwowania. Serwer nadal odpowiada na żądanie, a plik tekstowy nie ma sposobu, żeby wymusić cokolwiek po stronie klienta. Wartość sygnału polega na tym, że jest jednoznaczny i wysłany do właściwego adresata.
Jak sprawdzić własny plik w jednej komendzie?#
Przepuść curl -s z pliku przez awk i policz linie zaczynające się od user-agent wobec linii zaczynających się od content-signal; obie komendy stoją gotowe w treści wpisu. U nas wynik brzmiał dwadzieścia jeden do jednego, a po poprawce sygnał stoi w 18 grupach na 23. Arytmetyka jest tylko wskazówką, bo ABNF z RFC 9309 dopuszcza kilka linii User-agent otwierających jedną grupę. Wiążąca jest druga komenda, która wypisuje nazwy grup bez sygnału.

Potrzebujesz FAQ dopasowanego do branży i rynku? Przygotujemy wersję pod Twoje cele biznesowe.

Porozmawiajmy

Polecane artykuły