<?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: Amitabh Mohan</title>
    <description>The latest articles on DEV Community by Amitabh Mohan (@amitabh_mohan_7a01e0fa12f).</description>
    <link>https://dev.to/amitabh_mohan_7a01e0fa12f</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%2F4233367%2Fe674ac3c-fb51-4863-bdb2-ffe9e7b7451a.jpg</url>
      <title>DEV Community: Amitabh Mohan</title>
      <link>https://dev.to/amitabh_mohan_7a01e0fa12f</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amitabh_mohan_7a01e0fa12f"/>
    <language>en</language>
    <item>
      <title>How I Built a 5-Stage B2B Lead Enrichment Waterfall in n8n &amp; Python (75%+ Local SMB Coverage at ~$0.03/Lead)</title>
      <dc:creator>Amitabh Mohan</dc:creator>
      <pubDate>Sun, 08 Nov 2026 10:14:16 +0000</pubDate>
      <link>https://dev.to/amitabh_mohan_7a01e0fa12f/how-i-built-a-5-stage-b2b-lead-enrichment-waterfall-in-n8n-python-75-local-smb-coverage-at-2j1p</link>
      <guid>https://dev.to/amitabh_mohan_7a01e0fa12f/how-i-built-a-5-stage-b2b-lead-enrichment-waterfall-in-n8n-python-75-local-smb-coverage-at-2j1p</guid>
      <description>&lt;p&gt;If you have ever built a lead generation pipeline for local businesses, you already know the harsh reality: scraping &lt;code&gt;mailto:&lt;/code&gt; links from homepages only gets you about &lt;strong&gt;20% of SMB owners&lt;/strong&gt;. The rest are buried behind contact forms, Cloudflare email obfuscation, generic info@ or hello@ front-desk inboxes, or barebones booking portals.&lt;/p&gt;

&lt;p&gt;To fix this without paying $500+/month for a Clay + Apollo + NeverBounce stack, I built a self-healing &lt;strong&gt;n8n + Python/Apify 5-stage enrichment waterfall&lt;/strong&gt;. To prove it works, I benchmarked it against a raw Google Maps export of 50 Med Spas in Austin, TX.&lt;/p&gt;

&lt;h3&gt;
  
  
  📊 Benchmark: 50 Austin Med Spas
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Named Decision-Makers&lt;/th&gt;
&lt;th&gt;Verified Deliverable Emails&lt;/th&gt;
&lt;th&gt;Direct Executive Inboxes (&lt;code&gt;first@&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;Ad Pixels &amp;amp; Tech Stack&lt;/th&gt;
&lt;th&gt;Est. Cost for 50 Leads&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Basic Homepage &lt;code&gt;mailto:&lt;/code&gt; Scraper&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4 (8%)&lt;/td&gt;
&lt;td&gt;11 (22%)&lt;/td&gt;
&lt;td&gt;1 (2%)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;~$0.10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Static B2B Database (Apollo)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;14 (28%)&lt;/td&gt;
&lt;td&gt;16 (32%)&lt;/td&gt;
&lt;td&gt;9 (18%)&lt;/td&gt;
&lt;td&gt;Enterprise Only&lt;/td&gt;
&lt;td&gt;~$15.00+ (seat/credits)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Our 5-Stage Waterfall (n8n + Python)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;31 (62%)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;38 (76%)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;23 (46%)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100% (Meta / Google / TikTok)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~$1.48 ($0.029/lead)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Problem: Local SMBs Are Harder Than SaaS
&lt;/h2&gt;

&lt;p&gt;Finding decision-makers in B2B SaaS is easy because tech founders live on LinkedIn and Crunchbase. Local SMBs—Med Spas, dental practices, roofing contractors, and boutique gyms—rarely maintain active company pages. Standard Google Maps scrapers only give you a front-desk phone number and a URL, leaving you to either pitch &lt;code&gt;info@&lt;/code&gt; or overpay for stale database credits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 1: High-Concurrency Async Subpage Crawl + Cloudflare Decryption
&lt;/h2&gt;

&lt;p&gt;The first stage moves beyond the homepage. Using &lt;code&gt;httpx&lt;/code&gt; and &lt;code&gt;BeautifulSoup&lt;/code&gt;, the engine concurrently crawls high-signal internal links (&lt;code&gt;/about&lt;/code&gt;, &lt;code&gt;/our-team&lt;/code&gt;, &lt;code&gt;/providers&lt;/code&gt;, &lt;code&gt;/contact&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;While scanning the HTML, it does two critical things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zero-Cost Ad-Pixel Detection:&lt;/strong&gt; It checks script tags for &lt;strong&gt;Meta Pixel&lt;/strong&gt;, &lt;strong&gt;Google Ads / GTM&lt;/strong&gt;, and &lt;strong&gt;TikTok Pixel&lt;/strong&gt;—automatically flagging businesses actively spending money on ads as &lt;code&gt;High Intent (Running Ads)&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;Cloudflare Email De-Obfuscation:&lt;/strong&gt; ~15% of local sites use Cloudflare's &lt;code&gt;data-cfemail&lt;/code&gt; protection, hiding emails as &lt;code&gt;[email protected]&lt;/code&gt;. I built a 6-line hex-XOR decoder (&lt;code&gt;int(hex_str[i:i+2], 16) ^ int(hex_str[:2], 16)&lt;/code&gt;) to recover these hidden emails instantly at zero API cost. &lt;/p&gt;
&lt;h2&gt;
  
  
  Stage 2: Free US Federal NPI Registry API
&lt;/h2&gt;

&lt;p&gt;When a healthcare, dental, or aesthetics clinic doesn't list its owner on the website, we tap into federal government data. Every US clinic with a medical director is indexed in the &lt;strong&gt;CMS National Plan and Provider Enumeration System (NPPES)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Passing a raw Google Maps name like &lt;em&gt;"Light Touch Aesthetics"&lt;/em&gt; to the CMS NPI API often returns 0 results. The trick is to &lt;strong&gt;strip branch suffixes&lt;/strong&gt; and append a &lt;strong&gt;trailing wildcard (&lt;code&gt;*&lt;/code&gt;)&lt;/strong&gt;. This pulls the legal &lt;strong&gt;Authorized Official&lt;/strong&gt; (Owner, President, or Medical Director) and their exact medical credentials (&lt;code&gt;MD&lt;/code&gt;, &lt;code&gt;NP&lt;/code&gt;, &lt;code&gt;PA-C&lt;/code&gt;) for free.&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;httpx&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lookup_npi_official&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clinic_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Strip Google Maps branch suffixes (e.g., "Viva Day Spa | Domain" -&amp;gt; "Viva Day Spa")
&lt;/span&gt;    &lt;span class="n"&gt;clean_co&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clinic_name&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;|&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="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;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;version&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;2.1&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;organization_name&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;clean_co&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="c1"&gt;# Wildcard catches "PLLC" / "LLC" differences
&lt;/span&gt;        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;state&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&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="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;limit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&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;https://npiregistry.cms.hhs.gov/api/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;5.0&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;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&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;res&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;[]:&lt;/span&gt;
            &lt;span class="n"&gt;basic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&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;basic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basic&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;authorized_official_first_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="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="n"&gt;ln&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basic&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;authorized_official_last_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;ln&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;cred&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basic&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;authorized_official_credential&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="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="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;basic&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;authorized_official_title_or_position&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Owner&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="nf"&gt;title&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;Decision_Maker&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ln&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt;&lt;span class="p"&gt;()&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Job_Title&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;role&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;cred&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="n"&gt;cred&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;role&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="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Decision_Maker&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;N/A&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;Job_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;N/A&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;h2&gt;
  
  
  Stage 3 &amp;amp; 4: SERP X-Ray + Corporate Email Permutation
&lt;/h2&gt;

&lt;p&gt;Finding a name like "Jorge Ibarra (Medical Spa Director)" alongside a generic &lt;code&gt;info@lighttouchaustin.com&lt;/code&gt; inbox isn't enough for high-converting outbound.&lt;/p&gt;

&lt;p&gt;The engine executes targeted search dorks (LinkedIn &amp;amp; Web SERP X-Ray) to verify the true decision-maker. Next, it generates executive permutations (&lt;code&gt;jorge@&lt;/code&gt;, &lt;code&gt;j.ibarra@&lt;/code&gt;, &lt;code&gt;jorge.ibarra@&lt;/code&gt;) and verifies deliverability against a 9-provider pool—upgrading the generic front desk email into a Direct Executive Inbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 5: 6 Data Hygiene "Battle Scars"
&lt;/h2&gt;

&lt;p&gt;Scraping the data was only half the battle. During the initial Austin test runs, naive regexes and fallbacks produced massive hallucinations. Here are the 6 major bugs we had to squash to reach a 75%+ hit rate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Battle Scar #1: Google's Chief Procurement Officer&lt;/strong&gt;&lt;br&gt;
In raw Google Maps exports, listings without a website still have a &lt;code&gt;url&lt;/code&gt; column (the &lt;code&gt;google.com/maps/search/&lt;/code&gt; link). My initial fallback (&lt;code&gt;r.Website || r.website || r.url&lt;/code&gt;) saw that an Austin spa had no website, grabbed &lt;code&gt;r.url&lt;/code&gt;, and enriched &lt;code&gt;google.com&lt;/code&gt;—proudly reporting that a local Med Spa was run by Jennifer Moceri, Chief Procurement Officer at Google.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Battle Scar #2: The "Hydrafacial, MD" State-Code Hallucination&lt;/strong&gt;&lt;br&gt;
When extracting &lt;code&gt;City, State&lt;/code&gt; from page text, a standard 2-letter US state regex matched &lt;code&gt;MD&lt;/code&gt; (Medical Doctor) as Maryland and &lt;code&gt;IN&lt;/code&gt; (the preposition "in") as Indiana. That produced AI cold email openers like: &lt;em&gt;"Saw your team is running campaigns in Hydrafacial, MD"&lt;/em&gt; and &lt;em&gt;"in I also had, IN."&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Battle Scar #3: Meet "Dr. Ling Recommends" (The Verb-as-a-Surname Trap)&lt;/strong&gt;&lt;br&gt;
On a clinic's site, a heading read "Dr. Ling Recommends". My &lt;code&gt;Dr. [First] [Last]&lt;/code&gt; regex captured "Ling Recommends" as the doctor's full name, classified her as the Clinical Owner, and permuted &lt;code&gt;ling@&lt;/code&gt;. I had to build a human-name validator that blocks verbs, UI words, and 1-letter last initials.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Battle Scar #4: Apostrophe &amp;amp; Compound-Word Blindness&lt;/strong&gt;&lt;br&gt;
When normalizing company names for LinkedIn verification, replacing non-alphanumeric characters turned &lt;em&gt;"It's A Secret Med Spa"&lt;/em&gt; into &lt;em&gt;"it s a secret med spa"&lt;/em&gt;, failing 100% of word-boundary checks. Similarly, &lt;em&gt;"Medspa of Austin"&lt;/em&gt; returned zero LinkedIn hits until I built an alias generator expanding &lt;code&gt;medspa&lt;/code&gt; to &lt;code&gt;med spa&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Battle Scar #5: n8n’s &lt;code&gt;A1:Z2&lt;/code&gt; Empty-Cell Header Shift&lt;/strong&gt;&lt;br&gt;
In n8n’s native Google Sheets node, reading &lt;code&gt;A1:Z2&lt;/code&gt; uses Row 1 as keys and Row 2 as values. It &lt;em&gt;silently drops&lt;/em&gt; any column whose cell in Row 2 is empty. A single blank cell in a client's sheet shifted all headers to the left, corrupting the database. I had to bypass the native node entirely with a raw &lt;code&gt;GET !1:1&lt;/code&gt; HTTP Request to self-heal the schema.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Battle Scar #6: Multi-Location Chain Fan-Out&lt;/strong&gt;&lt;br&gt;
Local chains (like &lt;em&gt;Viva Day Spa&lt;/em&gt;) had multiple Austin branches in the same Google Sheet sharing one root domain. Deduplicating by domain meant only the first branch got updated. I engineered a &lt;code&gt;sheetLeadMap[domain]&lt;/code&gt; fan-out array in the n8n JavaScript node so one enrichment API call automatically populates every branch row in the sheet at zero extra cost.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Open source n8n workflow &amp;amp; Actor
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository (n8n JSON + Setup Guide):&lt;/strong&gt;
&lt;a href="https://github.com/amitabh-312/n8n-google-maps-lead-enrichment-workflow" rel="noopener noreferrer"&gt;n8n-google-maps-lead-enrichment-workflow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apify Enrichment Engine:&lt;/strong&gt;
&lt;a href="https://apify.com/amitabh_312/b2b-website-decision-maker-email-enricher" rel="noopener noreferrer"&gt;B2B Website Decision Maker, LinkedIn &amp;amp; Email Enricher&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2-Minute Live Walkthrough &amp;amp; Benchmark Video:&lt;/strong&gt;
  &lt;iframe src="https://www.youtube.com/embed/JIFyaEh-wvk" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>automation</category>
      <category>python</category>
      <category>webscraping</category>
      <category>lowcode</category>
    </item>
  </channel>
</rss>
