robots.txt is a file where the syntax is trivial and the semantics are not. Which of your rules actually decides a URL depends on match lengths, group choice and two wildcard characters, and nothing in the file tells you the result. Since Google retired the public robots.txt tester, the usual way to find out has been to guess. This page explains the matching rules the tester implements, and the mistakes it flags because we keep finding them in real files.
What the tester shows
Paste a robots.txt into the first field, the URLs you care about into the second, and pick the crawlers to test as in the row above: Googlebot, Bingbot, GPTBot, ClaudeBot, the * fallback that stands for every unnamed bot, or any custom token. Several at once is the point: you get a verdict matrix, one row per URL and bot.
Each verdict carries its justification: the winning line quoted from your file with its line number, the match length in octets that made it win, and the group that was chosen for that crawler. That trace is what the old Google tester showed and its replacements mostly do not, and it is the difference between knowing that a URL is blocked and knowing which of your 40 lines you have to change.
Below the verdicts, the findings list covers the file itself: rules that sit outside any group, directives that no crawler reads, patterns that can never match, encoding damage. Everything runs in this tab; a robots.txt is public anyway, but the URL paths you test against it often are not.
How rule matching works
The rules come from RFC 9309, which in 2022 finally standardised what Google had been doing for years. Three points cover almost everything:
- All matching rules compete, order is irrelevant. Every Allow and Disallow in the crawler's group is checked against the URL path. It does not matter which line comes first; robots.txt has no first-match semantics.
- The longest match wins. Among the rules that match, the one whose pattern has the most octets decides.
Disallow: /shop/is 6 octets,Allow: /shop/sale/is 11, so/shop/sale/bootsis allowed no matter where the two lines stand. - A tie goes to Allow. When an Allow and a Disallow match with exactly equal length, the less restrictive rule is used.
Matching is against the path plus query string of the URL, never the scheme or hostname. Rules are anchored at the start of the path: Disallow: /admin matches /admin, /admin/ and /administrator, that last one being a classic accident. The trailing slash is meaningful: Disallow: /admin/ no longer matches /administrator, but it also no longer matches /admin without the slash.
An empty Disallow: matches nothing and therefore allows everything, which makes it the canonical allow-all group. And a rule that does not start with / or * can never match, because every path starts with a slash; the tester flags those instead of quietly ignoring them the way crawlers do.
* and $ in patterns
Two characters carry all the pattern power robots.txt has. * matches any sequence of characters, including none. $ at the end of a pattern anchors it to the end of the path. There is no ^, no character classes, no regex.
| Pattern | Matches | Does not match |
|---|---|---|
/private | /private, /private/, /privates | /a/private |
/private/ | /private/, /private/x | /private, /privates |
/*.pdf$ | /a.pdf, /files/q3.pdf | /a.pdf?dl=1, /a.pdfx |
/*?sort= | /shop?sort=price, /x/y?a=1&sort=z | /sorted/ |
/*/download | /files/download, /a/b/download | /download |
/fish* | exactly what /fish matches | nothing extra: trailing * is redundant |
The $ plus query string interaction deserves its own warning, because it is the one that bites. Disallow: /*.pdf$ reads like "block all PDFs", but a link that arrives as /whitepaper.pdf?utm_source=x sails through: the path being matched includes the query string, and it does not end in .pdf anymore. If the goal is to keep PDFs out regardless of parameters, Disallow: /*.pdf without the anchor is the right rule, at the price of also matching a path that merely contains ".pdf". Wildcard match lengths count the pattern's octets as written, so /*.pdf$ competes with 7.
Which group a crawler follows
Rules live in groups, and a group starts with one or more User-agent lines followed by its rules. A crawler picks the single group whose token matches it most specifically, token length deciding specificity, and follows only that group. Googlebot-Image looks for Googlebot-Image, settles for Googlebot, and only without either falls back to *.
The consequence people trip over: groups do not stack. The moment a bot has its own group, your carefully built * section stops existing for it. We have seen a file with twenty Disallow lines under * and a two-line User-agent: Googlebot group added later "just for the sitemap note", and those two lines were the entirety of what Googlebot obeyed from then on.
Three structural details round out the picture. Consecutive User-agent lines share one rule set, which is how you address five AI crawlers with a single Disallow: /. Two groups naming the same token are merged, per RFC 9309. And rules above the first User-agent line belong to no group at all and are silently dropped, which is why a file that starts with a stray Disallow: /tmp/ blocks nothing; the tester reports that as an error rather than letting it pass.
Percent-encoding and case
Paths are matched byte-wise and case-sensitively. /Admin/ and /admin/ are different strings, and a Disallow for one does not cover the other. Directive names and user-agent tokens, by contrast, are case-insensitive.
Percent-encoding is normalised before matching, so Disallow: /café/ and Disallow: /caf%C3%A9/ mean the same rule, and both match a request for either spelling of the path. The one exception worth knowing: %2F, the encoded slash, is not the same as a literal / in a path, and the comparison keeps them apart. The tester applies the same normalisation to your patterns and your test URLs, so what you see is what a compliant parser computes.
Disallow is not noindex
The most consequential misunderstanding about robots.txt has nothing to do with syntax. Disallow controls crawling: whether a bot may fetch the URL. It says nothing about indexing: whether the URL may appear in search results. Google can and does index URLs it has never fetched, from anchor text and links alone, and shows them as "Indexed, though blocked by robots.txt", usually as a bare URL without a description.
That leads to a trap with a satisfying wrongness to it: blocking a page in robots.txt and putting <meta name="robots" content="noindex"> on it. The noindex would work, but the crawler that would read it is not allowed to fetch the page, so the tag might as well not exist. The page stays in the index, block and all.
The working combinations, by goal:
- Keep a page out of search results: allow crawling and serve noindex (meta tag or
X-Robots-Tagheader), or return 404/410, or require authentication. - Save crawl budget on endless parameter URLs: Disallow is the right tool; you do not care if a faceted URL is technically indexable, you care that Googlebot stops fetching a million of them.
- Keep something confidential: neither. robots.txt is a public file that every curious person reads first precisely because it lists what you consider sensitive. Authentication is the only mechanism that withholds content.
Mistakes that hide in real files
The findings section exists because most robots.txt problems produce no error anywhere, just different crawling than intended. The ones we check for:
- Rules before the first User-agent line. They belong to no group and are dropped. Typically the result of deleting a group header during an edit.
- A UTF-8 BOM at the start. Google strips it, but stricter parsers see
\ufeffUser-agentas an unknown directive, drop the line and orphan the whole first group. Windows editors add the BOM when saving as "UTF-8"; save without it. Noindex:as a directive. Google honoured it unofficially until September 2019 and ended support with an announcement; it has done nothing since. Files still carry it because it kept working in blog posts long after it stopped working in crawlers.- Rules without a leading slash.
Disallow: admin/matches nothing, ever, because every path starts with/. Compliant parsers do not fix it for you. Crawl-delay. Not an error, but worth knowing that Google ignores it and Bing reads it as seconds between requests, so it is a Bing-only throttle.- Typos in directive names.
Dissalowparses as an unknown directive and the line becomes a no-op. Since robots.txt has no error channel, the typo lives forever unless something points at it. - Encoding damage. A
U+FFFDreplacement character in a pattern means the file was saved through the wrong encoding, and that rule can never match a real path again.
Testing AI crawlers next to Googlebot
A modern robots.txt tends to serve two policies at once: normal search crawling stays open, AI training crawlers are shut out. Whether that actually holds is a group-choice question, and it is easy to get wrong in both directions. A GPTBot group with Disallow: / does block OpenAI's training crawler, but if your * group is where the real rules live, remember that GPTBot never reads them once it has its own group. Conversely, blocking * and allowing Googlebot by name shuts out every AI crawler and every other legitimate bot in one line.
The matrix view is built for exactly this check: put / and a couple of real URLs in the list, switch on Googlebot, GPTBot, ClaudeBot and *, and read the four verdicts side by side. The bot row includes the tokens that behave differently than their names suggest: Google-Extended is not a crawler but a control token that Googlebot reads for Gemini training, so blocking it changes AI training use without changing search. ChatGPT-User fetches pages on demand when a ChatGPT user asks, a different token and policy question than GPTBot. If building these groups is the task rather than checking them, the robots.txt generator assembles the file from a dated crawler list.
Online tester vs Search Console and libraries
Google's original robots.txt tester was retired from Search Console in December 2023. What remains there is the robots.txt report, which shows fetch status and parse warnings for your verified properties, but no longer answers "is this URL blocked for this bot" interactively, and it only works for sites you own. Bing's tester still exists inside Bing Webmaster Tools, behind a login and for Bingbot's view.
For bulk or CI use, Google open-sourced the exact C++ parser Googlebot uses (the google/robotstxt repository), and it is the reference we validated this tester's behaviour against: longest match, tie to Allow, group merging and the wildcard semantics all follow it. A local tester like this one sits in the gap between those options: no login, no property verification, any bot token including made-up ones, and a trace for every verdict. What it cannot know is what only the server knows, like whether your CDN serves a different robots.txt to crawlers than to you, so for a final check fetch https://yoursite/robots.txt yourself and paste exactly what came back.
When a rule does not match
How does Google decide which robots.txt rule wins?
By match length: among all Allow and Disallow rules that match the URL path, the one with the most octets in its pattern wins, and if an Allow and a Disallow tie exactly, the Allow wins. RFC 9309 standardised this in 2022 and Google, Bing and the open-source Google parser all implement it. Rule order in the file is irrelevant, which surprises people who expect first-match semantics like in a firewall. So Disallow: /shop/ (6 octets) loses to Allow: /shop/sale/ (11 octets) for any URL under /shop/sale/, wherever the two lines stand. Our tester prints exactly this arithmetic next to every verdict: the winning line, its pattern and its match length.
What do the * and $ wildcards mean in robots.txt?
* matches any sequence of characters including none, and $ at the end of a pattern anchors it to the end of the URL path. Disallow: /*.pdf$ blocks /report.pdf and /files/q3.pdf but not /report.pdf?download=1, because the query string makes the path continue past the $. Without the $, Disallow: /*.pdf also blocks /pdf-guide/ style paths where ".pdf" appears mid-URL. Patterns are implicitly anchored at the start of the path and implicitly open at the end, so a trailing * like /admin/* is redundant; /admin/ already matches everything below it. There is no ^ anchor and no regex syntax beyond these two characters.
Which user-agent group does a crawler follow when several match?
Exactly one: the group with the most specific matching user-agent token, and specificity means the longest token that matches the crawler name. Googlebot-Image follows a Googlebot-Image group if one exists, otherwise a Googlebot group, otherwise the * group. What crawlers never do is combine groups: a bot with its own named group ignores every rule in the * group completely. If several groups name the same token, RFC 9309 merges their rules into one set, but that is the only merging that happens. This is the single most common source of "why is this URL suddenly allowed" surprises, and the tester names the chosen group and its line number in every verdict for that reason.
Does Disallow in robots.txt remove a page from Google?
No. Disallow stops crawling, not indexing. A blocked URL can still be indexed from anchor text and links alone and then shows up as "Indexed, though blocked by robots.txt" in Search Console, usually with no description. To remove a page from the index you need the opposite of a block: the page must be crawlable so Google can read a noindex robots meta tag or an X-Robots-Tag header, or you return a 404/410, or you put the page behind authentication. Blocking a page and adding noindex to it at the same time is self-defeating, because the crawler that would read the noindex is not allowed in.
Does Google support Crawl-delay in robots.txt?
No, Googlebot ignores the line entirely and always has. Bing honours it as the number of seconds to wait between requests. Google's position is that crawl rate is managed automatically, with Search Console offering a report but no manual throttle anymore since the crawl-rate limiter tool was retired in January 2024. So a Crawl-delay: 10 slows Bingbot down and does nothing about the crawler people usually want to slow down. If Googlebot really hammers a site, the supported responses are faster pages, 429/503 responses, or a temporary block, not robots.txt.
Is robots.txt case-sensitive?
The paths are, the directives are not. disallow:, Disallow: and DISALLOW: all parse the same, and user-agent tokens match case-insensitively, so user-agent: googlebot works. But /Admin/ and /admin/ are different paths: Disallow: /admin/ does not block /Admin/panel on a server that serves both. The filename itself is also fixed: crawlers request exactly /robots.txt in lowercase, so a file uploaded as Robots.TXT on a case-sensitive host is a 404 and the whole site is treated as allowed.
Does a Disallow under User-agent: * also apply to GPTBot?
Only if the file has no GPTBot group. A crawler follows its most specific matching group and then stops looking, so the moment you add "User-agent: GPTBot" with any rule at all, GPTBot ignores every line in the * group. A file with a strict * section and a lenient GPTBot section gives GPTBot the lenient rules only. The practical consequence: when you add a named group for a bot, copy the * rules you still want into it. Testing the same URL as * and as GPTBot side by side, which this tester does in one run, makes the difference visible immediately.
What does an empty Disallow line mean in robots.txt?
Disallow: with no value means "nothing is disallowed", so the group allows everything. It is the standard way to write an allow-all file: User-agent: * followed by an empty Disallow. It also has a structural job: a User-agent line with no rule after it does not close the group, so the next User-agent line would merge into it. The empty Disallow is what keeps "User-agent: A" and a following "User-agent: B" apart when A is meant to have no restrictions. It never blocks anything; Disallow: / (with a slash) is the line that blocks the whole site, and the one-character difference has taken sites out of Google before.
How big can a robots.txt file be?
Google enforces a limit of 500 kibibytes (512,000 bytes) and ignores everything after it, and RFC 9309 requires parsers to handle at least that much. Rules that sit beyond the limit simply do not exist for the crawler, with no warning anywhere. Files usually get that big through generated per-URL Disallow lines, often from a plugin listing thousands of faceted-navigation URLs one by one. Wildcards fix that: one Disallow: /*?filter= line replaces thousands of literal ones. For comparison, a typical hand-written robots.txt is under 1 KB.
What happens when robots.txt returns a 404 or a 500?
A 404 (or any 4xx) means "no restrictions": crawlers treat a missing robots.txt as permission to crawl everything, which is fine and very common. Server errors are the dangerous case: on repeated 5xx responses Google treats the file as fully disallowed for the first 12 hours and stops crawling, then falls back to the last cached copy for up to 30 days, and after that either uses no restrictions or keeps the site uncrawled depending on availability. So a misconfigured server that answers /robots.txt with a 500 can quietly stop crawling of the whole site while every page is fine. A redirect is followed for up to five hops; more than that is treated like a 404.