<?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: A.R. Hashir</title>
    <description>The latest articles on DEV Community by A.R. Hashir (@arhashir).</description>
    <link>https://dev.to/arhashir</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%2F4204187%2F3db6084f-9d94-45aa-84a9-8376ac92a09a.png</url>
      <title>DEV Community: A.R. Hashir</title>
      <link>https://dev.to/arhashir</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arhashir"/>
    <language>en</language>
    <item>
      <title>Why isn't my site cited by ChatGPT? I tested my own blog.</title>
      <dc:creator>A.R. Hashir</dc:creator>
      <pubDate>Sun, 08 Nov 2026 15:04:33 +0000</pubDate>
      <link>https://dev.to/arhashir/why-isnt-my-site-cited-by-chatgpt-i-tested-my-own-blog-1lpn</link>
      <guid>https://dev.to/arhashir/why-isnt-my-site-cited-by-chatgpt-i-tested-my-own-blog-1lpn</guid>
      <description>&lt;p&gt;I spent two weeks assuming my website had a technical problem.&lt;/p&gt;

&lt;p&gt;That is what every article tells you. Check your robots.txt. Check your schema. Check whether your CMS is stripping your content. So I did all of it, carefully, on my own Blogspot site, expecting to find something broken.&lt;/p&gt;

&lt;p&gt;The technical layer came back clean. Seven checks out of seven.&lt;/p&gt;

&lt;p&gt;The problem was somewhere I had not thought to look: 282 headings across 93,270 words, and only fifteen of them were questions.&lt;/p&gt;

&lt;p&gt;This post is the audit, the numbers, and the three changes I am making as a result.&lt;/p&gt;

&lt;h2&gt;
  
  
  The site I audited
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://arhashirbooks.blogspot.com" rel="noopener noreferrer"&gt;arhashirbooks.blogspot.com&lt;/a&gt; — thirteen published posts, 93,270 words, written between late October and early November 2026. Topics are mostly AI search, structured data, and a few straight how-to guides. Nothing unusual. A standard Blogspot blog with a custom theme.&lt;/p&gt;

&lt;p&gt;My hypothesis was that the platform was the problem. Blogspot has a reputation for being technically limited compared to a self-hosted site, and I assumed that reputation had cost me citations.&lt;/p&gt;

&lt;p&gt;It had not.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I measured
&lt;/h2&gt;

&lt;p&gt;Every number below came from the live site, not from a dashboard. Blogspot publishes a full JSON feed of every post and its raw HTML content at a predictable URL, which makes this auditable by anyone.&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="s2"&gt;"https://arhashirbooks.blogspot.com/feeds/posts/default?alt=json&amp;amp;max-results=500"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; feed.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single request returns every post, its publish date, its permalink, and the complete HTML body. No scraping, no rendering, no third-party tool. If you are on Blogspot, you can run exactly the same audit on your own blog in about a minute.&lt;/p&gt;

&lt;p&gt;From that feed I extracted seven technical checks and four content checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 1: the technical layer was fine
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;robots.txt&lt;/code&gt; allows crawling&lt;/td&gt;
&lt;td&gt;Yes, only &lt;code&gt;/search&lt;/code&gt; and &lt;code&gt;/share-widget&lt;/code&gt; disallowed&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XML sitemap exists and is reachable&lt;/td&gt;
&lt;td&gt;200, listed in robots.txt&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canonical tag present on posts&lt;/td&gt;
&lt;td&gt;Yes, self-referencing&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON-LD structured data&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;BlogPosting&lt;/code&gt;, &lt;code&gt;Organization&lt;/code&gt;, &lt;code&gt;Person&lt;/code&gt;, &lt;code&gt;WebPage&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single &lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt; per page&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile viewport meta&lt;/td&gt;
&lt;td&gt;&lt;code&gt;width=device-width, initial-scale=1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open Graph image&lt;/td&gt;
&lt;td&gt;Present on posts&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Seven for seven. The platform ships a reasonable default template, and nothing was blocking anything.&lt;/p&gt;

&lt;p&gt;This matters because it kills the most common diagnosis. If your site is on a mainstream platform, the technical foundation is almost certainly not your problem. You are not being ignored because of a missing tag.&lt;/p&gt;

&lt;p&gt;You are being ignored because of what the crawler finds after it gets in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 2: 282 headings, 15 questions
&lt;/h2&gt;

&lt;p&gt;I pulled every &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; from every post and counted how many were phrased as an actual question — meaning they ended in a question mark and were asking something a reader might type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;15 out of 282. That is 5.3%.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is every post, sorted by length, with its heading count and question count:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Post&lt;/th&gt;
&lt;th&gt;Words&lt;/th&gt;
&lt;th&gt;H2&lt;/th&gt;
&lt;th&gt;Questions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;25 AI Workflows for Small Business&lt;/td&gt;
&lt;td&gt;20,713&lt;/td&gt;
&lt;td&gt;59&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Personal AI Assistant: 15 Best AI Agents&lt;/td&gt;
&lt;td&gt;11,371&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fractional Chief AI Officer (CAIO)&lt;/td&gt;
&lt;td&gt;8,019&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How to Focus Better at Work&lt;/td&gt;
&lt;td&gt;7,743&lt;/td&gt;
&lt;td&gt;27&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Structured Data for AI Search&lt;/td&gt;
&lt;td&gt;7,066&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What Is an SBOM?&lt;/td&gt;
&lt;td&gt;6,823&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How to Read Body Language&lt;/td&gt;
&lt;td&gt;6,611&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Visibility Audit&lt;/td&gt;
&lt;td&gt;6,263&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EU Cyber Resilience Act Deadlines&lt;/td&gt;
&lt;td&gt;5,293&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI Search Optimization&lt;/td&gt;
&lt;td&gt;3,914&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Which Task Is a Generative AI Task?&lt;/td&gt;
&lt;td&gt;3,707&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Crawled – Currently Not Indexed on Blogger&lt;/td&gt;
&lt;td&gt;3,490&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;How to Track AI Search Visibility&lt;/td&gt;
&lt;td&gt;2,257&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;93,270&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;282&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Look at the top row. My longest post — 20,713 words, 59 headings — has zero question headings. It is the most thorough thing I have written and it is structurally the least retrieval-friendly.&lt;/p&gt;

&lt;p&gt;Six of the thirteen posts had zero question headings. Not one.&lt;/p&gt;

&lt;p&gt;Here is what my headings actually look like, taken directly from the feed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Start with visible facts, not code"&lt;/li&gt;
&lt;li&gt;"What structured data can and cannot do"&lt;/li&gt;
&lt;li&gt;"The 100-point AI visibility scorecard"&lt;/li&gt;
&lt;li&gt;"Choose schema by the page's job"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not bad headings. They are clear, specific, and useful to a human reading top to bottom. I was proud of them.&lt;/p&gt;

&lt;p&gt;They are also invisible to a retrieval system that is trying to match a user's question to a passage of text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why question headings matter more than they sound
&lt;/h2&gt;

&lt;p&gt;When someone asks ChatGPT or Perplexity a question, the system does not read your whole page. It retrieves passages, and it matches them against the shape of the query.&lt;/p&gt;

&lt;p&gt;If the query is "does schema help AI search", a passage sitting under the heading "Does schema help AI search?" is a near-exact match. A passage sitting under "Start with visible facts, not code" might contain the same information and might be equally true — but the system has to infer that. Inference is work. Retrieval systems prefer not to work.&lt;/p&gt;

&lt;p&gt;That is the whole mechanism. It is not a trick and it is not a ranking factor in Google's classic sense. It is about making the match obvious instead of making the machine guess.&lt;/p&gt;

&lt;p&gt;One post on my blog already did this correctly, by accident. It has a heading that reads "Why is my website not showing up in ChatGPT? Start with this 60-second triage" and it remains the post with the most question-shaped structure I have written. That is the pattern to copy deliberately rather than land on by luck.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three heading mistakes I was making
&lt;/h2&gt;

&lt;p&gt;Rewriting 282 headings taught me that I had three specific habits, and all three are common.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Habit 1: clever headings instead of plain ones.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"Start with visible facts, not code" is a nice line. It also requires the reader to already know what the section is about. A plain heading — "Should you fix visible content before adding schema?" — tells the system what question lives underneath, in the words the searcher would use.&lt;/p&gt;

&lt;p&gt;Clever headings are written for a human who is already reading. Plain question headings are written for a human who is still deciding whether to read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Habit 2: compound headings that merge two ideas.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Several of mine did two jobs at once: "Structured data, schema and JSON-LD: three different jobs." That is a definition, a comparison, and a heading all crammed into one line. When a passage underneath a compound heading is retrieved, the system cannot tell which part you are answering.&lt;/p&gt;

&lt;p&gt;One heading, one question. If a section answers two questions, it should be two sections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Habit 3: navigational labels dressed up as headings.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"On this page" appeared as an &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; on more than one post. So did "The 10-minute map: where to start." Those are page furniture. They burn one of your heading slots on something that will never match a query.&lt;/p&gt;

&lt;p&gt;Page furniture belongs in a list, or as bold text, or as an actual table of contents component — not as a heading competing with your content headings.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a matching query actually looks like
&lt;/h2&gt;

&lt;p&gt;Concrete example, using a real section from my own blog.&lt;/p&gt;

&lt;p&gt;A searcher types: &lt;strong&gt;"does schema help AI search"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;My original heading: &lt;em&gt;"What structured data can and cannot do"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The paragraph underneath said something close to: schema does not directly make AI systems cite you, but it removes ambiguity about entities and facts, and the measurable benefit shows up in disambiguation rather than citation count.&lt;/p&gt;

&lt;p&gt;Everything needed to answer "does schema help AI search" was in that paragraph. Nothing in the heading matched the query.&lt;/p&gt;

&lt;p&gt;The rewrite: &lt;strong&gt;"Does schema help AI search? The honest evidence."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Same paragraph. Same claim. Now the heading contains every word of the query, in the same order, ending as a question. A retrieval system scanning for a passage about whether schema helps AI search no longer has to infer anything — the match is explicit.&lt;/p&gt;

&lt;p&gt;This is not clever. It is closer to janitorial work. But it is the specific work that most sites skip, because it is boring and because the old headings already felt finished.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rewrite, before and after
&lt;/h2&gt;

&lt;p&gt;I did not have to change any content. Only the headings.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Start with visible facts, not code&lt;/td&gt;
&lt;td&gt;Should you fix your visible content before adding schema?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What structured data can and cannot do&lt;/td&gt;
&lt;td&gt;What does structured data actually do for AI search?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The 100-point AI visibility scorecard&lt;/td&gt;
&lt;td&gt;How do you score AI visibility out of 100?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Choose schema by the page's job&lt;/td&gt;
&lt;td&gt;Which schema type should you use for each page?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Validate in five passes&lt;/td&gt;
&lt;td&gt;How do you validate JSON-LD without breaking existing markup?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Same content underneath. Same claims, same evidence, same order. The heading now names the question the passage answers.&lt;/p&gt;

&lt;p&gt;There is a limit on this. Do not turn every heading into a question, because that reads like a FAQ page and humans hate it. In a 3,000-word post, five or six question headings is enough to give the retrieval system clear anchors without turning the article into a quiz.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 3: eight of thirteen posts never linked to the thing I sell
&lt;/h2&gt;

&lt;p&gt;This one was worse than the heading problem, and it had nothing to do with AI.&lt;/p&gt;

&lt;p&gt;Of thirteen posts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;8&lt;/strong&gt; had no link to my product page at all&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5&lt;/strong&gt; had at least one&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0&lt;/strong&gt; linked to anywhere else I publish&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had 93,000 words of content that people were reading, and in most of it there was no next step. A reader who finished a 7,000-word guide on structured data had nowhere to go.&lt;/p&gt;

&lt;p&gt;That is not an SEO problem. That is a basic editorial mistake, and I had made it on sixty percent of my own library.&lt;/p&gt;

&lt;p&gt;The fix is not to stuff links everywhere. It is to add exactly one relevant next step per post, placed where the reader has just finished the problem you described. If the post is about AI visibility audits, the next step is the checklist. If it is about schema templates, the next step is the full set of templates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 4: zero posts pointed at my other platform
&lt;/h2&gt;

&lt;p&gt;Every post linked internally to other posts on the same blog. Good. None of them linked out to where I also publish.&lt;/p&gt;

&lt;p&gt;That is a missed connection, not a disaster. Cross-linking between your own properties does two things: it gives readers a second place to find you, and it makes the relationship between your entities explicit to anything reading the web.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am changing
&lt;/h2&gt;

&lt;p&gt;Three changes, in this order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Rewrite the headings on the five posts that already rank.&lt;/strong&gt; Not new content. Five or six question-shaped headings per post, using the actual questions those sections answer. This is a two-hour job across five posts and it touches nothing else — no title changes, no URL changes, no republishing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Add one next step to every post.&lt;/strong&gt; For the eight posts with no product link, one relevant link, placed after the section that solves the problem. For the five that already have one, check that it is in the right place rather than bolted onto the end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Add a link back from every post to the main blog and to my other writing.&lt;/strong&gt; Two lines at most. Intrusive link blocks at the bottom of posts do nothing; a sentence in context does something.&lt;/p&gt;

&lt;p&gt;I will report back with numbers. The honest expectation is that none of this moves anything for four to twelve weeks, and I would rather say that now than pretend otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which posts to fix first
&lt;/h2&gt;

&lt;p&gt;You cannot rewrite 282 headings in an afternoon, and you should not. The order matters more than the volume.&lt;/p&gt;

&lt;p&gt;I ranked my thirteen posts on three questions, and fixed them in that order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Does this post already get impressions from Google?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Check Search Console, not your feelings. A post with 400 impressions and a 0.4% click-through rate is a post Google already considers relevant but not compelling. That is the cheapest fix available to you: better headings on a page that already ranks.&lt;/p&gt;

&lt;p&gt;A post with zero impressions is a different problem entirely. Rewriting its headings will not create demand that does not exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Does the post answer a question someone would actually type?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not "would a reader find this useful" — literally, is there a search query that maps to this section. If the section is "How to Focus Better at Work", the queries are real and specific. If it is "The decision that matters before choosing a tool", the query is probably something like "how to choose an AI tool for my business", which is close but not the same.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Does the post end anywhere?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A post that solves a problem and then stops is a dead end. A post that solves a problem and then offers the next step is a funnel, and it does not require you to be pushy. It requires you to notice that the reader who just finished your 7,000-word guide on structured data might want the templates.&lt;/p&gt;

&lt;p&gt;My ranking, once I applied all three: the five AI-search posts first, because they have the clearest queries, the highest commercial intent, and they already rank for something. The generic how-to posts (focus, body language, generative AI tasks) last, because they bring traffic that has nothing to do with what I sell, and converting them is a different project.&lt;/p&gt;

&lt;p&gt;That last point is worth sitting with. Two of my thirteen posts are about body language and focus at work. They are fine posts. They will never sell a developer checklist, no matter how good the headings are.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I expect, and when
&lt;/h2&gt;

&lt;p&gt;It would be easy to end this post with the implication that fixing headings will get me cited next week. It will not.&lt;/p&gt;

&lt;p&gt;Here is what I actually expect, with the reasoning attached.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Timeframe&lt;/th&gt;
&lt;th&gt;What I expect to see&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Week 1–2&lt;/td&gt;
&lt;td&gt;Nothing. Google has to recrawl. Citations will not move.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week 3–4&lt;/td&gt;
&lt;td&gt;Possible movement on exact long-tail queries where I already rank.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week 6–8&lt;/td&gt;
&lt;td&gt;First honest signal. Either some queries start returning my pages, or they do not.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week 12&lt;/td&gt;
&lt;td&gt;Enough data to say whether this worked, with a real before-and-after.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The reason for the delay is not mysterious. Recrawling is not instant, retrieval indexes are rebuilt on their own schedule, and the queries I care about are ones where I currently rank nowhere. Even a perfect heading rewrite cannot shortcut a site that has no authority yet.&lt;/p&gt;

&lt;p&gt;Which is the part I want to be honest about: &lt;strong&gt;headings are a fix for a site that is already being found and not being chosen.&lt;/strong&gt; They will not make a site get found in the first place. If nobody knows your site exists, better headings change nothing, because there is no query reaching your pages at all.&lt;/p&gt;

&lt;p&gt;My site has been found — it has traffic and it has indexed pages. My headings were costing me the second step. That is the specific problem I am fixing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to run this on your own blog
&lt;/h2&gt;

&lt;p&gt;If you are on Blogspot, the whole audit is three commands.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get the feed:&lt;/strong&gt;&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="s2"&gt;"https://yourblog.blogspot.com/feeds/posts/default?alt=json&amp;amp;max-results=500"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; feed.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Count your headings and your questions:&lt;/strong&gt;&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="kn"&gt;import&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="n"&gt;feed&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="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;feed.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;total_h2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total_q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;feed&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;entry&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&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;$t&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;headings&lt;/span&gt; &lt;span class="o"&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;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;h2[^&amp;gt;]*&amp;gt;(.*?)&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;html&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;S&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;total_h2&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;total_q&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;headings&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;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;[^&amp;gt;]+&amp;gt;&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="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;?&lt;/span&gt;&lt;span class="sh"&gt;"&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="n"&gt;total_q&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total_h2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; headings are questions&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;&lt;strong&gt;Check what your headings actually say:&lt;/strong&gt;&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;feed&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;feed&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;entry&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;#&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&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;$t&lt;/span&gt;&lt;span class="sh"&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;h&lt;/span&gt; &lt;span class="ow"&gt;in&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;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;h2[^&amp;gt;]*&amp;gt;(.*?)&amp;lt;/h2&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&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;$t&lt;/span&gt;&lt;span class="sh"&gt;"&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;S&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  -&lt;/span&gt;&lt;span class="sh"&gt;"&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="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;[^&amp;gt;]+&amp;gt;&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="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it. If you are not on Blogspot, the same idea works with any sitemap and a loop over your &lt;code&gt;&amp;lt;h2&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;

&lt;p&gt;If you want the full version, with the technical checks and the scoring, I put the whole thing into a checklist:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://abrahman2.gumroad.com/l/ai-search-readiness-checklist" rel="noopener noreferrer"&gt;Free AI Search Readiness Checklist (20 pages, no email gate) →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And if you want the complete system — the 238-page handbook, the audit script, the schema templates and the scoring workbook:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://abrahman2.gumroad.com/l/structured-for-answers" rel="noopener noreferrer"&gt;Structured for Answers: the full AI Search &amp;amp; SEO Vault →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I still do not know
&lt;/h2&gt;

&lt;p&gt;Three things I want to be clear about, because the numbers above are easy to over-read.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I have not measured whether question headings increase citations.&lt;/strong&gt; I changed mine and I am watching. I do not have before-and-after data yet. The reasoning is sound and the mechanism is visible, but reasoning is not evidence, and I would rather say so than dress up a hypothesis as a result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thirteen posts is a small sample.&lt;/strong&gt; One blog, one niche, one author. It is a case study, not a study.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The heading count may not matter at all on its own.&lt;/strong&gt; It could be that question headings matter only when the content underneath them is genuinely good. My content was fine and my headings were not, which is a very specific starting condition. Yours may be the reverse.&lt;/p&gt;

&lt;p&gt;If you run the same audit on your own blog, I would like to see the number. Drop your question-heading percentage in the comments. I will collect them and publish the range, whatever it turns out to be.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I write about AI search and what actually moves citations, mostly by testing things on my own sites and publishing the numbers either way. The longer guides live at &lt;a href="https://arhashirbooks.blogspot.com" rel="noopener noreferrer"&gt;arhashirbooks.blogspot.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>blog</category>
      <category>seo</category>
    </item>
    <item>
      <title>AI Crawler Access: I Tested 11 Top SEO Sites. None Block.</title>
      <dc:creator>A.R. Hashir</dc:creator>
      <pubDate>Fri, 06 Nov 2026 16:17:00 +0000</pubDate>
      <link>https://dev.to/arhashir/ai-crawler-access-i-tested-11-top-seo-sites-none-block-1ch7</link>
      <guid>https://dev.to/arhashir/ai-crawler-access-i-tested-11-top-seo-sites-none-block-1ch7</guid>
      <description>&lt;p&gt;Almost every guide about getting cited by AI opens the same way.&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;robots.txt&lt;/code&gt; is blocking GPTBot. Your CDN is returning 403 to Perplexity. Fix that before you do anything else.&lt;/p&gt;

&lt;p&gt;I wanted to know whether that was actually true. So I ran the test against eleven sites that already rank well and already show up in AI answers: Ahrefs, Moz, Semrush, Search Engine Journal, Screaming Frog, Stripe, Shopify, GitHub, Cloudflare, Dev.to, and Vercel.&lt;/p&gt;

&lt;p&gt;I expected to find a few of them blocking. Maybe the big ones, protecting content behind a wall.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not one of them was.&lt;/strong&gt; Zero out of eleven. And the third finding was the one that actually surprised me.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four crawlers people keep confusing
&lt;/h2&gt;

&lt;p&gt;Before the results, one clarification, because most of the bad advice online comes from people mixing these up. They are not the same thing and they do very different jobs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;User agent&lt;/th&gt;
&lt;th&gt;Who runs it&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GPTBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;Trains models. Being blocked here does not stop ChatGPT from citing you.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OAI-SearchBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;Indexes pages for ChatGPT &lt;strong&gt;search&lt;/strong&gt;. This is the one that decides citations.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ChatGPT-User&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;Fetches a single page when a user pastes a URL or asks a live question.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PerplexityBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Perplexity&lt;/td&gt;
&lt;td&gt;Indexes and cites.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ClaudeBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;Crawls for Claude.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Google-Extended&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;td&gt;Controls Gemini training and grounding. &lt;strong&gt;Does not control AI Overviews.&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CCBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Common Crawl&lt;/td&gt;
&lt;td&gt;Public web archive used by many downstream models.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The one that matters most for getting cited is &lt;code&gt;OAI-SearchBot&lt;/code&gt;, and it is the one almost nobody mentions. Everyone writes about &lt;code&gt;GPTBot&lt;/code&gt;, which mostly affects training, not citations.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the test works
&lt;/h2&gt;

&lt;p&gt;Two checks per site. Both take under a minute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check one — what does robots.txt say?&lt;/strong&gt;&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/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;"gptbot|oai-searchbot|perplexitybot|claudebot|google-extended|ccbot"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get output with &lt;code&gt;Disallow: /&lt;/code&gt; under a bot's name, that bot is blocked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check two — what happens when the crawler actually shows up?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This one matters more, because &lt;code&gt;robots.txt&lt;/code&gt; is a polite request. A CDN, a WAF, or a bot-management toggle can ignore it completely and return 403 to anything it does not like. Many managed hosts do exactly this without telling you.&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;"GPTBot/1.2"&lt;/span&gt; &lt;span class="s2"&gt;"OAI-SearchBot/1.0"&lt;/span&gt; &lt;span class="s2"&gt;"PerplexityBot/1.0"&lt;/span&gt; &lt;span class="s2"&gt;"ClaudeBot/1.0"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&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;
  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; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"Mozilla/5.0 (compatible; &lt;/span&gt;&lt;span class="nv"&gt;$ua&lt;/span&gt;&lt;span class="s2"&gt;; +https://example.com)"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    https://example.com
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;200&lt;/code&gt; means the crawler gets in. A &lt;code&gt;403&lt;/code&gt; means it gets the door slammed in its face, no matter what robots.txt promised.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 1: nothing is blocked. Nothing.
&lt;/h2&gt;

&lt;p&gt;Eleven out of eleven sites allow GPTBot, OAI-SearchBot, PerplexityBot, ClaudeBot, Google-Extended, and CCBot. All of them, all six, no exceptions. No wildcard &lt;code&gt;Disallow: /&lt;/code&gt; anywhere.&lt;/p&gt;

&lt;p&gt;Then I sent each AI user agent to each home page. Every single combination came back HTTP 200.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Domain&lt;/th&gt;
&lt;th&gt;robots.txt&lt;/th&gt;
&lt;th&gt;GPTBot&lt;/th&gt;
&lt;th&gt;OAI-SearchBot&lt;/th&gt;
&lt;th&gt;PerplexityBot&lt;/th&gt;
&lt;th&gt;ClaudeBot&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ahrefs.com&lt;/td&gt;
&lt;td&gt;allow all&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;moz.com&lt;/td&gt;
&lt;td&gt;allow all&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;semrush.com&lt;/td&gt;
&lt;td&gt;allow all&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;searchenginejournal.com&lt;/td&gt;
&lt;td&gt;allow all&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;screamingfrog.co.uk&lt;/td&gt;
&lt;td&gt;allow all&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stripe.com&lt;/td&gt;
&lt;td&gt;allow all&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;shopify.com&lt;/td&gt;
&lt;td&gt;allow all&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;github.com&lt;/td&gt;
&lt;td&gt;allow all&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cloudflare.com&lt;/td&gt;
&lt;td&gt;allow all&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dev.to&lt;/td&gt;
&lt;td&gt;allow all&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;vercel.com&lt;/td&gt;
&lt;td&gt;allow all&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Fifty-five requests. Fifty-five &lt;code&gt;200&lt;/code&gt;s. Not a single &lt;code&gt;403&lt;/code&gt;, not a single challenge page, not a single rate limit.&lt;/p&gt;

&lt;p&gt;I want to be careful about what this proves. These are established sites with engineering teams who have looked at this question. It does not mean &lt;em&gt;your&lt;/em&gt; host is fine. Custom CDN rules, security plugins, and "block bad bots" toggles are exactly where this breaks, and they break silently. That is why the ninety-second check is still worth running on your own domain.&lt;/p&gt;

&lt;p&gt;But it does mean the blanket warning is wrong. The default state of the modern web is permissive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 2: eight of eleven publish an llms.txt
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;llms.txt&lt;/code&gt; is a plain text file at &lt;code&gt;yourdomain.com/llms.txt&lt;/code&gt;. It is not an official standard. No crawler is required to read it. It is just a short Markdown summary of what your site is, what it covers, and where the important pages live.&lt;/p&gt;

&lt;p&gt;Eight of the eleven serve one:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Domain&lt;/th&gt;
&lt;th&gt;llms.txt&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cloudflare&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;17 KB (plus a 169 KB full version)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stripe&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;69.8 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;28.6 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Semrush&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;14.9 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shopify&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;12.5 KB (plus 18.8 KB full version)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vercel&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;5.4 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dev.to&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;2.8 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ahrefs&lt;/td&gt;
&lt;td&gt;❌ 404&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Screaming Frog&lt;/td&gt;
&lt;td&gt;❌ 404&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moz&lt;/td&gt;
&lt;td&gt;❌ 403 on that path&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here is what they actually say, in their own words:&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;# Stripe&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; Stripe is a technology company that provides financial infrastructure&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; for businesses to accept payments, grow revenue, and access capital.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# GitHub&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; GitHub is a developer platform for building, shipping, and maintaining&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; software.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Cloudflare&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; Cloudflare is a global cloud connectivity company operating in 335+ cities.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# DEV Community&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; A Forem community where people share knowledge and participate in&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; discussions.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Semrush&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; Semrush is a brand visibility management platform that helps marketers&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; audit and improve their online presence.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every single one follows the same shape. A &lt;code&gt;#&lt;/code&gt; heading with the company name. A &lt;code&gt;&amp;gt;&lt;/code&gt; blockquote with one or two sentences describing what the company does. Then a list of links.&lt;/p&gt;

&lt;p&gt;That is the whole format. No schema, no JavaScript, no build step, no plugin.&lt;/p&gt;

&lt;p&gt;Look at what those sentences have in common. &lt;em&gt;Technology company that provides financial infrastructure. Developer platform for building software. Global cloud connectivity company. Brand visibility management platform.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Not one of them says "we empower businesses to unlock their potential." They say what the company &lt;strong&gt;is&lt;/strong&gt;, in a sentence a stranger can repeat back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 3: the uncomfortable one
&lt;/h2&gt;

&lt;p&gt;If access is not the bottleneck — and it clearly is not, at least among sites that are already succeeding — then something else decides who gets cited.&lt;/p&gt;

&lt;p&gt;Look at the eight that publish an &lt;code&gt;llms.txt&lt;/code&gt;. It is not that they are big. Ahrefs is big and does not have one. It is not that they are technical. It is that all eight wrote down, in one place, in plain sentences, what they are and what they do.&lt;/p&gt;

&lt;p&gt;The newest ones treat it as a product decision, not an SEO trick. Stripe's file is 69 kilobytes of clear statements about what Stripe is, who it is for, and where each piece of documentation lives. That is a business writing down its own facts in public.&lt;/p&gt;

&lt;p&gt;Which brings up the part most guides skip.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can allow every crawler in the world and still get ignored.&lt;/strong&gt; The crawler arrives, reads your page, and finds a sentence that says "we help businesses unlock their potential." That is not a fact a retrieval system can extract. It is a slogan, and slogans are noise.&lt;/p&gt;

&lt;p&gt;Access is a checkbox you can fix once. Clarity is the work, and it never ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crawled is not the same as indexed
&lt;/h2&gt;

&lt;p&gt;One more distinction this test does not cover, and it trips up a lot of people.&lt;/p&gt;

&lt;p&gt;Every site above returned &lt;code&gt;200&lt;/code&gt;. That proves the crawler got in the front door. It does &lt;strong&gt;not&lt;/strong&gt; prove the page ended up in an index. Getting crawled and getting indexed are two separate events, and the second one can fail for reasons that have nothing to do with access.&lt;/p&gt;

&lt;p&gt;Search Console has a status for exactly this: &lt;strong&gt;Crawled – currently not indexed.&lt;/strong&gt; It means Google fetched the page and then decided not to store it. Nothing was blocked. No 403, no &lt;code&gt;robots.txt&lt;/code&gt; rule, no permission problem. The page simply was not considered worth indexing.&lt;/p&gt;

&lt;p&gt;That is a different problem, with a different fix, and it comes up constantly on Blogger, where the same article is reachable at &lt;code&gt;?m=1&lt;/code&gt;, with UTM parameters, and through feed URLs, and canonical selection gets messy.&lt;/p&gt;

&lt;p&gt;I wrote a separate walkthrough for that specific situation, because it is not something crawler access testing can answer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://arhashirbooks.blogspot.com/2026/11/crawled-currently-not-indexed-blogger.html" rel="noopener noreferrer"&gt;Crawled – Currently Not Indexed on Blogger: What to Check (2026) →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The order matters. Check access first, using the commands in this post. Then check canonical selection. Then look at the page itself. Fixing indexing before you have fixed access is wasted effort, because you cannot index what a crawler cannot fetch.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this test does not prove
&lt;/h2&gt;

&lt;p&gt;Three honest limitations, because the data is only worth as much as its caveats.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The sample is small and biased.&lt;/strong&gt; Eleven sites, all of them already established, all of them English-language. A startup site on a cheap shared host with an unknown security plugin may behave completely differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Home pages are not content pages.&lt;/strong&gt; I tested the root domain. Individual article pages can have different rules, and article pages are the ones that get cited.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;llms.txt&lt;/code&gt; has no measured effect here.&lt;/strong&gt; I did not test whether the eight sites with &lt;code&gt;llms.txt&lt;/code&gt; get cited more often. I did not test whether the three without get cited less. That correlation would need far more data. What I can say is that eight of eleven chose to publish one, and all of them are free to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would check, in this order
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Actually run the two commands above.&lt;/strong&gt; Do not assume. Most managed hosts allow everything by default, but custom CDN rules and bot-management toggles quietly break this. Ninety seconds, and it either clears the question or finds a real problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Write an llms.txt.&lt;/strong&gt; Upload it to your root. One heading, one blockquote, a short list of your most important pages with plain descriptions. Twenty minutes.&lt;/p&gt;

&lt;p&gt;Here is a template you can copy, fill in, and upload:&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;# Your Company&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; One sentence. What you are, who it is for, what you sell.&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Write it so a stranger could repeat it back.&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;Home&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: what the product does
&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;: plans and costs
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Docs&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/docs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: how to use it

&lt;span class="gu"&gt;## About&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Company&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;: who we are
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Contact&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://example.com/contact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: how to reach us
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace every placeholder with a real sentence about your own site. Save as &lt;code&gt;llms.txt&lt;/code&gt;, upload to your domain root, confirm it loads at &lt;code&gt;yourdomain.com/llms.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Read your own home page as if you were a stranger who knows nothing about you.&lt;/strong&gt; Can you find, in plain sentences: what this is, who it is for, what it costs, and where to go next? If those four facts are buried under adjectives, no crawler permission will save you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Test a content page, not just your home page.&lt;/strong&gt; Pick your best article or product page and run the same two commands on it. That is where citations actually come from.&lt;/p&gt;

&lt;p&gt;I turned all of this into a scored checklist with the exact commands and a 100-point breakdown. It is free and there is no email gate before the download:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://abrahman2.gumroad.com/l/ai-search-readiness-checklist" rel="noopener noreferrer"&gt;AI Search Readiness Checklist →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One last thing
&lt;/h2&gt;

&lt;p&gt;I would genuinely like to know if anyone finds a site that &lt;em&gt;does&lt;/em&gt; block. Eleven out of eleven is a small sample, and I would rather my conclusion be wrong in public than quietly wrong in private.&lt;/p&gt;

&lt;p&gt;Drop the domain in the comments and I will add it to the table. If someone finds twenty sites that block, the whole premise of this post changes, and I would want to know.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>seo</category>
      <category>marketing</category>
    </item>
    <item>
      <title>The AI Search Audit: 8 Checks, 100 Points, One Script</title>
      <dc:creator>A.R. Hashir</dc:creator>
      <pubDate>Sat, 24 Oct 2026 11:03:18 +0000</pubDate>
      <link>https://dev.to/arhashir/the-ai-search-audit-8-checks-100-points-one-script-18jp</link>
      <guid>https://dev.to/arhashir/the-ai-search-audit-8-checks-100-points-one-script-18jp</guid>
      <description>&lt;p&gt;Your analytics flattened in March. Organic clicks are down 30%, then 40%. You shipped nothing wrong. Rankings look stable. The traffic just isn't arriving.&lt;/p&gt;

&lt;p&gt;Here is what most teams do next: they buy a "GEO audit," add more schema, publish more content. Six months later the numbers are worse and nobody can point at a single decision that caused it.&lt;/p&gt;

&lt;p&gt;The reason is almost never the thing being optimized. It's that three technical gates were failing the entire time, and every downstream fix was being applied to a page that a crawler could not fully read.&lt;/p&gt;

&lt;p&gt;This is a scored audit for finding that. Eight categories, 100 points, and one script that runs most of it in about thirty seconds.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this got harder in 2026, in numbers
&lt;/h2&gt;

&lt;p&gt;Three data points worth internalizing before the checklist:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;68% of Google searches now end without a click.&lt;/strong&gt; That is up from roughly 45% a decade ago. Search volume is at an all-time high and still growing — the capture rate collapsed, not the demand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When an AI Overview appears, click-through drops by about 61%.&lt;/strong&gt; AI Overviews trigger on a growing share of informational queries. The top organic result still exists; people just stop there less often.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Only 8% of visits click a traditional result when an AI summary is present, versus 15% when it isn't.&lt;/strong&gt; Users read the summary. They click the citation occasionally. They click the blue link rarely.&lt;/p&gt;

&lt;p&gt;One number moves in the opposite direction, and it's the one that matters for this audit: &lt;strong&gt;AI-referred visitors convert at roughly 3x the rate of traditional organic traffic.&lt;/strong&gt; Similarweb measured ChatGPT-referred sessions at about 15 minutes versus 8 for Google.&lt;/p&gt;

&lt;p&gt;So the shape of the opportunity changed. Fewer clicks, better clicks. Which means eligibility is now worth more than volume — a page that can be retrieved and cited is worth several that cannot.&lt;/p&gt;

&lt;p&gt;That reframes the work. You are not chasing rankings. You are making your content &lt;strong&gt;retrievable, quotable, and unambiguous&lt;/strong&gt;. That's a technical problem before it's a writing problem, and it's the subject of this audit.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 40/60 rule: why most audits start in the wrong place
&lt;/h2&gt;

&lt;p&gt;Here is the single most useful thing in this article.&lt;/p&gt;

&lt;p&gt;The eight categories below are not weighted equally, and two of them are &lt;strong&gt;blocking&lt;/strong&gt;. If Categories 1 and 2 fail, the other six are decoration.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Points&lt;/th&gt;
&lt;th&gt;Blocking&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;01&lt;/td&gt;
&lt;td&gt;Crawlability&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;02&lt;/td&gt;
&lt;td&gt;Renderability&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;03&lt;/td&gt;
&lt;td&gt;Entity clarity&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;04&lt;/td&gt;
&lt;td&gt;Structured data&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;05&lt;/td&gt;
&lt;td&gt;Content chunking&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;06&lt;/td&gt;
&lt;td&gt;Freshness &amp;amp; trust&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;07&lt;/td&gt;
&lt;td&gt;Answer formatting&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;08&lt;/td&gt;
&lt;td&gt;Measurement&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Categories 01 and 02 are 40% of the score and they gate everything downstream. &lt;strong&gt;If those two come in under 32 out of 40, stop. Fix rendering and robots.txt this week. Do not spend a single hour on schema.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I have watched teams spend a quarter perfecting &lt;code&gt;sameAs&lt;/code&gt; arrays and entity graphs while their documentation body copy was assembled in the browser after hydration. The audit spreadsheet looked excellent. The crawler was receiving an empty shell.&lt;/p&gt;

&lt;p&gt;That is the 40/60 rule. Apply it before you read further.&lt;/p&gt;




&lt;h2&gt;
  
  
  Category 01 — Crawlability (20 points)
&lt;/h2&gt;

&lt;p&gt;Can a non-browser client reach and read your URLs at all? This is binary, and everything else is downstream of it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Pts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;robots.txt&lt;/code&gt; returns HTTP 200 and contains no wildcard &lt;code&gt;Disallow: /&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;OAI-SearchBot&lt;/code&gt; explicitly allowed (or deliberately blocked, and documented)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Googlebot&lt;/code&gt; allowed on every route that matters&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;PerplexityBot&lt;/code&gt; explicitly allowed (or deliberately blocked)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Bingbot&lt;/code&gt; allowed — Copilot grounding depends on the Bing index&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sitemap exists at &lt;code&gt;/sitemap.xml&lt;/code&gt; and is referenced from &lt;code&gt;robots.txt&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sitemap contains only canonical, indexable, 200-status URLs&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No WAF, bot challenge or CDN rule returns 403/429/503 to AI user agents&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The silent failure that costs entire channels
&lt;/h3&gt;

&lt;p&gt;A CDN default that 403s &lt;code&gt;PerplexityBot&lt;/code&gt; costs you the whole channel and produces zero errors anywhere. No deploy, no alert, no log line you'll notice. This is the most common cause of "we optimized for AI search and nothing happened."&lt;/p&gt;

&lt;p&gt;Four lines of shell settles it:&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;"GPTBot/1.1"&lt;/span&gt; &lt;span class="s2"&gt;"OAI-SearchBot/1.0"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="s2"&gt;"PerplexityBot/1.0"&lt;/span&gt; &lt;span class="s2"&gt;"ClaudeBot/1.0"&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="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"Mozilla/5.0 (compatible; &lt;/span&gt;&lt;span class="nv"&gt;$ua&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt; https://yoursite.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;Four &lt;code&gt;200&lt;/code&gt;s, or you have found your first problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  Know which crawler does what
&lt;/h3&gt;

&lt;p&gt;The robots.txt snippets circulating online are two years stale, and most conflate three different jobs into one decision. These are separate agents:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Operator&lt;/th&gt;
&lt;th&gt;Governs&lt;/th&gt;
&lt;th&gt;Worth blocking?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GPTBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;Model training&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;OAI-SearchBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;ChatGPT search citations&lt;/td&gt;
&lt;td&gt;Rarely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ChatGPT-User&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;OpenAI&lt;/td&gt;
&lt;td&gt;User-triggered live fetch&lt;/td&gt;
&lt;td&gt;Rarely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ClaudeBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;Training + crawling&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Claude-SearchBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Anthropic&lt;/td&gt;
&lt;td&gt;Search grounding&lt;/td&gt;
&lt;td&gt;Rarely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PerplexityBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Perplexity&lt;/td&gt;
&lt;td&gt;Search index&lt;/td&gt;
&lt;td&gt;Rarely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Googlebot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;td&gt;Search + AI Overviews&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Never&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Google-Extended&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Google&lt;/td&gt;
&lt;td&gt;Gemini training only&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Bingbot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Microsoft&lt;/td&gt;
&lt;td&gt;Bing + Copilot grounding&lt;/td&gt;
&lt;td&gt;Rarely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CCBot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Common Crawl&lt;/td&gt;
&lt;td&gt;Upstream model data&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two corrections that change real decisions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Blocking &lt;code&gt;Google-Extended&lt;/code&gt; does not remove you from Google AI Overviews.&lt;/strong&gt; AI Overviews are served from the ordinary Google index, governed by &lt;code&gt;Googlebot&lt;/code&gt;. &lt;code&gt;Google-Extended&lt;/code&gt; only controls Gemini training.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Blocking &lt;code&gt;GPTBot&lt;/code&gt; does not remove you from ChatGPT search results.&lt;/strong&gt; Citations come from &lt;code&gt;OAI-SearchBot&lt;/code&gt;, and live URL fetches use &lt;code&gt;ChatGPT-User&lt;/code&gt;. Three separate entries, three separate decisions.&lt;/p&gt;

&lt;p&gt;A coherent default for most commercial sites is: &lt;strong&gt;block training, allow search.&lt;/strong&gt; That is defensible and, more importantly, deliberate rather than copied.&lt;/p&gt;




&lt;h2&gt;
  
  
  Category 02 — Renderability (20 points)
&lt;/h2&gt;

&lt;p&gt;Does the content exist in the delivered HTML, or does it appear only after JavaScript runs? This is where modern frameworks quietly lose 15 points.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Pts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary body copy present in raw HTML with JavaScript disabled&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;h1&lt;/code&gt;–&lt;code&gt;h3&lt;/code&gt; headings present in raw HTML&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internal links are real &lt;code&gt;&amp;lt;a href&amp;gt;&lt;/code&gt; elements in raw HTML&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON-LD present in raw HTML, not injected after hydration&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content survives &lt;code&gt;curl&lt;/code&gt; at 80%+ of the rendered word count&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# raw word count, tags stripped&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://yoursite.com/page | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;[^&amp;gt;]*&amp;gt;//g'&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare that against what the browser shows. Within 10% is fine. A 30% gap is a widget. &lt;strong&gt;A 3x gap means your content does not exist as far as retrieval is concerned&lt;/strong&gt; — no matter how clean your markup is.&lt;/p&gt;

&lt;h3&gt;
  
  
  The hydration trap
&lt;/h3&gt;

&lt;p&gt;This is the pattern that silently fails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ invisible to most AI crawlers&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/ld+json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&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="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is the fix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ present in the raw HTML response&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jsonLd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/ld+json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jsonLd&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify it in the only place that counts — not DevTools:&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://yoursite.com/page | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'application/ld+json'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;0&lt;/code&gt; means everything downstream of this section is theoretical.&lt;/p&gt;

&lt;p&gt;The practical answer is SSR, SSG, or ISR for every content route. Client-side rendering belongs to application state, not to published content.&lt;/p&gt;




&lt;h2&gt;
  
  
  Category 03 — Entity clarity (18 points)
&lt;/h2&gt;

&lt;p&gt;Retrieval systems resolve entities, not pages. Can a machine work out who you are, unambiguously, from any page on the site?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Pts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Exactly one &lt;code&gt;Organization&lt;/code&gt; (or &lt;code&gt;Person&lt;/code&gt;) node per page, consistent across pages&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;@id&lt;/code&gt; values used and cross-referenced between nodes&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;sameAs&lt;/code&gt; lists 3–8 live, populated profiles (no 404s, no empty accounts)&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same entity name in &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;, &lt;code&gt;og:title&lt;/code&gt;, JSON-LD and visible body copy&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Organization node has a resolvable &lt;code&gt;logo&lt;/code&gt; ImageObject at an absolute URL&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No duplicate or conflicting entity blocks from competing plugins&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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://yoursite.com/ | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'"@type":"Organization"'&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;span class="c"&gt;# expected: 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A return of &lt;code&gt;2&lt;/code&gt; means a plugin and a theme are both emitting an organization with different names or URLs. To a reconciling system that is two companies, and consolidation fails silently — no error, no warning, no dashboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On &lt;code&gt;sameAs&lt;/code&gt; discipline:&lt;/strong&gt; every URL must return 200 and carry real content. A dead profile is worse than no profile, because you asserted a fact that then failed verification. Three to eight links is the useful range. Forty reads as manipulation and gets discounted.&lt;/p&gt;




&lt;h2&gt;
  
  
  Category 04 — Structured data (15 points)
&lt;/h2&gt;

&lt;p&gt;Validators check shape. They do not check meaning, recency, or whether the markup agrees with the page. That gap is where these 15 points live.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Pts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Every JSON-LD block parses with zero syntax errors on priority URLs&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;datePublished&lt;/code&gt; / &lt;code&gt;dateModified&lt;/code&gt; in ISO 8601&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Visible page content matches every claim the markup makes&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;@type&lt;/code&gt; values correctly cased (&lt;code&gt;WebPage&lt;/code&gt;, not &lt;code&gt;Webpage&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All &lt;code&gt;image&lt;/code&gt; values are absolute &lt;code&gt;https://&lt;/code&gt; URLs&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;FAQPage&lt;/code&gt; uses nested &lt;code&gt;Question&lt;/code&gt; → &lt;code&gt;acceptedAnswer&lt;/code&gt; → &lt;code&gt;Answer&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Values that parse but degrade output
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Common value&lt;/th&gt;
&lt;th&gt;Correct value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;datePublished&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Oct 24, 2026&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2026-10-24&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/cover.png&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://yoursite.com/cover.png&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Webpage&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;WebPage&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;`Brand \&lt;/td&gt;
&lt;td&gt;Best Tools 2026`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;400-character paragraph&lt;/td&gt;
&lt;td&gt;150–160 chars, one sentence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;"Oct 24, 2026"&lt;/code&gt; is ambiguous enough that some parsers drop the field entirely, and &lt;code&gt;dateModified&lt;/code&gt; is one of the few freshness signals you fully control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The row people skip is row three.&lt;/strong&gt; If your markup asserts an answer the page does not visibly give, you have manufactured a confident wrong answer attributed to your brand. That is worse than silence, because it will be quoted.&lt;/p&gt;

&lt;p&gt;And one tool used for the wrong job: &lt;strong&gt;the Rich Results Test validates syntax. Syntax was never the failure mode.&lt;/strong&gt; Use it as a lint step, not a diagnosis.&lt;/p&gt;




&lt;h2&gt;
  
  
  Category 05 — Content chunking (12 points)
&lt;/h2&gt;

&lt;p&gt;Retrieval does not read your page top to bottom. It splits the page along heading and paragraph boundaries, embeds each piece, and fetches whichever pieces match. &lt;strong&gt;Write for the piece.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Pts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Each H2 section is self-contained and makes sense in isolation&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Each section opens with a direct answer in the first one or two sentences&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No context-dependent openers ("as mentioned above", a bare "this")&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paragraphs under roughly 120 words&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Key claims exist as text, not only inside images&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The isolation test
&lt;/h3&gt;

&lt;p&gt;Copy a single H2 section into a fresh chat with no surrounding page. If it makes sense and answers something, it survives chunking. If it opens with a pronoun pointing three sections up, it does not — and that chunk will never be retrieved no matter how good the page is as a whole.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Survives&lt;/th&gt;
&lt;th&gt;Does not&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Opening&lt;/td&gt;
&lt;td&gt;"JSON-LD works by placing a self-contained entity graph…"&lt;/td&gt;
&lt;td&gt;"It works by wrapping the entity, as mentioned above…"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope&lt;/td&gt;
&lt;td&gt;Names the subject in the first clause&lt;/td&gt;
&lt;td&gt;Relies on the H1 for context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Length&lt;/td&gt;
&lt;td&gt;One idea, under 120 words&lt;/td&gt;
&lt;td&gt;Four ideas in one 300-word block&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This category costs nothing to fix and is the one most often skipped. It is a writing-discipline change, not an engineering one — no deploy, no ticket, no framework upgrade.&lt;/p&gt;




&lt;h2&gt;
  
  
  Category 06 — Freshness &amp;amp; trust (8 points)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Pts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Long-lived pages show a visible "last updated" date&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;dateModified&lt;/code&gt; reflects real edits, not a mechanical bump&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Author or organization attribution visible on-page&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fact-heavy sections cite external sources with working links&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nothing material is stale in a fast-moving topic&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A 2023 page about 2026 crawler behaviour is not merely unranked — it gets retrieved, and it is wrong. Archive or update. Do not leave it up hoping.&lt;/p&gt;




&lt;h2&gt;
  
  
  Category 07 — Answer formatting (5 points)
&lt;/h2&gt;

&lt;p&gt;Deliberately the lowest-weighted category, because it is the easiest and everyone does it first.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Pts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Summary or TL;DR block near the top of long pages&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Comparison tables for "X vs Y" queries&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Procedural content uses ordered steps&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Formatting makes content easy to extract, so it feels productive. It is worth 5 points and will not rescue a site scoring 20 on the first two categories.&lt;/p&gt;




&lt;h2&gt;
  
  
  Category 08 — Measurement (2 points)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Pts&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Server logs accessible, AI crawler user agents filterable&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Five target questions probed weekly across ChatGPT, Perplexity and Google&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&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|ClaudeBot|PerplexityBot"&lt;/span&gt; &lt;span class="se"&gt;\&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things fall out in ninety seconds: whether these crawlers visit at all, which URLs they actually pull, and whether they receive 200 or bounce off a 403. If the answer to the first is no, the rest of your plan is theoretical.&lt;/p&gt;




&lt;h2&gt;
  
  
  The whole audit in one script
&lt;/h2&gt;

&lt;p&gt;Here is every automatable check above, in a single file. Save it as &lt;code&gt;audit.sh&lt;/code&gt;, make it executable, and pass one URL.&lt;/p&gt;

&lt;p&gt;It does not cover Categories 03 through 07 completely — those need human judgment — but it will find the blocking failures, which is where you should start.&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;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# ai-search-audit.sh — blocking checks only&lt;/span&gt;
&lt;span class="c"&gt;# usage: ./audit.sh https://yoursite.com/page&lt;/span&gt;

&lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?usage:&lt;span class="p"&gt; ./audit.sh &amp;lt;url&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&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#(https?://[^/]+).*#\1#'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;PASS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;FAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

ok&lt;span class="o"&gt;()&lt;/span&gt;   &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  PASS  &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;PASS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;PASS+1&lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
bad&lt;span class="o"&gt;()&lt;/span&gt;  &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  FAIL  &lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;FAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;FAIL+1&lt;span class="k"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"== 01 CRAWLABILITY =="&lt;/span&gt;

&lt;span class="nv"&gt;ROBOTS&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="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;/robots.txt"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ROBOTS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"200"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ok &lt;span class="s2"&gt;"robots.txt returns 200"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                      &lt;span class="o"&gt;||&lt;/span&gt; bad &lt;span class="s2"&gt;"robots.txt returned &lt;/span&gt;&lt;span class="nv"&gt;$ROBOTS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;/robots.txt"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qiE&lt;/span&gt; &lt;span class="s1"&gt;'^Disallow: *\*? *$|^Disallow: */$'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;bad &lt;span class="s2"&gt;"robots.txt contains a wildcard Disallow"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;ok &lt;span class="s2"&gt;"no wildcard Disallow in robots.txt"&lt;/span&gt;
&lt;span class="k"&gt;fi

for &lt;/span&gt;ua &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"GPTBot/1.1"&lt;/span&gt; &lt;span class="s2"&gt;"OAI-SearchBot/1.0"&lt;/span&gt; &lt;span class="s2"&gt;"PerplexityBot/1.0"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
          &lt;span class="s2"&gt;"ClaudeBot/1.0"&lt;/span&gt; &lt;span class="s2"&gt;"Googlebot/2.1"&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="se"&gt;\&lt;/span&gt;
          &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"Mozilla/5.0 (compatible; &lt;/span&gt;&lt;span class="nv"&gt;$ua&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;%%/*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"200"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then &lt;/span&gt;ok &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt; reaches the page (200)"&lt;/span&gt;
  &lt;span class="k"&gt;else &lt;/span&gt;bad &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt; got &lt;/span&gt;&lt;span class="nv"&gt;$code&lt;/span&gt;&lt;span class="s2"&gt; — blocked by WAF/CDN?"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi
done

&lt;/span&gt;&lt;span class="nv"&gt;SM&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="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BASE&lt;/span&gt;&lt;span class="s2"&gt;/sitemap.xml"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SM&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"200"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ok &lt;span class="s2"&gt;"sitemap.xml returns 200"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                  &lt;span class="o"&gt;||&lt;/span&gt; bad &lt;span class="s2"&gt;"sitemap.xml returned &lt;/span&gt;&lt;span class="nv"&gt;$SM&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo
echo&lt;/span&gt; &lt;span class="s2"&gt;"== 02 RENDERABILITY =="&lt;/span&gt;

&lt;span class="nv"&gt;RAW&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="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;RAW_WORDS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RAW&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/&amp;lt;[^&amp;gt;]*&amp;gt;//g'&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RAW_WORDS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-ge&lt;/span&gt; 300 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ok &lt;span class="s2"&gt;"raw HTML has &lt;/span&gt;&lt;span class="nv"&gt;$RAW_WORDS&lt;/span&gt;&lt;span class="s2"&gt; words"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                         &lt;span class="o"&gt;||&lt;/span&gt; bad &lt;span class="s2"&gt;"raw HTML has only &lt;/span&gt;&lt;span class="nv"&gt;$RAW_WORDS&lt;/span&gt;&lt;span class="s2"&gt; words — JS-rendered?"&lt;/span&gt;

&lt;span class="nv"&gt;LD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RAW&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'application/ld+json'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-ge&lt;/span&gt; 1 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ok &lt;span class="s2"&gt;"JSON-LD present in raw HTML (&lt;/span&gt;&lt;span class="nv"&gt;$LD&lt;/span&gt;&lt;span class="s2"&gt; block(s))"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="o"&gt;||&lt;/span&gt; bad &lt;span class="s2"&gt;"no JSON-LD in raw HTML — injected after hydration?"&lt;/span&gt;

&lt;span class="nv"&gt;H1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RAW&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;h1'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$H1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-ge&lt;/span&gt; 1 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ok &lt;span class="s2"&gt;"h1 present in raw HTML"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                &lt;span class="o"&gt;||&lt;/span&gt; bad &lt;span class="s2"&gt;"no h1 in raw HTML"&lt;/span&gt;

&lt;span class="nv"&gt;LINKS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RAW&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'href="http'&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LINKS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-ge&lt;/span&gt; 5 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ok &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LINKS&lt;/span&gt;&lt;span class="s2"&gt; absolute internal/external links in raw HTML"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                   &lt;span class="o"&gt;||&lt;/span&gt; bad &lt;span class="s2"&gt;"only &lt;/span&gt;&lt;span class="nv"&gt;$LINKS&lt;/span&gt;&lt;span class="s2"&gt; links in raw HTML"&lt;/span&gt;

&lt;span class="nb"&gt;echo
echo&lt;/span&gt; &lt;span class="s2"&gt;"== 04 STRUCTURED DATA (syntax) =="&lt;/span&gt;

&lt;span class="nv"&gt;ORG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RAW&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'"@type":"Organization"'&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ORG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 1 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then &lt;/span&gt;ok &lt;span class="s2"&gt;"exactly one Organization node"&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ORG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then &lt;/span&gt;bad &lt;span class="s2"&gt;"no Organization node found"&lt;/span&gt;
&lt;span class="k"&gt;else &lt;/span&gt;bad &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ORG&lt;/span&gt;&lt;span class="s2"&gt; Organization nodes — duplicate entity data"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RAW&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qE&lt;/span&gt; &lt;span class="s1"&gt;'"date[A-Za-z]+":"[0-9]{4}-[0-9]{2}-[0-9]{2}"'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ok &lt;span class="s2"&gt;"ISO 8601 dates present"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; bad &lt;span class="s2"&gt;"no ISO 8601 date fields detected"&lt;/span&gt;

&lt;span class="nb"&gt;echo
echo&lt;/span&gt; &lt;span class="s2"&gt;"== RESULT =="&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  passed: &lt;/span&gt;&lt;span class="nv"&gt;$PASS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  failed: &lt;/span&gt;&lt;span class="nv"&gt;$FAIL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FAIL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  blocking categories look clear."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
                  &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  fix the FAILs above before touching schema."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it. If anything prints &lt;code&gt;FAIL&lt;/code&gt; in the first two sections, you have your work order for the week and the other six categories can wait.&lt;/p&gt;




&lt;h2&gt;
  
  
  Your score sheet
&lt;/h2&gt;

&lt;p&gt;Fill this in after running the script and scoring the human-judgment rows.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Max&lt;/th&gt;
&lt;th&gt;Yours&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;01 · Crawlability&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;02 · Renderability&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;03 · Entity clarity&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;04 · Structured data&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;05 · Content chunking&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;06 · Freshness &amp;amp; trust&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;07 · Answer formatting&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;08 · Measurement&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TOTAL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What your score means
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;85–100&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Eligible. Remaining gap is content quality, not technical&lt;/td&gt;
&lt;td&gt;Stop auditing. Write better pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;60–84&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Partially eligible. Citations will be inconsistent&lt;/td&gt;
&lt;td&gt;Close 01–02 first, then 03–04&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;35–59&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mostly invisible. Likely blocked, JS-only, or unparseable&lt;/td&gt;
&lt;td&gt;Everything else is wasted until 01–02 pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;0–34&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not reachable. Do not buy tooling yet&lt;/td&gt;
&lt;td&gt;Fix rendering and robots.txt this week&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Fastest wins, ranked by minutes-to-impact
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Typical points&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Unblock AI UAs in robots.txt / WAF&lt;/td&gt;
&lt;td&gt;15 min&lt;/td&gt;
&lt;td&gt;up to 8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ISO-format all dates&lt;/td&gt;
&lt;td&gt;20 min&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove &lt;code&gt;display:none&lt;/code&gt;-only body content&lt;/td&gt;
&lt;td&gt;30 min&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deduplicate Organization blocks&lt;/td&gt;
&lt;td&gt;45 min&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add an &lt;code&gt;@graph&lt;/code&gt; with &lt;code&gt;@id&lt;/code&gt; cross-references&lt;/td&gt;
&lt;td&gt;2 hrs&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSR/ISR the main content routes&lt;/td&gt;
&lt;td&gt;1–3 days&lt;/td&gt;
&lt;td&gt;up to 20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last row is the only expensive one, and it is also the only one that can move a site from "not reachable" to "eligible" on its own.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three things that do not do what you think
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. The Rich Results Test.&lt;/strong&gt; It validates syntax. Syntax was never the failure mode. Use it as a lint step before deploying, not as a diagnosis of why you are not cited.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. &lt;code&gt;llms.txt&lt;/code&gt;.&lt;/strong&gt; A proposal published in late 2024, not a standard, with no major AI provider having confirmed publicly that it reads the file. Adding one costs twenty minutes and breaks nothing. Treating it as the fix is a mistake. If someone tells you otherwise, ask which provider confirmed it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Adding more schema types.&lt;/strong&gt; If you already have a clean &lt;code&gt;Organization&lt;/code&gt; node and a correct &lt;code&gt;Article&lt;/code&gt; node and are still uncited, more types will not help. At that point the constraint is whether your content is the clearest available answer to a specific question — which is a writing problem, not a markup problem.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Does any of this guarantee I'll be cited?&lt;/strong&gt;&lt;br&gt;
No. It makes you eligible. Selection depends on whether your content is the clearest, most specific answer available for a given question. That is a writing problem, and no audit solves it for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do AI crawlers run JavaScript?&lt;/strong&gt;&lt;br&gt;
Mostly no, or unreliably. Googlebot renders. The rest generally fetch raw HTML. Build on the assumption that JS-only content does not exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I block GPTBot?&lt;/strong&gt;&lt;br&gt;
Decide per purpose, not wholesale. Blocking &lt;code&gt;GPTBot&lt;/code&gt; (training) does not affect ChatGPT search. Blocking &lt;code&gt;OAI-SearchBot&lt;/code&gt; does. Blocking &lt;code&gt;Google-Extended&lt;/code&gt; does not affect AI Overviews. Three separate decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is &lt;code&gt;llms.txt&lt;/code&gt; supported by anyone?&lt;/strong&gt;&lt;br&gt;
Not confirmed by any major provider as of writing. Harmless to add, wrong to rely on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How often do these crawlers revisit?&lt;/strong&gt;&lt;br&gt;
Popular, frequently updated pages within days. Low-traffic pages within weeks to months. Your own server logs are the only reliable answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What score should a small site target?&lt;/strong&gt;&lt;br&gt;
80+. Sites below 60 usually have one or two blocking issues, not a hundred small ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long until structured data shows an effect?&lt;/strong&gt;&lt;br&gt;
Recrawl cadence is the limiter, not the markup. Expect a quarter, not a week, and track server-log bot hits rather than inferring from traffic.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to do this week
&lt;/h2&gt;

&lt;p&gt;Score all eight categories honestly, without giving yourself the benefit of the doubt. "Probably fine" is a zero.&lt;/p&gt;

&lt;p&gt;If Categories 01 and 02 come in under 32, fix rendering and robots.txt before anything else. Deploy one &lt;code&gt;Organization&lt;/code&gt; graph and verify it with &lt;code&gt;curl&lt;/code&gt;, not with DevTools.&lt;/p&gt;

&lt;p&gt;Then write down five questions your site should be the answer to, and probe them weekly in ChatGPT, Perplexity and Google. Log which URL gets cited. Over a month, that log tells you more than any audit tool will.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you want this audit as a scored checklist you can actually fill in — 20 pages, all eight categories with every row and point value, plus three production-ready JSON-LD templates (&lt;code&gt;Organization&lt;/code&gt; + &lt;code&gt;WebSite&lt;/code&gt;, &lt;code&gt;Article&lt;/code&gt; + &lt;code&gt;Person&lt;/code&gt;, &lt;code&gt;FAQPage&lt;/code&gt;) wired with &lt;code&gt;@id&lt;/code&gt; cross-references — it's free: *&lt;/em&gt;&lt;a href="https://abrahman2.gumroad.com/l/ai-search-readiness-checklist" rel="noopener noreferrer"&gt;100-Point AI Search Readiness Checklist&lt;/a&gt;***&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And if you want the full build rather than the audit — the complete template set, the raw-vs-rendered diff tooling, the log-analysis queries, and the rewrite patterns for making each section survive chunking — that's the reference: *&lt;/em&gt;&lt;a href="https://abrahman2.gumroad.com/l/structured-for-answers" rel="noopener noreferrer"&gt;Structured for Answers →&lt;/a&gt;***&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Earlier in this series: &lt;a href="https://dev.to/arhashir/json-ld-for-ai-search-7-mistakes-that-block-citations-1ea6"&gt;JSON-LD for AI Search: 7 Mistakes That Block Citations&lt;/a&gt; — why valid markup can still leave you uncited.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>seo</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>JSON-LD for AI Search: 7 Mistakes That Block Citations</title>
      <dc:creator>A.R. Hashir</dc:creator>
      <pubDate>Sat, 24 Oct 2026 10:00:21 +0000</pubDate>
      <link>https://dev.to/arhashir/json-ld-for-ai-search-7-mistakes-that-block-citations-1ea6</link>
      <guid>https://dev.to/arhashir/json-ld-for-ai-search-7-mistakes-that-block-citations-1ea6</guid>
      <description>&lt;p&gt;Most structured data audits end the same way: the validator reports zero errors, the Rich Results Test passes, and six months later the site has still never appeared in a single ChatGPT or Perplexity answer.&lt;/p&gt;

&lt;p&gt;I have been through this on enough sites to say the uncomfortable part plainly — &lt;strong&gt;the problem is almost never syntax.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is that the JSON-LD describes &lt;em&gt;a page&lt;/em&gt; while the retrieval system is looking for &lt;em&gt;an entity&lt;/em&gt;. And it is that the page's actual content never reaches the crawler in the first place, so the markup is describing something that was never read.&lt;/p&gt;

&lt;p&gt;Seven failures, ordered by what they cost you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short version, if you read nothing else:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;WebPage&lt;/code&gt; is your only node, you described a container, not a publisher.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;sameAs&lt;/code&gt; is missing or points at a 404, the entity cannot be resolved.&lt;/li&gt;
&lt;li&gt;If your JSON-LD is injected after hydration, most AI crawlers never see it.&lt;/li&gt;
&lt;li&gt;If your body copy renders client-side, nothing else in this article matters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest of this is the long version of those four lines.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. You described the page, not the entity
&lt;/h2&gt;

&lt;p&gt;The default pattern is a single &lt;code&gt;WebPage&lt;/code&gt; block. That tells a machine "this is a page of type WebPage" — which is roughly as useful as telling it "this is a file."&lt;/p&gt;

&lt;p&gt;Retrieval and grounding systems need to resolve &lt;strong&gt;who you are&lt;/strong&gt;, not which tag wraps the URL. There is no path from &lt;code&gt;WebPage&lt;/code&gt; to a knowledge graph node, because nothing in that block claims to be a thing in the world.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WebPage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Analytics — Product Page"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acme.dev/product"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@graph"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Organization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acme.dev/#organization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Analytics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acme.dev/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"logo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ImageObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acme.dev/logo-512.png"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sameAs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/acme-analytics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"https://www.crunchbase.com/organization/acme-analytics"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SoftwareApplication"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acme.dev/product#app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Analytics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"applicationCategory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BusinessApplication"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"operatingSystem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Web"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"publisher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acme.dev/#organization"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Privacy-first web analytics with cookieless session tracking."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acme.dev/product"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WebPage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acme.dev/product#webpage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acme.dev/product"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"about"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"@id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://acme.dev/product#app"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;@id&lt;/code&gt; values are the actual work. They turn three disconnected blocks into one addressable graph, so any node can be referenced from anywhere on the site without repeating the data inside it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost of skipping this:&lt;/strong&gt; the page can be indexed and still be unciteable, because there is no unambiguous subject to attribute the claim to.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. &lt;code&gt;sameAs&lt;/code&gt; is missing, or points at dead profiles
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;sameAs&lt;/code&gt; is the cheapest disambiguation signal that exists, and it is the one most often skipped.&lt;/p&gt;

&lt;p&gt;An LLM asked "what is Acme Analytics" has no way to know that your domain is the authority on Acme Analytics. It &lt;strong&gt;does&lt;/strong&gt; know what a GitHub organisation, a Crunchbase entry, and a Wikidata item are. &lt;code&gt;sameAs&lt;/code&gt; is how you hand it the bridge between the two.&lt;/p&gt;

&lt;p&gt;Four rules that matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Only link profiles that exist and are populated.&lt;/strong&gt; A 404, a private repo, or a profile with no bio is worse than no link — it reads as a failed verification.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wikipedia and Wikidata beat everything else.&lt;/strong&gt; If you have either, that is your strongest edge and it belongs first in the array.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three to eight links is the working range.&lt;/strong&gt; Forty looks like spam and gets discounted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never invent one.&lt;/strong&gt; A broken &lt;code&gt;sameAs&lt;/code&gt; is a trust signal pointing the wrong direction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cost of skipping this:&lt;/strong&gt; every query about your brand becomes a coin flip between your site and someone else's, and whoever has the cleaner identity graph wins.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Your JSON-LD is injected after hydration
&lt;/h2&gt;

&lt;p&gt;This is the quiet killer on Next.js, Nuxt, React SPAs, and anything using a head-management library.&lt;/p&gt;

&lt;p&gt;If this is how your schema reaches the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// invisible to most AI crawlers&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/ld+json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;script&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="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…then the crawler has to execute JavaScript, &lt;em&gt;and&lt;/em&gt; wait for hydration, &lt;em&gt;and&lt;/em&gt; wait for your effect to flush before the markup exists at all. Googlebot will sometimes manage it. Most AI crawlers will not.&lt;/p&gt;

&lt;p&gt;The fix is boring: serialize the JSON server-side and render it as static text in the document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// present in the raw HTML response&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jsonLd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/ld+json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;dangerouslySetInnerHTML&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="na"&gt;__html&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jsonLd&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then verify it the only way that counts — not in DevTools, in the actual response:&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://acme.dev/product | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'application/ld+json'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that returns &lt;code&gt;0&lt;/code&gt; while your browser shows perfectly valid schema, you have found your bug.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost of skipping this:&lt;/strong&gt; you keep maintaining markup that no retrieval pipeline has ever parsed.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Your content only exists after JavaScript runs
&lt;/h2&gt;

&lt;p&gt;Same root cause as above, much larger consequence. Schema is metadata. &lt;strong&gt;Content is what gets embedded and cited.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If your product copy, documentation body, or article text renders client-side, you are serving an empty shell to every crawler that does not run a browser.&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;# what a crawler sees vs what a user sees&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="s2"&gt;"GPTBot"&lt;/span&gt; https://acme.dev/docs/getting-started | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://acme.dev/docs/getting-started | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 30-word difference is a widget. A &lt;strong&gt;900-word difference&lt;/strong&gt; means your documentation does not exist as far as retrieval is concerned — no matter how clean the JSON-LD on top of it is.&lt;/p&gt;

&lt;p&gt;The practical answer is SSR, SSG, or ISR for every route you want cited. Client-side rendering is for application state, not published content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost of skipping this:&lt;/strong&gt; the largest one on this list, and the only one that silently caps your ceiling no matter what you fix afterward.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Valid structure, broken values
&lt;/h2&gt;

&lt;p&gt;Validators check shape, not meaning. Every row below passes validation and still degrades the output.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Broken&lt;/th&gt;
&lt;th&gt;Fixed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;datePublished&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"Oct 24, 2026"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"2026-10-24"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"/cover.png"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"https://acme.dev/cover.png"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"Webpage"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"WebPage"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;"Article "&lt;/code&gt; (trailing space)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"Article"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;`"Acme Analytics \&lt;/td&gt;
&lt;td&gt;Best Tools"`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;400-character paragraph&lt;/td&gt;
&lt;td&gt;one sentence, 150–160 chars&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;ISO dates matter more than they look. &lt;code&gt;"Oct 24, 2026"&lt;/code&gt; is ambiguous enough that some parsers drop the field entirely, and &lt;code&gt;dateModified&lt;/code&gt; is one of the few freshness signals you fully control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost of skipping this:&lt;/strong&gt; a validator that says "0 errors" while the values quietly fail to resolve.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. &lt;code&gt;FAQPage&lt;/code&gt; used as a keyword dump
&lt;/h2&gt;

&lt;p&gt;Two separate mistakes get made here constantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistake A — malformed structure.&lt;/strong&gt; &lt;code&gt;mainEntity&lt;/code&gt; must be an array of &lt;code&gt;Question&lt;/code&gt; objects, each with a nested &lt;code&gt;acceptedAnswer&lt;/code&gt; of type &lt;code&gt;Answer&lt;/code&gt;. A flat &lt;code&gt;{"question": "...", "answer": "..."}&lt;/code&gt; is not Schema.org.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://schema.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FAQPage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mainEntity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Question"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Does JSON-LD improve AI search visibility?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"acceptedAnswer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Answer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JSON-LD does not directly improve rankings. It removes ambiguity about what a page and its publisher are, which helps retrieval systems select the page as a source."&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Mistake B — mismatched pairs.&lt;/strong&gt; The marked-up question has to be answered by the visible text directly below it. If the markup asks "How much does it cost?" and the visible answer is about onboarding, you have created a false pair. That is worse than no markup, because the system now has a confident wrong answer attributed to you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One honest caveat:&lt;/strong&gt; Google restricted FAQ rich results to authoritative government and health sites in 2023, and removed HowTo rich results entirely. This markup will not win you a SERP feature. What it still does is produce clean, self-contained question-answer chunks that retrieval pipelines can lift without parsing your surrounding prose. That is the reason to keep it — not the rich result.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost of skipping this:&lt;/strong&gt; nothing, if you skip it entirely. The cost is in doing it badly.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Conflicting entity data across pages
&lt;/h2&gt;

&lt;p&gt;Bolt on a plugin, add a second one a year later, and you end up with two &lt;code&gt;Organization&lt;/code&gt; blocks per page saying different things:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Organization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Ltd"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Organization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acme Analytics Inc."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.acme.dev"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To a system that reconciles entities, that is two companies. Consolidation fails silently, and you get no error anywhere.&lt;/p&gt;

&lt;p&gt;Pick canonical values once — exact legal name, exact canonical URL, exact logo — and use them in &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt;, &lt;code&gt;og:title&lt;/code&gt;, and every &lt;code&gt;Organization&lt;/code&gt; node on the site. Then dedupe and verify:&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;# should return exactly 1 per page&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://acme.dev/ | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'"@type":"Organization"'&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cost of skipping this:&lt;/strong&gt; partial credit on every entity query, forever, with no signal that anything is wrong.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 5-minute audit order
&lt;/h2&gt;

&lt;p&gt;If you do five things after reading this, do them in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;curl&lt;/code&gt; your three most important URLs and confirm the body copy is there without JavaScript&lt;/li&gt;
&lt;li&gt;Count &lt;code&gt;application/ld+json&lt;/code&gt; blocks in the raw HTML — zero means everything else is moot&lt;/li&gt;
&lt;li&gt;Check that every &lt;code&gt;sameAs&lt;/code&gt; URL returns 200 and has real content on it&lt;/li&gt;
&lt;li&gt;Confirm &lt;code&gt;dateModified&lt;/code&gt; is ISO 8601 and actually recent&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;"@type":"Organization"&lt;/code&gt; and make sure it appears once, with consistent values&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notice that none of these involve the Rich Results Test. It tells you the markup is well-formed, which was never the question.&lt;/p&gt;




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

&lt;p&gt;&lt;strong&gt;Does adding JSON-LD get my site cited by ChatGPT?&lt;/strong&gt;&lt;br&gt;
Not on its own. Citation depends on whether the page is crawlable, whether its content is retrievable without JavaScript, and whether it is the clearest available answer to the question. Schema removes ambiguity about the publisher and the entity; it does not create content authority.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I block GPTBot?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;GPTBot&lt;/code&gt; is OpenAI's training crawler. It is separate from &lt;code&gt;OAI-SearchBot&lt;/code&gt;, which handles ChatGPT search, and &lt;code&gt;ChatGPT-User&lt;/code&gt;, which fires when a user asks ChatGPT to fetch a URL. Blocking &lt;code&gt;GPTBot&lt;/code&gt; does not remove you from ChatGPT search results. Blocking &lt;code&gt;OAI-SearchBot&lt;/code&gt; does. Make that a deliberate decision rather than a copied robots.txt snippet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does &lt;code&gt;FAQPage&lt;/code&gt; markup still do anything?&lt;/strong&gt;&lt;br&gt;
Not for rich results on most sites. It still produces clean question-answer pairs that are trivial to chunk during retrieval, which is a real but modest benefit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long until structured data shows an effect?&lt;/strong&gt;&lt;br&gt;
Recrawl cadence is the limiter, not the markup. Crawlers revisit popular pages within days and low-traffic pages within weeks to months. Expect a quarter, not a week, and track server-log bot hits rather than trying to infer it from traffic.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Start with the free one.&lt;/strong&gt; The scored version of this audit — eight categories, 100 points, every row and point value, plus three production-ready JSON-LD templates (&lt;code&gt;Organization&lt;/code&gt; + &lt;code&gt;WebSite&lt;/code&gt;, &lt;code&gt;Article&lt;/code&gt; + &lt;code&gt;Person&lt;/code&gt;, &lt;code&gt;FAQPage&lt;/code&gt;) already wired with &lt;code&gt;@id&lt;/code&gt; cross-references: &lt;strong&gt;&lt;a href="https://abrahman2.gumroad.com/l/ai-search-readiness-checklist" rel="noopener noreferrer"&gt;100-Point AI Search Readiness Checklist&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The full build.&lt;/strong&gt; If you want the complete template set, the raw-vs-rendered diff tooling, the log-analysis queries, and the rewrite patterns for making each section survive chunking: &lt;strong&gt;&lt;a href="https://abrahman2.gumroad.com/l/structured-for-answers" rel="noopener noreferrer"&gt;Structured for Answers&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next in this series:&lt;/strong&gt; &lt;strong&gt;&lt;a href="https://dev.to/arhashir/the-ai-search-audit-8-checks-100-points-one-script-18jp"&gt;The AI Search Audit: 8 Checks, 100 Points, One Script&lt;/a&gt;&lt;/strong&gt; — the full scored audit, including the 40/60 rule that tells you which two categories gate the other six, and one script that runs most of it in about thirty seconds.&lt;/p&gt;

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