Table of contents
- Quick summary
- A subpath robots.txt is not a robots.txt
- Where baseUrl puts your file
- Write the rules into static/robots.txt
- Deploying under a repository path
- Build the file from siteConfig instead of typing your domain
- The Docusaurus project's own site names no crawler
- Read it back the way a crawler would
- Where AIScan fits, and where it doesn't
- Push it live, then re-run the scan
Docusaurus gives you somewhere to put a robots.txt in about ten seconds. Making sure a crawler ever reads it is the harder half, because the most common Docusaurus deployment shape files the rules at a URL where they carry no force at all.
That gap bites harder here than anywhere else. When we covered llms.txt on Docusaurus, a file under a repository path was still valid, because the llms.txt specification allows one at any subpath. The Robots Exclusion Protocol allows nothing of the kind.
Quick summary
| Step | What you do | Where | Time |
|---|---|---|---|
| 1 | See which AI rules your site already serves | npx aiscan-cli yoursite.com, read D1 and B2 | 2 min |
| 2 | Write named crawler groups | static/robots.txt | 5 min |
| 3 | Check where baseUrl will publish it | docusaurus.config.js | 2 min |
| 4 | Move to a custom domain if you are on a project path | Host settings | 15 min |
| 5 | Read the live URL back | curl at the origin root | 1 min |
The one thing to get right: the rules have to answer at https://yourdomain.com/robots.txt, not at https://yourdomain.com/your-project/robots.txt.
A subpath robots.txt is not a robots.txt
RFC 9309, the standard that defines the protocol, says verbatim:
The rules MUST be accessible in a file named "/robots.txt" (all lowercase) in the top-level path of the service.
The document then gives the only URI form a crawler will construct: scheme:[//authority]/robots.txt. There is no second location and no fallback. A crawler asks the authority for /robots.txt and stops.
The consequence is unforgiving. If your rules answer one directory down, a compliant crawler never sees them, and RFC 9309 is equally clear about what happens then: if no group matches a crawler and no * group exists, "or no groups are present at all, no rules apply." Your carefully written allow and deny lines do not fail loudly. They simply do not exist, and every bot proceeds as though you had said nothing.
Where baseUrl puts your file
Docusaurus copies the static folder wholesale. In its own words, from the static assets documentation:
Every file you put into that directory will be copied into the root of the generated build folder with the directory hierarchy preserved.
The build root is then served under baseUrl, and the same page spells out both cases:
baseUrl in your config | static/robots.txt answers at | Crawler reads it? |
|---|---|---|
'/' | https://yoursite.com/robots.txt | Yes |
'/my-project/' | https://yoursite.com/my-project/robots.txt | No |
According to the deployment guide, a site published at https://my-org.com/my-project/ needs url set to https://my-org.com/ and baseUrl set to /my-project/. That configuration is correct, documented, and the reason your rules are invisible.
Write the rules into static/robots.txt
Create the file at static/robots.txt in your project root. Other source folders added through staticDirectories behave identically.
User-agent: OAI-SearchBot
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: GPTBot
Disallow: /
User-agent: ClaudeBot
Disallow: /
User-agent: Google-Extended
Disallow: /
Sitemap: https://yoursite.com/sitemap.xml
Two decisions are packed into that block. Each crawler gets a named group of its own, because a scanner cannot distinguish a deliberate allow from an absent rule when all it finds is User-agent: *. And the retrieval bots sit apart from the training bots, so you can change your mind about model training without also removing yourself from the answers those tools cite. Our verified AI crawler user-agent list has every current token, and the crawler category breakdown explains which bot belongs in which group before you commit.
Deploying under a repository path
If your docs live at org.github.io/project/, no edit to static/robots.txt can fix this, because the origin root belongs to the account rather than to your repository. Verified on 6 September 2026, facebook.github.io/robots.txt and microsoft.github.io/robots.txt both return 404: even those accounts publish no rules at the only address that counts.
You have three honest options.
| Situation | What to do |
|---|---|
| Docs on a project path you control the domain for | Attach a custom domain, set baseUrl: '/', redeploy |
| Docs on Netlify, Vercel, Render or Cloudflare Pages | Already at the root; static/robots.txt works as written |
Docs genuinely stuck on org.github.io/project/ | Publish rules on the user or organisation site instead, and accept they cover every repository |
A user or organisation Pages site is served at the root, so a robots.txt there is read. It also governs everything else that account publishes, which is a real trade rather than a workaround.
Build the file from siteConfig instead of typing your domain
Hard-coding the Sitemap: line means it drifts the first time the domain changes. Docusaurus exposes a plugin lifecycle hook that runs once the build is finished, documented as postBuild(props), with siteConfig, baseUrl and outDir on the props object:
import fs from 'fs';
import path from 'path';
export default function robotsPlugin() {
return {
name: 'robots-txt',
async postBuild({siteConfig, baseUrl, outDir}) {
if (baseUrl !== '/') {
throw new Error(`robots.txt is unreachable under baseUrl "${baseUrl}"`);
}
const rules = `User-agent: OAI-SearchBot\nAllow: /\n\nUser-agent: GPTBot\nDisallow: /\n\nSitemap: ${siteConfig.url}/sitemap.xml\n`;
fs.writeFileSync(path.join(outDir, 'robots.txt'), rules);
},
};
}
The thrown error is the useful part. It turns the silent subpath problem into a failed build.
The Docusaurus project's own site names no crawler
Fetched from docusaurus.io/robots.txt on 6 September 2026, the file returns 200 and text/plain and runs to twenty lines, every one of them a comment: the Content Signals licence preamble and nothing else. Zero User-agent lines, zero Allow or Disallow rules, no Sitemap line. Under the rule quoted earlier, no groups present means no rules apply.
The file exists, it returns 200, and a status-code check calls it healthy while it says nothing about AI crawlers.
Read it back the way a crawler would
Start with the scan, because it answers the question in one command and reads both halves of it:
npx aiscan-cli yoursite.com
Read D1 for whether a parseable robots.txt answers at all, and B2 for whether it names AI crawlers explicitly. B2 is what fails when the file exists but carries only a * group, and it is what fails when baseUrl hid the file. You can also paste the URL at aiscan.site, free and without an account.
Prefer to check by hand? Two commands finish it:
curl -s -o /dev/null -w '%{http_code} %{content_type}\n' https://yoursite.com/robots.txt
curl -s https://yoursite.com/robots.txt | grep -iE 'GPTBot|SearchBot|Perplexity|Sitemap'
The first must print 200 text/plain. The second must print your named groups. If the first prints 404 while the same file answers under your project path, baseUrl is the cause and no amount of editing the file will change it.
Where AIScan fits, and where it doesn't
AIScan grades what your site returns to an ordinary fetch: whether the file is there, whether it parses, whether it names AI crawlers. It cannot tell you whether a crawler obeyed the rules, and the protocol itself notes these rules "are not a form of access authorization." A Disallow line is a request. It is not a lock, and anything you need genuinely restricted belongs behind authentication.
Our own scanner also asks the origin root only, which is why a Docusaurus site on a project path shows a bare HTTP 404 in the evidence field rather than "your file is one directory too deep." That is a known limit on our side, not a verdict on your file.
Push it live, then re-run the scan
Commit static/robots.txt, deploy, and run npx aiscan-cli yoursite.com once more to confirm D1 and B2 both pass. The bot access checks page explains what each one grades, what belongs in robots.txt against llms.txt and sitemap.xml settles which file carries which job, and the rest of the platform walkthroughs are indexed at aiscan.site/guides. If a WordPress blog sits alongside your docs, ThinkRank manages robots.txt, robots meta, schema and llms.txt there from one plugin, which is the shorter path than reconciling three that each want to own the same virtual file.
Frequently asked questions
My robots.txt is in static/ but the live URL returns 404. What went wrong?
Your baseUrl is not '/'. Docusaurus copies static/ to the build root and serves the build root under baseUrl, so on a site configured with baseUrl: '/my-project/' the file answers at /my-project/robots.txt and the origin root has nothing. The file is fine; the address is wrong. Either move the site to a custom domain with baseUrl: '/', or accept that crawlers will not read those rules.
AIScan reports B2 failing even though my robots.txt is live and returns 200. Why?
B2 grades whether you name AI crawlers explicitly, not whether a file exists. A robots.txt containing only a User-agent: * group passes D1 and fails B2, because a scanner cannot tell a deliberate allow from a rule you never wrote. Add a named group for each crawler you have an opinion about, then re-scan.
I moved my docs to GitHub Pages and my crawler rules stopped being obeyed. What changed?
A GitHub Pages project site is served under a repository path, which forces baseUrl to /<project>/. RFC 9309 requires the rules at the top-level path of the service, so a file one directory down is not read at all. Nothing about your file changed; its URL did.
Where exactly does robots.txt go in a Docusaurus project?
At static/robots.txt, in the project root next to docusaurus.config.js. Docusaurus copies every file in that folder into the root of the build output with the directory hierarchy preserved, so the file needs no front matter, no extension change and no registration anywhere.
Does Docusaurus generate a robots.txt for me?
There is no robots.txt setting in Docusaurus, and the documented route is the static folder. If you want the file built rather than hand-written, a small plugin using the postBuild lifecycle hook can write it into outDir with the domain pulled from siteConfig.url.
Can I keep robots.txt somewhere other than static/?
Yes. The staticDirectories option in docusaurus.config.js accepts a list of source folders, so setting staticDirectories: ['public', 'static'] lets you keep the file in public/ instead. The copy behaviour and the resulting URL are identical either way.
My Sitemap: line points at the old domain after a rename. How do I stop that recurring?
Stop hard-coding it. Write robots.txt from a postBuild hook and interpolate siteConfig.url into the Sitemap line, so the value tracks whatever the config says. Adding a check that throws when baseUrl is not '/' turns the silent subpath failure into a failed build at the same time.
Should I block GPTBot and ClaudeBot on a documentation site?
That is a judgement call, and the two halves are separable. Training crawlers such as GPTBot, ClaudeBot and Google-Extended collect content for model training. Retrieval crawlers such as OAI-SearchBot and PerplexityBot fetch pages to answer questions and cite sources. Blocking the second group removes your docs from answers that would otherwise link to you.
Related guides
Gate AI readiness in CI so a regression fails the build
A green pipeline is supposed to mean the site is fine. On an AI readiness check it often means something narrower: that the gate could not tell a file from a phantom. This step, which appears in a…
Stealth Crawling vs User-Driven Fetching in 2026: What 75 Sites Actually Do
On 4 August 2025 Cloudflare removed Perplexity from its verified bot list and published the evidence. Perplexity's answer was that fetching a page because a person asked for it is not the same act as…
The complete AI readiness setup for Wix in 2026
Every other platform in this series asks you to create something. Wix has already created it. Before you open a single panel, a Wix site is serving a robots.txt, a sitemap index, serverrendered HTML…
How to declare allow/deny rules for named AI crawlers in robots.txt on Wix
Wix writes your robots.txt for you. Fetched on 7 September 2026, the file at www.wix.com/robots.txt ran to 90 nonempty lines: one Useragent: group, 87 Disallow rules, and a single Sitemap: line at…
