# Web Design Leads: Website Audit for Outdated & Broken Sites (`mortenm/web-design-leads`) Actor

Website audit for web design and redesign leads: find local businesses with outdated sites, no HTTPS, not mobile friendly, old copyright years, old WordPress, Wix/GoDaddy builders, broken domains or no website. Get emails, phones and a lead score. Works with Google Maps Scraper.

- **URL**: https://apify.com/mortenm/web-design-leads.md
- **Developed by:** [Lead Notebook](https://apify.com/mortenm) (community)
- **Categories:** Lead generation, SEO tools, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 website auditeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Web Design Leads: Website Audit for Outdated & Broken Sites

**Find local businesses that need a new website, with proof you can put in your pitch.** Paste a list of business websites, or pick the results of a Google Maps Scraper run, and this Actor audits each website in bulk. It flags outdated design, no HTTPS, sites that aren't mobile friendly, old copyright years, outdated WordPress, DIY builders like Wix and GoDaddy, broken or expired domains, missing contact forms, missing analytics and basic SEO gaps. Each business gets a **lead score from 0 to 100**, a plain-English list of what's wrong, and the emails and phone numbers found on the site.

You pay only for websites that were actually audited. **Broken, expired, parked, blocked and missing websites are reported for free.**

### What it finds

| Finding | Why a web designer cares |
|---|---|
| 🔒 **No HTTPS / SSL certificate problems** | Browsers show "Not secure" or a full-page warning |
| 📱 **Not mobile friendly** (no responsive viewport) | The site shows as a shrunken desktop page on phones |
| 📅 **Outdated copyright year** (e.g. © 2016) | The site has likely not been touched in years |
| 🧓 **Obsolete HTML**: frames, Flash, `<font>`, `<marquee>`, HTML 4 doctype | A hand-built site from the 2000s |
| 🧩 **Outdated WordPress** (version 5.x or older) and **jQuery 1.x** | Old, unmaintained website software |
| 🛠️ **DIY website builders**: Wix, Squarespace, GoDaddy Website Builder, Weebly, Square Online, Duda, Webflow, GoHighLevel | Owners who built the site themselves |
| 💀 **Broken websites**: domain doesn't resolve, expired certificate, server errors, parked or for-sale domains | The business is still listed but has no working website |
| 🚫 **No website at all** (Google Maps listings without one) | The easiest pitch there is |
| 📨 **No contact form, booking tool or chat** | The site loses enquiries |
| ☎️ **No tap-to-call link** on the homepage | Mobile visitors can't call with one tap |
| 📊 **No analytics** or only the retired Universal Analytics | The owner has no idea how the site performs |
| 🔎 **SEO basics**: missing title, meta description, H1, schema.org business markup, social preview tags, favicon | Quick wins to mention in an SEO pitch |
| 🐢 **Slow homepage** (over 3 s for the HTML alone) | Visitors leave before it loads |

Every finding comes with the **evidence** that triggered it (the copyright text, the generator tag, the measured time, the viewport tag) and the page it was found on, so you can quote it in your outreach.

### How to get web design leads from Google Maps

1. Run [Google Maps Scraper](https://apify.com/compass/crawler-google-places) for a search such as "plumbers in Austin" or "dentists in Denver".
2. Open **Web Design Leads**, and under **Or: Google Maps Scraper results** pick that run's dataset.
3. Run it. Sort the **Leads** table by **Score**: the top rows are businesses with the most visible website problems, with emails and phone numbers next to them.

The business name, city, country and Google place ID are copied from Maps to every row. Businesses that have **no website** on Maps come back as `NO_WEBSITE` leads, free of charge.

You can also paste websites directly (one per line), or send rows with your own CRM IDs in **Businesses with your own IDs**.

### Lead score

The score adds up points for each finding and is capped at 100.

- **High (50–100):** several serious problems, for example not mobile friendly, © 2015 and no HTTPS, or a dead or parked domain.
- **Medium (25–49):** a clear problem or a few smaller ones.
- **Low (0–24):** a reasonably maintained site, usually with only SEO details missing.

The score measures **how much visible work the website needs**. It doesn't measure the business's budget or whether it wants a new website.

### Output example

```json
{
  "opportunityScore": 100,
  "opportunityLevel": "high",
  "businessName": "Oldtown Plumbing & Heating",
  "website": "https://mortenmyrmel03.github.io/lbpq-demo-sites/oldtown-plumbing/",
  "auditStatus": "AUDITED",
  "issueCount": 12,
  "issues": ["not_mobile_friendly", "outdated_copyright", "obsolete_html", "outdated_jquery", "legacy_analytics_only", "no_online_lead_capture", "no_click_to_call", "..."],
  "issueSummary": "No responsive viewport tag: on phones the page most likely shows as a shrunken desktop layout. | The newest copyright year on the homepage is 2013 (13 years ago) ...",
  "platform": null,
  "https": true,
  "mobileViewport": false,
  "copyrightYear": 2013,
  "hasContactForm": false,
  "hasClickToCall": false,
  "emails": ["office@oldtown-plumbing.example"],
  "phones": ["+12175550163"],
  "issueDetails": [
    {
      "id": "outdated_copyright",
      "severity": "high",
      "points": 20,
      "message": "The newest copyright year on the homepage is 2013 (13 years ago): the site has likely not been updated since.",
      "evidence": "© 2013",
      "sourceUrl": "https://mortenmyrmel03.github.io/lbpq-demo-sites/oldtown-plumbing/"
    }
  ]
}
```

(Fictional demo business. Click **Try for free** to run the prefilled demo yourself.)

Export the results to **CSV, Excel, JSON or Google Sheets**, or open the **Issue details** view for one row per finding.

### Pricing

**$5 per 1,000 audited websites** ($0.005 each), plus Apify's tiny run-start fee.

- Charged only when a homepage was actually fetched and analysed.
- **Free:** broken, expired and unreachable websites, parked domains, sites that block crawlers, businesses with no website, invalid URLs and rows over your limits.
- The same website appearing twice is audited and charged **once**.
- Set a maximum charge per run and the Actor stops starting new websites before it's reached. The rest come back as `NOT_PROCESSED` so you can resubmit them.

In our test, a Google Maps Scraper run with 700 plumbers in Houston (468 unique websites) was audited in about 3.5 minutes.

### Input options

| Field | Default | Meaning |
|---|---|---|
| `websites` | demo list | Websites or domains, one per line |
| `datasetId` | none | A Google Maps Scraper dataset (or any dataset with a `website` column) |
| `maxWebsites` | 200 | Unique websites to audit (up to 5,000) |
| `maxPagesPerSite` | 2 | 1 = homepage only; 2 also reads the contact page for more emails and forms |
| `businesses` | none | `[{"website", "clientRecordId", "businessName", "city", "country"}]` for CRM lists |
| `defaultCountry` | `US` | Country used to read phone numbers written without +country code |
| `excludedDomains` | none | Domains to skip, for example your current clients |

### Statuses

| `auditStatus` | Meaning | Charged |
|---|---|---|
| `AUDITED` | Homepage fetched and analysed | Yes |
| `UNREACHABLE` | Domain doesn't resolve, certificate or server error, timeout | No |
| `PARKED_DOMAIN` | Parked, for-sale or under-construction page | No |
| `NO_WEBSITE` | No website in your data | No |
| `BLOCKED` | The site refuses crawlers (robots.txt, 403, bot challenge) | No |
| `INVALID` | Not a usable URL, or a private/internal address | No |
| `NOT_PROCESSED` | Over your limits; resubmit later | No |

### How it works and its limits

- Reads the public homepage (and by default the contact page) with plain HTTP requests. It doesn't run a browser, log in, fill in forms or use proxies, and it respects robots.txt.
- Findings describe the **HTML the site serves**. Pages drawn entirely by JavaScript get the platform, security and speed checks; content checks are skipped and noted in `warnings`.
- "Not observed" means not found in the fetched pages, not proof that something doesn't exist anywhere on the site.
- Load time is one measurement from a US data center for the HTML only, so treat it as a hint.
- Dead domains can be temporary. Re-check before you mention it to the business.
- Emails and phone numbers are the ones the business publishes on its own website. Government addresses shown on a business's site, such as the licensing-board complaint notice Texas plumbers must display (`@tsbpe.texas.gov`, `@hpc.state.tx.us`), are never listed as the business's email, and the board's phone number in that notice (for example (512) 936-5200) is never listed as the business's phone; the row's `warnings` names them. Follow your local rules on cold outreach (CAN-SPAM, GDPR and similar).

### FAQ

**Is this a Wappalyzer or BuiltWith alternative?** It covers the website platforms and marketing tags that matter when selling websites (WordPress, Wix, Squarespace, GoDaddy, Webflow, Duda, GA4, Tag Manager, Meta Pixel and booking tools). It isn't a full technology database. Its job is to tell you **which businesses need a better website, and why**.

**Can I use it for SEO leads?** Yes. Missing titles, meta descriptions, H1 headings, schema.org markup, social preview tags, no HTTPS and slow pages are all reported per site.

**Does it work outside the US?** Yes, for any public website. Set `defaultCountry` (for example `GB` or `AU`) so local phone numbers are read correctly. The findings are language-independent.

**Can I enrich my existing lead list with emails, services and tech stack instead?** Use our [Local Business Leads Enricher](https://apify.com/mortenm/local-business-prospect-qualifier), which focuses on contact routes and service evidence for contractor leads.

**Can I call it from the API, Make, Zapier or n8n?** Yes, like any Apify Actor. Send `{"websites": ["example.com"]}` and read the dataset.

Questions or a feature request? Open an issue on the **Issues** tab.

### More tools from the same developer

- [Local Business Leads Enricher](https://apify.com/mortenm/local-business-prospect-qualifier): paste business websites, get emails, phones, contact forms, services and tech stack with the source page for each.
- [SEO Audit Leads](https://apify.com/mortenm/seo-audit-leads): bulk on-page, technical and local SEO audit of business websites with an SEO score, grade, lead level and the fixes to pitch.
- [Local Business Leads by City & Category](https://apify.com/mortenm/business-leads-overture): find businesses by type and city (a Google Maps alternative from open data), with phones, websites and emails.
- [Google Trends Trending Now + Bluesky, Wikipedia & Songs](https://apify.com/mortenm/social-trends-radar): what is trending right now across Google Trends, Bluesky, Mastodon, Wikipedia, Hacker News and Apple Music.

# Actor input Schema

## `websites` (type: `array`):

One website or domain per line, e.g. bobsplumbing.com or https://www.example-roofing.com/. Up to 5,000 per run (together with the other inputs).

## `datasetId` (type: `string`):

Pick the dataset of a Google Maps Scraper run (or any dataset with a "website" column). The business name, city, country and place ID are kept in the output. Businesses without a website are listed as NO_WEBSITE leads for free. The Actor can read only the dataset you pick here.

## `maxWebsites` (type: `integer`):

Stop after this many unique websites (duplicates are audited and billed once). Rows over the limit are returned as NOT_PROCESSED and can be resubmitted.

## `maxPagesPerSite` (type: `integer`):

1 = homepage only (fastest). 2 (default) also fetches the contact page, which finds more emails and contact forms. Up to 4.

## `businesses` (type: `array`):

For CRM lists: \[{"website": "acme-roofing.com", "clientRecordId": "crm-123", "businessName": "Acme Roofing", "city": "Austin", "country": "US"}]. Every field except website is optional and is copied to the output so results join back to your records.

## `defaultCountry` (type: `string`):

ISO country code used to read phone numbers written without a +country prefix (e.g. (512) 555-0147). Leave empty to keep only numbers with a + prefix. A country given per business overrides it.

## `excludedDomains` (type: `array`):

Websites on these domains are not fetched or billed (e.g. your existing clients).

## `runTimeBudgetSecs` (type: `integer`):

No new website is started after this time; the rest is returned as NOT_PROCESSED. About 500 websites take 3-4 minutes.

## `perSiteTimeBudgetSecs` (type: `integer`):

Total time for one website's pages.

## `requestTimeoutSecs` (type: `integer`):

Timeout for a single page request.

## Actor input object example

```json
{
  "websites": [
    "https://mortenmyrmel03.github.io/lbpq-demo-sites/oldtown-plumbing/",
    "https://mortenmyrmel03.github.io/lbpq-demo-sites/summit-ridge-roofing/",
    "https://mortenmyrmel03.github.io/lbpq-demo-sites/clearwater-plumbing/",
    "https://mortenmyrmel03.github.io/lbpq-demo-sites/brightside-hvac/",
    "https://mortenmyrmel03.github.io/lbpq-demo-sites/parked-domain-demo/",
    "expired-demo-domain.invalid"
  ],
  "maxWebsites": 200,
  "maxPagesPerSite": 2,
  "defaultCountry": "US",
  "runTimeBudgetSecs": 1200,
  "perSiteTimeBudgetSecs": 45,
  "requestTimeoutSecs": 15
}
```

# Actor output Schema

## `leads` (type: `string`):

No description

## `issues` (type: `string`):

No description

## `allFields` (type: `string`):

No description

## `runSummary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "websites": [
        "https://mortenmyrmel03.github.io/lbpq-demo-sites/oldtown-plumbing/",
        "https://mortenmyrmel03.github.io/lbpq-demo-sites/summit-ridge-roofing/",
        "https://mortenmyrmel03.github.io/lbpq-demo-sites/clearwater-plumbing/",
        "https://mortenmyrmel03.github.io/lbpq-demo-sites/brightside-hvac/",
        "https://mortenmyrmel03.github.io/lbpq-demo-sites/parked-domain-demo/",
        "expired-demo-domain.invalid"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mortenm/web-design-leads").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "websites": [
        "https://mortenmyrmel03.github.io/lbpq-demo-sites/oldtown-plumbing/",
        "https://mortenmyrmel03.github.io/lbpq-demo-sites/summit-ridge-roofing/",
        "https://mortenmyrmel03.github.io/lbpq-demo-sites/clearwater-plumbing/",
        "https://mortenmyrmel03.github.io/lbpq-demo-sites/brightside-hvac/",
        "https://mortenmyrmel03.github.io/lbpq-demo-sites/parked-domain-demo/",
        "expired-demo-domain.invalid",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("mortenm/web-design-leads").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "websites": [
    "https://mortenmyrmel03.github.io/lbpq-demo-sites/oldtown-plumbing/",
    "https://mortenmyrmel03.github.io/lbpq-demo-sites/summit-ridge-roofing/",
    "https://mortenmyrmel03.github.io/lbpq-demo-sites/clearwater-plumbing/",
    "https://mortenmyrmel03.github.io/lbpq-demo-sites/brightside-hvac/",
    "https://mortenmyrmel03.github.io/lbpq-demo-sites/parked-domain-demo/",
    "expired-demo-domain.invalid"
  ]
}' |
apify call mortenm/web-design-leads --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mortenm/web-design-leads"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/fQk2L3giMamcYHdm0/builds/DKn8HY3v6wMStThu5/openapi.json
