No-Website Leads (Verified)
Pricing
from $1.00 / 1,000 result delivereds
No-Website Leads (Verified)
Local business leads with no live website, a social-only presence, a dead/parked domain, or a DIY-builder site -- every candidate is actually fetched and checked, not just filtered on an empty Google Maps field.
Pricing
from $1.00 / 1,000 result delivereds
Rating
0.0
(0)
Developer
Adam Aly
Maintained by CommunityActor stats
0
Bookmarked
5
Total users
2
Monthly active users
5 days ago
Last modified
Categories
Share
Finds local businesses with no live website, a social-only presence, a dead/parked domain, or a DIY-builder site -- ready-to-pitch leads for web design agencies, SEO consultants, and local lead-gen teams.
What makes this different from other "no website" scrapers
Every competing Actor we researched on Apify Store determines "no website" purely by checking whether the Google Maps listing's website field is empty. That produces a lot of false positives (a business can have a perfectly good site that just isn't linked on Maps) and misses the very common case of a business whose only real web presence is a Facebook page.
This Actor instead:
- Actually fetches and checks every candidate website (
src/classify.js) -- classifying it as healthy, outdated/DIY-builder, a dead link, a parked/for-sale domain, a directory profile, or genuinely absent -- instead of trusting an empty Maps field. - Defaults to "healthy" on any ambiguous case. A false "you have no website" pitch to a business that has a working site is the fastest way to burn a buyer's trust.
- Cross-sources Facebook (
src/facebook.js) for businesses whose Maps listing has no website field but who do have a linked Facebook Page -- a lead type every competitor we found misses entirely. - Attempts email recovery for site-less leads (
src/emailRecovery.js), the #1 complaint about this whole category of tool ("there are no websites to scrape for emails"). - Deduplicates across runs, not just within one run (
src/dedupe.js), so a customer running the same search next month doesn't get billed for leads they already have. - Bills pay-per-event, not pay-per-result -- a small charge for every business checked, a larger charge only for confirmed qualified leads. See "Pricing" below.
Project structure
.actor/actor.json Actor manifestinput_schema.json Defines the input form shown in Apify Consolesrc/main.js Entry point / orchestrationclassify.js Live website verification (the core differentiator)facebook.js Facebook cross-sourcing (best-effort)emailRecovery.js Email recovery for site-less leadsscoring.js 0-100 lead scoringdedupe.js Cross-run deduplication via a named key-value storetest/run-unit-tests.js Unit tests for the network-independent logicDockerfilepackage.json
How it works, end to end
- You give it a
category(e.g. "plumber") and one or morelocations(e.g.["Austin, TX"]). - It calls a base Google Maps scraper Actor (default:
compass/crawler-google-places, a well-established public Actor) to get the raw list of businesses. You need your own Apify credits to cover that call -- this Actor doesn't reimplement Maps scraping itself, it adds a verification and enrichment layer on top of an existing scraper, which is both faster to build correctly and easier to keep working if Google changes Maps' page structure. - For each business, it classifies the website status, scores the lead, attempts Facebook cross-sourcing and email recovery, and skips anything already delivered to this same customer in a prior run.
- Qualified leads are written to the Actor's dataset with a lead score and a plain-English reason for the classification.
Setting this up for real (steps you need to do -- I can't do these from here)
- Create a free Apify account at apify.com if you don't have one (no card required, $5/month in free platform credit).
- Install the Apify CLI locally:
npm install -g apify-cli - From this project folder, run:
This uploads and builds the Actor under your account.apify loginapify push - Open it in Apify Console and go to the Publication tab to fill in the Store listing (title, description, category tags) -- see "Launch checklist" below.
- Set up monetization (Publication tab -> Monetization -> Pay per event):
- Add an event named exactly
business-checked-- suggested price $0.001 - Add an event named exactly
qualified-lead-delivered-- suggested price $0.012-$0.015 - These event names must match the strings used in
src/main.js(Actor.charge({ eventName: ... })) exactly, or billing won't fire. - Note: significant pricing changes take a 14-day notice period on Apify before they apply, so set your initial pricing carefully.
- Add an event named exactly
- Enable a free trial (a handful of free qualified leads) in the Monetization settings -- with zero reviews at launch, letting people see real output before paying is your main trust signal.
- Submit for publish. Apify reviews new Actors before they appear in Store search.
Known issue found and fixed during real testing (read this)
The first real test run against Google Maps data for "plumber" in Austin, TX flagged 4 leads out of 20 checked. Manual verification found 3 of those 4 actually have real, working websites (aaa-auger.com, rooterman.com, radiantplumbing.com) -- only 1 (a business whose only linked presence was a Facebook page) was a genuinely correct lead. That's a 75% false-positive rate on that batch, traced to this cause:
Small business websites are increasingly protected by bot-detection services
(Cloudflare and similar) that block automated requests from cloud servers
like Apify's, even though the site works completely normally for a real
visitor in a browser. The original code treated any failed automated fetch
as UNREACHABLE (a qualifying lead), which is wrong -- a bot-block and a
truly dead site look similar to a simple fetch, but they are not the same
thing.
The fix, already applied in this version:
- Added a new
COULD_NOT_VERIFYstatus, used when a fetch fails with a status code (403/429/503) or page content commonly associated with bot detection/challenge pages, rather than a real dead-site signal. COULD_NOT_VERIFYis hard-blocked from ever counting as a qualified lead inscoring.jsitself (not just via the input schema), so it can't be miscounted even by a direct API call that bypasses the Console UI.- Each classification attempt now retries once with a different simulated browser before giving up, since a single failed request against a real live site is common and often transient.
UNREACHABLEwas removed from the default qualifying statuses -- it's still available as an opt-in, but given what this test found, treat it as a weaker, higher-false-positive signal than the others until you've validated it further.
This does not mean the false-positive problem is now fully solved -- it means the most identifiable cause found in one real test batch was addressed. Re-run the same manual verification process (see below) against the new build before trusting it with real customers, and expect to keep tightening this over time as new failure patterns turn up.
Testing before you rely on it
I validated everything I could without live access to Google Maps or arbitrary business websites (this sandbox's network is restricted to a fixed allowlist). What was verified:
- All unit tests pass (
npm test) -- covers every classification branch that doesn't require reaching an arbitrary external site (empty website, Facebook/Instagram/Yelp short-circuit detection), plus all of the scoring logic. - The live HTTP fetch pipeline itself (request, redirect handling, timeout/error
handling, HTML parsing) was verified end-to-end against real reachable URLs and
correctly produces
HEALTHYfor a working page andUNREACHABLEfor a non-existent domain.
What was not and could not be verified from here:
- Real classification accuracy against actual Google Maps data and real business websites -- you should run a small test batch (10-20 businesses in your own city) right after deploying and manually check a sample of the classifications before opening it up to customers.
- The Facebook cross-sourcing module's real-world hit rate. Facebook aggressively rate-limits and blocks non-browser traffic; this module is deliberately best-effort and fails closed. Expect a real miss rate, and expect to revisit it as Facebook's page structure changes.
- The
compass/crawler-google-placesbase actor's current exact output field names. I've defensively mapped a couple of common variants inmain.js, but confirm the actual field names in a real run and adjust the mapping if needed. - Parked-domain and DIY-builder detection patterns will need periodic maintenance as hosting providers and parking-page templates change over time -- this is a known, expected maintenance task, not a one-time build.
Pricing rationale
Existing competitors charge $1.50-$5.00 per 1,000 raw results, regardless of how many are actually qualified -- and since typically only 1-5% of businesses lack a website, buyers end up effectively paying far more than the sticker price per usable lead. Charging per verified qualified lead instead means the price you show is the price they actually pay per usable result, which is both more transparent and (per the research) a real, provable gap versus every incumbent found.
Legal / compliance notes (not legal advice)
- Scraping public, logged-out Google Maps listing data has supportive precedent for the "not a computer-crime" question (hiQ v. LinkedIn; Meta Platforms v. Bright Data), but it still violates Google's own Maps Platform Terms of Service. The practical risk is IP blocking/rate-limiting, not criminal liability -- but don't represent this Actor as fully ToS-compliant with Google.
- The real legal exposure sits downstream, with the buyer's outreach: CAN-SPAM and TCPA penalties are real and significant. Consider adding a short, visible disclaimer in your Store listing about buyer responsibility for compliant outreach.
- This Actor does not send any messages itself -- it only produces a data list. Keep it that way for v1; sending messages is a materially different compliance situation.
Explicitly out of scope for this version
- No cold-email or SMS sending
- No CRM integration
- No AI-generated outreach message drafting
- No guaranteed Facebook detection or email discovery -- both are best-effort by design, documented above
Extending this later
- Swap the search-guessing approach in
facebook.jsfor a more thorough Facebook Page lookup once you've validated demand for it. - Add a vertical-specific mode (e.g. contractor license lookups) as a separate higher-priced pay-per-event tier rather than folding it into the base price.
- Add a CRM/Zapier/Make output integration once you have paying customers asking for it.