A supplier is not a manufacturer
Google Maps categories are the most useful column in a scraped row and the easiest to misread. "Electronic parts supplier" and "Electronics manufacturer" sit next to each other in the results for the same query and describe businesses on opposite sides of a transaction. One of them buys a soldering robot. The other sells solder. Getting this distinction into code is what took a raw scrape from unusable to sendable.
The rule the filter encodes is narrow and stated once: keep businesses that FABRICATE, drop businesses that resell, distribute, install or service. Under that rule an "Electronic parts supplier" is a drop — it distributes components and never assembles a board. A "Furniture store" is a drop; it resells furniture and does not cut it. A "Cabinet maker" is a keep. So is a "Sign shop", a "Plastic fabrication company", a "Machine shop" and a "Millwork" business, because every one of those has a person on the premises turning material into a product.
The mechanism is two lists and an order. A KEEP list of substrings that mean fabrication — manufactur, fabricat, machine shop, sign shop, cabinet maker, millwork, injection molding, makerspace — and a DROP list of substrings that mean commerce or service: store, supplier, supply, wholesal, retail, distributor, dealer, rental, repair, installation, contractor, remodeler, consultant, school. The DROP list is checked FIRST, and that ordering is the entire trick.
Check them the other way round and "Woodworking supply store" matches "woodwork" on the keep list and is admitted — a shop that sells chisels to woodworkers, filed as a woodworker. The same collision catches "Electronics repair store", "Sign supply company" and "Cabinet dealer". Every one of them contains a fabrication word and is not a fabricator. Because a DROP is checked first it loses despite the match, and the substring lists stay short and readable instead of growing a thicket of negative lookaheads.
On top of the categories there is a name-level blocklist for the big-box chains, because a Home Depot or a Lowe’s occasionally files itself under a category that passes. That is eleven hardcoded names and it is the least interesting part of the filter, but it removes the most obviously embarrassing rows from a list you are about to email.
A row with no category at all is dropped. That is a deliberate asymmetry: an unknown business is more likely to be noise than to be a hidden prospect, and the cost of a bad send — a spam complaint against a domain being warmed — is much higher than the cost of missing one lead out of a thousand. The same logic applies to the email column, which is validated separately: placeholder addresses scraped off website templates ([email protected], [email protected]), role addresses that reach nobody (noreply@, postmaster@, abuse@), and the tracking addresses left behind by site builders like Wix and GoDaddy are all stripped. Where a business exposes several addresses, a role address at its own domain — info@, sales@, contact@ — is preferred over a free webmail one, because it is the address that survives a staff change.
Every rejected row is written to rejected.csv with the reason that killed it, and reading that file after changing a rule is not optional. It is where you find out that a category you assumed was commerce is actually the one a whole regional industry files itself under. The filter is only trustworthy because it is cheap to check.
Frequently asked questions
How do you tell a manufacturer from a supplier in scraped data?
By the Google Maps category, read against one rule: does this business fabricate, or does it move goods someone else fabricated. "Electronics manufacturer" keeps; "Electronic parts supplier" drops. The word "supplier" is the tell, and it is common enough to encode as a substring rule.
Why check the blocklist before the allowlist?
Because "Woodworking supply store" matches both. It contains "woodwork", which is a fabrication signal, and "store" plus "supply", which are commerce signals. Checking DROP first means the commerce signal wins, which is correct, and keeps both lists short.
What percentage of scraped rows should be filtered out?
Around 35% in our runs, before deduplication. If you are filtering out far less than that, your rules are too loose and you are about to email a lot of retailers.
Should you keep rows with no category?
No. An uncategorised row is far more likely to be noise than a hidden prospect, and the cost of a spam complaint against a domain you are warming is much higher than the cost of missing one lead in a thousand.
Which scraped email addresses should be discarded?
Template placeholders ([email protected], [email protected]), unattended role addresses (noreply@, postmaster@, abuse@) and site-builder tracking addresses from Wix or GoDaddy. Prefer a role address at the company’s own domain over a free webmail one — it survives a staff change.