<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: AURA GEO</title>
    <description>The latest articles on DEV Community by AURA GEO (@aurageo).</description>
    <link>https://dev.to/aurageo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4196619%2Fe7b34d26-e0f1-4ff2-b821-5f8d51327934.png</url>
      <title>DEV Community: AURA GEO</title>
      <link>https://dev.to/aurageo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aurageo"/>
    <language>en</language>
    <item>
      <title>Is That Really GPTBot? How to Find and Verify AI Crawlers in Your Server Logs</title>
      <dc:creator>AURA GEO</dc:creator>
      <pubDate>Wed, 21 Oct 2026 16:14:49 +0000</pubDate>
      <link>https://dev.to/aurageo/is-that-really-gptbot-how-to-find-and-verify-ai-crawlers-in-your-server-logs-33m5</link>
      <guid>https://dev.to/aurageo/is-that-really-gptbot-how-to-find-and-verify-ai-crawlers-in-your-server-logs-33m5</guid>
      <description>&lt;p&gt;You've allowed AI search bots in &lt;code&gt;robots.txt&lt;/code&gt;. Great. But are they actually reaching your pages, and are the requests in your logs really from them?&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;User-Agent&lt;/code&gt; header is just a string. Anyone can send &lt;code&gt;GPTBot&lt;/code&gt; in a curl request. So "I saw GPTBot in my logs" proves very little until you check two things: &lt;strong&gt;what status code the bot got&lt;/strong&gt; and &lt;strong&gt;whether the IP really belongs to the vendor&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This guide shows how to do both with standard tools: &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;awk&lt;/code&gt; and a short Python script.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Know which bots you're looking for
&lt;/h2&gt;

&lt;p&gt;Major AI vendors now separate bots by purpose. This matters, because blocking the wrong one can quietly remove you from AI search answers. According to the vendors' own documentation:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Vendor&lt;/th&gt;
&lt;th&gt;Bot&lt;/th&gt;
&lt;th&gt;What it's for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OAI-SearchBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Surfacing sites in ChatGPT search results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GPTBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Crawling content that may be used for model training&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ChatGPT-User&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Visits triggered by a user's request in ChatGPT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Perplexity&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PerplexityBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Surfacing and linking sites in Perplexity search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Perplexity&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Perplexity-User&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fetches triggered by a user's question&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Claude-SearchBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Improving Claude's search results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ClaudeBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Collecting content that may be used for training&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Claude-User&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fetches when a user asks Claude a question&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two practical notes from the docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAI says sites opted out of &lt;code&gt;OAI-SearchBot&lt;/code&gt; won't be shown in ChatGPT search answers (except as navigational links), and that a &lt;code&gt;robots.txt&lt;/code&gt; change can take about 24 hours to take effect for search. Perplexity also mentions up to 24 hours.&lt;/li&gt;
&lt;li&gt;User-triggered fetchers (&lt;code&gt;ChatGPT-User&lt;/code&gt;, &lt;code&gt;Perplexity-User&lt;/code&gt;) are documented as acting on behalf of a user, so &lt;code&gt;robots.txt&lt;/code&gt; rules may not apply to them in the same way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sources: &lt;a href="https://platform.openai.com/docs/bots" rel="noopener noreferrer"&gt;OpenAI crawlers&lt;/a&gt;, &lt;a href="https://docs.perplexity.ai/guides/bots" rel="noopener noreferrer"&gt;Perplexity crawlers&lt;/a&gt;, &lt;a href="https://support.claude.com/en/articles/8896518-does-anthropic-crawl-data-from-the-web-and-how-can-site-owners-block-the-crawler" rel="noopener noreferrer"&gt;Anthropic crawlers&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Find AI bot hits in your access log
&lt;/h2&gt;

&lt;p&gt;The examples assume the standard nginx/Apache "combined" log format, where the client IP is the first field, the status code is the ninth, and the user agent is the sixth field when you split on double quotes.&lt;/p&gt;

&lt;p&gt;Count requests per bot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-oE&lt;/span&gt; &lt;span class="s1"&gt;'OAI-SearchBot|GPTBot|ChatGPT-User|PerplexityBot|Perplexity-User|Claude-SearchBot|ClaudeBot|Claude-User'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  /var/log/nginx/access.log | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See which pages a specific bot requested:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'OAI-SearchBot'&lt;/span&gt; /var/log/nginx/access.log &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $7}'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your logs are rotated and gzipped, use &lt;code&gt;zgrep&lt;/code&gt; on &lt;code&gt;access.log.*.gz&lt;/code&gt; the same way.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Check the status codes — this is where problems hide
&lt;/h2&gt;

&lt;p&gt;A bot that "visits" but receives &lt;code&gt;403&lt;/code&gt; or &lt;code&gt;429&lt;/code&gt; isn't reading your content. This is very common on sites behind a CDN or WAF with aggressive bot protection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'OAI-SearchBot|PerplexityBot|Claude-SearchBot'&lt;/span&gt; /var/log/nginx/access.log &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $9}'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What to look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;200&lt;/strong&gt; on real content pages — good.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;301/302&lt;/strong&gt; — fine if they resolve to a 200; check that redirects don't loop or land on a login page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;403&lt;/strong&gt; — usually a firewall or bot-protection rule. Perplexity's docs, for example, describe allowing their bots in Cloudflare or AWS WAF by combining a user-agent match with their published IP ranges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;429&lt;/strong&gt; — rate limiting. Bots may back off and come back less often.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5xx&lt;/strong&gt; — your server failed; the bot got nothing useful.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important: if a CDN blocks a request at the edge, it may never reach your origin server logs at all. In that case, check the CDN's own firewall/security events too.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Verify the IP, not just the user agent
&lt;/h2&gt;

&lt;p&gt;OpenAI and Perplexity publish JSON files with the IP ranges their bots use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://openai.com/searchbot.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://openai.com/gptbot.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://openai.com/chatgpt-user.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://www.perplexity.ai/perplexitybot.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;https://www.perplexity.ai/perplexity-user.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each file contains a &lt;code&gt;prefixes&lt;/code&gt; list with &lt;code&gt;ipv4Prefix&lt;/code&gt; or &lt;code&gt;ipv6Prefix&lt;/code&gt; entries. Here's a small script that checks IPs from your log against them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;verify_ai_bots.py — check which logged AI-bot IPs match official ranges.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ipaddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;

&lt;span class="n"&gt;SOURCES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OAI-SearchBot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://openai.com/searchbot.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GPTBot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://openai.com/gptbot.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ChatGPT-User&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://openai.com/chatgpt-user.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PerplexityBot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.perplexity.ai/perplexitybot.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Perplexity-User&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.perplexity.ai/perplexity-user.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_ranges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User-Agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;range-check&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;nets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prefixes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt;
        &lt;span class="n"&gt;cidr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ipv4Prefix&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ipv6Prefix&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cidr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;nets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipaddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ip_network&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cidr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;nets&lt;/span&gt;

&lt;span class="n"&gt;ranges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;load_ranges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;SOURCES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
&lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replace&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;bot&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ranges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;rf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;\b&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
                &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setdefault&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="nf"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
    &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ipaddress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ip_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ranges&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OK  &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;FAKE?&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; hits&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 verify_ai_bots.py /var/log/nginx/access.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anything marked &lt;code&gt;FAKE?&lt;/code&gt; claims to be an AI bot but comes from an IP outside the published ranges. Don't panic: the ranges change over time, so re-download them before drawing conclusions. But if a "GPTBot" is hammering your site from a random hosting provider, it's very likely not OpenAI.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: if your server sits behind a reverse proxy or CDN, the first log field may be the proxy's IP. Make sure you log the real client IP (for example via &lt;code&gt;X-Forwarded-For&lt;/code&gt; / &lt;code&gt;CF-Connecting-IP&lt;/code&gt; with a trusted-proxy config).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  5. For Googlebot and Bingbot: reverse DNS
&lt;/h2&gt;

&lt;p&gt;Google and Bing also publish IP lists (&lt;code&gt;googlebot.json&lt;/code&gt;, &lt;code&gt;bingbot.json&lt;/code&gt;), and both support the classic reverse-then-forward DNS check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;host 66.249.66.1
&lt;span class="c"&gt;# → ...googlebot.com&lt;/span&gt;
host crawl-66-249-66-1.googlebot.com
&lt;span class="c"&gt;# → must resolve back to 66.249.66.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the reverse lookup doesn't end in a Google-owned domain (such as &lt;code&gt;googlebot.com&lt;/code&gt; or &lt;code&gt;google.com&lt;/code&gt;), or the forward lookup doesn't return the same IP, it isn't Googlebot. The same idea works for Bingbot with &lt;code&gt;search.msn.com&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. What a verified visit does — and doesn't — prove
&lt;/h2&gt;

&lt;p&gt;A verified &lt;code&gt;OAI-SearchBot&lt;/code&gt; hit with a &lt;code&gt;200&lt;/code&gt; tells you one thing: the bot could fetch that page. It does &lt;strong&gt;not&lt;/strong&gt; prove that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the page is indexed in that assistant's search,&lt;/li&gt;
&lt;li&gt;the page will be cited in an answer,&lt;/li&gt;
&lt;li&gt;anyone will click through.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are separate stages, and each needs its own evidence: a saved answer that links to your page, and a real referral visit in your analytics. Treat bot logs as the first link in that chain, not the finish line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] List AI bots in your logs and count hits per bot&lt;/li&gt;
&lt;li&gt;[ ] Check status codes for search bots — no 403/429 on public pages&lt;/li&gt;
&lt;li&gt;[ ] Check CDN/WAF events for edge blocks that never reach your origin&lt;/li&gt;
&lt;li&gt;[ ] Verify IPs against the official JSON ranges (re-download them regularly)&lt;/li&gt;
&lt;li&gt;[ ] Use reverse DNS for Googlebot and Bingbot&lt;/li&gt;
&lt;li&gt;[ ] Don't treat a crawl as a citation&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you'd rather not script this by hand, &lt;a href="https://aurageo.io/en/" rel="noopener noreferrer"&gt;AURA GEO&lt;/a&gt; runs these accessibility checks for your site, keeps a crawl history for AI bots and shows real referral visits from AI assistants — and your own agent can pick up the fixes over MCP. There's also an English write-up on &lt;a href="https://aurageo.io/en/learn/vizit-ii-bota-ne-raven-citirovaniyu/" rel="noopener noreferrer"&gt;why a bot visit isn't a citation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>ai</category>
      <category>devops</category>
    </item>
    <item>
      <title>How to Get Your Site Ready for AI Search: robots.txt, llms.txt, Schema and AI Bots — A Practical Checklist</title>
      <dc:creator>AURA GEO</dc:creator>
      <pubDate>Tue, 20 Oct 2026 17:07:16 +0000</pubDate>
      <link>https://dev.to/aurageo/kak-podghotovit-sait-k-ii-poisku-robotstxt-llmstxt-schema-i-ii-boty-praktichieskii-chieklist-6e0</link>
      <guid>https://dev.to/aurageo/kak-podghotovit-sait-k-ii-poisku-robotstxt-llmstxt-schema-i-ii-boty-praktichieskii-chieklist-6e0</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk3hs7pnfr9eqmd1hftcx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk3hs7pnfr9eqmd1hftcx.png" alt="AURA GEO — hero" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More and more people skip the ten blue links and search directly in ChatGPT, Gemini, Perplexity or Claude. An assistant with web search finds pages on its own, reads them and builds an answer with links to its sources. If your site is blocked, slow or hard to parse for these systems, it won't make it into the answer — even if it ranks well on Google.&lt;/p&gt;

&lt;p&gt;Preparing a site for this kind of search is called &lt;strong&gt;GEO (Generative Engine Optimization)&lt;/strong&gt;. The good news: the technical foundation of GEO overlaps almost entirely with good SEO. The bad news: there are a few places where sites break all the time, and a standard SEO audit doesn't catch them.&lt;/p&gt;

&lt;p&gt;Below is a checklist you can get through in an evening. Every item can be checked with a terminal command or a couple of lines of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Allow AI bots in robots.txt
&lt;/h2&gt;

&lt;p&gt;The first thing any crawler does is read &lt;code&gt;robots.txt&lt;/code&gt;. Over the past few years, plenty of sites copied "protective" rules and accidentally locked out AI search bots.&lt;/p&gt;

&lt;p&gt;It's important to tell two kinds of bots apart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Training bots&lt;/strong&gt; (e.g. &lt;code&gt;GPTBot&lt;/code&gt;, &lt;code&gt;ClaudeBot&lt;/code&gt;, &lt;code&gt;Google-Extended&lt;/code&gt;) collect data to train models.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search and user-triggered bots&lt;/strong&gt; (e.g. &lt;code&gt;OAI-SearchBot&lt;/code&gt;, &lt;code&gt;ChatGPT-User&lt;/code&gt;, &lt;code&gt;PerplexityBot&lt;/code&gt;, &lt;code&gt;Claude-User&lt;/code&gt;) show up when an assistant is looking for an answer for a specific user. These are the ones that bring citations and clicks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can block training and still allow search. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# AI search and user-triggered bots — allow
User-agent: OAI-SearchBot
Allow: /

User-agent: ChatGPT-User
Allow: /

User-agent: PerplexityBot
Allow: /

User-agent: Claude-User
Allow: /

# Classic search engines
User-agent: Googlebot
Allow: /

User-agent: Bingbot
Allow: /

User-agent: *
Allow: /
Disallow: /admin/

Sitemap: https://example.com/sitemap.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check: make sure the file returns a 200 and doesn't contain a blanket &lt;code&gt;Disallow: /&lt;/code&gt; for the agents you care about.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"%{http_code}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; https://example.com/robots.txt
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://example.com/robots.txt | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s2"&gt;"user-agent|disallow"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Don't forget your CDN and WAF
&lt;/h3&gt;

&lt;p&gt;A common trap: &lt;code&gt;robots.txt&lt;/code&gt; allows everything, but Cloudflare or another WAF serves bots a 403 or a captcha. Check the server response with different User-Agents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;ua &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"OAI-SearchBot"&lt;/span&gt; &lt;span class="s2"&gt;"ChatGPT-User"&lt;/span&gt; &lt;span class="s2"&gt;"PerplexityBot"&lt;/span&gt; &lt;span class="s2"&gt;"Googlebot"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"%{http_code}"&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ua&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; https://example.com/&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ua&lt;/span&gt;&lt;span class="s2"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If anything isn't a 200, look at your bot-protection rules.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Serve text in HTML, not just via JavaScript
&lt;/h2&gt;

&lt;p&gt;Many AI crawlers don't execute JavaScript, or only do so in a limited way. If your content only appears after an SPA hydrates, the bot sees an empty &lt;code&gt;&amp;lt;div id="root"&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A simple check — download the page and see whether the main text is there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://example.com/pricing &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;[^&amp;gt;]*&amp;gt;//g'&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;' \n'&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; 1500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see prices, descriptions and the FAQ, you're good. If all you get is the menu and empty space, you need SSR, SSG or prerendering (Next.js, Nuxt, Astro, Remix, etc.).&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Add llms.txt
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;llms.txt&lt;/code&gt; is a proposed format: a Markdown file at the site root that briefly explains what the site is and lists key pages with descriptions. It isn't a standard, and no major assistant officially promises to use it. But it's cheap, useful for agents and developers, and it forces you to put the essentials of your product into words.&lt;/p&gt;

&lt;p&gt;Minimal example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Example Inc.&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; Example is an online booking service for small yoga studios.&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Operates in Latvia and Lithuania, interface in Russian and English.&lt;/span&gt;

&lt;span class="gu"&gt;## Main pages&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Pricing&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/pricing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: three plans, free trial.
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;API docs&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/docs/api&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: REST API for client bookings.
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;About&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/about&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: team, contacts, company details.

&lt;span class="gu"&gt;## FAQ&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;FAQ&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/faq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: refunds, payments, integrations.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A good live example is &lt;a href="https://aurageo.io/llms.txt" rel="noopener noreferrer"&gt;AURA GEO's llms.txt&lt;/a&gt;: besides the list of pages, it honestly states what the service does &lt;em&gt;not&lt;/em&gt; do (for instance, that it doesn't "index sites in AI directly"). Explicit limitations like this are useful — models have less to fill in on their own.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Schema.org markup (JSON-LD)
&lt;/h2&gt;

&lt;p&gt;Structured data helps search engines — and, indirectly, AI — understand who you are and what you sell. The minimum set for a SaaS or service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Organization&lt;/code&gt; — name, logo, &lt;code&gt;sameAs&lt;/code&gt; with links to external profiles;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;WebSite&lt;/code&gt; — site name;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SoftwareApplication&lt;/code&gt; or &lt;code&gt;Product&lt;/code&gt; — for the product and pricing;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FAQPage&lt;/code&gt; — for a Q&amp;amp;A block;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Article&lt;/code&gt; — for blog posts and knowledge-base articles.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Organization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Example Inc.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/logo.png&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sameAs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://github.com/example&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.producthunt.com/products/example&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;FAQPage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mainEntity&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Question&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Is there a free plan?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;acceptedAnswer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Answer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Yes, you can connect one site for free.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The golden rule: markup must match the visible text. If your JSON-LD contains an FAQ that isn't on the page, that's worse than having no markup at all.&lt;/p&gt;

&lt;p&gt;Check it with Google's Rich Results Test or validator.schema.org.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Sitemap, canonical and noindex
&lt;/h2&gt;

&lt;p&gt;AI assistants with search lean heavily on the Google and Bing indexes. A page that isn't indexed has almost no chance of making it into an answer. Check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# sitemap is reachable&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"%{http_code}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; https://example.com/sitemap.xml

&lt;span class="c"&gt;# no accidental noindex, and canonical points to itself&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://example.com/pricing | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s1"&gt;'noindex|rel="canonical"'&lt;/span&gt;
curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://example.com/pricing | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; x-robots-tag
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also go into Google Search Console and Bing Webmaster Tools and review the report on non-indexed pages. Bing matters especially: several AI assistants rely on its index.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. IndexNow: report updates right away
&lt;/h2&gt;

&lt;p&gt;IndexNow is a protocol for notifying Bing, Yandex and other participating search engines about new or changed URLs. Google doesn't use it, but for Bing it's the fastest route.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# the key must be available at https://example.com/&amp;lt;KEY&amp;gt;.txt&lt;/span&gt;
curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s2"&gt;"https://api.indexnow.org/indexnow"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json; charset=utf-8"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "host": "example.com",
    "key": "&amp;lt;KEY&amp;gt;",
    "urlList": ["https://example.com/pricing", "https://example.com/faq"]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind: a successful submission only means "notification received" — not "page indexed", and certainly not "AI is citing it". These are separate stages, and each is worth checking on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Write pages that are easy to cite
&lt;/h2&gt;

&lt;p&gt;Technical work opens the door, but content is what gets cited. What works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Answer in the first paragraph.&lt;/strong&gt; Question in the heading, a direct 2–3 sentence answer right below it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specifics.&lt;/strong&gt; Prices, timelines, countries, limitations, versions. "Free for one site" beats "affordable pricing".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verifiable facts.&lt;/strong&gt; Last-updated date, author, source of the numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structure.&lt;/strong&gt; H2/H3, lists, comparison tables.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One page per question.&lt;/strong&gt; A "How much does X cost" page gets cited more than a paragraph buried in a giant landing page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't pass off demo data as facts.&lt;/strong&gt; If your landing page has nice example numbers in an interface mockup, label them as examples — otherwise a model may repeat them as real.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Measure: bot logs and AI referrals
&lt;/h2&gt;

&lt;p&gt;Without measurement, GEO turns into guesswork. The minimum:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Server logs.&lt;/strong&gt; Look for AI bot visits:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s2"&gt;"GPTBot|OAI-SearchBot|ChatGPT-User|PerplexityBot|ClaudeBot|Claude-User"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  /var/log/nginx/access.log | &lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print $1, $7, $12}'&lt;/span&gt; | &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Referrers in analytics.&lt;/strong&gt; Visits come from domains like &lt;code&gt;chatgpt.com&lt;/code&gt;, &lt;code&gt;perplexity.ai&lt;/code&gt;, &lt;code&gt;gemini.google.com&lt;/code&gt;, &lt;code&gt;copilot.microsoft.com&lt;/code&gt;. Create a separate segment for them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manual answer checks.&lt;/strong&gt; Ask your customers' neutral questions in fresh chats with search enabled, save the answer and the list of sources, and repeat after making changes. A single check proves nothing — the trend is what matters.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can stitch all of this together with scripts, or keep it in one dashboard. For example, &lt;a href="https://aurageo.io/en/" rel="noopener noreferrer"&gt;AURA GEO&lt;/a&gt; runs a technical audit (robots.txt, accessible HTML, noindex, sitemap), counts recognized AI referrals, lets you hand tasks to your own AI agent via MCP, and submits updated pages through IndexNow. The basic plan for one site is free.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final checklist
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;How to check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;robots.txt allows AI search bots&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;curl robots.txt&lt;/code&gt;, grep for User-agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WAF doesn't block bots&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;curl -A "ChatGPT-User"&lt;/code&gt; → 200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text is in HTML without JS&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;curl&lt;/code&gt; + strip tags&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;llms.txt at the root&lt;/td&gt;
&lt;td&gt;&lt;code&gt;curl /llms.txt&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON-LD: Organization, FAQPage&lt;/td&gt;
&lt;td&gt;Rich Results Test&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sitemap, canonical, no noindex&lt;/td&gt;
&lt;td&gt;grep + Search Console / Bing WMT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IndexNow configured&lt;/td&gt;
&lt;td&gt;200/202 response from the API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pages answer specific questions&lt;/td&gt;
&lt;td&gt;content review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bot logs and AI referrers are tracked&lt;/td&gt;
&lt;td&gt;log grep, analytics segment&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is GEO in plain terms?
&lt;/h3&gt;

&lt;p&gt;GEO (Generative Engine Optimization) is preparing a site so that AI assistants with web search can find, read and cite its pages. SEO is about rankings in regular search results; GEO is about showing up in answers from ChatGPT, Gemini, Perplexity and others.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I block GPTBot to protect my content?
&lt;/h3&gt;

&lt;p&gt;That's your call. Blocking training bots (GPTBot, ClaudeBot, Google-Extended) doesn't affect search bots like OAI-SearchBot and ChatGPT-User. If you want citations, don't block search and user-triggered bots.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is llms.txt required?
&lt;/h3&gt;

&lt;p&gt;No. It's an optional format, and major assistants don't officially promise to use it. But it's cheap, useful for AI agents and developers, and helps you describe your product clearly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does schema.org help you get into AI answers?
&lt;/h3&gt;

&lt;p&gt;There are no direct guarantees, but markup helps search engines understand the entities on a page, and AI search relies heavily on their indexes. The key is that markup matches the visible text.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does submitting to IndexNow mean the page will show up in ChatGPT?
&lt;/h3&gt;

&lt;p&gt;No. IndexNow only notifies search engines. Indexing, a bot visit, a citation and a click are separate stages, and each needs to be checked separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I know AI is already sending traffic?
&lt;/h3&gt;

&lt;p&gt;Look for &lt;code&gt;chatgpt.com&lt;/code&gt;, &lt;code&gt;perplexity.ai&lt;/code&gt; and &lt;code&gt;gemini.google.com&lt;/code&gt; referrers in your analytics and AI bot visits in your logs. And regularly check how assistants answer your customers' questions.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>ai</category>
      <category>webdev</category>
      <category>geo</category>
    </item>
  </channel>
</rss>
