The quick check: open ChatGPT with search on and ask "What does yourdomain.com do?" If it returns real details from your pages, ChatGPT can see you. If it says it can't access the site — or invents an answer — you're blocked. Confirm at the crawler level: curl -A "GPTBot/1.2" -I https://yourdomain.com should return 200.
Ask ChatGPT about your product category and watch who gets cited. If it's never you, the failure lives in exactly one of three places: access (the crawler can't reach you), extraction (it reaches you but sees nothing), or grounding (it sees you but won't cite you). This guide tests all three in under ten minutes — by hand, or in one automated AEO scan.
TL;DR
yourdomain.com do?" A vague, refused, or uncited answer means you aren't readable.GPTBot (training), OAI-SearchBot (the ChatGPT Search index), ChatGPT-User (fetches a link on demand when a user asks).GPTBot does not remove you from ChatGPT Search — that index belongs to OAI-SearchBot.Disallow: /, WAF and bot-fight rules, client-side rendering, and geo-blocks or login walls.Google-Extended governs Gemini training and grounding only. It has no effect on Google Search inclusion or ranking.No tooling required, and nothing to install. Run all three tests — they fail in different ways, and the difference is the diagnosis.
1. ChatGPT, with search enabled. Paste this exactly, swapping in your domain:
What does yourdomain.com do? Cite the pages you used.
Then force a live fetch with a specific URL:
Summarize the pricing page at https://yourdomain.com/pricing in three bullets.
Because that second prompt names a URL, ChatGPT fetches it on demand as ChatGPT-User instead of reading its search index. Useful signal — but a URL-paste that works does not prove OAI-SearchBot has you indexed. Always run the first prompt too.
2. Perplexity. Same prompts, unchanged. Perplexity searches on every query, so it's the cleanest read on whether PerplexityBot has actually indexed you:
What does yourdomain.com do? List your sources.
3. A branded-versus-generic pair. Ask by name, then ask by category:
What is [Your Product] and who is it for?
What are the best tools for [your category]?
What a good result looks like
What a bad result looks like
Every major answer engine announces itself with a distinct user agent, and the split matters: within a single company, one agent feeds model training and a different one feeds the search index you actually want to appear in.
| User agent | Operator | What it does | robots.txt token |
|---|---|---|---|
| GPTBot | OpenAI | Crawls content that may be used to train and improve OpenAI's foundation models | GPTBot |
| OAI-SearchBot | OpenAI | Builds the index that surfaces and links websites in ChatGPT's search features | OAI-SearchBot |
| ChatGPT-User | OpenAI | Fetches a page on demand when a user or Custom GPT asks ChatGPT to visit it — not an automatic crawler | ChatGPT-User |
| ClaudeBot | Anthropic | Collects web content that may contribute to training Anthropic's models | ClaudeBot |
| Claude-SearchBot | Anthropic | Crawls to improve the relevance and accuracy of Claude's search results | Claude-SearchBot |
| Claude-User | Anthropic | Visits sites when an individual user's question to Claude requires it | Claude-User |
| PerplexityBot | Perplexity | Indexes pages so they can be surfaced and linked in Perplexity results; not used for foundation-model training | PerplexityBot |
| Perplexity-User | Perplexity | Visits a page in response to a specific user question; generally ignores robots.txt because a human requested the fetch | Perplexity-User |
| Google-Extended | A control token, not a crawler: governs whether content Google already crawls may be used for Gemini training and grounding | Google-Extended | |
| Googlebot | Google Search's crawler. AI Overviews and AI Mode are served from the Search index, so they follow your Search-level controls, not Google-Extended | Googlebot | |
| Meta-ExternalAgent | Meta | Crawls for use cases such as training AI models and indexing content directly to improve products | meta-externalagent |
| Meta-WebIndexer | Meta | Crawls to improve Meta AI search quality so Meta AI can cite and link your content | meta-webindexer |
| Bingbot | Microsoft | Bing's search crawler. Microsoft Copilot draws on the Bing index; there is no separate Copilot crawler token | bingbot |
| MistralAI-Index | Mistral | Crawls to index content for Mistral's search; explicitly not used for generative AI training | MistralAI-Index |
| MistralAI-User | Mistral | Fetches a page in response to a user's request in Mistral's assistant, and links the source in its answer | MistralAI-User |
| MistralAI-Training | Mistral | Collects web content for datasets used to train Mistral's generative models | MistralAI-Training |
The two most useful facts in that table: GPTBot is training-only, and Google-Extended is not a crawler at all — it's an opt-out switch for Gemini, with zero bearing on whether Google indexes or ranks you.
Drop this at https://yourdomain.com/robots.txt and edit the private paths at the bottom. It allows every search-time and user-initiated agent while opting out of training-only crawlers:
# Answer engines — allow these if you want to be cited
User-agent: OAI-SearchBot
Allow: /
User-agent: ChatGPT-User
Allow: /
User-agent: Claude-SearchBot
Allow: /
User-agent: Claude-User
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Perplexity-User
Allow: /
User-agent: meta-webindexer
Allow: /
User-agent: MistralAI-Index
Allow: /
User-agent: MistralAI-User
Allow: /
# Training-only crawlers — delete these groups if you're happy to be trained on
User-agent: GPTBot
Disallow: /
User-agent: ClaudeBot
Disallow: /
User-agent: Google-Extended
Disallow: /
User-agent: meta-externalagent
Disallow: /
User-agent: MistralAI-Training
Disallow: /
# Everyone else
User-agent: *
Disallow: /admin/
Disallow: /api/
Allow: /
Sitemap: https://yourdomain.com/sitemap.xml
Two things to understand before you paste it:
GPTBot says nothing about OAI-SearchBot, and blocking ClaudeBot says nothing about Claude-SearchBot. That separation is the entire point of the split tokens — use it deliberately.Open https://yourdomain.com/robots.txt and read it top to bottom. Three things to look for:
User-agent: * with Disallow: /. The single most common cause, and almost always accidental — a staging config that shipped, a framework default, or a "coming soon" file nobody deleted. It blocks every well-behaved crawler in the table above.Disallow: /. Usually inherited from a "privacy-focused" robots.txt template copied in 2024, when the prevailing advice was to block anything with Bot in the name.Also confirm the file returns 200 with a plain-text content type. A single-page app that serves its shell at every path will hand crawlers an HTML page where robots.txt should be — which parses as no rules and no Sitemap: line:
curl -sI https://yourdomain.com/robots.txt | head -3
The fix: delete the block, or scope it to paths you genuinely want private. Blocking AI crawlers is a legitimate choice — but it should be a decision, not an inherited accident.
robots.txt is only half of access. Cloudflare, Vercel's firewall, AWS WAF, Fastly, and most bot-protection products ship one-click "block AI bots" controls — and some are enabled by default.
Test every crawler in one pass:
for ua in "GPTBot/1.2" "OAI-SearchBot/1.0" "ClaudeBot/1.0" "Claude-SearchBot/1.0" "PerplexityBot/1.0"; do
printf '%-22s %s\n' "$ua" "$(curl -s -o /dev/null -w '%{http_code}' -A "$ua" https://yourdomain.com)"
done
Anything that isn't 200 — or a redirect to your canonical URL — is a block. 403 is an outright deny, 429 is rate limiting, and a 200 that's only a few hundred bytes of "Checking your browser…" is a JavaScript challenge, which crawlers cannot solve.
On Cloudflare specifically, three separate settings can each cause this, and they live in different places:
cf.client.bot or user-agent string matches often predate the search-time crawlers and catch them by accident.The fix: allowlist by verified-bot category rather than by user-agent string. A UA string can be spoofed by anyone; verified-bot matching checks the request against the vendor's published IP ranges, so the real crawler gets in without opening a hole for impersonators. Then re-run the loop above and confirm 200 across the board.
Most AI crawlers do not execute JavaScript. They take whatever HTML your server returns and parse it. If your site is client-side rendered, that HTML is often an empty <div id="root"></div> and a script tag.
Test the raw response — no browser, no rendering:
curl -s https://yourdomain.com | grep -i "your headline text"
No match means no answer engine has ever read that sentence. Two more worth running:
# How much content is actually in the HTML? A few KB or less is a shell.
curl -s https://yourdomain.com | wc -c
# Do the title and description survive without JS?
curl -s https://yourdomain.com | grep -iE "<title>|<meta name=\"description\""
This failure hides behind good Google rankings, because Googlebot renders JavaScript and most AI crawlers don't. You can sit on page one of Google and be completely invisible to ChatGPT at the same time.
The fix: server-side render or statically generate every page you want cited. Next.js, Astro, SvelteKit, and Remix all do this by default — but client-only useEffect data fetching, auth-gated shells, and "loading…" skeletons still leak into marketing pages constantly. Pure-SPA builders are the worst case: why AI engines can't find your Lovable site walks through the prerendering fix for that specific stack.
Almost every "ChatGPT can't see my site" case is one of these four. They produce different symptoms, so the symptom tells you which one you have.
| Blocker | Symptom | Where to look | Fix |
|---|---|---|---|
| robots.txt disallow-all | The engine says it can't access the site; server logs show zero crawler hits | /robots.txt | Scope the disallow to private paths, or name only the agents you mean to block |
| WAF / bot-fight rules | A crawler user agent gets 403, 429, or a challenge page while your browser loads fine | Cloudflare Security → Bots, Vercel Firewall, AWS WAF | Set verified bots to Allow; turn off blanket AI-bot toggles |
| Client-side rendering | The engine answers with vague filler, or knows only your page title | Raw HTML from curl — a few KB means a shell | Server-render or prerender every public page |
| Geo-blocks and login walls | Works for you, fails for the engine, and robots.txt and the WAF are both clean | Country rules, datacenter-ASN blocks, middleware redirects to /login | Serve the full public page to crawler regions with no session |
The last row is the one people miss, so it's worth spelling out.
Geo-blocking. Crawlers fetch from their vendor's own infrastructure, largely US datacenter ranges. If you geo-restrict to one country, block datacenter ASNs wholesale, or serve a consent interstitial to EU IPs before any content renders, the crawler gets the interstitial and nothing else. Test with curl from a VPS in another region, or check your firewall's country and ASN rules against the crawler IP ranges each vendor publishes.
Login walls and soft paywalls. Middleware that redirects unauthenticated requests to /login redirects crawlers too — and if the matcher is broad, it can swallow your marketing pages along with your app. Same story for content that exists in the HTML but sits under a "sign up to read" overlay: the crawler is served text your visitors can't see, which is exactly the mismatch engines discount.
One more, less dramatic: redirect chains. http → https → www → trailing slash is four hops, and a canonical tag pointing at a URL that 404s is worse. Crawlers give up sooner than browsers do.
All four are what an AEO scanner automates — the same probes, run per engine, so you see which specific bot gets stopped where.
Access gets you read. Structure gets you quoted. Answer engines lift passages, so audit your key pages for:
The full playbook is in our AEO explainer, and the structural overlap with classic search is covered in SEO vs AEO.
Everything above can regress with one robots.txt edit, one WAF update, or one framework migration — and nothing will alert you. There is no Search Console for ChatGPT.
CheckVibe's AEO scanner runs all of these tests automatically:
Run a free scan and you'll know in about a minute whether the AI engines your customers use can actually see you.
No. GPTBot is OpenAI's training crawler — blocking it keeps your content out of future model training and nothing else. ChatGPT's search feature is served by a different agent, OAI-SearchBot, with on-demand fetches handled by ChatGPT-User. Leave those two allowed and you can still be surfaced and linked inside ChatGPT answers. The real cost of blocking GPTBot is subtler: the model carries no baked-in knowledge of you for the times search doesn't fire.
Four causes, in rough order of likelihood: robots.txt disallows the fetching agent; your WAF or Cloudflare Bot Fight Mode returns a 403 or a JavaScript challenge to non-browser traffic; the page sits behind a login or is geo-restricted away from the crawler's datacenter IPs; or the URL lands in a redirect loop. Reproduce it in one line — curl -A "OAI-SearchBot/1.0" -I https://yourdomain.com — and whatever status code comes back is your answer.
Usually, yes. Most AI crawlers fetch your HTML and parse it without running scripts, so anything injected client-side simply isn't there for them. Googlebot does render JavaScript, which is why a site can rank well on Google and stay invisible to ChatGPT and Perplexity. Check it with curl -s https://yourdomain.com | grep "your headline" — if your text isn't in the raw response, no answer engine has ever read it.
Check your server logs for the user agents GPTBot, OAI-SearchBot, or ChatGPT-User with OpenAI's published IP ranges. No hits in weeks usually means you're blocked at robots.txt or WAF level — or your site has too little linked, extractable content to attract crawls.
Because Googlebot renders JavaScript and is whitelisted by every WAF, while AI crawlers mostly don't render JS and are frequently blocked by default bot rules. Your site can be page one on Google and a blank 403 to GPTBot simultaneously. Test each engine separately.
If you sell content itself (journalism, research, courses), blocking training crawlers can be rational. For products and services, blocking answer engines mostly means your competitors get recommended instead of you. You can also split the difference: allow search-time crawlers like OAI-SearchBot while blocking training-time crawlers like GPTBot.
llms.txt is an emerging convention — a markdown file at /llms.txt that gives language models a curated index of your site's most important content. It's cheap to add and several tools already read it. It complements rather than replaces robots.txt: robots.txt controls access, llms.txt aids understanding.
Search-time crawlers (OAI-SearchBot, PerplexityBot, Claude-SearchBot) re-fetch popular pages within days, so an access fix can show up that fast. Training-data inclusion moves on model-release timescales — months. Re-run the ChatGPT and Perplexity prompts about a week after you deploy the fix; if the answer is still wrong, you have a second blocker, not a patience problem.
Paste your URL and get a security report in 30 seconds — 100+ automated checks with AI-ready fix prompts.
Related articles
AEO for vibe-coded apps means making AI-generated sites readable and citable. Why they are disproportionately invisible — and the exact fixes.
Client-only SPAs are invisible to AI crawlers. The exact steps to make a vibe-coded React app rank in ChatGPT, Perplexity and Claude.
ChatGPT, Claude and Perplexity can't read most Lovable sites — they ship client-rendered React. The 60-second diagnosis, then the exact fixes.