This is the hands-on companion to our article on why AI search cites some local businesses and ignores others. Five checks, in the order that matters: crawler access first, markup in the middle, llms.txt last. Every command runs from a normal terminal on macOS or Linux, or from Git Bash on Windows.
Replace https://www.example.com with your own address everywhere below. Every name, number and address in the templates is an example and must be replaced with your real details.
Step 1. Ask your site who it lets in
Servers and firewalls usually filter by the user-agent name, so sending the name is enough to reproduce a block. Run this and read the codes:
for ua in OAI-SearchBot GPTBot ChatGPT-User Claude-SearchBot ClaudeBot Claude-User PerplexityBot Googlebot AdsBot-Google bingbot; do
printf '%-18s ' "$ua"
curl -s -o /dev/null -w '%{http_code}\n' -A "Mozilla/5.0 (compatible; $ua)" https://www.example.com/
done
What the codes mean:
| Code | Meaning | What to do |
|---|---|---|
| 200 | The bot gets the page | Nothing |
| 301 / 302 | A redirect | Run again with the final address |
| 403 | The server refuses this bot | Find the filter in hosting or the firewall |
| 429 | Too many requests | Wait a minute and test one bot at a time |
A 403 for OAI-SearchBot means ChatGPT search will not show your site. A 403 for Claude-SearchBot can reduce your visibility in Claude's search results. A 403 for Googlebot, AdsBot or bingbot from this test is a warning but not proof, because some firewalls reject anyone who claims to be Googlebot from a non-Google address. Confirm those in Search Console with URL Inspection.
In our scan of 100 Tallinn business sites, seven returned 403 to Claude-SearchBot while their robots.txt allowed everything. The filter lived in the hosting account, so the fix was a support ticket, not a code change.
Step 2. Check that missing pages really are missing
curl -s -o /dev/null -w '%{http_code}\n' https://www.example.com/this-page-does-not-exist-7f3k
curl -s -o /dev/null -w '%{http_code} %{content_type}\n' https://www.example.com/llms.txt
The first line must print 404. If it prints 200, the site tells every crawler that broken links are real pages. The second line shows whether /llms.txt exists: a real file returns 200 with text/plain or text/markdown. A 200 with text/html means the CMS is serving a page in its place, which we found on ten sites out of a hundred.
Step 3. robots.txt that says what you mean
Search crawlers and training crawlers are separate. You can allow search and still opt out of training. AdsBot ignores User-agent: * and only obeys rules that name it, so never write a rule for it unless you mean it.
User-agent: *
Allow: /
# Optional: opt out of model training, stay in AI search
User-agent: GPTBot
Disallow: /
User-agent: ClaudeBot
Disallow: /
User-agent: CCBot
Disallow: /
Sitemap: https://www.example.com/sitemap.xml
The three training blocks are a business decision, not a recommendation. OpenAI and Anthropic both document that blocking GPTBot or ClaudeBot does not remove you from their search crawlers, OAI-SearchBot and Claude-SearchBot. Leave them out if you have no reason to block.
Step 4. LocalBusiness markup that matches the page
Google's guidelines ask for the most specific subtype that fits (Plumber, Electrician, Locksmith, Dentist, AutoRepair and so on), with name and address required. Everything in the markup must also be visible on the page. Put this inside the homepage head or at the end of body:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Plumber",
"@id": "https://www.example.com/#business",
"name": "Example Plumbing OÜ",
"url": "https://www.example.com/",
"telephone": "+372 5000 0000",
"email": "info@example.com",
"image": "https://www.example.com/images/team.jpg",
"priceRange": "from €45",
"address": {
"@type": "PostalAddress",
"streetAddress": "Example tn 1",
"addressLocality": "Tallinn",
"postalCode": "10111",
"addressCountry": "EE"
},
"geo": { "@type": "GeoCoordinates", "latitude": 59.43696, "longitude": 24.75357 },
"areaServed": [
{ "@type": "City", "name": "Tallinn" },
{ "@type": "AdministrativeArea", "name": "Harju maakond" }
],
"openingHoursSpecification": [{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "08:00",
"closes": "18:00"
}],
"sameAs": [
"https://www.facebook.com/exampleplumbing",
"https://www.google.com/maps?cid=0000000000000000000"
]
}
</script>
Rules that save a rejection:
- The phone includes the country code, the same number as in the visible footer.
- Coordinates have at least five decimal places. Copy them from your Google Business Profile pin.
priceRangestays under 100 characters, or Google drops it.- Leave out
aggregateRatingfor your own business. Google's local business guidelines reserve review markup for sites that review other businesses. sameAslists only profiles that exist and belong to you. Your Google Business Profile link is the most useful one.
Validate the page in Google's Rich Results Test and in the Schema Markup Validator. Fix anything marked as an error. Then inspect the live URL in Search Console to confirm Google sees the same markup.
Step 5. A short llms.txt
llms.txt is a 2024 proposal, not a standard, and Google does not use it for AI Overviews. It takes ten minutes, so it goes last. The format: one H1 with the name, a one-paragraph summary as a quote, then H2 sections with links. Save it as plain text at /llms.txt:
# Example Plumbing OÜ
> Plumbing repairs and installation in Tallinn and Harju County. Mon–Fri 08:00–18:00, phone +372 5000 0000. Prices from €45, final price after inspection.
## Services
- [Leak repair](https://www.example.com/leak-repair): call-out within Tallinn, prices from €45
- [Boiler installation](https://www.example.com/boilers): supply and installation, written quote first
## Company
- [Contact and service area](https://www.example.com/contact): address, hours, districts served
- [Prices](https://www.example.com/prices): starting prices for common jobs
## Optional
- [Blog](https://www.example.com/blog): maintenance advice
Every fact in it should be identical to the website and the markup. Three sources that disagree about your hours are worse than one that is right.
Step 6. Repeat after every change
Hosting migrations, new firewall rules and CMS plugin updates are how sites get blocked without anyone noticing. Rerun steps 1 and 2 after any of them, and once a month either way. Our free quick score below also flags a homepage with no structured data, markup that never names the business, and a homepage without phone or email links.
Common questions
Which LocalBusiness subtype should I use?
The most specific one schema.org offers for what you do: Plumber, Electrician, Locksmith, Dentist, AutoRepair, HairSalon and so on. Google recommends the most specific subtype and accepts an array if more than one applies.
Can I add star ratings to my own LocalBusiness markup?
Google's local business guidelines recommend aggregateRating and review markup only for sites that capture reviews about other local businesses. For your own company, leave it out.
Will blocking GPTBot remove me from ChatGPT?
Not from ChatGPT search. OpenAI uses OAI-SearchBot for search and GPTBot for training, and documents the two settings as independent.
Where do I put llms.txt?
At the root of the domain, as /llms.txt, served as plain text. A request for it must not return your homepage or an HTML error page with status 200.
Check your own site free
The same engine behind this article runs a 50-point Quick Score on your homepage in about 30 seconds — free, no account needed.
Run my free Quick ScoreSee a real sample audit first