<?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: Curt Kloc</title>
    <description>The latest articles on DEV Community by Curt Kloc (@curt_kloc_fcc334102122c33).</description>
    <link>https://dev.to/curt_kloc_fcc334102122c33</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%2F4012700%2F2c21b20a-f989-42b3-bbf5-227b3a8a8b53.png</url>
      <title>DEV Community: Curt Kloc</title>
      <link>https://dev.to/curt_kloc_fcc334102122c33</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/curt_kloc_fcc334102122c33"/>
    <language>en</language>
    <item>
      <title>How I Built Software to Show Business Owners What Google and AI Understand About Their Company</title>
      <dc:creator>Curt Kloc</dc:creator>
      <pubDate>Thu, 02 Jul 2026 19:30:01 +0000</pubDate>
      <link>https://dev.to/curt_kloc_fcc334102122c33/how-i-built-software-to-show-business-owners-what-google-and-ai-understand-about-their-company-29ej</link>
      <guid>https://dev.to/curt_kloc_fcc334102122c33/how-i-built-software-to-show-business-owners-what-google-and-ai-understand-about-their-company-29ej</guid>
      <description>&lt;p&gt;I was frustrated.&lt;/p&gt;

&lt;p&gt;Not because local SEO is impossible.&lt;/p&gt;

&lt;p&gt;Not because websites are hard to build.&lt;/p&gt;

&lt;p&gt;I was frustrated because business owners could not see the thing that was costing them visibility.&lt;/p&gt;

&lt;p&gt;A local business owner would have a website, a Google Business Profile, some reviews, a service page, a contact page, and maybe even a decent-looking homepage.&lt;/p&gt;

&lt;p&gt;To them, the site looked finished.&lt;/p&gt;

&lt;p&gt;But when I looked at it through the lens of Google, Google Maps, and AI search, the picture was usually very different.&lt;/p&gt;

&lt;p&gt;The business existed online, but it was not clearly explained.&lt;/p&gt;

&lt;p&gt;Google had to guess what the company did.&lt;/p&gt;

&lt;p&gt;Google had to guess where it operated.&lt;/p&gt;

&lt;p&gt;Google had to guess which services mattered most.&lt;/p&gt;

&lt;p&gt;Google had to guess which pages supported which local searches.&lt;/p&gt;

&lt;p&gt;AI systems had to piece together the company from scattered fragments.&lt;/p&gt;

&lt;p&gt;And when search systems have to guess, they often choose a competitor that is easier to understand.&lt;/p&gt;

&lt;p&gt;That is the problem we built software to expose at Firm IQ.&lt;/p&gt;

&lt;p&gt;Not another generic SEO audit.&lt;/p&gt;

&lt;p&gt;Not a page-speed report.&lt;/p&gt;

&lt;p&gt;Not a keyword list.&lt;/p&gt;

&lt;p&gt;We built a Google &amp;amp; AI Visibility Infrastructure Audit.&lt;/p&gt;

&lt;p&gt;The goal was simple:&lt;/p&gt;

&lt;p&gt;Show a business owner what Google, Maps, and AI can likely understand about their company — and what they still have to guess.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;At Firm IQ, we built audit software that analyzes how a local business appears to Google, Google Maps, and AI search systems.&lt;/p&gt;

&lt;p&gt;The software reviews:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;homepage clarity&lt;/li&gt;
&lt;li&gt;service pages&lt;/li&gt;
&lt;li&gt;location pages&lt;/li&gt;
&lt;li&gt;service-location gaps&lt;/li&gt;
&lt;li&gt;Google Business Profile landing-page alignment&lt;/li&gt;
&lt;li&gt;schema and structured data&lt;/li&gt;
&lt;li&gt;internal linking&lt;/li&gt;
&lt;li&gt;site footprint&lt;/li&gt;
&lt;li&gt;competitor contrast&lt;/li&gt;
&lt;li&gt;map visibility&lt;/li&gt;
&lt;li&gt;authority signals&lt;/li&gt;
&lt;li&gt;AI understanding infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The report translates technical visibility gaps into plain-English business consequences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;why the business may not be showing up&lt;/li&gt;
&lt;li&gt;why competitors may be easier for Google to recommend&lt;/li&gt;
&lt;li&gt;where local demand is leaking&lt;/li&gt;
&lt;li&gt;what pages or proof are missing&lt;/li&gt;
&lt;li&gt;what should be fixed first&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hardest parts were not just crawling websites.&lt;/p&gt;

&lt;p&gt;The hardest parts were:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Turning messy website data into a business-owner-friendly diagnosis.&lt;/li&gt;
&lt;li&gt;Comparing a business against map competitors without making it a full competitor audit.&lt;/li&gt;
&lt;li&gt;Explaining AI visibility as a documentation problem, not just an SEO problem.&lt;/li&gt;
&lt;li&gt;Creating a report that creates urgency without exaggeration.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;p&gt;The first working version was built as a Flask-based web app, developed with AI-assisted coding in Antigravity, deployed on Render, and connected to external visibility data where useful.&lt;/p&gt;

&lt;p&gt;The system includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flask web app&lt;/li&gt;
&lt;li&gt;website crawler&lt;/li&gt;
&lt;li&gt;page classifier&lt;/li&gt;
&lt;li&gt;schema detector&lt;/li&gt;
&lt;li&gt;service/location matching logic&lt;/li&gt;
&lt;li&gt;Google Business Profile landing-page alignment check&lt;/li&gt;
&lt;li&gt;competitor contrast module&lt;/li&gt;
&lt;li&gt;Ahrefs authority/context integration&lt;/li&gt;
&lt;li&gt;AI understanding infrastructure diagnostic&lt;/li&gt;
&lt;li&gt;PDF report generator&lt;/li&gt;
&lt;li&gt;plain-English recommendation layer&lt;/li&gt;
&lt;li&gt;Render deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The app is not meant to be a traditional SEO crawler.&lt;/p&gt;

&lt;p&gt;The goal is not just to say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This page has a missing meta description.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The goal is to say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This business may not be giving Google and AI enough structured evidence to understand, trust, and recommend it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That changed how we designed the whole product.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem I Was Actually Solving
&lt;/h2&gt;

&lt;p&gt;Most business owners think visibility works like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have a website, so Google should know what I do.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But that is not how modern search works.&lt;/p&gt;

&lt;p&gt;Having a website is not the same as being understood.&lt;/p&gt;

&lt;p&gt;A website can look professional to a human and still be weak evidence for Google.&lt;/p&gt;

&lt;p&gt;A business can be great at what it does and still be difficult for AI systems to summarize, classify, or recommend.&lt;/p&gt;

&lt;p&gt;This is especially obvious in local search.&lt;/p&gt;

&lt;p&gt;A buyer does not usually search for vague categories.&lt;/p&gt;

&lt;p&gt;They search for specific services in specific places.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;handyman Fort Lauderdale&lt;/li&gt;
&lt;li&gt;bathroom renovation Fort Lauderdale&lt;/li&gt;
&lt;li&gt;roof repair Chandler&lt;/li&gt;
&lt;li&gt;commercial HVAC Dallas&lt;/li&gt;
&lt;li&gt;kitchen remodeling near me&lt;/li&gt;
&lt;li&gt;personal injury lawyer Phoenix&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those searches combine service intent with location intent.&lt;/p&gt;

&lt;p&gt;If a business has one generic services page, no dedicated location pages, no service-location pages, weak schema, and a Google Business Profile pointing to a generic homepage, Google has to infer too much.&lt;/p&gt;

&lt;p&gt;Meanwhile, a competitor may have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a strong homepage&lt;/li&gt;
&lt;li&gt;dedicated service pages&lt;/li&gt;
&lt;li&gt;dedicated city pages&lt;/li&gt;
&lt;li&gt;local proof&lt;/li&gt;
&lt;li&gt;reviews&lt;/li&gt;
&lt;li&gt;project examples&lt;/li&gt;
&lt;li&gt;FAQs&lt;/li&gt;
&lt;li&gt;schema markup&lt;/li&gt;
&lt;li&gt;internal links&lt;/li&gt;
&lt;li&gt;a stronger landing page connected to the Google Business Profile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That competitor may not be better.&lt;/p&gt;

&lt;p&gt;They may simply be easier for Google to understand.&lt;/p&gt;

&lt;p&gt;That became one of the core ideas behind the software:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The current map winners are not always unbeatable. They are often just giving Google a clearer picture.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why Existing SEO Audits Weren’t Enough
&lt;/h2&gt;

&lt;p&gt;There are plenty of SEO audit tools.&lt;/p&gt;

&lt;p&gt;Many of them are useful.&lt;/p&gt;

&lt;p&gt;But most of them output technical issues, not business clarity.&lt;/p&gt;

&lt;p&gt;They tell you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;missing title tag&lt;/li&gt;
&lt;li&gt;meta description too short&lt;/li&gt;
&lt;li&gt;missing H1&lt;/li&gt;
&lt;li&gt;no alt text&lt;/li&gt;
&lt;li&gt;low word count&lt;/li&gt;
&lt;li&gt;broken link&lt;/li&gt;
&lt;li&gt;schema missing&lt;/li&gt;
&lt;li&gt;low domain authority&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those things can matter.&lt;/p&gt;

&lt;p&gt;But a business owner usually does not care about a missing H1 by itself.&lt;/p&gt;

&lt;p&gt;They care about calls.&lt;/p&gt;

&lt;p&gt;They care about estimates.&lt;/p&gt;

&lt;p&gt;They care about appointments.&lt;/p&gt;

&lt;p&gt;They care about whether the competitor down the street is showing up while they are buried.&lt;/p&gt;

&lt;p&gt;So the report could not just say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Missing location page.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It needed to say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Google does not have a dedicated local page that supports this target market, which can make competitors with clearer location assets easier to rank and recommend.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It could not just say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thin content.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It needed to say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The site may not provide enough service-specific evidence for Google and AI systems to confidently match this business to high-intent buyer searches.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was the real challenge.&lt;/p&gt;

&lt;p&gt;The crawler had to find the data.&lt;/p&gt;

&lt;p&gt;But the report had to explain the consequence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Building the Website Crawler
&lt;/h2&gt;

&lt;p&gt;The first layer was the crawler.&lt;/p&gt;

&lt;p&gt;The software needed to accept a business website URL, normalize it, crawl the site, classify pages, and extract signals.&lt;/p&gt;

&lt;p&gt;Simple in theory.&lt;/p&gt;

&lt;p&gt;Messy in practice.&lt;/p&gt;

&lt;p&gt;Real-world local business websites are unpredictable.&lt;/p&gt;

&lt;p&gt;Some use WordPress.&lt;/p&gt;

&lt;p&gt;Some use Wix.&lt;/p&gt;

&lt;p&gt;Some use Squarespace.&lt;/p&gt;

&lt;p&gt;Some use custom builders.&lt;/p&gt;

&lt;p&gt;Some have no sitemap.&lt;/p&gt;

&lt;p&gt;Some have multiple sitemaps.&lt;/p&gt;

&lt;p&gt;Some block automated requests.&lt;/p&gt;

&lt;p&gt;Some redirect between &lt;code&gt;www&lt;/code&gt; and non-&lt;code&gt;www&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Some have modern domains like &lt;code&gt;.realtor&lt;/code&gt;, &lt;code&gt;.construction&lt;/code&gt;, or &lt;code&gt;.ai&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Some return unusual HTTP statuses.&lt;/p&gt;

&lt;p&gt;Some sites are indexed by Google but still block a normal server-side crawler.&lt;/p&gt;

&lt;p&gt;So the crawler had to become practical.&lt;/p&gt;

&lt;p&gt;It needed to handle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;http&lt;/code&gt; and &lt;code&gt;https&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;www&lt;/code&gt; and non-&lt;code&gt;www&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;trailing slashes&lt;/li&gt;
&lt;li&gt;redirects&lt;/li&gt;
&lt;li&gt;modern TLDs&lt;/li&gt;
&lt;li&gt;sitemap discovery&lt;/li&gt;
&lt;li&gt;timeout failures&lt;/li&gt;
&lt;li&gt;crawler blocking&lt;/li&gt;
&lt;li&gt;empty HTML&lt;/li&gt;
&lt;li&gt;non-HTML responses&lt;/li&gt;
&lt;li&gt;shallow websites&lt;/li&gt;
&lt;li&gt;large websites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At a high level, URL normalization looked something like this:&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;from&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlparse&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;normalize_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;raw_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw_url&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="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;raw_url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="n"&gt;raw_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;raw_url&lt;/span&gt;

    &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;urlparse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;netloc&lt;/span&gt; &lt;span class="ow"&gt;or&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="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;netloc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid domain or URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;raw_url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rstrip&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="o"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That sounds basic, but it matters.&lt;/p&gt;

&lt;p&gt;If your validator rejects modern TLDs like &lt;code&gt;.realtor&lt;/code&gt;, the crawler never even gets a chance.&lt;/p&gt;

&lt;p&gt;If your crawler only tries one URL variant, you miss sites that resolve only on &lt;code&gt;www&lt;/code&gt;, redirect weirdly, or respond differently over HTTP/HTTPS.&lt;/p&gt;

&lt;p&gt;So the crawler eventually needed fallback attempts:&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;def&lt;/span&gt; &lt;span class="nf"&gt;build_url_variants&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;clean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://&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="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://&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="nf"&gt;strip&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;variants&lt;/span&gt; &lt;span class="o"&gt;=&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="s"&gt;https://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="si"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;www.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="si"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="si"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://www.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;www.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;clean&lt;/span&gt;&lt;span class="si"&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="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromkeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;variants&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal was not perfection.&lt;/p&gt;

&lt;p&gt;The goal was reliability across messy local business websites.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Extracting Page-Level Signals
&lt;/h2&gt;

&lt;p&gt;Once a page is fetched, the software extracts the basic signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;title tag&lt;/li&gt;
&lt;li&gt;meta description&lt;/li&gt;
&lt;li&gt;H1&lt;/li&gt;
&lt;li&gt;word count&lt;/li&gt;
&lt;li&gt;internal links&lt;/li&gt;
&lt;li&gt;schema presence&lt;/li&gt;
&lt;li&gt;page type&lt;/li&gt;
&lt;li&gt;contact/NAP signals&lt;/li&gt;
&lt;li&gt;Google Maps or GBP evidence&lt;/li&gt;
&lt;li&gt;review/proof signals&lt;/li&gt;
&lt;li&gt;service terms&lt;/li&gt;
&lt;li&gt;location terms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simplified extraction pass might look like this:&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;def&lt;/span&gt; &lt;span class="nf"&gt;extract_page_signals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
    &lt;span class="n"&gt;h1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;h1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;get_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;h1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;
    &lt;span class="n"&gt;body_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_text&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;strip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;internal_links&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_internal_links&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;schema_blocks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;script&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/ld+json&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="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="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;h1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;word_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;body_text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;internal_link_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;internal_links&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;schema_present&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;schema_blocks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body_text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But raw extraction is only the first step.&lt;/p&gt;

&lt;p&gt;The bigger challenge is interpretation.&lt;/p&gt;

&lt;p&gt;A page with 300 words is not automatically bad.&lt;/p&gt;

&lt;p&gt;A page with schema is not automatically strong.&lt;/p&gt;

&lt;p&gt;A page that mentions a city is not automatically a location page.&lt;/p&gt;

&lt;p&gt;That is where classification came in.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 3: Classifying Pages by Visibility Role
&lt;/h2&gt;

&lt;p&gt;The software needed to classify pages by their visibility role.&lt;/p&gt;

&lt;p&gt;A page could be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Homepage&lt;/li&gt;
&lt;li&gt;Service Page&lt;/li&gt;
&lt;li&gt;Location Page&lt;/li&gt;
&lt;li&gt;Service-Location Page&lt;/li&gt;
&lt;li&gt;FAQ Page&lt;/li&gt;
&lt;li&gt;Contact Page&lt;/li&gt;
&lt;li&gt;About Page&lt;/li&gt;
&lt;li&gt;Gallery/Proof Page&lt;/li&gt;
&lt;li&gt;Blog/Resource Page&lt;/li&gt;
&lt;li&gt;Supporting Page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters because local visibility depends on structure.&lt;/p&gt;

&lt;p&gt;A website with ten random pages is different from a website with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one homepage&lt;/li&gt;
&lt;li&gt;five dedicated service pages&lt;/li&gt;
&lt;li&gt;three dedicated location pages&lt;/li&gt;
&lt;li&gt;ten service-location pages&lt;/li&gt;
&lt;li&gt;pricing page&lt;/li&gt;
&lt;li&gt;process page&lt;/li&gt;
&lt;li&gt;FAQ page&lt;/li&gt;
&lt;li&gt;reviews page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second site gives Google more evidence.&lt;/p&gt;

&lt;p&gt;Not just more content.&lt;/p&gt;

&lt;p&gt;More structured evidence.&lt;/p&gt;

&lt;p&gt;A simplified classifier might look like this:&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;def&lt;/span&gt; &lt;span class="nf"&gt;classify_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body_text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&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;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;body_text&lt;/span&gt;&lt;span class="si"&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;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;service_matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="k"&gt;if&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;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;location_matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;locations&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;is_homepage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Homepage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;contact&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Contact&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;faq&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;questions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FAQ&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;service_matches&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;location_matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Service-Location Page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;service_matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Service Page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;location_matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Location Page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Supporting Page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, the real logic needs more nuance.&lt;/p&gt;

&lt;p&gt;A city in the footer should not turn a page into a true location page.&lt;/p&gt;

&lt;p&gt;A generic services page should not count as a dedicated service page.&lt;/p&gt;

&lt;p&gt;A single mention of “kitchen” should not mean the page supports “kitchen renovation Fort Lauderdale.”&lt;/p&gt;

&lt;p&gt;So we created stricter status labels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;True Dedicated Page&lt;/li&gt;
&lt;li&gt;Broad Supporting Page&lt;/li&gt;
&lt;li&gt;Related Supporting Page&lt;/li&gt;
&lt;li&gt;Mentioned Only&lt;/li&gt;
&lt;li&gt;Missing&lt;/li&gt;
&lt;li&gt;Unclear&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That distinction matters.&lt;/p&gt;

&lt;p&gt;The report should not flatter the website.&lt;/p&gt;

&lt;p&gt;It should tell the truth.&lt;/p&gt;

&lt;p&gt;If the page does not clearly support the buyer intent, the report should say so.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 4: Turning Missing Pages Into Local Demand Gaps
&lt;/h2&gt;

&lt;p&gt;The next layer was translating missing structure into local demand.&lt;/p&gt;

&lt;p&gt;This became the “Local Demand Capture Gaps” section.&lt;/p&gt;

&lt;p&gt;Instead of saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are missing service-location pages.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The software shows buyer-intent searches like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;handyman Fort Lauderdale&lt;/li&gt;
&lt;li&gt;general contractor Fort Lauderdale&lt;/li&gt;
&lt;li&gt;home improvement Fort Lauderdale&lt;/li&gt;
&lt;li&gt;kitchen renovation Fort Lauderdale&lt;/li&gt;
&lt;li&gt;bathroom renovation Fort Lauderdale&lt;/li&gt;
&lt;li&gt;painting contractor Fort Lauderdale&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then it explains why those searches matter.&lt;/p&gt;

&lt;p&gt;This is where the report becomes more useful for a business owner.&lt;/p&gt;

&lt;p&gt;They can immediately understand:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These are the kinds of searches buyers use when they are ready to call.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The audit is not pretending to be a full keyword research report.&lt;/p&gt;

&lt;p&gt;It is saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These are real-world search patterns, and your website does not currently provide clear assets to capture them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That connects the technical gap to revenue.&lt;/p&gt;

&lt;p&gt;Missing page becomes missed demand.&lt;/p&gt;

&lt;p&gt;Missed demand becomes missed calls.&lt;/p&gt;

&lt;p&gt;Missed calls become missed jobs.&lt;/p&gt;

&lt;p&gt;That is the language business owners understand.&lt;/p&gt;

&lt;p&gt;A simplified service-location matrix might look like this:&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;def&lt;/span&gt; &lt;span class="nf"&gt;build_missing_asset_matrix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;crawled_pages&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;matrix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;services&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;location&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;locations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;find_best_matching_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;crawled_pages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;matrix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;location&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Missing&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;matching_page&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;matrix&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The technical output is a matrix.&lt;/p&gt;

&lt;p&gt;The business output is a revenue-risk story.&lt;/p&gt;

&lt;p&gt;That translation layer is what makes the audit useful.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 5: Google Business Profile Landing-Page Alignment
&lt;/h2&gt;

&lt;p&gt;For local businesses, the Google Business Profile is often one of the most important visibility assets.&lt;/p&gt;

&lt;p&gt;But most audits either ignore it or overstate what they can check.&lt;/p&gt;

&lt;p&gt;We decided to check something narrow and useful:&lt;/p&gt;

&lt;p&gt;Does the Google Business Profile website link point to the expected URL?&lt;/p&gt;

&lt;p&gt;That is a link alignment check.&lt;/p&gt;

&lt;p&gt;It does not mean the Google Business Profile is optimized.&lt;/p&gt;

&lt;p&gt;It does not mean the categories are correct.&lt;/p&gt;

&lt;p&gt;It does not mean the services are built out.&lt;/p&gt;

&lt;p&gt;It does not mean the reviews support the target services.&lt;/p&gt;

&lt;p&gt;It simply means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The GBP points to this page.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then the report asks a more important question:&lt;/p&gt;

&lt;p&gt;Is that landing page strong enough?&lt;/p&gt;

&lt;p&gt;Many businesses point their Google Business Profile to a generic homepage.&lt;/p&gt;

&lt;p&gt;That can be okay if the homepage is strong.&lt;/p&gt;

&lt;p&gt;But if the homepage lacks local proof, clear service signals, contact evidence, schema, review support, map evidence, and links to service/location pages, the GBP is pointing to a weak local visibility asset.&lt;/p&gt;

&lt;p&gt;That led to one of the report’s plain-English lines:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Google Business Profiles pointing to a generic homepage often make Google rely on weaker local/service signals.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the kind of sentence a business owner can understand.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 6: Competitor Contrast
&lt;/h2&gt;

&lt;p&gt;The competitor section changed the entire feel of the report.&lt;/p&gt;

&lt;p&gt;Before competitor contrast, the audit could show:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You have a weak structure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Useful, but not urgent enough.&lt;/p&gt;

&lt;p&gt;After competitor contrast, it could show:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here are the businesses Google is surfacing ahead of you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That creates a different kind of pain.&lt;/p&gt;

&lt;p&gt;The software allows us to enter top map competitors and compare them against the target business.&lt;/p&gt;

&lt;p&gt;The comparison looks at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;observed map rank&lt;/li&gt;
&lt;li&gt;site footprint&lt;/li&gt;
&lt;li&gt;service pages&lt;/li&gt;
&lt;li&gt;location pages&lt;/li&gt;
&lt;li&gt;service-location evidence&lt;/li&gt;
&lt;li&gt;local proof&lt;/li&gt;
&lt;li&gt;schema&lt;/li&gt;
&lt;li&gt;overall visibility picture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not to run a full competitor audit.&lt;/p&gt;

&lt;p&gt;The goal is to show the business owner why competitors may be easier for Google to surface.&lt;/p&gt;

&lt;p&gt;One key addition was site footprint.&lt;/p&gt;

&lt;p&gt;If the target business has 6 pages and a competitor has 50+ pages, that tells a story.&lt;/p&gt;

&lt;p&gt;It does not mean the competitor has better SEO automatically.&lt;/p&gt;

&lt;p&gt;But it does show that the competitor may have built more evidence.&lt;/p&gt;

&lt;p&gt;More pages do not always mean better visibility.&lt;/p&gt;

&lt;p&gt;But a larger, better-structured site often gives Google more information about services, locations, proof, and relevance.&lt;/p&gt;

&lt;p&gt;The table puts competitors first, then the target business.&lt;/p&gt;

&lt;p&gt;That matters psychologically.&lt;/p&gt;

&lt;p&gt;The report reads like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here are the map winners. Here is where you are.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then it explains:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The problem is not that competitors have perfect websites. The problem is that even imperfect competitors are still easier for Google to surface in the map results today.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That line became one of the strongest parts of the report.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 7: Schema and Structured Data
&lt;/h2&gt;

&lt;p&gt;The software also checks schema markup and structured data.&lt;/p&gt;

&lt;p&gt;Schema helps search engines understand what kind of entity they are looking at.&lt;/p&gt;

&lt;p&gt;A local business website may include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Organization schema&lt;/li&gt;
&lt;li&gt;LocalBusiness schema&lt;/li&gt;
&lt;li&gt;Service schema&lt;/li&gt;
&lt;li&gt;FAQ schema&lt;/li&gt;
&lt;li&gt;Review schema&lt;/li&gt;
&lt;li&gt;Person schema&lt;/li&gt;
&lt;li&gt;Breadcrumb schema&lt;/li&gt;
&lt;li&gt;Website schema&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simplified detector might look like this:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;detect_schema_types&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;schema_types&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;scripts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;script&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/ld+json&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;script&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;scripts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="ow"&gt;or&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;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;data&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;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;schema_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="n"&gt;schema_types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;schema_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;schema_types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema_types&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But we had to be careful not to overvalue schema.&lt;/p&gt;

&lt;p&gt;Schema is useful, but it is not magic.&lt;/p&gt;

&lt;p&gt;A website can have schema on every page and still have weak content.&lt;/p&gt;

&lt;p&gt;A site can technically pass a schema check while still failing to clearly explain services, locations, pricing, process, proof, and customer fit.&lt;/p&gt;

&lt;p&gt;So the report treats schema as one layer of understanding.&lt;/p&gt;

&lt;p&gt;Not the whole story.&lt;/p&gt;

&lt;p&gt;The deeper question is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does the website give search engines and AI systems enough structured explanation to understand and recommend the business?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That led to the next section.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 8: AI Understanding Infrastructure
&lt;/h2&gt;

&lt;p&gt;This is the part I think will matter more over time.&lt;/p&gt;

&lt;p&gt;Most businesses do not have a single clear source of truth about the company.&lt;/p&gt;

&lt;p&gt;They have scattered information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;homepage&lt;/li&gt;
&lt;li&gt;about page&lt;/li&gt;
&lt;li&gt;service page&lt;/li&gt;
&lt;li&gt;reviews&lt;/li&gt;
&lt;li&gt;social profiles&lt;/li&gt;
&lt;li&gt;directory listings&lt;/li&gt;
&lt;li&gt;maybe a few blog posts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But there is usually no structured knowledge layer that explains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what the company is&lt;/li&gt;
&lt;li&gt;what it does&lt;/li&gt;
&lt;li&gt;where it operates&lt;/li&gt;
&lt;li&gt;who it serves&lt;/li&gt;
&lt;li&gt;what problems it solves&lt;/li&gt;
&lt;li&gt;what the process looks like&lt;/li&gt;
&lt;li&gt;what pricing factors exist&lt;/li&gt;
&lt;li&gt;what proof supports it&lt;/li&gt;
&lt;li&gt;who the owner or team is&lt;/li&gt;
&lt;li&gt;how services connect to locations&lt;/li&gt;
&lt;li&gt;how all the business entities relate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That matters because AI systems need a coherent explanation.&lt;/p&gt;

&lt;p&gt;They are not just ranking pages.&lt;/p&gt;

&lt;p&gt;They are generating answers.&lt;/p&gt;

&lt;p&gt;They are summarizing companies.&lt;/p&gt;

&lt;p&gt;They are deciding which businesses to mention, compare, or recommend.&lt;/p&gt;

&lt;p&gt;So we added an AI Understanding Infrastructure diagnostic.&lt;/p&gt;

&lt;p&gt;It checks for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;company/entity explanation&lt;/li&gt;
&lt;li&gt;service catalog clarity&lt;/li&gt;
&lt;li&gt;location catalog clarity&lt;/li&gt;
&lt;li&gt;service-location relationships&lt;/li&gt;
&lt;li&gt;pricing/cost explanation&lt;/li&gt;
&lt;li&gt;process explanation&lt;/li&gt;
&lt;li&gt;FAQs/customer questions&lt;/li&gt;
&lt;li&gt;proof/project evidence&lt;/li&gt;
&lt;li&gt;structured data depth&lt;/li&gt;
&lt;li&gt;entity/SameAs links&lt;/li&gt;
&lt;li&gt;knowledge/resource layer&lt;/li&gt;
&lt;li&gt;AI Knowledge Catalog or subdomain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This section does not just ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does the site have content?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does the site teach Google and AI what this business is?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a more important question.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 9: The AI Knowledge Catalog Idea
&lt;/h2&gt;

&lt;p&gt;One of the recommendations that came out of this work is what we call an AI Knowledge Catalog.&lt;/p&gt;

&lt;p&gt;This is not a blog.&lt;/p&gt;

&lt;p&gt;A blog is chronological.&lt;/p&gt;

&lt;p&gt;A knowledge catalog is structural.&lt;/p&gt;

&lt;p&gt;A blog says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here are posts we published over time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A knowledge catalog says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here is what this company is, what it does, who it helps, where it operates, what proof supports it, and how all of those pieces connect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The main website can remain conversion-focused.&lt;/p&gt;

&lt;p&gt;The knowledge catalog can be understanding-focused.&lt;/p&gt;

&lt;p&gt;It could live on a subdomain like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;knowledge.company.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data.company.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;answers.company.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The purpose is not to replace the main website.&lt;/p&gt;

&lt;p&gt;The purpose is to give search engines and AI systems a clean, crawlable company reference layer.&lt;/p&gt;

&lt;p&gt;For example, a knowledge catalog might include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;company/entity page&lt;/li&gt;
&lt;li&gt;service catalog&lt;/li&gt;
&lt;li&gt;location catalog&lt;/li&gt;
&lt;li&gt;service-location relationship pages&lt;/li&gt;
&lt;li&gt;pricing factor pages&lt;/li&gt;
&lt;li&gt;process pages&lt;/li&gt;
&lt;li&gt;FAQ catalog&lt;/li&gt;
&lt;li&gt;proof/case study catalog&lt;/li&gt;
&lt;li&gt;founder/team pages&lt;/li&gt;
&lt;li&gt;glossary&lt;/li&gt;
&lt;li&gt;sameAs/entity links&lt;/li&gt;
&lt;li&gt;schema markup&lt;/li&gt;
&lt;li&gt;sitemap&lt;/li&gt;
&lt;li&gt;internal linking map&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most businesses have never heard of this.&lt;/p&gt;

&lt;p&gt;That is exactly why it is interesting.&lt;/p&gt;

&lt;p&gt;For years, businesses were told to publish blogs.&lt;/p&gt;

&lt;p&gt;But in the AI search era, random blog posts may be less useful than a structured company knowledge layer.&lt;/p&gt;

&lt;p&gt;AI cannot recommend what it does not understand.&lt;/p&gt;

&lt;p&gt;The knowledge catalog is designed to reduce guessing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 10: Making the Report Useful
&lt;/h2&gt;

&lt;p&gt;The hardest part was making the report readable.&lt;/p&gt;

&lt;p&gt;It is easy to generate data.&lt;/p&gt;

&lt;p&gt;It is harder to create clarity.&lt;/p&gt;

&lt;p&gt;The report had to answer the business owner’s real questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is my website broken?&lt;/li&gt;
&lt;li&gt;Are we likely losing customers?&lt;/li&gt;
&lt;li&gt;What is our biggest visibility gap?&lt;/li&gt;
&lt;li&gt;Do we need a new website?&lt;/li&gt;
&lt;li&gt;What should we fix first?&lt;/li&gt;
&lt;li&gt;Why are competitors showing up?&lt;/li&gt;
&lt;li&gt;Why does this matter now?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the report structure became:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Headline scores&lt;/li&gt;
&lt;li&gt;Owner summary&lt;/li&gt;
&lt;li&gt;Plain-English diagnosis&lt;/li&gt;
&lt;li&gt;Revenue risk summary&lt;/li&gt;
&lt;li&gt;Local demand capture gaps&lt;/li&gt;
&lt;li&gt;Local map visibility snapshot&lt;/li&gt;
&lt;li&gt;Competitor visibility contrast&lt;/li&gt;
&lt;li&gt;Top problems costing visibility&lt;/li&gt;
&lt;li&gt;What Google/AI sees vs. what it still has to guess&lt;/li&gt;
&lt;li&gt;AI Understanding Infrastructure&lt;/li&gt;
&lt;li&gt;Google &amp;amp; AI Visibility Scorecard&lt;/li&gt;
&lt;li&gt;90-day roadmap&lt;/li&gt;
&lt;li&gt;Expected business impact&lt;/li&gt;
&lt;li&gt;Technical appendix&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The technical appendix still matters.&lt;/p&gt;

&lt;p&gt;It contains page inventories, schema checks, crawl evidence, authority context, and detailed diagnostics.&lt;/p&gt;

&lt;p&gt;But the owner does not need to start there.&lt;/p&gt;

&lt;p&gt;The owner needs the story first.&lt;/p&gt;

&lt;p&gt;Then the evidence.&lt;/p&gt;

&lt;p&gt;That was a major design principle.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 11: Scoring Without Overclaiming
&lt;/h2&gt;

&lt;p&gt;Scoring is tricky.&lt;/p&gt;

&lt;p&gt;A score creates urgency.&lt;/p&gt;

&lt;p&gt;But a bad score can destroy trust if it feels arbitrary.&lt;/p&gt;

&lt;p&gt;So we made the scoring painful but explainable.&lt;/p&gt;

&lt;p&gt;The report evaluates areas like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;homepage foundation&lt;/li&gt;
&lt;li&gt;website structure/content&lt;/li&gt;
&lt;li&gt;service page coverage&lt;/li&gt;
&lt;li&gt;location page coverage&lt;/li&gt;
&lt;li&gt;service-location coverage&lt;/li&gt;
&lt;li&gt;thin page risk&lt;/li&gt;
&lt;li&gt;schema coverage&lt;/li&gt;
&lt;li&gt;internal linking&lt;/li&gt;
&lt;li&gt;authority/search context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also added caps so weak sites do not accidentally score too high.&lt;/p&gt;

&lt;p&gt;For example, if a site has no schema, no search visibility, no service-location assets, and only a handful of thin pages, it should not receive a comfortable score.&lt;/p&gt;

&lt;p&gt;A site with six pages, no organic keywords, no organic traffic, no true location pages, no service-location pages, and thin content should feel urgent.&lt;/p&gt;

&lt;p&gt;Not exaggerated.&lt;/p&gt;

&lt;p&gt;Urgent.&lt;/p&gt;

&lt;p&gt;The label matters too.&lt;/p&gt;

&lt;p&gt;A score like &lt;code&gt;35/100&lt;/code&gt; with &lt;code&gt;Severe local visibility gap&lt;/code&gt; is much clearer than a vague &lt;code&gt;needs improvement&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Business owners need to feel the size of the gap.&lt;/p&gt;

&lt;p&gt;But they also need to believe it is fixable.&lt;/p&gt;

&lt;p&gt;That balance became central to the report.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 12: The 90-Day Roadmap
&lt;/h2&gt;

&lt;p&gt;The report does not stop at diagnosis.&lt;/p&gt;

&lt;p&gt;It gives a practical roadmap.&lt;/p&gt;

&lt;p&gt;A typical roadmap might include:&lt;/p&gt;

&lt;h3&gt;
  
  
  Days 1–30: Homepage and GBP Landing Page Strengthening
&lt;/h3&gt;

&lt;p&gt;Clarify title tags, H1s, metadata, primary service, primary location, contact signals, local proof, map evidence, schema, and internal links.&lt;/p&gt;

&lt;h3&gt;
  
  
  Days 31–60: Build Service-Location Assets
&lt;/h3&gt;

&lt;p&gt;Create dedicated pages for high-value service-location combinations.&lt;/p&gt;

&lt;p&gt;Add localized proof, FAQs, internal links, and structured data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Days 61–90: Expand Proof, Schema, and AI Understanding
&lt;/h3&gt;

&lt;p&gt;Add project evidence, customer questions, process explanations, pricing factors, local proof, schema, and potentially an AI Knowledge Catalog.&lt;/p&gt;

&lt;p&gt;That roadmap is important because it turns the report from criticism into a plan.&lt;/p&gt;

&lt;p&gt;The business owner does not just learn what is wrong.&lt;/p&gt;

&lt;p&gt;They see what to do next.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;After building and testing this software, a few lessons stood out.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Business owners do not need more jargon.
&lt;/h3&gt;

&lt;p&gt;They need translation.&lt;/p&gt;

&lt;p&gt;A missing location page is not just a missing page.&lt;/p&gt;

&lt;p&gt;It is a missing local visibility asset.&lt;/p&gt;

&lt;p&gt;Thin content is not just a content issue.&lt;/p&gt;

&lt;p&gt;It is weak evidence.&lt;/p&gt;

&lt;p&gt;A generic homepage is not just a design choice.&lt;/p&gt;

&lt;p&gt;It may be the page Google is relying on to understand the entire business.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Competitor contrast creates urgency.
&lt;/h3&gt;

&lt;p&gt;A score is useful.&lt;/p&gt;

&lt;p&gt;But seeing named competitors at &lt;code&gt;#1&lt;/code&gt; and &lt;code&gt;#2&lt;/code&gt; while the prospect is buried creates a different level of clarity.&lt;/p&gt;

&lt;p&gt;It turns the report from theoretical to real.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. AI visibility is really an understanding problem.
&lt;/h3&gt;

&lt;p&gt;People talk about AI search like it is a completely separate thing.&lt;/p&gt;

&lt;p&gt;But the foundation is similar:&lt;/p&gt;

&lt;p&gt;Can the system understand the business?&lt;/p&gt;

&lt;p&gt;Can it classify the entity?&lt;/p&gt;

&lt;p&gt;Can it connect services, locations, proof, and authority?&lt;/p&gt;

&lt;p&gt;Can it recommend the business without guessing?&lt;/p&gt;

&lt;h3&gt;
  
  
  4. More content is not the answer.
&lt;/h3&gt;

&lt;p&gt;Better structured evidence is the answer.&lt;/p&gt;

&lt;p&gt;Random blogs are not enough.&lt;/p&gt;

&lt;p&gt;A company needs clear service pages, location pages, proof pages, FAQs, process pages, pricing explanations, schema, and internal links.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. A good-looking website can still be underbuilt.
&lt;/h3&gt;

&lt;p&gt;This may be the most important lesson.&lt;/p&gt;

&lt;p&gt;Design and visibility are not the same thing.&lt;/p&gt;

&lt;p&gt;A website can look beautiful and still fail to explain the business in a way Google and AI can use.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Outcome
&lt;/h2&gt;

&lt;p&gt;The final software gives business owners a report that explains how their company appears to Google, Google Maps, and AI search systems.&lt;/p&gt;

&lt;p&gt;It shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where local demand may be leaking&lt;/li&gt;
&lt;li&gt;why competitors may be easier to recommend&lt;/li&gt;
&lt;li&gt;what pages are missing&lt;/li&gt;
&lt;li&gt;where the homepage is weak&lt;/li&gt;
&lt;li&gt;whether the Google Business Profile points to a strong landing page&lt;/li&gt;
&lt;li&gt;whether the site has enough structured data&lt;/li&gt;
&lt;li&gt;whether the company has an AI understanding layer&lt;/li&gt;
&lt;li&gt;what should be fixed first&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the benefit.&lt;/p&gt;

&lt;p&gt;Not a generic SEO audit.&lt;/p&gt;

&lt;p&gt;A visibility infrastructure diagnosis.&lt;/p&gt;

&lt;p&gt;The goal is not to scare business owners.&lt;/p&gt;

&lt;p&gt;The goal is to show them what they have never been able to see before.&lt;/p&gt;

&lt;p&gt;Why they are not getting found.&lt;/p&gt;

&lt;p&gt;Why competitors may be easier to understand.&lt;/p&gt;

&lt;p&gt;Why Google and AI still have to guess.&lt;/p&gt;

&lt;p&gt;And what can be built to close the gap.&lt;/p&gt;

&lt;p&gt;At Firm IQ, we are making these Google &amp;amp; AI Visibility Infrastructure Audits available for a limited time.&lt;/p&gt;

&lt;p&gt;You can request one here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://firmiq.io/free-search-ai-audit/" rel="noopener noreferrer"&gt;https://firmiq.io/free-search-ai-audit/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also view an example report here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://drive.google.com/file/d/12CbK11O35tYAw9SIRCWKXY-o7zUwCp7f/view?usp=sharing" rel="noopener noreferrer"&gt;https://drive.google.com/file/d/12CbK11O35tYAw9SIRCWKXY-o7zUwCp7f/view?usp=sharing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The search problem is changing.&lt;/p&gt;

&lt;p&gt;It is no longer just:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can your website rank?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is becoming:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do Google and AI understand your business well enough to recommend it?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the problem this software was built to show.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>google</category>
      <category>seo</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
