"Block GPTBot" is one of the most common requests site owners make about AI. It is also often the wrong request, because OpenAI runs several bots. They do different jobs, follow different rules and come from different IP ranges. This article lists them, links the official files, and shows how to verify each one so your rules hit what you meant.
Everything below comes from OpenAI's own crawler documentation and the JSON files it links, checked on 12 November 2026. OpenAI updates both, so treat the official page as the source of truth.
The four OpenAI bots at a glance
| User agent | What it does | Robots.txt | Official IP list |
|---|---|---|---|
GPTBot | Crawls content that may be used to train OpenAI's generative AI foundation models | Respected; disallowing it is the documented training opt-out | openai.com/gptbot.json |
OAI-SearchBot | Finds and indexes sites for ChatGPT's search features | Respected; controls search visibility | openai.com/searchbot.json |
ChatGPT-User | Fetches a page when a ChatGPT user, a custom GPT or a GPT Action asks for it | "robots.txt rules may not apply" (user-initiated) | openai.com/chatgpt-user.json |
OAI-AdsBot | Checks landing pages submitted as ads on ChatGPT | Not stated by OpenAI | openai.com/adsbot.json |
A few points from OpenAI's documentation are worth repeating, because they are often missed:
- Training and search are separate. You can disallow
GPTBot(no training) and still allowOAI-SearchBot(appear in ChatGPT search). OpenAI notes that robots.txt changes for OAI-SearchBot can take about 24 hours to apply. - ChatGPT-User is not a crawler. It does not crawl the web on its own. It visits a page because a person asked ChatGPT about it. That is why OpenAI says robots.txt rules may not apply to it.
- OAI-AdsBot only visits pages submitted as ads, and OpenAI says the data it collects is not used to train foundation models. Many third-party bot lists don't include it yet.
What the IP files look like
All four files use the same format Google uses for its crawlers: a generation timestamp and a list of CIDR prefixes.
{
"creationTime": "2026-09-22T00:00:00.000000",
"prefixes": [
{ "ipv4Prefix": "192.0.2.0/28" },
{ "ipv4Prefix": "198.51.100.64/28" }
]
}The prefixes above are documentation placeholders. Always read the live file. When we checked, gptbot.json held 18 IPv4 prefixes, searchbot.json 39 and chatgpt-user.json 237, and the creationTime values ranged from January to November 2026. Two lessons:
- ChatGPT-User has by far the most addresses, because it handles live requests from many users.
- The files change on different schedules. One refresh a month is not enough for the busiest file.
Writing robots.txt rules that match your intent
Robots.txt is still the first tool, because OpenAI documents it as the way to opt out. A common setup is "no training, yes search":
User-agent: GPTBot
Disallow: /
User-agent: OAI-SearchBot
Allow: /To keep OpenAI out completely, disallow both crawlers. Be aware that user-triggered ChatGPT-User fetches may still happen, as OpenAI states.
Robots.txt has one weakness: it works on the honour system, and it only identifies bots by the user agent they send. That is fine for the real GPTBot, which follows it. It does nothing about a scraper that borrows the GPTBot name, or about ChatGPT-User. For those you need the IP.
Verifying a request claims to be OpenAI
The rule is simple. If the user agent claims an OpenAI bot, the source IP must be inside that bot's published list. If it isn't, the request is not from that OpenAI bot, whatever the header says.
Here is an Express middleware that tags each request with the verified OpenAI bot, if any. It loads the four lists at startup and refreshes them every six hours:
import express from 'express';
import { BlockList, isIPv6 } from 'node:net';
const FILES = {
GPTBot: 'https://openai.com/gptbot.json',
'OAI-SearchBot': 'https://openai.com/searchbot.json',
'ChatGPT-User': 'https://openai.com/chatgpt-user.json',
'OAI-AdsBot': 'https://openai.com/adsbot.json'
};
let lists = {};
async function loadLists() {
const next = {};
for (const [bot, url] of Object.entries(FILES)) {
const res = await fetch(url, { signal: AbortSignal.timeout(10000) });
if (!res.ok) throw new Error(`${bot} list: HTTP ${res.status}`);
const block = new BlockList();
for (const p of (await res.json()).prefixes || []) {
const cidr = p.ipv4Prefix || p.ipv6Prefix;
if (!cidr) continue;
const [addr, bits] = cidr.split('/');
block.addSubnet(addr, Number(bits), p.ipv6Prefix ? 'ipv6' : 'ipv4');
}
next[bot] = block;
}
lists = next;
}
function openAiBotFor(ip) {
const type = isIPv6(ip) ? 'ipv6' : 'ipv4';
return Object.keys(lists).find((bot) => lists[bot].check(ip, type)) || null;
}
const app = express();
app.set('trust proxy', 1); // only if you are behind exactly one proxy you control
app.use((req, res, next) => {
const claimed = Object.keys(FILES).find((bot) => (req.get('user-agent') || '').includes(bot));
const verified = openAiBotFor(req.ip);
req.openai = { claimed, verified };
if (claimed && verified !== claimed) {
return res.status(403).send('Unverified crawler');
}
next();
});
await loadLists();
setInterval(() => loadLists().catch((e) => console.error(e.message)), 6 * 3600 * 1000);Get the client IP right before you trust any of this. Behind a CDN or load balancer, req.ip is only correct if trust proxy matches your setup exactly. Otherwise an attacker can put any address they like in X-Forwarded-For.
The middleware rejects impostors and leaves real OpenAI bots and normal visitors alone. Swap the 403 for whatever policy you want: a lower rate limit, a log entry or a header for your cache.
Doing it with one API call
If you would rather not maintain four downloads, refresh jobs and failure alerts for OpenAI alone, plus the same again for every other AI company, the IPAPI.GR lookup API does it for you. With a Pro key the response includes risk.is_ai, built from published lists like OpenAI's:
curl "https://fast.ipapi.gr/api/lookup/203.0.113.50?key=YOUR_API_KEY"{
"ip": "203.0.113.50",
"country": "United States",
"country_code": "US",
"isp": "Example Network",
"organization": "Example Network",
"asn": "64500",
"risk": { "is_ai": true, "is_crawler": false, "is_scanner": false }
}is_ai tells you the address belongs to published AI infrastructure. It does not say which bot, so keep the user agent check to tell GPTBot from ChatGPT-User. An address can also be both is_ai and is_crawler, for example when an operator uses the same infrastructure for AI and classic search crawling. All fields are described in the API docs, and plan limits are on the pricing page.
Common mistakes
- Copying IP ranges from a blog post. Including this one. Ranges change, so always fetch the official file.
- Using one list for all OpenAI traffic. GPTBot's ranges do not cover ChatGPT-User. A request from ChatGPT-User's ranges with a GPTBot user agent is suspicious.
- Blocking ChatGPT-User by accident. If you want people to be able to ask ChatGPT about your page, don't block its user-triggered fetcher just because you disallowed training.
- Treating "not in the list" as "human". It only means "not an OpenAI bot". It could be any other crawler, a scanner or a person.
FAQ
Does blocking GPTBot remove my site from ChatGPT search?
No. Search uses OAI-SearchBot, which has its own robots.txt group. Disallow GPTBot to opt out of training and allow OAI-SearchBot to stay in search.
Are ChatGPT-User requests made by a person?
They're triggered by a person's request to ChatGPT, a custom GPT or a GPT Action, but the HTTP request comes from OpenAI's infrastructure and is listed in chatgpt-user.json.
Why do I see GPTBot requests from IPs that aren't in gptbot.json?
Either another OpenAI bot is sending a misleading user agent (unlikely), or, much more often, someone else is using the GPTBot name. Treat unverified "GPTBot" traffic like any other unknown client.
Is there an IPv6 list?
When we checked, gptbot.json contained IPv4 prefixes only. If IPv6 entries appear, they will use ipv6Prefix, and the code above already handles them.
Summary
OpenAI publishes four bots with four IP files: GPTBot for training, OAI-SearchBot for search, ChatGPT-User for user requests and OAI-AdsBot for ad checks. Use robots.txt to express your policy, and use the published IPs to enforce it and catch impostors. For the general approach across every AI company, read How to verify AI crawler IP addresses. For Anthropic and Perplexity, see ClaudeBot and PerplexityBot IP addresses.