Tutorial

How to Find Businesses Without Websites at Scale

Use SERP data to identify local businesses that lack a website. Build a lead list of web design prospects from search results at $0.005/query.

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.

Python
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.

Python
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.

Python
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

Python
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

JavaScript
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

JSON
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

Related Tutorials

Frequently Asked Questions

Most developers complete this tutorial in 15 to 30 minutes. You will need a Scavio API key (free tier works) and a working Python or JavaScript environment.

Python 3.9+ installed. requests library installed. A Scavio API key from scavio.dev. A Scavio API key gives you 250 free credits per month.

Yes. The free tier includes 250 credits per month, which is more than enough to complete this tutorial and prototype a working solution.

Scavio has a native LangChain package (langchain-scavio), an MCP server, and a plain REST API that works with any HTTP client. This tutorial uses the raw REST API, but you can adapt to your framework of choice.

Start Building

Use SERP data to identify local businesses that lack a website. Build a lead list of web design prospects from search results at $0.005/query.