Our site had beautiful code, perfect bot access, and every schema type. But 3 missing tags made the AI engines think we were 4,100 km from Edmonton. Here's how we caught it, why it happens to your clients, and the 5-minute fix.
TransCanadaDigital.com passed every major AI-readiness check: LocalBusiness schema, FAQ markup, GPTBot access, sitemap, fast load time. The engine returned a 95/100 — an "AI Dominant" grade.
But when the Visibility Matrix loaded competitor data, something was wrong. Instead of Edmonton agencies, the dashboard showed:
If you send a "Local" competitor analysis to a business owner in Edmonton and it shows rivals from Florida, you lose all credibility instantly. The data is technically correct — the AI just didn't know where to look.
The scan pipeline extracts your city from schema markup. If your JSON-LD doesn't declare a city, the API calls have nothing to "anchor" to. Without an anchor, Google Places and Serper default to the server's IP location — which, on Railway's US infrastructure, landed in St. Louis / Jacksonville.
geoThe engine extracted @type: "Organization" with an addressLocality: "Edmonton", but no GeoCoordinates were present. Without latitude/longitude, there's no mathematical proof of location.
areaServed declaredThe AI had no way to know which neighborhoods, cities, or provinces the business serves. So it searched everywhere.
hasMap link in schemaWithout a direct Google Maps URL in the structured data, the search engine couldn't "handshake" between the website and the Maps listing. The website and Google Maps were disconnected.
With no city anchor, the competitor lookup fell back to the physical location of the cloud server — a US-based data center. Competitors from Jacksonville and St. Louis appeared because that's where the server is, not where the business is.
"My site is beautiful, but because I was missing GeoCoordinates and areaServed, the AI literally didn't know if I was in Edmonton, St. Louis, or Jacksonville. If the machines can't pinpoint you, 'Near Me' queries will skip you every time."
Every one of these is a machine-readable signal. Without them, AI engines treat your business like a "Global Ghost" — they can see your name but have no idea where you exist.
Without explicit $\text{latitude}$ and $\text{longitude}$ values in your schema, AI cannot mathematically verify your physical location. It treats you as a "floating" entity — you exist somewhere on the internet, but nowhere on the map.
What "Near Me" actually means to AI: When someone searches "web developer near me," the AI engine calculates a distance function between the searcher's coordinates and every business with declared geo data. No coordinates = you're excluded from the calculation entirely.
This property tells AI engines the exact geographic boundaries of your service area. Without it, the machine has to guess — and guess wrong. A plumber in Edmonton without areaServed looks identical to a plumber in Tampa to an LLM.
Why it costs you leads: When ChatGPT or Gemini recommends "the best web developer in Edmonton," it only includes businesses that have declared Edmonton as a service area. No declaration = no recommendation.
hasMap is the bridge between your website and your Google Maps listing. It's the "Social-to-Web glue" that tells search engines: "This website and this Maps pin are the same business." Without it, they're treated as two separate entities.
The disconnection effect: Your website says you're a business. Your Google Maps listing says you're a business. But without hasMap linking them, the AI sees two disconnected data points and can't build a unified "entity graph."
This is the exact code we added to our own site's <script type="application/ld+json"> to go from "Jacksonville Ghost" to "Edmonton #1." Copy it, change the values, deploy.
"address": {
"@type": "PostalAddress",
"streetAddress": "Downtown Edmonton",
"addressLocality": "Edmonton",
"addressRegion": "AB",
"postalCode": "T5H 3S4",
"addressCountry": "CA"
}
// No "geo" property
// No "areaServed" property
// No "hasMap" property
"address": { ... },
"geo": {
"@type": "GeoCoordinates",
"latitude": 53.5461,
"longitude": -113.4937
},
"areaServed": [
{ "@type": "City",
"name": "Edmonton" },
{ "@type": "AdministrativeArea",
"name": "Alberta" },
{ "@type": "Country",
"name": "Canada" }
],
"hasMap": "https://maps.google.com
/?cid=YOUR_GOOGLE_CID"
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Your Business Name",
"address": {
"@type": "PostalAddress",
"streetAddress": "123 Main Street",
"addressLocality": "Edmonton",
"addressRegion": "AB",
"postalCode": "T5H 3S4",
"addressCountry": "CA"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 53.5461,
"longitude": -113.4937
},
"areaServed": [
{ "@type": "City", "name": "Edmonton" },
{ "@type": "AdministrativeArea", "name": "Alberta" },
{ "@type": "Country", "name": "Canada" }
],
"hasMap": "https://maps.google.com/?cid=YOUR_CID",
"telephone": "+1-780-555-0100",
"url": "https://yourdomain.com"
}
Search your business on Google Maps, click your listing, and copy the URL. The cid= parameter is your unique Google Customer ID. Paste the full Maps URL as your hasMap value.
| Missing Property | Status | AI Consequence | Severity |
|---|---|---|---|
geo (GeoCoordinates) |
Missing | AI cannot verify physical existence. Excluded from all proximity queries. "Near Me" = invisible. | CRITICAL |
areaServed |
Missing | AI doesn't know your service area. Competitors who declared their city get recommended instead. | CRITICAL |
hasMap |
Missing | Website and Google Maps are disconnected. Entity graph can't merge web + maps authority. | HIGH |
addressLocality |
Present | AI knows the city name — but without geo/areaServed, it can't prove it mathematically. | OK (alone: insufficient) |
After adding the 3 missing tags and redeploying, the next scan anchored correctly. The AI knew exactly where to look.
You stop competing with the entire world and start dominating your local city — because the machines finally have a "Source of Truth" to trust. The fix took 5 minutes. The competitor data corrected itself on the very next scan.
Every client you audit will have at least one of these 3 gaps. Most have all three. That's not a bug — it's your opening.
Send your prospect to transcanadadigital.com/facebook-scan. The engine will scan their schema in 60 seconds. If they're missing geo, areaServed, or hasMap, the AI Blind Spots section will flag every one in red.
When their competitors show up from a different state or province, that's your visual proof: "See? The AI thinks you're in Jacksonville. Your customers in [their city] will never find you." This is more persuasive than any keyword report.
The fix is 3 JSON-LD properties — you can add them in one deployment. But the value is that their business goes from invisible to recommended. That's worth a retainer, not a one-time fee.
"I built this software to find the exact invisible gaps that manual audits miss. Once the engine identifies the missing hasMap link or geo data, you can fix it in minutes and become AI-Congruent."
The full guide to how AI search engines decide who to recommend.
GBP Fix GuideFix your schema, address, CID, hours, and bot access step-by-step.
Rich Results ExplainedStars, prices, and FAQs in Google Search β what they are and how schema triggers them.
Answer Engine OptimizationThe new SEO: how to get cited by ChatGPT, Claude, and Perplexity AI.
Schema Doctor Proβ’ DashboardInteractive AI intelligence dashboard with deployable fix code for your schema health.
Plans & PricingFrom $27 audits to $997/mo full agency suites. See what fits your needs.
Run the same audit we used to catch our own blind spot. It takes 10 seconds and costs $27 β one payment, no subscription. If you're missing even one of these 3 tags, the AI engines are showing your competitors β not you.
Run a $27 Prospect Audit →