# Construction Lead Intelligence Scraper (`techforce.global/construction-lead-intelligence-scraper`) Actor

Scrape verified leads for contractors, interior designers & builders from Google Maps. Get emails, SEO/security grades, and ready-to-use sales pitches.

- **URL**: https://apify.com/techforce.global/construction-lead-intelligence-scraper.md
- **Developed by:** [Techforce Global](https://apify.com/techforce.global) (community)
- **Categories:** Agents, Automation, Real estate
- **Stats:** 2 total users, 1 monthly users, 66.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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

### Construction Lead Intelligence Scraper

Find **construction-industry leads on Google Maps** — general contractors, architecture firms, interior designers, roofing contractors, construction companies, and real estate agencies — complete with verified contact emails, working hours, and reviews. **No manual Google Maps searching, no copy-pasting contact details, no guessing which leads are worth a pitch.**

Built for **agencies, freelancers, and sales teams** selling web design, SEO, or digital services to the construction trade, who need a ready-to-call lead list with a sales angle already attached — not an afternoon of scrolling Google Maps and guessing who needs help.

> **Pick a business type and city → get every matching company with contact info → know exactly who to pitch and why.**

***

### ⭐ Why This Actor?

- ✅ **Just pick a business type and city** — or drop in a full Google Maps search/URL — no manual scrolling through Maps results.
- ✅ **Construction-only, on purpose** — the Actor validates every search against the construction trade (general contractors, architects, interior designers, roofing, construction companies, real estate); anything else is rejected before it burns a run.
- ✅ **Finds a real contact email** — visits each business's website and checks the homepage/footer plus high-probability contact/about pages for the best email, not just a scrape of whatever's on the homepage.
- ✅ **Optional lead-intelligence report** — turn on Advanced Web Analysis to get a website health scorecard, SEO/SSL/technical grades, a recommended sales pitch, and estimated revenue potential for each lead.
- ✅ **Fast, concurrent scraping** — a pool of parallel browser pages processes multiple businesses at once instead of one at a time.
- ✅ **Deliver anywhere via MCP connectors** — push scraped leads straight into Notion, Slack, Airtable, or any other MCP-compatible tool.
- ✅ **Export-ready** — JSON and CSV are saved automatically, and new runs merge with previous results instead of overwriting them.

***

### 📝 Use Cases & ROI

| Use Case | Time Saved | What You Get |
| --- | --- | --- |
| **Agency lead prospecting** | 3–6 hrs/city | A contactable shortlist of construction businesses with emails and pitch angles |
| **Web/SEO service sales** | 2–4 hrs/list | Website health grades and pain points to open the conversation with |
| **Local market mapping** | 2–5 hrs/report | Every general contractor, architect, or interior designer in a city, in one dataset |
| **Cold outreach campaigns** | 1–3 hrs/batch | Ready-to-import CSV/JSON of names, emails, phones, and hours |
| **CRM enrichment** | 2–4 hrs/batch | Fresh construction-lead records ready to import via API |

***

### 🚀 How to Use

1. Open the Actor on Apify.
2. Pick a **Business type** (e.g. `General contractor`, `Interior designer`) and enter a **Location** — or use **Search by business name, Google Maps URL, or custom query** for a specific target.
3. Set **Maximum businesses** to analyze (1–500, default 20).
4. Leave **Advanced business opportunity analysis** on to get the full lead-intelligence report, or turn it off for basic contact scraping only.
5. Adjust **Parallel browser pages**, **Email pages per website**, and **Audit pages per website** if needed — the defaults work for most runs.
6. Optional: select an **MCP connector** and fill in **Delivery mode**, **Connector tool name**, and **Connector tool arguments** to push leads straight into Notion, Slack, or Airtable as they're scraped.
7. Click **Run** — results are saved to the dataset as each business is processed.
8. Download as JSON or CSV, or pull results via the Apify API.

> 💳 **Free plan**: Advanced Web Analysis is capped at **20 companies per run**. Basic contact scraping (name, phone, email, hours) is unaffected by this cap.
> 💰 **Paid runs**: Advanced Web Analysis is billed as a pay-per-event charge (`advanced-web-analysis`) and only runs when the actor is published with pay-per-event pricing configured in Apify Console — otherwise it's skipped and the run falls back to basic details only.

***

### 🧩 Input Configuration

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `searchQueries` | String | Optional | Business name, Google Maps URL, or custom query. Only construction-related searches are accepted (e.g. `"General contractor in Ahmedabad"`); non-construction searches are rejected. Overrides `category`/`subcategory`/`location` when set. |
| `category` | Enum | Optional | Business category. Currently `Construction` only. Used only when `searchQueries` is empty. |
| `subcategory` | Enum | Optional | Exact business type: `Architecture firm`, `Real estate agency`, `General contractor`, `Interior designer`, `Roofing contractor`, `Construction company`. Default: `General contractor`. |
| `location` | String | Optional | City, area, state, or country to search in (e.g. `"Ahmedabad"`, `"Chicago, USA"`). Default: `"Ahmedabad"`. |
| `maxResults` | Integer | Optional | Maximum businesses to analyze (1–500). Default: `20`. |
| `language` | String | Optional | Google Maps language code. Default: `"en"`. |
| `batchSize` | Integer | Optional | Businesses processed in parallel (1–20). Lower this if pages load slowly. Default: `4`. |
| `maxEmailPagesPerSite` | Integer | Optional | Max pages checked per website for email/social links (1–25). Default: `4`. |
| `advanceWebAnalysis` | Boolean | Optional | Generates the lead priority, pitch strategy, service recommendations, website scorecard, and technical intel for each business. Default: `true`. |
| `maxAuditPagesPerSite` | Integer | Optional | Max website pages sampled for the opportunity report (1–25). Default: `6`. |
| `mcpConnector` | String | Optional | ID of a connector you've authorized in Apify (Notion, Slack, Airtable, etc.). Leave empty to skip delivery and keep leads in the dataset only. |
| `deliveryMode` | Enum | Optional | How leads are sent to the connector: `perLead` (one call per lead), `summary` (one call for the whole list), `chunked` (batched calls under a size limit), or `none`. Default: `perLead`. |
| `mcpTool` | String | Optional | The tool to call on the connector, e.g. `create_page` (Notion), `send_message` (Slack), `create_record` (Airtable). |
| `mcpArguments` | JSON | Optional | Arguments passed to the connector tool. Any string value can contain `{placeholders}` (see below). |
| `mcpMessageTemplate` | String | Optional | Template rendered per lead (or per chunk/summary) and exposed as the `{message}` placeholder inside `mcpArguments`. |

#### Example — Basic contact list, no lead report

```json
{
    "subcategory": "Interior designer",
    "location": "Ahmedabad",
    "maxResults": 30,
    "advanceWebAnalysis": false
}
```

#### Example — Full lead-intelligence report

```json
{
    "subcategory": "General contractor",
    "location": "Mumbai",
    "maxResults": 20,
    "advanceWebAnalysis": true,
    "maxAuditPagesPerSite": 6
}
```

#### Example — Custom search query

```json
{
    "searchQueries": "Roofing contractor in Chicago",
    "maxResults": 25
}
```

#### Example — Deliver each lead to Slack as it's found

```json
{
    "subcategory": "General contractor",
    "location": "Austin, USA",
    "maxResults": 15,
    "mcpConnector": "your-slack-connector-id",
    "deliveryMode": "perLead",
    "mcpTool": "send_message",
    "mcpArguments": {
        "channel": "#construction-leads",
        "text": "{message}"
    },
    "mcpMessageTemplate": "🔥 {leadPriority}: {name} ({category})\n{phone} · {email}\n{salesAngle}"
}
```

#### Example — One Notion page per lead

```json
{
    "subcategory": "Interior designer",
    "location": "Ahmedabad",
    "maxResults": 25,
    "mcpConnector": "your-notion-connector-id",
    "deliveryMode": "perLead",
    "mcpTool": "create_page",
    "mcpArguments": {
        "parent_page_id": "your-notion-parent-page-id",
        "title": "{name}",
        "content": "{message}"
    },
    "mcpMessageTemplate": "Category: {category}\nPhone: {phone}\nEmail: {email}\nWebsite: {website}\nRating: {rating} ({reviews} reviews)\nPitch: {recommendedPitch}\nWebsite grade: {finalGrade}"
}
```

#### Example — One Airtable record per lead

```json
{
    "subcategory": "Roofing contractor",
    "location": "Chicago, USA",
    "maxResults": 30,
    "mcpConnector": "your-airtable-connector-id",
    "deliveryMode": "perLead",
    "mcpTool": "create_record",
    "mcpArguments": {
        "table": "Leads",
        "fields": {
            "Name": "{name}",
            "Phone": "{phone}",
            "Email": "{email}",
            "Website": "{website}",
            "Lead Priority": "{leadPriority}",
            "Grade": "{finalGrade}"
        }
    }
}
```

#### Example — Chunked delivery for a large run

```json
{
    "subcategory": "Construction company",
    "location": "Mumbai",
    "maxResults": 200,
    "mcpConnector": "your-notion-connector-id",
    "deliveryMode": "chunked",
    "mcpTool": "append_blocks",
    "mcpArguments": {
        "page_id": "your-notion-page-id",
        "text": "Part {part}/{partCount}\n\n{leads}"
    }
}
```

#### Placeholders available in `mcpArguments` and `mcpMessageTemplate`

| Placeholder | Available in | Description |
| --- | --- | --- |
| `{name}`, `{category}`, `{address}`, `{phone}`, `{email}`, `{website}`, `{rating}`, `{reviews}`, `{mapsUrl}` | `perLead` | The business's basic contact fields |
| `{leadPriority}`, `{salesAngle}`, `{recommendedPitch}`, `{finalGrade}` | `perLead` | Lead-intelligence fields (only populated when Advanced Web Analysis ran) |
| `{leadCount}` | all modes | Total number of leads in this run |
| `{leads}` | `summary`, `chunked` | All leads (or the current chunk) formatted as readable text blocks |
| `{part}`, `{partCount}` | `chunked` | The current chunk number and total chunk count |
| `{message}` | all modes | The rendered `mcpMessageTemplate`, ready to drop into `mcpArguments` |

***

### 📦 Output Fields

Every record is a structured lead report:

| Section | Description |
| --- | --- |
| `LEAD_OVERVIEW` | Lead priority, revenue opportunity level, sales angle, recommended pitch, and estimated monthly/one-time service potential |
| `BUSINESS_PROFILE` | Name, category, address, phone, website, email, working hours, Google rating/reviews, Maps URL |
| `PITCH_STRATEGY` | Opening hook, best services to pitch, pain points to highlight, outcomes to promise, closing strategy |
| `WEBSITE_HEALTH_SCORECARD` | Final grade/classification and a per-area grade breakdown (technical quality, SEO, SSL/security, navigation, performance) |
| `SERVICE_RECOMMENDATIONS` | Prioritized list of services to sell, with what to fix, why it matters, and the expected outcome |
| `TECHNICAL_INTEL` | Tech stack, SSL status, robots.txt/sitemap status, pages audited, and key technical issues found |

When **Advanced Web Analysis** is off (or unavailable on a free run past the cap), the record keeps the same structure but the lead-intelligence fields (`LEAD_OVERVIEW`, `PITCH_STRATEGY`, `WEBSITE_HEALTH_SCORECARD`, `SERVICE_RECOMMENDATIONS`, `TECHNICAL_INTEL`) are left empty since no analysis ran — the `BUSINESS_PROFILE` contact fields (name, category, address, phone, website, email, working hours, rating, review count, Maps URL) are always fully populated either way.

#### Example Output (abridged)

```json
{
    "LEAD_OVERVIEW": {
        "leadPriority": "Hot Lead",
        "revenueOpportunityLevel": "High",
        "estimatedMonthlyServicePotential": "₹25,000 - ₹75,000",
        "estimatedOneTimeProjectPotential": "₹75,000 - ₹2,00,000"
    },
    "BUSINESS_PROFILE": {
        "businessName": "Home Hancer Services Pvt Ltd",
        "category": "General contractor",
        "phone": "091576 91572",
        "website": "http://www.homehancer.co.in/",
        "googleRating": "4.8",
        "totalReviews": "352"
    },
    "WEBSITE_HEALTH_SCORECARD": {
        "finalGrade": "D",
        "finalClassification": "Critical improvement required: core website quality issues should be prioritized"
    }
}
```

> You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. Results are also merged into local combined JSON/CSV files, so re-running a query doesn't overwrite previously saved companies.

***

### 🔌 Integrations & Delivery

Leads don't have to sit in the dataset — point the Actor at any MCP connector you've authorized in Apify (Notion, Slack, Airtable, or anything else on the Apify MCP registry) and each run pushes results straight there as they're scraped.

- **How it connects** — delivery runs through the Apify MCP Proxy. The Actor authenticates with its own run token; Apify injects your connector's credentials server-side, so the Actor never sees or stores your Notion/Slack/Airtable secrets.
- **Delivery modes** — `perLead` calls the tool once per business (best for Slack pings or one-record-per-lead tables); `chunked` batches leads into a handful of calls that stay under a connector's size limits (best for large Notion pages); `summary` sends the whole run in a single call; `none` skips delivery entirely.
- **Any tool, any shape** — `mcpTool` names the exact tool to call (e.g. `create_page`, `send_message`, `create_record`), and `mcpArguments` is a free-form JSON object matching that tool's schema, with `{placeholders}` filled in per lead. If the tool name doesn't match one on the connector, the run logs the available tools and skips delivery instead of failing silently.
- **Delivery never blocks your data** — leads are saved to the Apify dataset first; connector delivery happens afterward and a delivery failure never affects the saved results.

***

### 🛠️ How It Works

`my_actor/main.py` drives a real Playwright browser through Google Maps, then:

1. Builds the search from `category` + `subcategory` + `location`, or uses `searchQueries` directly — rejecting anything that isn't construction-related.
2. Queues the matching Google Maps place URLs and visits each one (through a pool of parallel browser pages) to scrape name, address, phone, hours, rating, and reviews.
3. Visits the business's website to find the best contact email and any social media links, checking the homepage/footer first, then high-probability contact/about pages.
4. If **Advanced Web Analysis** is enabled and available for the run, audits the website's SEO, SSL/security, technical quality, and navigation, then generates the lead priority, pitch strategy, service recommendations, and revenue estimate for that business.
5. Saves every result to the Apify dataset immediately, and merges it into local combined JSON/CSV output files.
6. If an **MCP connector** is selected, delivers the scraped leads to it using the chosen delivery mode — this step runs last and never affects what's already saved.

**Built with:** [Apify SDK for Python](https://docs.apify.com/sdk/python/) · [Playwright](https://playwright.dev/python/) · [Beautiful Soup](https://www.crummy.com/software/BeautifulSoup/) · [Model Context Protocol](https://modelcontextprotocol.io/)

***

### 🆘 Support

For issues, custom sourcing requests, or feature suggestions:

**Email**: bhavin.shah@techforceglobal.com

***

#### Need a Custom Pipeline?

Want multi-city batch runs, deeper enrichment (phone verification, employee counts), or a full CRM integration?

#### [📅 Book a Free 15-min Consultation](https://calendly.com/techforce-global/intro-meeting)

***

Made with ❤️ by **[Techforce](https://www.techforceglobal.com)**
Specialists in High-Performance Web Scrapers and AI Automation.

***

### Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Google or Google Maps. All trademarks are property of their respective owners. The Actor collects only publicly available business information surfaced through Google Maps and public business websites, and does not log into, or scrape behind the authentication of, any platform. Use the data responsibly and in compliance with applicable laws (including GDPR/CCPA) and the terms of the platforms you operate on.

# Actor input Schema

## `searchQueries` (type: `string`):

Optional. Only construction-related searches are accepted, such as 'General contractor in Ahmedabad', 'Architecture firm in Mumbai', 'Roofing contractor in Chicago', or a full Google Maps place/location URL. Non-construction searches are ignored and the actor exits without scraping.

## `category` (type: `string`):

Used only when the custom search field is empty.

## `subcategory` (type: `string`):

The exact type of business to search for when using category + location.

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

Enter one specific city, area, state, or country for this run. Example: 'Ahmedabad' or 'Chicago, USA'. Run one location at a time for cleaner lead lists.

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

Maximum number of Google Maps businesses to analyze.

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

Language code used for Google Maps pages.

## `batchSize` (type: `integer`):

Number of businesses processed at once. Lower this if Google Maps or websites load slowly.

## `maxEmailPagesPerSite` (type: `integer`):

Maximum pages to check on each business website for email and social links.

## `advanceWebAnalysis` (type: `boolean`):

Analyze each website and generate lead priority, pitch strategy, service recommendations, website scorecard, and technical intel.

## `maxAuditPagesPerSite` (type: `integer`):

Maximum website pages to audit for the business opportunity report.

## `mcpConnector` (type: `string`):

Optionally deliver scraped leads into a connector you have authorized — Notion, Slack, Airtable, or any other MCP-compatible connector. Leave empty to only save results to the dataset.

## `deliveryMode` (type: `string`):

How to deliver to the connector: 'perLead' (one call per lead), 'chunked' (split a long lead list across a few calls so services like Notion never time out), 'summary' (one call listing all leads), or 'none' (save to dataset only).

## `mcpTool` (type: `string`):

Name of the tool to call on the connector (e.g. 'create\_page' for Notion, 'send\_message' for Slack, 'create\_record' for Airtable). If unsure, run once with a connector selected — the log lists the connector's available tools.

## `mcpArguments` (type: `object`):

Arguments passed to the connector tool. String values support {placeholders}. In 'perLead' mode: {name}, {category}, {address}, {phone}, {email}, {website}, {rating}, {reviews}, {mapsUrl}, {leadPriority}, {salesAngle}, {recommendedPitch}, {finalGrade} and {message}. In 'summary' mode: {leadCount}, {leads} (all leads as text blocks) and {message}. In 'chunked' mode: same as summary but {leads} holds one part of the list, and {part}/{partCount} give the 1-based part number and total (e.g. use in a page title: 'Leads (part {part}/{partCount})'). Example for Slack: {"channel": "#leads", "text": "{message}"}.

## `mcpMessageTemplate` (type: `string`):

Optional template rendered and exposed as the {message} placeholder in the tool arguments. Per-lead example: '{leadPriority}: {name} ({category}) - {phone} - {email}'. Summary example: 'Found {leadCount} leads:\n\n{leads}'.

## Actor input object example

```json
{
  "searchQueries": "",
  "category": "Construction",
  "subcategory": "General contractor",
  "location": "Ahmedabad",
  "maxResults": 5,
  "language": "en",
  "batchSize": 4,
  "maxEmailPagesPerSite": 4,
  "advanceWebAnalysis": true,
  "maxAuditPagesPerSite": 6,
  "deliveryMode": "perLead",
  "mcpTool": "",
  "mcpArguments": {},
  "mcpMessageTemplate": ""
}
```

# Actor output Schema

## `results` (type: `string`):

Default dataset items produced by this actor.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("techforce.global/construction-lead-intelligence-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("techforce.global/construction-lead-intelligence-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 '{}' |
apify call techforce.global/construction-lead-intelligence-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,techforce.global/construction-lead-intelligence-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/1gn6b6bRjNdIlsIwg/builds/cJ7NqumGSB7cSIF6u/openapi.json
