<?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: Nearbia</title>
    <description>The latest articles on DEV Community by Nearbia (nearbia-notes).</description>
    <link>https://dev.to/nearbia-notes</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%2Forganization%2Fprofile_image%2F15271%2Fdab11067-b662-44e9-8bf3-d065d6072b12.png</url>
      <title>DEV Community: Nearbia</title>
      <link>https://dev.to/nearbia-notes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nearbia-notes"/>
    <language>en</language>
    <item>
      <title>Starting a Local Directory From Public Records: Notes on the License Frame</title>
      <dc:creator>Nearbia</dc:creator>
      <pubDate>Wed, 28 Oct 2026 12:16:17 +0000</pubDate>
      <link>https://dev.to/nearbia-notes/starting-a-local-directory-from-public-records-notes-on-the-license-frame-39ih</link>
      <guid>https://dev.to/nearbia-notes/starting-a-local-directory-from-public-records-notes-on-the-license-frame-39ih</guid>
      <description>&lt;p&gt;Most local business directories begin with whatever businesses submit about themselves. We are trying the opposite order for &lt;a href="https://nearbia.com" rel="noopener noreferrer"&gt;Nearbia&lt;/a&gt;: start with the records that say who is allowed to do the work, then find websites, then check each site. The directory is not live yet. What is live is a set of plain guides and a work log, and this post walks through the data side of that work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why start with licenses
&lt;/h2&gt;

&lt;p&gt;In Florida, contracting without a state license is a crime, and the state's Department of Business and Professional Regulation (DBPR) is the body that issues trade licenses. For a directory of contractors, that makes the license file a natural "frame": the set of entities that should be in scope before you look at anything else.&lt;/p&gt;

&lt;p&gt;The license data itself is surprisingly structured. A Florida contractor license number starts with a few letters, and those letters encode two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The trade.&lt;/strong&gt; CFC is a certified plumbing contractor, CAC is air conditioning, CGC is general, EC is electrical. Two easy ones to misread: CCC is roofing and CPC is pool/spa.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The scope.&lt;/strong&gt; Codes starting with C are &lt;em&gt;certified&lt;/em&gt; (passed a board-approved exam, valid in any Florida jurisdiction). Codes starting with R are &lt;em&gt;registered&lt;/em&gt; (met local competency rules, valid only where those rules were met).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are modelling this, the prefix is effectively a compound key: &lt;code&gt;trade&lt;/code&gt; + &lt;code&gt;scope&lt;/code&gt;. Treat "certified vs registered" as a first-class field, because it changes where a business can legally work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stages, as a pipeline
&lt;/h2&gt;

&lt;p&gt;The Nearbia work log lays the process out in stages. Paraphrased as a pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;National list of websites.&lt;/strong&gt; Free open datasets of US places are downloaded whole. Each website gets one key so duplicates collapse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License frame.&lt;/strong&gt; Florida's contractor license file lists everyone allowed to work. The log notes the state site blocks automated downloads, so a saved copy from a public web archive is used, and freshness is not guaranteed. That is an honest constraint worth designing around: version your snapshots and record their dates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;City domain list.&lt;/strong&gt; Sites with a plumbing category or name, inside or near city limits, are pulled from the national list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Other candidate sources.&lt;/strong&gt; Building permits, the state business entity registry, and paid search listings for the city.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Merge into companies.&lt;/strong&gt; Records join on license number, then phone, then name and city, then final domain after redirects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Place addresses in city limits.&lt;/strong&gt; A mailing city is not a city boundary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Website check in a real browser.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first slice is deliberately small: one trade (plumbers) in one city (St. Petersburg, Florida).&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that bite you
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Join order matters.&lt;/strong&gt; License number is the strongest key when present. Phone numbers are shared, recycled and tracked. Names drift ("Inc." vs "LLC", DBAs). Domains redirect. Ordering joins from strongest to weakest key keeps bad matches from cascading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mailing city ≠ city.&lt;/strong&gt; The work log points out that some St. Petersburg ZIP codes reach into Seminole, Kenneth City and Pinellas Park. If your city page filters on the mailing city string, you will list businesses that are not in the city. Geocode and test against the actual boundary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Neighbouring cities overlap.&lt;/strong&gt; The log reports that St. Petersburg and Clearwater shared about 80% of the same companies within a radius in their tests. Their decision: a city page lists only companies with an office inside that city. Whatever you choose, make the rule explicit, because "serves the area" and "is located here" are different claims.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not every record says what you think.&lt;/strong&gt; A local business tax receipt is not a contractor license. Registering an LLC does not qualify anyone to contract. If you are merging state corporate filings with license data, keep them as separate attributes rather than collapsing them into one "verified" flag.&lt;/p&gt;

&lt;h2&gt;
  
  
  Public records are a toolbox
&lt;/h2&gt;

&lt;p&gt;Beyond licenses, Florida law opens state, county and city records to inspection by anyone, with specific exceptions. For a contractor, that includes corporate filings and fictitious names (Sunbiz), building permits (county portals), code enforcement cases, court dockets and liens, OSHA inspections, and federal exclusions in SAM.gov. Each answers a different question, and each has blind spots. A permit portal, for example, cannot show work that was done without a permit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to read more
&lt;/h2&gt;

&lt;p&gt;The full write-ups, including the stage table with dates and the record-by-record reference, are in the work log published by &lt;a href="https://nearbia.com/work-log/" rel="noopener noreferrer"&gt;Nearbia&lt;/a&gt;. If you work with licensing or permit data and have hit any of the same problems, I would be glad to hear how you handled them in the comments.&lt;/p&gt;

</description>
      <category>data</category>
      <category>webdev</category>
      <category>opendata</category>
      <category>scraping</category>
    </item>
    <item>
      <title>Why One HTTP Request Misjudged 200 Business Websites, and the Browser + LLM Pipeline That Replaced It</title>
      <dc:creator>Nearbia</dc:creator>
      <pubDate>Tue, 13 Oct 2026 08:41:20 +0000</pubDate>
      <link>https://dev.to/nearbia-notes/why-one-http-request-misjudged-200-business-websites-and-the-browser-llm-pipeline-that-replaced-pb3</link>
      <guid>https://dev.to/nearbia-notes/why-one-http-request-misjudged-200-business-websites-and-the-browser-llm-pipeline-that-replaced-pb3</guid>
      <description>&lt;p&gt;For one slice of &lt;a href="https://nearbia.com/" rel="noopener noreferrer"&gt;Nearbia&lt;/a&gt;, a US local business directory assembled from public records, the team had to answer a narrow question: which candidate websites really belong to a plumber that serves St. Petersburg, Florida? The list started with 200 domains, and fewer than half passed. Below are the pipeline, the first version that failed, and the numbers from a snapshot taken on Oct 1, 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inputs: eight sources, 200 domains
&lt;/h2&gt;

&lt;p&gt;Candidates came from five free sources and three paid ones.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Free&lt;/th&gt;
&lt;th&gt;Paid&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Overture Maps&lt;/td&gt;
&lt;td&gt;Google business listings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Foursquare&lt;/td&gt;
&lt;td&gt;Google Maps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenStreetMap&lt;/td&gt;
&lt;td&gt;Google organic results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AllThePlaces&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Florida license records&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The inclusion rule was geographic. A domain stayed on the list if at least one source put it inside the city boundary (US Census Bureau TIGERweb, Places layer) or within 3 km of that line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;92 domains inside the city;&lt;/li&gt;
&lt;li&gt;90 just outside, in places like Gulfport, Kenneth City and Pinellas Park;&lt;/li&gt;
&lt;li&gt;17 only from organic search results, with no coordinates;&lt;/li&gt;
&lt;li&gt;1 with nothing but a postal city.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every source missed something. 30 domains came from Foursquare and nowhere else, 21 from Overture only, 17 from Google organic results only. All Google lookups for the slice cost about $0.18.&lt;/p&gt;

&lt;h2&gt;
  
  
  Version 1: one request per homepage
&lt;/h2&gt;

&lt;p&gt;The first pass was cheap. It sent a single request to each homepage, took the first 400 KB of raw HTML and searched it for the city name and plumbing words. It failed in both directions.&lt;/p&gt;

&lt;p&gt;Real plumbers it rejected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sites that render their content with JavaScript;&lt;/li&gt;
&lt;li&gt;sites that keep the address on the contact page only;&lt;/li&gt;
&lt;li&gt;sites that say "Tampa Bay" rather than the city name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wrong sites it accepted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lead-generation sites and directories, which repeat the city name all over the page;&lt;/li&gt;
&lt;li&gt;parked domains and server placeholder pages, which it counted as live.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Against a real browser, the quick check undercounted dead domains (27 instead of 36) and let six lead-generation domains through. On Oct 1, 2026 it lost its say in verdicts: now it only reports whether a domain answers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where the checker runs matters too
&lt;/h3&gt;

&lt;p&gt;From a computer in the Netherlands, 47 of the 200 sites did not respond. From a US IP address, 15 of those 47 loaded right away. Since then, every check runs from the US.&lt;/p&gt;

&lt;h2&gt;
  
  
  Version 2: render, label, verify, locate
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Render.&lt;/strong&gt; Every live homepage loads in ordinary Chrome with JavaScript enabled, five browsers in parallel. The 171 homepages that answered took about 40 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Label.&lt;/strong&gt; A language model hosted on Nearbia's own server reads each captured page and assigns one site type: a local company's own site, a franchise location page, a national chain, a directory, a lead-generation site, unrelated, or dead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify.&lt;/strong&gt; The model must quote the page to back its label, and code confirms that each quote really appears there. Labels with confidence below 0.6 go to a person.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Locate.&lt;/strong&gt; Whether a business is local is not the model's call. Code decides it from evidence found on the site.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Location evidence, strongest first
&lt;/h2&gt;

&lt;p&gt;Code reads the homepage first. When it finds nothing there, it opens up to two more pages: contact, service area, or a chain's local page.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Detail&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Phone on the site matches the phone the sources list for that domain&lt;/td&gt;
&lt;td&gt;Those source records already sit in the city. Toll-free 8xx numbers are ignored, since a chain uses the same one everywhere.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Area ZIP code in the address or structured data&lt;/td&gt;
&lt;td&gt;33701 to 33716, 33730 to 33747, 33781, 33782&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;A city from the zone next to "FL" or "Florida"&lt;/td&gt;
&lt;td&gt;The state is mandatory: Gulfport also exists in Mississippi, and Tennessee has a Petersburg.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weak&lt;/td&gt;
&lt;td&gt;Only a region (Pinellas, Tampa Bay) or only the 727 area code&lt;/td&gt;
&lt;td&gt;Not enough to enter the corpus&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Before three duplicates were merged, 91 sites had evidence. The strongest signal was a phone match for 58 of them, city plus state for 19 and a ZIP code for 14. Ten of the 91 were local pages of franchises.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final split of the 200 domains (Oct 1, 2026)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Group&lt;/th&gt;
&lt;th&gt;Domains&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Local plumbers with location evidence&lt;/td&gt;
&lt;td&gt;88&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local plumbers, region only&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local plumbers, no location evidence&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local businesses in another trade (HVAC, appliance repair)&lt;/td&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;National chains and brands&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Directories and lead-generation sites&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Not home services&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplicates redirecting to another domain on the list&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blocked by bot protection, even in a browser&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dead, parked or no DNS&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;200&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 88 form the corpus, and only they go on to a full crawl and fact extraction. Of the 88, 45 sit inside city limits and 38 within 3 km of the boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three things the data got wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A wrong website on a local record.&lt;/strong&gt; Five domains tied to St. Petersburg belonged to plumbers in Colorado, Idaho, Mississippi, Broward County and Orange City, Florida. Without evidence on the sites themselves, they would have entered the directory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gaps in the starting database.&lt;/strong&gt; It lacked 21 of the 45 in-city plumbers in the corpus. Google alone found 11 of those 45.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invented trades.&lt;/strong&gt; The model once labeled a sewer pipe lining company as window cleaning. That is why a person reviews the "another trade" group.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Known limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;This is a single snapshot from Oct 1, 2026. Sites change, and dead domains may come back.&lt;/li&gt;
&lt;li&gt;The check reads the homepage plus at most two pages. A plumber that names its area only deeper in the site lands in "region only" or "no location evidence", and those 17 domains still need a human review.&lt;/li&gt;
&lt;li&gt;Only businesses with a known website are covered. Florida records list 93 active plumbing licenses with a St. Petersburg address; for 69 of them no domain is known, and some have no website at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do you confirm that a website really belongs to a business at a given place? Curious which signals others rely on.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was written with AI assistance from Nearbia's original field notes; every figure in it comes from those notes.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webscraping</category>
      <category>llm</category>
      <category>opendata</category>
      <category>datascience</category>
    </item>
  </channel>
</rss>
