Site Files Checker
Reads the files a site publishes for crawlers, SEO tools and AI agents (robots.txt, its sitemaps, llms.txt, llms-full.txt, security.txt and ai.txt) and explains each one in plain words: present or missing, parse errors and warnings, robots.txt groups and rules with a URL tester, which known AI crawlers are allowed, sitemap URL counts and families, sitemap URLs that robots.txt blocks, llms.txt structure and security.txt required fields and expiry. A checker for site owners and SEOs: it reads only files any visitor can open.
POST https://YOUR_API_HOST/v1/site-files
Credits and caching
- Success billing. 2 credits per site checked (a site that cannot be reached is free). You are charged only when the lookup finds something; a not-found result is free.
- Results are cached per account for 0 days. Repeating the same lookup in that window is free and returns
cache_hit: true. - Invalid input, rate limits and errors are never charged.
- Read the billing rules for the full picture.
Request
Send a JSON body with Authorization: Bearer <key>. The body can be up to 64 KB.
| Field | Type | Required | Notes |
|---|---|---|---|
url | string | no | Up to 2048 characters. |
domain | string | no | Up to 253 characters. |
test_url | string | no | A URL or a path such as /private/page to test against robots.txt Up to 2048 characters. |
user_agent | string | no | The crawler name for the URL tester and the sitemap cross-check. Default: * (any crawler) Pattern ^[\x21-\x7e ]+$. Up to 200 characters. |
Example request
curl -X POST https://YOUR_API_HOST/v1/site-files \
-H "Authorization: Bearer $LOOKVALID_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain":"cloudflare.com","test_url":"/cdn-cgi/trace","user_agent":"GPTBot"}'
const response = await fetch("https://YOUR_API_HOST/v1/site-files", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LOOKVALID_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"domain": "cloudflare.com",
"test_url": "/cdn-cgi/trace",
"user_agent": "GPTBot"
}),
});
const result = await response.json();
if (!response.ok) throw new Error(`${result.error.code}: ${result.error.fix}`);
console.log(result.found, result.data, result.credits_charged);
import os
import requests
response = requests.post(
"https://YOUR_API_HOST/v1/site-files",
headers={"Authorization": f"Bearer {os.environ['LOOKVALID_API_KEY']}"},
json={
"domain": "cloudflare.com",
"test_url": "/cdn-cgi/trace",
"user_agent": "GPTBot",
},
timeout=30,
)
result = response.json()
if not response.ok:
raise RuntimeError(f"{result['error']['code']}: {result['error']['fix']}")
print(result["found"], result["data"], result["credits_charged"])
Response
The status is 200 whether or not anything was found. Check found. Every response also carries the X-Request-Id, X-Credits-Charged, X-Credits-Remaining and X-RateLimit-* headers.
Envelope
| Field | Type | Notes |
|---|---|---|
request_id | string | - |
product | "site-files" | - |
found | boolean | False means the lookup ran and found nothing; it is free. |
reason | string or null | Why nothing was found; null when found. |
sources | array of string | Where the data came from, including any attribution the licence requires. |
credits_charged | integer | 0 for a cache hit, a not-found result or an error. |
credits_remaining | integer | - |
cache_hit | boolean | True when the account already paid for this lookup within the cache window. |
cache | object | - |
The data object
Present when found is true, otherwise null.
| Field | Type | Notes |
|---|---|---|
site | string | The origin that was checked |
checked_at | string | - |
overall | object | - |
overall.summary | string | - |
overall.files_present | integer | - |
overall.errors | integer | - |
overall.warnings | integer | - |
robots | object | - |
robots.file | string | The file name, such as robots.txt |
robots.url | string | The address that was read, after redirects |
robots.status | string | present: a file was served; missing: the site has no such file; error: the answer could not be used One of present, missing, error. |
robots.http_status | integer or null | - |
robots.bytes | integer or null | - |
robots.content_type | string or null | - |
robots.summary | string | One plain sentence on what this file is doing for the site |
robots.findings | array of object | - |
robots.findings[].severity | string | error: the file is broken or ignored; warning: likely a mistake or a risk; info: good to know One of error, warning, info. |
robots.findings[].message | string | What was found and what it means, in plain words |
robots.findings[].line | integer or null | The line of the file the finding is about, when there is one |
robots.access | string | How crawlers treat the site given what robots.txt returned: follow its rules, treat everything as allowed, treat everything as blocked for now, or unknown One of rules, allow_all, disallow_all_temporarily, unknown. |
robots.groups | array of object | - |
robots.groups[].agents | array of string | - |
robots.groups[].rules | array of object | - |
robots.groups[].rules[].type | string | One of allow, disallow. |
robots.groups[].rules[].pattern | string | - |
robots.groups[].rules[].line | integer | - |
robots.groups[].rules_truncated | boolean | - |
robots.groups[].crawl_delay_seconds | number or null | - |
robots.groups[].content_signals | object or null | The Content-Signal preferences for AI services, when the group sets them |
robots.groups[].content_signals.search | string or null | - |
robots.groups[].content_signals.ai_input | string or null | - |
robots.groups[].content_signals.ai_train | string or null | - |
robots.groups[].content_signals.line | integer | - |
robots.groups[].line | integer | - |
robots.groups[].explanation | string | - |
robots.groups_truncated | boolean | - |
robots.rule_count | integer | - |
robots.sitemaps_listed | array of string | - |
sitemaps | object | - |
sitemaps.summary | string | - |
sitemaps.files | array of object | - |
sitemaps.files[].file | string | The file name, such as robots.txt |
sitemaps.files[].url | string | The address that was read, after redirects |
sitemaps.files[].status | string | present: a file was served; missing: the site has no such file; error: the answer could not be used One of present, missing, error. |
sitemaps.files[].http_status | integer or null | - |
sitemaps.files[].bytes | integer or null | - |
sitemaps.files[].content_type | string or null | - |
sitemaps.files[].summary | string | One plain sentence on what this file is doing for the site |
sitemaps.files[].findings | array of object | - |
sitemaps.files[].findings[].severity | string | error: the file is broken or ignored; warning: likely a mistake or a risk; info: good to know One of error, warning, info. |
sitemaps.files[].findings[].message | string | What was found and what it means, in plain words |
sitemaps.files[].findings[].line | integer or null | The line of the file the finding is about, when there is one |
sitemaps.files[].kind | string or null | - |
sitemaps.files[].entry_count | integer or null | URLs in a sitemap, or sitemaps in an index |
sitemaps.files[].listed_in_robots | boolean | - |
sitemaps.files[].found_in | string or null | The sitemap index this file was found through |
sitemaps.files[].lastmod_count | integer or null | - |
sitemaps.files[].extensions | array of string | - |
sitemaps.total_urls | integer | URLs in every sitemap that was read |
sitemaps.complete | boolean | False when some sitemaps were not read, so total_urls is a lower bound |
sitemaps.families | array of object | - |
sitemaps.families[].prefix | string | - |
sitemaps.families[].urls | integer | - |
sitemaps.families[].example | string | - |
sitemaps.families_sampled | boolean | True when the families count only the first URLs of large sitemaps |
sitemaps.blocked_by_robots | object or null | - |
sitemaps.blocked_by_robots.user_agent | string | - |
sitemaps.blocked_by_robots.checked | integer | - |
sitemaps.blocked_by_robots.blocked | integer | - |
sitemaps.blocked_by_robots.examples | array of object | - |
sitemaps.blocked_by_robots.examples[].url | string | - |
sitemaps.blocked_by_robots.examples[].rule | string | - |
sitemaps.blocked_by_robots.explanation | string | - |
sitemaps.findings | array of object | - |
sitemaps.findings[].severity | string | error: the file is broken or ignored; warning: likely a mistake or a risk; info: good to know One of error, warning, info. |
sitemaps.findings[].message | string | What was found and what it means, in plain words |
sitemaps.findings[].line | integer or null | The line of the file the finding is about, when there is one |
llms_txt | object | - |
llms_txt.file | string | The file name, such as robots.txt |
llms_txt.url | string | The address that was read, after redirects |
llms_txt.status | string | present: a file was served; missing: the site has no such file; error: the answer could not be used One of present, missing, error. |
llms_txt.http_status | integer or null | - |
llms_txt.bytes | integer or null | - |
llms_txt.content_type | string or null | - |
llms_txt.summary | string | One plain sentence on what this file is doing for the site |
llms_txt.findings | array of object | - |
llms_txt.findings[].severity | string | error: the file is broken or ignored; warning: likely a mistake or a risk; info: good to know One of error, warning, info. |
llms_txt.findings[].message | string | What was found and what it means, in plain words |
llms_txt.findings[].line | integer or null | The line of the file the finding is about, when there is one |
llms_txt.title | string or null | - |
llms_txt.has_summary | boolean | - |
llms_txt.sections | array of object | - |
llms_txt.sections[].heading | string | - |
llms_txt.sections[].links | integer | - |
llms_txt.link_count | integer | - |
llms_full_txt | object | - |
llms_full_txt.file | string | The file name, such as robots.txt |
llms_full_txt.url | string | The address that was read, after redirects |
llms_full_txt.status | string | present: a file was served; missing: the site has no such file; error: the answer could not be used One of present, missing, error. |
llms_full_txt.http_status | integer or null | - |
llms_full_txt.bytes | integer or null | - |
llms_full_txt.content_type | string or null | - |
llms_full_txt.summary | string | One plain sentence on what this file is doing for the site |
llms_full_txt.findings | array of object | - |
llms_full_txt.findings[].severity | string | error: the file is broken or ignored; warning: likely a mistake or a risk; info: good to know One of error, warning, info. |
llms_full_txt.findings[].message | string | What was found and what it means, in plain words |
llms_full_txt.findings[].line | integer or null | The line of the file the finding is about, when there is one |
security_txt | object | - |
security_txt.file | string | The file name, such as robots.txt |
security_txt.url | string | The address that was read, after redirects |
security_txt.status | string | present: a file was served; missing: the site has no such file; error: the answer could not be used One of present, missing, error. |
security_txt.http_status | integer or null | - |
security_txt.bytes | integer or null | - |
security_txt.content_type | string or null | - |
security_txt.summary | string | One plain sentence on what this file is doing for the site |
security_txt.findings | array of object | - |
security_txt.findings[].severity | string | error: the file is broken or ignored; warning: likely a mistake or a risk; info: good to know One of error, warning, info. |
security_txt.findings[].message | string | What was found and what it means, in plain words |
security_txt.findings[].line | integer or null | The line of the file the finding is about, when there is one |
security_txt.contacts | array of string | - |
security_txt.expires | string or null | - |
security_txt.days_until_expiry | integer or null | - |
security_txt.signed | boolean | - |
security_txt.fields | array of string | - |
ai_txt | object | - |
ai_txt.file | string | The file name, such as robots.txt |
ai_txt.url | string | The address that was read, after redirects |
ai_txt.status | string | present: a file was served; missing: the site has no such file; error: the answer could not be used One of present, missing, error. |
ai_txt.http_status | integer or null | - |
ai_txt.bytes | integer or null | - |
ai_txt.content_type | string or null | - |
ai_txt.summary | string | One plain sentence on what this file is doing for the site |
ai_txt.findings | array of object | - |
ai_txt.findings[].severity | string | error: the file is broken or ignored; warning: likely a mistake or a risk; info: good to know One of error, warning, info. |
ai_txt.findings[].message | string | What was found and what it means, in plain words |
ai_txt.findings[].line | integer or null | The line of the file the finding is about, when there is one |
ai_crawlers | array of object | - |
ai_crawlers[].token | string | The name to put in a User-agent line of robots.txt |
ai_crawlers[].operator | string | - |
ai_crawlers[].purpose | string | One of training, search, user_request, other. |
ai_crawlers[].status | string | allowed: nothing blocks it; partly_blocked: some paths are blocked; blocked: the whole site is blocked; unknown: robots.txt could not be read One of allowed, partly_blocked, blocked, unknown. |
ai_crawlers[].rule_source | string | Which part of robots.txt decided One of own_group, wildcard_group, no_group, no_robots. |
ai_crawlers[].explanation | string | - |
url_test | object or null | - |
url_test.url | string | - |
url_test.user_agent | string | - |
url_test.applies | boolean | False when the URL is on another host, which this robots.txt does not govern |
url_test.allowed | boolean or null | Null when the answer cannot be known |
url_test.matched_rule | string or null | - |
url_test.rule_group | string or null | - |
url_test.explanation | string | - |
Captured example (2026-10-18)
A real run of this lookup on 2026-10-18, using the request above, which is a public input. The envelope fields are left out.
{
"product": "site-files",
"found": true,
"data": {
"site": "https://cloudflare.com",
"checked_at": "2026-10-18T17:16:47.720Z",
"overall": {
"summary": "5 of the 6 site files are present. 1 error and 0 warnings to look at.",
"files_present": 5,
"errors": 1,
"warnings": 0
},
"robots": {
"file": "robots.txt",
"url": "https://www.cloudflare.com/robots.txt",
"status": "present",
"http_status": 200,
"bytes": 1099,
"content_type": "text/plain",
"summary": "robots.txt has 9 groups, 9 rules and lists 1 sitemap.",
"findings": [
{
"severity": "info",
"message": "Line 40: Content signals: search indexing allowed, use in AI answers allowed, AI training allowed. These are preferences you state for AI services. They are not enforced, and each service decides whether to honor them.",
"line": 40
}
],
"access": "rules",
"groups": [
{
"agents": [
"*"
],
"rules": [
{
"type": "allow",
"pattern": "/",
"line": 4
}
],
"rules_truncated": false,
"crawl_delay_seconds": null,
"content_signals": null,
"line": 3,
"explanation": "For every crawler that has no group of its own: nothing is blocked."
},
{
"agents": [
"GPTBot"
],
"rules": [
{
"type": "allow",
"pattern": "/",
"line": 15
}
],
"rules_truncated": false,
"crawl_delay_seconds": null,
"content_signals": null,
"line": 14,
"explanation": "For GPTBot: nothing is blocked."
},
{
"agents": [
"ChatGPT-User"
],
"rules": [
{
"type": "allow",
"pattern": "/",
"line": 18
}
],
"rules_truncated": false,
"crawl_delay_seconds": null,
"content_signals": null,
"line": 17,
"explanation": "For ChatGPT-User: nothing is blocked."
},
{
"agents": [
"Google-Extended"
],
"rules": [
{
"type": "allow",
"pattern": "/",
"line": 21
}
],
"rules_truncated": false,
"crawl_delay_seconds": null,
"content_signals": null,
"line": 20,
"explanation": "For Google-Extended: nothing is blocked."
},
{
"agents": [
"Anthropic-AI"
],
"rules": [
{
"type": "allow",
"pattern": "/",
"line": 24
}
],
"rules_truncated": false,
"crawl_delay_seconds": null,
"content_signals": null,
"line": 23,
"explanation": "For Anthropic-AI: nothing is blocked."
},
{
"agents": [
"Claude-Web"
],
"rules": [
{
"type": "allow",
"pattern": "/",
"line": 27
}
],
"rules_truncated": false,
"crawl_delay_seconds": null,
"content_signals": null,
"line": 26,
"explanation": "For Claude-Web: nothing is blocked."
},
{
"agents": [
"CCBot"
],
"rules": [
{
"type": "allow",
"pattern": "/",
"line": 30
}
],
"rules_truncated": false,
"crawl_delay_seconds": null,
"content_signals": null,
"line": 29,
"explanation": "For CCBot: nothing is blocked."
},
{
"agents": [
"PerplexityBot"
],
"rules": [
{
"type": "allow",
"pattern": "/",
"line": 33
}
],
"rules_truncated": false,
"crawl_delay_seconds": null,
"content_signals": null,
"line": 32,
"explanation": "For PerplexityBot: nothing is blocked."
},
{
"agents": [
"Cohere-ai"
],
"rules": [
{
"type": "allow",
"pattern": "/",
"line": 36
}
],
"rules_truncated": false,
"crawl_delay_seconds": null,
"content_signals": {
"search": "yes",
"ai_input": "yes",
"ai_train": "yes",
"line": 40
},
"line": 35,
"explanation": "For Cohere-ai: nothing is blocked. Content signals: search indexing allowed, use in AI answers allowed, AI training allowed."
}
],
"groups_truncated": false,
"rule_count": 9,
"sitemaps_listed": [
"https://www.cloudflare.com/sitemap.xml"
]
},
"sitemaps": {
"summary": "1 sitemap file read, listing 1,010 URLs.",
"files": [
{
"file": "sitemap.xml",
"url": "https://www.cloudflare.com/sitemap.xml",
"status": "present",
"http_status": 200,
"bytes": 1628250,
"content_type": "application/xml",
"summary": "sitemap.xml lists 1,010 URLs.",
"findings": [],
"kind": "urlset",
"entry_count": 1010,
"listed_in_robots": true,
"found_in": null,
"lastmod_count": 1010,
"extensions": [
"alternate languages"
]
}
],
"total_urls": 1010,
"complete": true,
"families": [
{
"prefix": "/learning/",
"urls": 524,
"example": "https://www.cloudflare.com/learning/security/account-takeover"
},
{
"prefix": "/case-studies/",
"urls": 265,
"example": "https://www.cloudflare.com/case-studies/123milhas"
},
{
"prefix": "/perspectives/",
"urls": 100,
"example": "https://www.cloudflare.com/perspectives/whats-the-best-edge-platform-for-running-a-headless-cms-backend"
},
{
"prefix": "/products/",
"urls": 70,
"example": "https://www.cloudflare.com/products/artifacts"
},
{
"prefix": "/",
"urls": 27,
"example": "https://www.cloudflare.com/"
},
{
"prefix": "/resource/",
"urls": 13,
"example": "https://www.cloudflare.com/resource/app-innovation-report"
},
{
"prefix": "/solutions/",
"urls": 7,
"example": "https://www.cloudflare.com/solutions/ai"
},
{
"prefix": "/policies/",
"urls": 2,
"example": "https://www.cloudflare.com/policies/privacy"
},
{
"prefix": "/careers/",
"urls": 1,
"example": "https://www.cloudflare.com/careers/jobs"
},
{
"prefix": "/partners/",
"urls": 1,
"example": "https://www.cloudflare.com/partners/cloud-and-platform/oracle"
}
],
"families_sampled": false,
"blocked_by_robots": {
"user_agent": "GPTBot",
"checked": 1010,
"blocked": 0,
"examples": [],
"explanation": "None of the 1,010 sitemap URLs tested is blocked by robots.txt for GPTBot."
},
"findings": []
},
"llms_txt": {
"file": "llms.txt",
"url": "https://www.cloudflare.com/llms.txt",
"status": "present",
"http_status": 200,
"bytes": 17173,
"content_type": "text/plain",
"summary": "llms.txt gives AI agents 90 links in 13 sections.",
"findings": [
{
"severity": "info",
"message": "The \"Optional\" section marks links an agent may skip when its context window is short. That is what the proposal intends.",
"line": null
}
],
"title": "Cloudflare",
"has_summary": true,
"sections": [
{
"heading": "About Cloudflare",
"links": 0
},
{
"heading": "Developer Platform - Compute",
"links": 11
},
{
"heading": "Developer Platform - Storage",
"links": 7
},
{
"heading": "Developer Platform - AI",
"links": 6
},
{
"heading": "Developer Platform - Media",
"links": 4
},
{
"heading": "Application Security",
"links": 14
},
{
"heading": "Zero Trust / SASE (Cloudflare One)",
"links": 11
},
{
"heading": "Network & Performance",
"links": 14
},
{
"heading": "Solutions",
"links": 10
},
{
"heading": "Pricing",
"links": 3
},
{
"heading": "Other Pages",
"links": 2
},
{
"heading": "External Resources",
"links": 7
},
{
"heading": "Optional",
"links": 1
}
],
"link_count": 90
},
"llms_full_txt": {
"file": "llms-full.txt",
"url": "https://www.cloudflare.com/llms-full.txt",
"status": "present",
"http_status": 200,
"bytes": 169547,
"content_type": "text/plain",
"summary": "llms-full.txt holds 166 KB of text with 781 headings.",
"findings": []
},
"security_txt": {
"file": "security.txt",
"url": "https://www.cloudflare.com/.well-known/security.txt",
"status": "present",
"http_status": 200,
"bytes": 368,
"content_type": "text/plain",
"summary": "security.txt exists but has 1 error, so researchers may not be able to use it.",
"findings": [
{
"severity": "error",
"message": "There is no Expires field. It is required, so that readers can tell when the contact details went stale.",
"line": null
}
],
"contacts": [
"https://hackerone.com/cloudflare",
"https://www.cloudflare.com/abuse/"
],
"expires": null,
"days_until_expiry": null,
"signed": false,
"fields": [
"Contact",
"Policy",
"Hiring",
"Preferred-Languages",
"Canonical"
]
},
"ai_txt": {
"file": "ai.txt",
"url": "https://www.cloudflare.com/ai.txt",
"status": "missing",
"http_status": 404,
"bytes": null,
"content_type": null,
"summary": "ai.txt is missing. It is not a standard and nothing depends on it, so having none is normal.",
"findings": []
},
"ai_crawlers": [
{
"token": "GPTBot",
"operator": "OpenAI",
"purpose": "training",
"status": "allowed",
"rule_source": "own_group",
"explanation": "OpenAI's GPTBot (AI training) collects pages that may be used to train OpenAI models. It has its own group in robots.txt, and nothing in it is blocked."
},
{
"token": "OAI-SearchBot",
"operator": "OpenAI",
"purpose": "search",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "OpenAI's OAI-SearchBot (AI search) finds pages to show in ChatGPT search results. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "ChatGPT-User",
"operator": "OpenAI",
"purpose": "user_request",
"status": "allowed",
"rule_source": "own_group",
"explanation": "OpenAI's ChatGPT-User (a user request) opens a page when a ChatGPT user asks about it. It has its own group in robots.txt, and nothing in it is blocked."
},
{
"token": "ClaudeBot",
"operator": "Anthropic",
"purpose": "training",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "Anthropic's ClaudeBot (AI training) collects pages that may be used to train Claude models. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "Claude-SearchBot",
"operator": "Anthropic",
"purpose": "search",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "Anthropic's Claude-SearchBot (AI search) finds pages to improve search results in Claude. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "Claude-User",
"operator": "Anthropic",
"purpose": "user_request",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "Anthropic's Claude-User (a user request) opens a page when a Claude user asks about it. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "PerplexityBot",
"operator": "Perplexity",
"purpose": "search",
"status": "allowed",
"rule_source": "own_group",
"explanation": "Perplexity's PerplexityBot (AI search) finds pages to show in Perplexity answers. It has its own group in robots.txt, and nothing in it is blocked."
},
{
"token": "Perplexity-User",
"operator": "Perplexity",
"purpose": "user_request",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "Perplexity's Perplexity-User (a user request) opens a page when a Perplexity user asks about it. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "Google-Extended",
"operator": "Google",
"purpose": "training",
"status": "allowed",
"rule_source": "own_group",
"explanation": "Google's Google-Extended (AI training) a switch that controls whether Google may use your pages for Gemini training and grounding. It has its own group in robots.txt, and nothing in it is blocked."
},
{
"token": "Applebot-Extended",
"operator": "Apple",
"purpose": "training",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "Apple's Applebot-Extended (AI training) a switch that controls whether Apple may use your pages to train its AI models. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "Meta-ExternalAgent",
"operator": "Meta",
"purpose": "training",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "Meta's Meta-ExternalAgent (AI training) collects pages that may be used to train Meta AI models. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "Meta-ExternalFetcher",
"operator": "Meta",
"purpose": "user_request",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "Meta's Meta-ExternalFetcher (a user request) opens a page when a Meta AI user asks about it. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "CCBot",
"operator": "Common Crawl",
"purpose": "training",
"status": "allowed",
"rule_source": "own_group",
"explanation": "Common Crawl's CCBot (AI training) builds the open Common Crawl archive that many AI models train on. It has its own group in robots.txt, and nothing in it is blocked."
},
{
"token": "Amazonbot",
"operator": "Amazon",
"purpose": "other",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "Amazon's Amazonbot (other AI use) collects pages for Amazon services such as Alexa answers. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "Bytespider",
"operator": "ByteDance",
"purpose": "training",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "ByteDance's Bytespider (AI training) collects pages for ByteDance AI models. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "DuckAssistBot",
"operator": "DuckDuckGo",
"purpose": "search",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "DuckDuckGo's DuckAssistBot (AI search) finds pages for DuckDuckGo AI-assisted answers. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "MistralAI-User",
"operator": "Mistral",
"purpose": "user_request",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "Mistral's MistralAI-User (a user request) opens a page when a Le Chat user asks about it. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "cohere-ai",
"operator": "Cohere",
"purpose": "training",
"status": "allowed",
"rule_source": "own_group",
"explanation": "Cohere's cohere-ai (AI training) collects pages for Cohere models. It has its own group in robots.txt, and nothing in it is blocked."
},
{
"token": "Diffbot",
"operator": "Diffbot",
"purpose": "training",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "Diffbot's Diffbot (AI training) collects pages for the Diffbot knowledge graph. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
},
{
"token": "YouBot",
"operator": "You.com",
"purpose": "search",
"status": "allowed",
"rule_source": "wildcard_group",
"explanation": "You.com's YouBot (AI search) finds pages for You.com AI search. It has no group of its own, so it follows the \"*\" group, and nothing in it is blocked."
}
],
"url_test": {
"url": "https://cloudflare.com/cdn-cgi/trace",
"user_agent": "GPTBot",
"applies": true,
"allowed": true,
"matched_rule": "Allow: /",
"rule_group": "the group for GPTBot",
"explanation": "Crawling this URL is allowed for GPTBot. The deciding rule is \"Allow: /\" (line 15) in the group for GPTBot. When several rules match, the longest one wins, and Allow wins a tie."
}
},
"sources": [
"Public site files served by cloudflare.com, read on 2026-10-18"
]
}
Errors
400invalid_input: The request input is invalid.401unauthorized: The API key is missing, malformed, revoked or unknown.402insufficient_credits: The account does not have enough credits for this lookup. Error code: insufficient_credits. During a trial whose allowance is used up the code is trial_allowance_exhausted: nothing is charged and the customer starts the plan from the billing page.405method_not_allowed: This endpoint does not accept that HTTP method.413payload_too_large: The request body is too large.429rate_limited: Too many requests for this API key.500internal_error: An unexpected error occurred.503provider_unavailable: The data source for this product is unavailable right now.