Millions of local businesses still operate without a website, relying only on Google Business Profile, Yelp, or Facebook. These are prime prospects for web design agencies, local SEO services, and digital marketing. This tutorial uses SERP data to identify businesses that appear only on directory listings but lack their own domain. Each search costs $0.005 and typically surfaces 3-5 website-less businesses per query.
Prerequisites
- Python 3.9+ installed
- requests library installed
- A Scavio API key from scavio.dev
Walkthrough
Step 1: Search for local businesses and classify results
Search for a business category and location, then classify each result as having its own website or only appearing on directories.
import requests, os, re
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
DIRECTORY_DOMAINS = {
'yelp.com', 'yellowpages.com', 'facebook.com', 'bbb.org',
'angi.com', 'homeadvisor.com', 'thumbtack.com', 'mapquest.com',
'manta.com', 'chamberofcommerce.com', 'google.com',
'nextdoor.com', 'bark.com', 'expertise.com'
}
def classify_result(result: dict) -> str:
link = result.get('link', '')
domain = link.split('/')[2] if '/' in link else ''
base = '.'.join(domain.split('.')[-2:]) # e.g., yelp.com
if base in DIRECTORY_DOMAINS:
return 'directory'
return 'own_website'
def find_no_website(category: str, location: str) -> list:
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': f'{category} in {location}', 'country_code': 'us', 'num_results': 10})
results = resp.json().get('organic_results', [])
directory_only = []
for r in results:
if classify_result(r) == 'directory':
# Extract business name from directory listing title
name = r['title'].split(' - ')[0].split(' | ')[0].strip()
directory_only.append({
'name': name, 'listing_url': r['link'],
'directory': r['link'].split('/')[2],
'snippet': r.get('snippet', ''),
'category': category, 'location': location
})
return directory_only
prospects = find_no_website('plumber', 'Austin TX')
print(f'Found {len(prospects)} businesses without websites')
for p in prospects[:5]:
print(f' {p["name"]} (via {p["directory"]})')Step 2: Verify businesses truly lack a website
Double-check by searching for each business name directly. If no owned domain appears in results, they likely have no website.
import time
def verify_no_website(business_name: str, location: str) -> dict:
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': f'{business_name} {location}',
'country_code': 'us', 'num_results': 5})
results = resp.json().get('organic_results', [])
for r in results:
if classify_result(r) == 'own_website':
return {'has_website': True, 'website': r['link']}
return {'has_website': False, 'website': None}
# Verify top prospects
verified_prospects = []
for p in prospects[:5]:
check = verify_no_website(p['name'], p['location'])
p['verified_no_website'] = not check['has_website']
p['found_website'] = check['website']
if not check['has_website']:
verified_prospects.append(p)
status = 'NO WEBSITE' if not check['has_website'] else f'Has: {check["website"]}'
print(f' {p["name"]}: {status}')
time.sleep(0.3)
print(f'\nVerified {len(verified_prospects)} businesses without websites')Step 3: Scale across multiple locations and export
Run the pipeline across many location-category pairs and export the verified prospects.
import csv
def pipeline(categories: list, locations: list) -> list:
all_prospects = []
queries = 0
for loc in locations:
for cat in categories:
prospects = find_no_website(cat, loc)
queries += 1
for p in prospects[:3]: # verify top 3 per query
check = verify_no_website(p['name'], p['location'])
queries += 1
if not check['has_website']:
all_prospects.append(p)
time.sleep(0.3)
print(f'Queries used: {queries} (${queries * 0.005:.3f})')
return all_prospects
categories = ['plumber', 'electrician']
locations = ['Austin TX', 'Denver CO']
prospects = pipeline(categories, locations)
if prospects:
with open('no_website_leads.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['name', 'directory', 'listing_url',
'category', 'location'])
writer.writeheader()
for p in prospects:
writer.writerow({k: p[k] for k in writer.fieldnames})
print(f'Exported {len(prospects)} leads to no_website_leads.csv')Python Example
import requests, os
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
DIRS = {'yelp.com', 'yellowpages.com', 'facebook.com', 'bbb.org', 'angi.com'}
def find_no_website(category, location):
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': f'{category} in {location}', 'country_code': 'us', 'num_results': 10})
prospects = []
for r in resp.json().get('organic_results', []):
domain = r['link'].split('/')[2] if '/' in r['link'] else ''
base = '.'.join(domain.split('.')[-2:])
if base in DIRS:
prospects.append({'name': r['title'].split(' - ')[0], 'directory': base})
return prospects
for p in find_no_website('plumber', 'Austin TX'):
print(f'{p["name"]} (via {p["directory"]})')JavaScript Example
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
const DIRS = new Set(['yelp.com', 'yellowpages.com', 'facebook.com', 'bbb.org', 'angi.com']);
async function findNoWebsite(category, location) {
const resp = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query: `${category} in ${location}`, country_code: 'us', num_results: 10 })
});
const data = await resp.json();
return (data.organic_results || []).filter(r => {
const domain = new URL(r.link).hostname.split('.').slice(-2).join('.');
return DIRS.has(domain);
}).map(r => ({ name: r.title.split(' - ')[0], directory: new URL(r.link).hostname }));
}
findNoWebsite('plumber', 'Austin TX').then(p => p.forEach(x => console.log(`${x.name} (${x.directory})`)));Expected Output
Found 5 businesses without websites
Joe's Plumbing (via yelp.com)
Reliable Plumbing Services (via yellowpages.com)
Quick Fix Plumbing (via facebook.com)
Joe's Plumbing: NO WEBSITE
Reliable Plumbing Services: Has: reliableplumbingaustin.com
Quick Fix Plumbing: NO WEBSITE
Verified 3 businesses without websites
Queries used: 10 ($0.050)
Exported 8 leads to no_website_leads.csv