# 🏠 Roofing Leads Scraper - Roofing Company Emails & Phones (`renzomacar/roofing-leads-scraper`) Actor

City in, roofing company list out: every roofer with phone, website, emails, socials and review counts, extracted live from each company's website. Built for lead-gen agencies and vendors selling to roofing contractors — an industry that pays premium for pipeline. $8 per 1,000 leads.

- **URL**: https://apify.com/renzomacar/roofing-leads-scraper.md
- **Developed by:** [Renzo Madueno](https://apify.com/renzomacar) (community)
- **Categories:** Lead generation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $7.44 / 1,000 leads

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## 🏠 Roofing Leads Scraper — Roofing Company Emails & Phones

Roofing is the vertical where lead-gen money is made: a single replacement job is worth $10k–30k, so roofers pay premium for marketing — and the agencies, software vendors and suppliers who reach them first win. This Actor builds your roofer prospect list on demand: pick a market, get every roofing company with phone, website, **emails and social profiles read live from each roofer's own website**, plus review counts to tell the established contractors from the one-truck operations.

### Start with one line

```json
{ "location": "Phoenix, AZ" }
```

That alone sweeps the default roofing segments — roofing contractor, roof repair, roof replacement, commercial roofing, storm damage roof repair. Narrow it when you need to:

```json
{
  "location": "Phoenix, AZ",
  "keywords": ["commercial roofing"],
  "maxResults": 100,
  "maxPagesPerSite": 2
}
```

Or chase a storm path across cities in one run:

```json
{ "searchQueries": ["roof repair in Tulsa, OK", "storm damage roof repair in Oklahoma City, OK"] }
```

### Roofing segments you can target

`keywords` takes any free text, but these are the segments that come back as genuinely different lists — each one is its own Maps search against your location:

| Keyword | Why you'd pick it |
|---|---|
| `roofing contractor` | The broad list, highest volume in every market — the default starting point |
| `roof repair` | Smaller, service-led operators; the best fit for scheduling and call-tracking software |
| `roof replacement` | Full-replacement crews — the highest job value, so the biggest ad budgets |
| `commercial roofing` | Commercial-only firms; fewer companies, far larger contracts and longer sales cycles |
| `storm damage roof repair` | Insurance-restoration roofers; pair this with a hail or wind event for warm timing |
| `metal roofing` | Specialist installers — the target for metal suppliers and coating manufacturers |
| `flat roof contractor` | Flat/low-slope specialists, concentrated in commercial and multifamily work |
| `gutter installation` | Adjacent trade that usually shares the same buyer; widens a thin market cheaply |

Leaving `keywords` empty sweeps the first five. Add `metal roofing`, `flat roof contractor` or `gutter installation` explicitly when a market is too small on the defaults alone.

### Every roofer, one row

`name` · `category` · `phone` · `website` · `email` + `emails[]` (from the roofer's site) · `socialProfiles` (Facebook is king in roofing; Instagram/LinkedIn/Twitter too) · `websitePhones[]` · `address` with parsed `city`/`country` and coordinates · `rating` + `reviewsCount` · `techStack[]` · `contactPageUrl` · `placeUrl` · `searchQuery` · `scrapedAt`.

Sort by `reviewsCount` descending and you have the market leaders (big budgets, harder to win). Sort ascending among roofers *with* a website and you have the growth-hungry mid-tier — the classic agency sweet spot.

### Gutter, siding and other exterior trades

`keywords` is free text — it is pasted in front of your `location` to form a Maps search — so the same run covers the trades that sit next to roofing and usually share the same owner, the same truck and the same buying decision. Nothing in the Actor is hard-wired to the word "roof":

```json
{
  "location": "Charlotte, NC",
  "keywords": ["gutter installation", "gutter cleaning", "siding contractor", "exterior remodeling"],
  "maxResults": 100
}
```

Useful ones, and what each list looks like:

- `gutter installation` — installers and gutter-guard companies. Often the same firms as roofing, often a separate small operator; either way a short, cheap list to add to a thin market.
- `gutter cleaning` — a different business entirely: recurring-service, route-based, tiny websites, high phone dependence. Good for scheduling and route software, poor for email coverage.
- `siding contractor` and `window replacement` — exterior-envelope trades that buy the same lead-gen and financing products as roofers.
- `general contractor` — the widest net; use only when a market is too small on the trade terms.

Every row is tagged with the `searchQuery` that found it, so a mixed run stays sortable by trade afterwards instead of turning into one undifferentiated list. Deduplication runs across all queries in the same run, so a company that shows up under both `roofing contractor` and `gutter installation` is delivered and charged once.

### Storm and disaster restoration lists

Restoration is a separate ecosystem from ordinary roofing: insurance-funded, event-driven, and buying supplies, labour, financing and canvassing software in a hurry after a hail or wind event. The default sweep already includes `storm damage roof repair`; run it alongside the neighbouring restoration terms to get the whole local response network in one pass:

```json
{
  "searchQueries": [
    "storm damage roof repair in Tulsa, OK",
    "water damage restoration in Tulsa, OK",
    "disaster restoration in Oklahoma City, OK",
    "public adjuster in Oklahoma City, OK"
  ],
  "maxResults": 100
}
```

Timing is the whole game here. These companies are reachable and buying in the days after an event and back to normal within weeks, which is why a list scraped live at run time is worth more than a database export — a restoration list bought six months old is a list of companies that already spent the money.

### Playbooks

**The roofing-agency playbook.** You sell SEO/PPC/lead-gen to roofers. Run one city per client-prospecting sprint, filter `emailFound = true`, personalize with their `rating` and `techStack` ("you're on a stock template and rank below 8 competitors"), and load into Instantly or Smartlead. A 300-roofer city list costs about $2.50.

**The storm-response playbook.** After a hail event, run the affected metros with "roof repair" + "storm damage roof repair". You get the local restoration ecosystem — the companies about to be drowning in work and buying supplies, labor, financing and canvassing software.

**The supplier/manufacturer playbook.** Distributors and shingle/metal manufacturers map dealers and certified-installer candidates per territory, with direct emails instead of LinkedIn guesswork.

**The commercial-only playbook.** `keywords: ["commercial roofing", "flat roof contractor"]` isolates the commercial segment for B2B services that don't fit residential.

### What it costs

$0.008 per roofing company delivered — **$8 per 1,000** — plus $0.01 when a run starts. No plan, no minimum. Most single-city runs land between $1 and $5.

### FAQ

**How complete is email coverage for roofers?**
Roofing skews traditional: many strong companies still run thin websites. Expect emails on roughly 40–60% of roofers that have a site; every lead keeps `emailFound` so you can filter, and phone coverage is near-universal — which suits an industry that answers the phone.

**Can I exclude the guys with no website?**
Yes: `onlyWithWebsite: true`. Dropped companies are never charged. Keep them in if you cold-call — a roofer with no website and 80 reviews is often a great agency prospect.

**Residential vs commercial — can I split them?**
Search them separately (the `searchQuery` field tags every row with the keyword that found it) rather than guessing from names.

**Is this list resellable as "exclusive roofing leads"?**
These are contractor business contacts (B2B), not homeowner job leads. They're for reaching roofing *companies* — don't confuse the two, and don't resell the raw data as something it isn't.

**How does it stay accurate?**
Nothing is cached from a database: discovery and website extraction happen at run time, so you see each company exactly as it presents itself today.

**And the legal side?**
It collects publicly available business listings plus contact details roofers publish on their own sites. Outreach compliance (CAN-SPAM, TCPA for calls/SMS, GDPR abroad) is on you as the sender.

**Can it run on a schedule per territory?**
Yes — weekly scheduled runs per metro via Apify make a rolling "new roofers in market" feed; diff against the previous dataset.

**Worst case, what does a dud search cost me?**
$0.01 — a zero-result run succeeds with an empty dataset and no per-lead charges.

### Same author, adjacent tools

- [B2B Leads Finder](https://apify.com/renzomacar/b2b-leads-finder) — general engine for any niche a client throws at you.
- [Website Contact Finder](https://apify.com/renzomacar/website-contact-finder) — extract contacts from roofer URLs you already collected.
- [Email Verifier](https://apify.com/renzomacar/email-verifier) — protect your sender domain before mailing the list.

# Actor input Schema

## `location` (type: `string`):

City, region or country to search in, e.g. 'Phoenix, AZ', 'San Diego, CA', 'London, UK'.

## `keywords` (type: `array`):

Which roofing business types to search for, one per line. Good options: 'roofing contractor', 'roof repair', 'roof replacement', 'commercial roofing', 'storm damage roof repair', 'metal roofing', 'flat roof contractor', 'gutter installation'. Leave empty to search all common roofing types at once.

## `searchQueries` (type: `array`):

Full searches, one per line (e.g. 'roofing contractor in Phoenix, AZ'). When set, these override Location + roofing service types. Use several queries to cover multiple cities in one run.

## `maxResults` (type: `integer`):

Maximum number of companies to find per search. One search typically yields up to ~120 companies.

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

How many pages to check on each company website when hunting for emails (homepage, /contact, /about...). More pages = more emails found, slightly slower run.

## `onlyWithWebsite` (type: `boolean`):

Drop companies that have no website (they can never have an email). You are not charged for dropped companies.

## `includeGenericEmails` (type: `boolean`):

Keep addresses like info@, hello@, contact@. Disable to keep only personal/role emails (fewer results).

## `language` (type: `string`):

Language code for the discovery search (e.g. 'en', 'es', 'fr', 'de').

## Actor input object example

```json
{
  "location": "Phoenix, AZ",
  "keywords": [
    "roofing contractor"
  ],
  "maxResults": 5,
  "maxPagesPerSite": 1,
  "onlyWithWebsite": false,
  "includeGenericEmails": true,
  "language": "en"
}
```

# Actor output Schema

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

Roofing Leads Scraper results (business, website, phone, address, emails, social profiles), one item per lead in the default dataset.

# 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 = {
    "location": "Phoenix, AZ",
    "keywords": [
        "roofing contractor"
    ],
    "maxResults": 5,
    "maxPagesPerSite": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("renzomacar/roofing-leads-scraper").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 = {
    "location": "Phoenix, AZ",
    "keywords": ["roofing contractor"],
    "maxResults": 5,
    "maxPagesPerSite": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("renzomacar/roofing-leads-scraper").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 '{
  "location": "Phoenix, AZ",
  "keywords": [
    "roofing contractor"
  ],
  "maxResults": 5,
  "maxPagesPerSite": 1
}' |
apify call renzomacar/roofing-leads-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/dwO1qOApXCIvgdCUR/builds/qPMCgCVWfmOZzp8kF/openapi.json
