Construction Lead Intelligence Scraper avatar

Construction Lead Intelligence Scraper

Pricing

from $8.00 / 1,000 results

Go to Apify Store
Construction Lead Intelligence Scraper

Construction Lead Intelligence Scraper

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

Pricing

from $8.00 / 1,000 results

Rating

0.0

(0)

Developer

Techforce Global

Techforce Global

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

Share

Construction Lead Intelligence Scraper — Contractor, Architect & Real Estate Leads with Emails, Website Grades & Pitch Playbooks

Apify Actor MCP Ready Pricing Target

Purpose-built construction and property prospecting: pick a business type (general contractor, architecture firm, interior designer, roofing contractor, construction company, real estate agency) or type your own construction search, and get every firm's phone, address, website, company email scraped from its own site, rating, reviews, hours and Maps URL. An optional Advanced Web Analysis pass adds lead priority, pitch strategy, a website performance grade, prioritized improvements and a tech audit. Billed per result — $10.00 per 1,000 on the Free tier, down to $8.00 per 1,000 on Business. Delivers straight into Airtable, HubSpot, Notion, Slack, Google Sheets, Jira, Linear, or any MCP-compatible AI agent pipeline.


Official Google Places API vs. this Actor

The decisive gap is contact data: the Places API exposes no email field at all, and no view of how good a contractor's website is.

Feature / CapabilityOfficial Google Places APIThis Actor (Apify)
Firm email address❌ Not part of the Places data model✅ Scraped from the firm's own website (up to 25 pages crawled per site)
Construction taxonomy⚠️ Generic place types (general_contractor, real_estate_agency)✅ 6 preset business types plus free-text construction queries, guarded by a 30-term vocabulary
Website quality / audit❌ Not offered✅ Letter grade, 7-area breakdown, tech stack, SSL, robots.txt, sitemap — up to 25 pages/site
Sales intelligence❌ Not offered✅ Lead priority, revenue opportunity, pitch, hook, pain points, close
Authentication & setup❌ Google Cloud project + billing-enabled API key✅ Zero target-site credentials; only an Apify token
Results per text query⚠️ Capped at ~60 (3 pages × 20)⚠️ Capped at 100 per run (20 on free plans)
AI agent / MCP native❌ Requires a custom tool wrapper✅ Native MCP tool and pushes leads into your own MCP connectors
Cost modelPer-request SKU pricing on a GCP billPay-per-result: $10.00 / 1,000 (Free tier) down to $8.00 / 1,000 (Business)

⚠️ Verify before publishing: the ~60-results-per-text-query ceiling and the absence of an email field are long-standing Places API behaviours, but re-confirm both against Google's current Places API docs before relying on this row.


🤖 AI Discovery & MCP Metadata

Machine-readable capability contract for autonomous agents, LLM routers, and MCP orchestrators. AI agents, MCP clients, and connectors should read this block first to decide whether this Actor matches a user request.

ai_discovery:
slug: "techforce.global/construction-lead-intelligence-scraper"
one_line: "Scrape construction and property firms from Google Maps by preset business type or a construction search query, enrich each with the company email from its website, and optionally run one paid Advanced Web Analysis pass that adds lead intelligence, a website grade, improvement recommendations and a tech audit."
primary_purpose: "extract"
secondary_purpose: "enrich"
tertiary_purpose: "deliver"
entity: "construction and property firm leads"
vertical: "construction (fixed - non-construction searches are refused)"
supported_platforms:
- "google.com/maps"
- "the firm's own website (for email + audit)"
supported_tasks:
- "search-construction-firms-by-preset-type-and-location"
- "search-by-custom-construction-query"
- "search-by-google-maps-place-or-location-url"
- "find-firm-email-from-its-website"
- "extract-phone-address-rating-reviews-hours"
- "grade-firm-website-quality"
- "generate-sales-pitch-and-lead-priority"
- "generate-prioritized-service-recommendations"
- "deliver-leads-to-mcp-connector-or-crm"
unsupported_tasks:
- "search-non-construction-business-types (the run exits without scraping)"
- "several-preset-business-types-in-one-run (subcategory is a single value)"
- "scrape-project-tenders-permits-or-planning-applications"
- "extract-owner-or-project-manager-names-or-personal-emails"
- "verify-or-validate-email-deliverability"
- "retrieve-licence-bonding-or-insurance-status"
- "extract-gps-coordinates-or-place-photos"
- "scrape-more-than-100-firms-per-run"
- "send-outreach-emails"
search_keywords:
- "construction lead scraper"
- "contractor email scraper"
- "architect lead generation"
- "roofing contractor leads"
- "interior designer contact data"
- "real estate agency lead list"
- "google maps construction leads"
- "builder prospecting tool"
- "trades lead generation"
- "mcp crm construction lead tool"
synonyms:
- "contractor lead extractor"
- "builder email finder"
- "trades prospecting tool"
- "property firm finder"
related_concepts:
["construction marketing", "trades sales", "proptech", "architecture practice sales", "CRM enrichment", "website audit"]
input_entities:
- "preset business type (1 of 6) OR a free-text construction query"
- "location (city / area / state / country)"
- "max firms (1-100; 20 on free plans)"
- "advanceWebAnalysis toggle (adds the five intelligence blocks)"
output_entities: ["firm", "email", "website grade", "recommendation", "pitch"]
input_rules:
searchQueries_format:
description: "Optional free text. It must read as a construction search (matched against a ~30-term construction vocabulary) or be a Google Maps place/location URL, otherwise the run exits without scraping. When set, it overrides category + subcategory."
examples: ["General contractor in Ahmedabad", "Roofing contractor in Chicago", "https://www.google.com/maps/place/..."]
subcategory_format:
type: "enum (single value, not an array)"
values: ["Architecture firm", "Real estate agency", "General contractor", "Interior designer", "Roofing contractor", "Construction company"]
description: "Used only when searchQueries is empty. One business type per run."
maxResults_format:
type: "integer"
range: [1, 100]
description: "Hard ceiling of 100 per run (schema and code agree). Free Apify plans are further capped at 20."
limits:
max_firms_per_run: 100
free_plan_cap: 20
preset_business_types: 6
business_types_per_run: 1
email_pages_per_site_default: 4
email_pages_per_site_max: 25
audit_pages_per_site_default: 6
audit_pages_per_site_max: 25
parallel_pages_default: 4
parallel_pages_max: 20
service_recommendations_per_firm: 4
pricing:
model: "pay-per-result"
rate_per_1000_by_tier:
free: 10.00
starter: 9.33
scale: 8.67
business: 8.00
note: "Every returned firm is billed at the account tier's per-result rate. Apify platform usage (compute units, residential proxies) is billed separately at plan rates."
known_issue: "The code gates Advanced Web Analysis behind pay-per-EVENT pricing, so on this pay-per-RESULT listing paid runs currently return contacts only - see the Pricing section."
when_to_use: >
You sell to contractors, architects, interior designers or property agencies
— web design, SEO, estimating or project software, materials, staffing — and
want a worked prospect list for one construction business type in a place,
with contact details plus a reason to reach out.
when_not_to_use: >
Your target is not construction (the run exits without scraping), you need
several preset types in one run, tender/permit/planning data, licence or
bonding status, personal names or emails, verified deliverable emails, or
more than 100 firms per run.
alternatives:
- "Use techforce.global/google-maps-leads-sales-intelligence-tool for ANY business type, and for several unrelated types in one run"
- "Use techforce.global/google-maps-scraper when you only need plain listing fields at the lowest cost"
- "Use techforce.global/google-maps-healthcare-leads-sales-intelligence-tool, google-maps-hospitality-lead-scraper or finance-google-maps-lead-scraper for those verticals"
- "Use techforce.global/gov-uk-business-scraper to match UK contractor names against Companies House records"
- "Use an email-verification service on top of companyEmail before sending outreach"
- "Loop this Actor per business type or per city for broader coverage"

What this Actor does

💡 Not targeting construction? This Actor refuses non-construction searches — a query that doesn't read as construction ends the run without scraping. For any other business type use Google Maps Business Leads & Sales Intelligence (free-text queries, any industry), or a sibling vertical: Healthcare, Hospitality, Finance. For plain listings at the lowest cost, use Google Maps Scraper (from $0.80 / 1,000).

  • Two ways in: pick one of 6 preset construction business types with a location, or type your own query — a construction phrase or a full Google Maps place/location URL.
  • Refuses off-vertical work. A custom query is checked against a ~30-term construction vocabulary (architect, builder, civil/concrete/electrical/masonry/mechanical/plumbing/roofing contractor, developer, infrastructure, interior design, structural engineer, real estate agency…). Anything else is ignored and the run ends without scraping — you are never billed for a mis-targeted run.
  • Collects listings with Playwright using resilient extraction that tolerates Google's rotating markup — name, category, rating, review count, address, phone, website, hours.
  • Visits each firm's own website for the company email and social links — up to 25 pages per site if you raise maxEmailPagesPerSite (default 4). This layer is not charged by the Actor.
  • One optional Advanced Web Analysis event — a single per-run charge, not per business — adds LEAD_OVERVIEW, PITCH_STRATEGY, WEBSITE_HEALTH_SCORECARD, SERVICE_RECOMMENDATIONS and TECHNICAL_INTEL, auditing up to 25 pages per site.
  • Fails safe on billing. If the analysis cannot be billed as a pay-per-event charge, the Actor logs a warning, disables the analysis, and still returns contacts — it never aborts the run over it. ⚠️ On the current pay-per-result listing this means paid runs return contacts only; see Cost Control.
  • Free Apify plans get the analysis for up to 20 companies.
  • Runs email discovery and the website audit concurrently per business (separate pages), roughly halving per-firm wall-clock time.
  • Optionally pushes leads to an authorized MCP connector in four delivery modes — one call per lead, chunked parts for long lists, one digest, or none. The dataset is always saved regardless of delivery settings.

When to use it — and when not to

ScenarioFit
Selling web design / SEO / marketing to contractors and architects✅ Strong (this is the core use case)
Estimating, project-management or CRM software prospecting✅ Strong
Materials, equipment or trade-supply distribution✅ Strong
Construction cold outreach with an email and a reason to call✅ Strong
A contacts-only list✅ Strong — turn advanceWebAnalysis off (results are still billed per result)
Deep website audits (up to 25 pages per firm)✅ Strong on free plans; ⚠️ currently gated on paid plans — see Pricing
CRM / Airtable / HubSpot enrichment via connector✅ Strong (deliveryMode: "perLead")
Several preset business types in one runsubcategory is a single value — run once per type
A business type outside construction❌ The run exits without scraping — use the any-industry Actor
More than 100 firms in one execution⚠️ Hard cap of 100 (20 on free plans) — split across runs
Guaranteed-deliverable email addresses⚠️ Emails are scraped, not verified — validate before sending
Tenders, permits, planning applications, project pipelines❌ Not extracted — Google Maps listings only
Licence, bonding or insurance status❌ Not extracted — pair with a registry source
Owner / project-manager names or personal emails❌ Not supported — firm-level public contacts only
Review text, reviewer names, place photos, GPS coordinates❌ Not extracted

⚡ Execution Rules (Avoid Common Agent Failures)

  1. Nothing is required, and every field has a default. required is empty: an input of {} scrapes General contractor in London, maxResults: 5, with Advanced Web Analysis ON. It will not raise a validation error. API and MCP callers should always send subcategory (or searchQueries), location and maxResults explicitly.
  2. maxResults defaults to just 5 — the lowest default in the family. Set it explicitly or you will get a five-row dataset.
  3. subcategory is a single string, not an array. One preset business type per run: Architecture firm, Real estate agency, General contractor, Interior designer, Roofing contractor, Construction company. To cover several, run the Actor once per type.
  4. searchQueries overrides category + subcategory when it is non-empty.
  5. A non-construction searchQueries value ends the run without scraping. The string must contain a construction term (or be a Google Maps URL). "dentist in Austin" produces an empty, successful run — check itemCount and the log, not just run status.
  6. maxResults is capped at 100 per run, matching every sibling Actor; schema and code agree, so >100 is rejected up front. Free Apify plans are further capped at 20.
  7. Results are billed per result, at the account tier's rate — $10.00 / 1,000 on Free down to $8.00 / 1,000 on Business. The advanceWebAnalysis toggle changes what each item contains and how long the run takes; it does not add a separate per-result charge.
  8. The analysis can silently switch itself off. The code requires pay-per-event pricing plus a configured advanced-web-analysis event plus a permissive maxTotalChargeUsd. This listing is priced pay-per-result, so for paying users the first check fails and the run continues on contacts only, with a warning in the log. Free-tier runs skip the check and do get the analysis. Read advancedWebAnalysis in the output to know which mode you actually got.
  9. Every item is the same nested 6-block objectLEAD_OVERVIEW, BUSINESS_PROFILE, PITCH_STRATEGY, WEBSITE_HEALTH_SCORECARD, SERVICE_RECOMMENDATIONS, TECHNICAL_INTEL. Contact fields live inside BUSINESS_PROFILE, not at the top level — this differs from every sibling Actor, whose profile fields are flat. Read item["BUSINESS_PROFILE"]["companyEmail"], never item["companyEmail"].
  10. With the analysis off, the analysis blocks are present but empty. They are not removed — expect empty strings/arrays rather than missing keys, so branch on content, not on key presence.
  11. A missing email is the string "NA". Read BUSINESS_PROFILE.emailStatus first: ok · no_email_found · failed (site wouldn't load) · no_website.
  12. maxEmailPagesPerSite and maxAuditPagesPerSite both go up to 25. They are the two biggest run-time levers; defaults are 4 and 6.
  13. There is no proxy input. This Actor has no proxyConfiguration field and always uses the container's direct connection.
  14. deliveryMode defaults to perLead, not none. With a connector selected, a 100-firm run makes 100 connector calls. For dataset-only runs leave mcpConnector empty or set deliveryMode: "none".
  15. Delivery placeholders use short names{name}, {email}, {rating}, {reviews}, {mapsUrl}not the sibling Actors' {businessName} / {companyEmail} / {googleRating}. A template copied from another Actor in this family will render empty.
dependencies:
- rule: "searchQueries (when non-empty) overrides category + subcategory"
note: "leave it empty to use the preset business type"
- rule: "a non-construction searchQueries value ends the run with zero items"
on_violation: "run is SUCCEEDED with itemCount 0; nothing is scraped or charged"
- rule: "advanceWebAnalysis requires the 'advanced-web-analysis' event configured under pay-per-EVENT pricing"
on_violation: "analysis is disabled with a warning; contacts and emails are still returned"
live_effect: "this listing is pay-per-RESULT, so paid runs currently hit this path"
- rule: "free Apify plans get the analysis but are capped at 20 companies"
note: "the free-tier branch returns before the pricing check"
- rule: "contact fields are nested inside BUSINESS_PROFILE"
on_violation: "top-level lookups like item['companyEmail'] return nothing"
- rule: "delivery requires mcpConnector AND mcpTool"
on_violation: "delivery step is skipped with a warning; the dataset is still written in full"
- rule: "mcpArguments must reference {message} for the rendered template to appear anywhere"
on_violation: "message body is empty; the tool is still called"
- rule: "mcpConnector only resolves when the Actor runs on the Apify platform"
on_violation: "local runs log 'APIFY_MCP_PROXY_URL is not set' and skip delivery; the dataset is unaffected"
authentication:
actor_input: none
platform: "Apify API token required for API / SDK / MCP invocation"
target_site: "no Google account, API key, or GCP billing project required (public listings and public website content only)"

📥 Input Contract

.actor/input_schema.json is authoritative — if any table on this page disagrees with the schema files, the schema files win.

Scraping Parameters

FieldTypeRequiredDefaultAllowed Values / FormatExample
searchQueriesstring⬜ No""A construction phrase, or a Google Maps place/location URL. Overrides category+subcategoryRoofing contractor in Chicago
categorystring (enum)⬜ NoConstructionConstruction onlyConstruction
subcategorystring (enum)⬜ NoGeneral contractorOne of the 6 preset typesArchitecture firm
locationstring⬜ NoLondonCity / area / state / countryAhmedabad
maxResultsinteger⬜ No51100 (free plans capped at 20)100
languagestring⬜ NoenGoogle Maps language codeen
batchSizeinteger⬜ No4120 parallel browser pages8
maxEmailPagesPerSiteinteger⬜ No4125 pages crawled for email/social10
advanceWebAnalysisboolean⬜ NotrueUnlocks all five analysis blocks (see Pricing for the current gating)false
maxAuditPagesPerSiteinteger⬜ No6125 (only used when the analysis runs)20

Preset business types — all 6 values

Business typeTypical buyer for it
General contractorWeb/SEO, estimating software, materials, staffing
Construction companyERP, project management, equipment, insurance
Architecture firmCAD/BIM tooling, rendering, marketing, recruitment
Interior designerSourcing platforms, 3D visualisation, lead gen
Roofing contractorLocal SEO, lead gen, materials, financing
Real estate agencyProptech, listing marketing, photography, CRM

Custom-query vocabulary

A non-empty searchQueries must contain one of ~30 construction terms, or be a Google Maps URL. Accepted terms include:

architecture · architect(s) · builder(s) · building contractor · civil contractor · commercial construction · concrete contractor · construction · construction company · construction firm · contractor(s) · developer(s) · electrical contractor · engineering firm · general contractor · home builder · infrastructure · interior designer · interior design · landscaping contractor · masonry contractor · mechanical contractor · plumbing contractor · property developer · real estate agency · real estate developer · renovation contractor · roofing contractor · structural engineer

Anything else — "dentist in Austin", "cafe in Goa" — is ignored and the run ends without scraping.

Examples

Preset type, contacts only — fastest run, smallest payload:

{
"subcategory": "General contractor",
"location": "Ahmedabad",
"maxResults": 100,
"advanceWebAnalysis": false,
"deliveryMode": "none"
}

Full intelligence on a focused set — one analysis charge covers the whole run:

{
"subcategory": "Architecture firm",
"location": "London",
"maxResults": 50,
"advanceWebAnalysis": true,
"maxAuditPagesPerSite": 20,
"deliveryMode": "none"
}

Custom construction query with a deeper email crawl:

{
"searchQueries": "Roofing contractor in Chicago",
"maxResults": 80,
"maxEmailPagesPerSite": 12,
"advanceWebAnalysis": false,
"deliveryMode": "none"
}

MCP Delivery Configuration (Optional)

ParameterTypeDefaultDescription
mcpConnectorstring""Authorized MCP connector on your Apify account (Airtable, HubSpot, Notion, Slack, Sheets, Jira, GitHub, Linear, …). Leave empty for dataset-only runs.
deliveryModeenumperLeadperLead (one call per lead) · chunked (split a long list across calls) · summary (one digest) · none.
mcpToolstring""Tool name on the connector: create_record, send_message, create_page, create_issue. Run once with a connector selected — the log lists the connector's available tools.
mcpArgumentsobject{}Arguments passed to the tool. String leaves support {placeholders}.
mcpMessageTemplatestring""Template rendered and exposed to mcpArguments as {message}.

Placeholders by mode — short names, unlike every sibling Actor:

ModePlaceholders
perLead{name}, {category}, {address}, {phone}, {email}, {website}, {rating}, {reviews}, {mapsUrl}, {leadPriority}, {salesAngle}, {recommendedPitch}, {finalGrade}, {message}
summary{leadCount}, {leads} (all leads as text blocks), {message}
chunkedthe above, plus {part} and {partCount} — and {leads} holds one part

Chunked delivery groups lead blocks into parts under ~72,000 characters, so services with per-request block or timeout caps (Notion in particular) never reject the call.

One Airtable/CRM record per lead:

{
"subcategory": "Roofing contractor",
"location": "Chicago",
"maxResults": 60,
"mcpConnector": "<your-authorized-airtable-connector>",
"deliveryMode": "perLead",
"mcpTool": "create_record",
"mcpArguments": {
"fields": {
"Name": "{name}",
"Type": "{category}",
"Phone": "{phone}",
"Email": "{email}",
"Website": "{website}",
"Rating": "{rating}",
"Priority": "{leadPriority}",
"Grade": "{finalGrade}",
"Maps": "{mapsUrl}"
}
}
}

One Slack digest for the whole run:

{
"subcategory": "General contractor",
"location": "Manchester",
"maxResults": 40,
"mcpConnector": "<your-authorized-slack-connector>",
"deliveryMode": "summary",
"mcpTool": "send_message",
"mcpArguments": { "channel": "#construction-leads", "text": "{message}" },
"mcpMessageTemplate": "{leadCount} construction leads:\n\n{leads}"
}

Chunked into Notion pages for a long list:

{
"subcategory": "Construction company",
"location": "Mumbai",
"maxResults": 100,
"mcpConnector": "<your-authorized-notion-connector>",
"deliveryMode": "chunked",
"mcpTool": "notion-create-pages",
"mcpArguments": {
"parent": { "page_id": "<your-page-id>" },
"pages": [
{
"properties": { "title": "Mumbai construction leads (part {part}/{partCount})" },
"content": "{leads}"
}
]
}
}

📤 Output Contract & Data Structure

Storage: Apify Dataset (one JSON object per firm). Pagination: limit & offset on the dataset items endpoint. Duplicates: one record per listing within a run. Cross-run deduplication is the consumer's responsibility — use BUSINESS_PROFILE.googleMapsUrl as the key.

⚠️ Nested shape — different from every sibling Actor. Each item has six top-level blocks and the contact fields live inside BUSINESS_PROFILE:

{
LEAD_OVERVIEW: {...}, // analysis
BUSINESS_PROFILE: {...}, // ← name, phone, email, website, rating…
PITCH_STRATEGY: {...}, // analysis
WEBSITE_HEALTH_SCORECARD: {...}, // analysis
SERVICE_RECOMMENDATIONS: [...], // analysis
TECHNICAL_INTEL: {...} // analysis
}

With advanceWebAnalysis off (or disabled by billing), the five analysis blocks are still present but empty — empty strings, empty arrays, Unknown — rather than removed. Branch on content, not on key presence.

BUSINESS_PROFILE — always populated

FieldTypeMeaning
businessNamestringFirm name as listed
categorystringGoogle Maps category for the firm
addressstringFull address as displayed
phonestringPhone number as displayed
websitestringWebsite URL from the listing
companyEmailstringEmail found on the firm's website; the literal string "NA" when none was found
emailStatusstringok · no_email_found · failed · no_website
workingHoursobject/stringOpening hours by day (formatted)
googleRatingstringStar rating as a string — e.g. "4.7"
totalReviewsstringReview count as a string
googleMapsUrlstringListing URL — use as the dedupe key
searchQuerystringThe resolved query that produced this record

LEAD_OVERVIEW — requires Advanced Web Analysis

KeyTypeMeaning
leadPrioritystringTriage label — e.g. High
revenueOpportunityLevelstringOpportunity size
salesAnglestringWhy this firm is worth calling
recommendedPitchstringThe pitch to lead with
estimatedMonthlyServicePotentialstringRecurring revenue estimate
estimatedOneTimeProjectPotentialstringProject revenue estimate

PITCH_STRATEGY — requires Advanced Web Analysis

KeyTypeMeaning
openingHookstringOpening line tailored to the firm's rating/reviews/site
bestServicesToPitcharrayServices worth proposing (up to 4)
painPointsToHighlightarrayUp to 5 concrete weaknesses to raise
outcomesToPromisearrayResults to promise
closingStrategystringSuggested close

WEBSITE_HEALTH_SCORECARD — requires Advanced Web Analysis

KeyTypeMeaning
finalGradestringLetter grade for the website overall
finalClassificationstringPlain-language verdict — e.g. Needs Improvement
gradeBreakdownarray of {area, grade, status}Per-area grades. Areas: Technical Quality · Technical SEO · SSL / Security · Navigation Structure · Performance · SEO Readiness · SEO Parameters. Areas with no grade are omitted.

SERVICE_RECOMMENDATIONS — requires Advanced Web Analysis

Array, at most 4 items, sorted High → Medium → Low priority:

KeyTypeMeaning
prioritystringHigh · Medium · Low
servicestringService to sell, in human-readable form
currentGradestringThe area's current grade
whatToFixstringThe concrete work required
whyItMattersstringBusiness rationale
outcomeAfterFixstringExpected result once fixed
sellingPointstringThe line to use in the proposal

TECHNICAL_INTEL — requires Advanced Web Analysis

KeyTypeMeaning
techStackstringDetected stack, or Unknown
sslStatusstringStatus with grade — e.g. "Good (Grade A)"
robotsTxtStatusstringHTTP status label for robots.txt
sitemapUrlstringSitemap URL if found
auditedPagesintegerHow many pages of that site were audited (up to maxAuditPagesPerSite)
auditedUrlsarrayThe exact URLs audited
navigationNotesstringNavigation-structure summary
keyTechnicalIssuesarrayNotable problems found

Consumer rules: read contacts from BUSINESS_PROFILE; googleRating and totalReviews are strings; a missing email is the literal "NA"; analysis blocks exist even when the analysis didn't run; and there is no socialMedia, coordinate, or photo field in the output.

Example output item

{
"LEAD_OVERVIEW": {
"leadPriority": "High",
"revenueOpportunityLevel": "High",
"salesAngle": "Strong local reputation but a dated site with no project gallery or quote form.",
"recommendedPitch": "Rebuild the site around project photography and a quote request flow.",
"estimatedMonthlyServicePotential": "$700–$1,400/mo",
"estimatedOneTimeProjectPotential": "$4,000–$8,000"
},
"BUSINESS_PROFILE": {
"businessName": "Halewood Building Contractors",
"category": "General contractor",
"address": "42 Ordsall Ln, Manchester M5 4RR",
"phone": "+44 161 555 0100",
"website": "https://halewoodbuilding.co.uk",
"companyEmail": "office@halewoodbuilding.co.uk",
"emailStatus": "ok",
"workingHours": { "Monday": "8:00 AM – 5:00 PM" },
"googleRating": "4.7",
"totalReviews": "58",
"googleMapsUrl": "https://www.google.com/maps/place/...",
"searchQuery": "General contractor in Manchester"
},
"PITCH_STRATEGY": {
"openingHook": "You have a 4.7-star rating with 58 reviews - strong social proof.",
"bestServicesToPitch": ["Website redesign", "Local SEO"],
"painPointsToHighlight": ["Performance: slow pages lose quote requests"],
"outcomesToPromise": ["More qualified quote requests from the same traffic"],
"closingStrategy": "Offer a paid audit that credits toward the rebuild."
},
"WEBSITE_HEALTH_SCORECARD": {
"finalGrade": "C",
"finalClassification": "Needs Improvement",
"gradeBreakdown": [
{ "area": "Performance", "grade": "D", "status": "Poor (Grade D)" },
{ "area": "SSL / Security", "grade": "A", "status": "Good (Grade A)" }
]
},
"SERVICE_RECOMMENDATIONS": [
{
"priority": "High",
"service": "Website performance optimization",
"currentGrade": "D",
"whatToFix": "Compress project photos and defer unused scripts.",
"whyItMatters": "Slow galleries lose mobile visitors before they request a quote.",
"outcomeAfterFix": "Faster load and more completed quote forms.",
"sellingPoint": "Turn existing search traffic into booked site visits."
}
],
"TECHNICAL_INTEL": {
"techStack": "WordPress",
"sslStatus": "Good (Grade A)",
"robotsTxtStatus": "200 OK",
"sitemapUrl": "https://halewoodbuilding.co.uk/sitemap.xml",
"auditedPages": 6,
"auditedUrls": ["https://halewoodbuilding.co.uk/"],
"navigationNotes": "Primary navigation is clear; no dedicated services pages.",
"keyTechnicalIssues": ["Large uncompressed gallery images"]
}
}

What a successful run looks like

{
"status": "SUCCEEDED",
"defaultDatasetId": "<datasetId>",
"stats": { "itemCount": 47 }
}

The terminal log line reads Finished <n> companies in <t>s. plus the connector count when delivery ran. itemCount: 0 with a SUCCEEDED status usually means the query was not recognised as construction — check the log before treating it as a scraper failure. On free plans, itemCount stops at 20.


▶️ Invocation & Integration

Lifecycle: Discover → Understand → Configure → Execute → Retrieve → Validate. Authenticate every call with Authorization: Bearer <APIFY_TOKEN>.

Apify Console

Open the Actor → Input tab → either type a construction search or pick a Business type and Location → raise Maximum businesses from the default of 5 → decide on Advanced business opportunity analysis → tune the email/audit page depths → Start → export from the Dataset tab (JSON, CSV, Excel, XML).

Model Context Protocol (MCP)

claude mcp add --transport http apify \
"https://mcp.apify.com?tools=techforce.global/construction-lead-intelligence-scraper"

Python (apify-client)

import os
from apify_client import ApifyClient
client = ApifyClient(os.getenv("APIFY_TOKEN"))
run = client.actor("techforce.global/construction-lead-intelligence-scraper").call(run_input={
"subcategory": "General contractor",
"location": "Manchester",
"maxResults": 100, # 100 is the ceiling; free plans stop at 20
"advanceWebAnalysis": True, # one charge for the whole run
"maxAuditPagesPerSite": 10,
"deliveryMode": "none",
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(f"{len(items)} firms")
# Contacts are NESTED under BUSINESS_PROFILE - not at the top level.
for item in items[:5]:
profile = item.get("BUSINESS_PROFILE", {})
overview = item.get("LEAD_OVERVIEW", {})
print(
profile.get("businessName", "-"),
"|", profile.get("phone", "-"),
"|", profile.get("companyEmail", "NA"),
"|", overview.get("leadPriority") or "(no analysis)",
)
emailable = [
i for i in items
if i.get("BUSINESS_PROFILE", {}).get("companyEmail", "NA") != "NA"
]
print(f"{len(emailable)} with a usable email")

JavaScript / TypeScript (apify-client)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client
.actor('techforce.global/construction-lead-intelligence-scraper')
.call({
searchQueries: 'Roofing contractor in Chicago',
maxResults: 80,
advanceWebAnalysis: false, // contacts only - fastest run
maxEmailPagesPerSite: 10,
deliveryMode: 'none',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
const withEmail = items.filter(
(i) => i.BUSINESS_PROFILE?.companyEmail && i.BUSINESS_PROFILE.companyEmail !== 'NA',
);
console.log(`${items.length} contractors, ${withEmail.length} with an email`);

cURL — synchronous (returns items directly; 300s limit)

curl -X POST \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
-d '{"subcategory":"General contractor","location":"London","maxResults":20,"advanceWebAnalysis":false,"deliveryMode":"none"}' \
'https://api.apify.com/v2/acts/techforce.global~construction-lead-intelligence-scraper/run-sync-get-dataset-items'

Use the async pattern below for anything beyond ~20 firms — website crawling and auditing make this Actor far slower per record than a listings-only scraper.

# 1. Start execution with a hard spend limit
# NOTE: too low a cap makes the Actor skip Advanced Web Analysis and return contacts only.
curl -X POST -H 'Content-Type: application/json' \
-H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
-d '{"subcategory":"Architecture firm","location":"London","maxResults":100,"advanceWebAnalysis":true,"deliveryMode":"none"}' \
'https://api.apify.com/v2/acts/techforce.global~construction-lead-intelligence-scraper/runs?maxTotalChargeUsd=2.00'
# 2. Poll
curl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
'https://api.apify.com/v2/actor-runs/<runId>'
# 3. Retrieve when SUCCEEDED
curl -H 'Authorization: Bearer <YOUR_APIFY_TOKEN>' \
'https://api.apify.com/v2/datasets/<DATASET_ID>/items?clean=true&format=json&limit=1000&offset=0'

⚠️ Autonomous Agent Error Handling & Resolution Matrix

Error CodeDetection ConditionUnderlying CauseDeterministic Agent Action
AUTH_INVALIDHTTP 401Missing or malformed APIFY_TOKENAbort & Prompt User: request a valid API token.
RATE_LIMITEDHTTP 429Apify API rate / concurrency limitsRetry: exponential backoff (2s, 4s, 8s).
SYNC_TIMEOUTHTTP 408 on the sync endpointRun exceeded the 300s synchronous ceiling — easy to hit hereReconfigure: switch to async POST /runs + polling.
SILENT_DEFAULTResults are General contractors in London you never asked forNo field is required; subcategory/location defaultedModify Input: always pass both explicitly from API/MCP/SDK.
TINY_DEFAULT_RUNExactly 5 items when you expected manymaxResults defaults to 5Modify Input: set maxResults explicitly.
NON_CONSTRUCTION_QUERYSUCCEEDED, itemCount: 0, nothing scrapedsearchQueries didn't match the construction vocabularyModify Input: add a construction term, use a preset subcategory, or re-route to the any-industry Actor.
MULTI_TYPE_REQUESTUser wants several preset types at oncesubcategory is a single valueReconfigure: one run per type, then merge datasets.
EMPTY_RESULTSSUCCEEDED, itemCount: 0, log shows a valid queryType/location combination has no Google Maps matchesModify Input: widen the location or change the type.
CAP_REACHEDitemCount == maxResults == 100Per-run maximum of 100 truncated the result setReconfigure: partition by city or business type across runs.
MAX_RESULTS_REJECTEDInput validation rejects maxResults above 100The schema maximum is 100 (schema and code agree)Modify Input: send 100 or less and run repeatedly for more.
FREE_PLAN_CAPitemCount stops at 20, log Reached free-tier limitFree Apify plan caps the run at 20 companiesPrompt User: upgrade for full-volume runs.
ANALYSIS_NOT_PRICEDLog not running with pay-per-event pricingThe listing is pay-per-result, but the code requires pay-per-event — the expected path on paid runs todayNot a run failure. Consume contacts; the Actor owner must relax the gate (see Pricing).
ANALYSIS_EVENT_MISSINGLog event 'advanced-web-analysis' is not configuredThe event isn't defined in Apify ConsoleNot a run failure. Consume contacts; ask the owner to add the event.
ANALYSIS_CHARGE_REFUSEDLog max charge limit does not allow the premium eventmaxTotalChargeUsd too low for the analysis chargeReconfigure: raise the spend cap and re-run if you need the analysis.
ANALYSIS_MISSINGAnalysis blocks present but emptyThe analysis did not run (any of the three reasons above, or advanceWebAnalysis: false)Check advancedWebAnalysis / the log before assuming an extraction bug.
WRONG_FIELD_PATHTop-level companyEmail / businessName is undefinedContact fields are nested inside BUSINESS_PROFILEFix Consumer: read item["BUSINESS_PROFILE"]["companyEmail"].
NO_EMAILBUSINESS_PROFILE.emailStatus: "no_email_found" or email "NA"The site published no discoverable email within the crawled pagesNot an error. Fall back to phone, or raise maxEmailPagesPerSite.
NO_WEBSITEBUSINESS_PROFILE.emailStatus: "no_website"The listing has no website, so no email or audit is possibleNot an error. Analysis blocks will carry no website grades.
SITE_UNREACHABLEemailStatus: "failed", log Homepage load failed for …The firm's site timed out or refused the connectionNot an error. Retry later if the email matters.
NO_LICENCE_DATANo licence / bonding / insurance fieldsNot part of Google Maps listingsEnrich elsewhere: pair with a licensing board, or GOV.UK Business Scraper for UK entities.
PLACEHOLDER_EMPTYConnector message renders blank fieldsSibling-style placeholders ({businessName}, {companyEmail}) were usedModify Input: use this Actor's short names — {name}, {email}, {rating}, {mapsUrl}.
SLOW_RUNRun approaching the timeoutmaxEmailPagesPerSite and maxAuditPagesPerSite both up to 25Reconfigure: lower both, raise batchSize, or turn the analysis off.
DELIVERY_SKIPPEDLog no tool name was providedmcpConnector set but mcpTool emptyModify Input: set mcpTool; the dataset is already saved.
DELIVERY_TOOL_UNKNOWNLog Tool 'x' is not available on this connectorWrong tool name for that connectorModify Input: pick a name from the Available tools: list in the same log line.
DELIVERY_EMPTYConnector called, body emptymcpArguments omitted the {message} placeholderModify Input: map {message} inside mcpArguments.
DELIVERY_FLOODHundreds of connector calls / connector rate limitsdeliveryMode defaults to perLeadReconfigure: use summary or chunked.
MCP_PROXY_MISSINGLog APIFY_MCP_PROXY_URL is not setRunning locally instead of on the platformReconfigure: apify push and run on the platform.

⚠️ Verify before publishing: the HTTP status rows reflect standard Apify API behavior; every log-line and field condition above is taken from this Actor's source. Re-confirm the 408/429 rows against current platform behavior if you depend on them for automated retry logic.


🗣️ Natural Language → Actor Mapping

User saysIntentConstructed Actor input
"Find general contractors in Manchester with their emails"Construction lead gen{"subcategory":"General contractor","location":"Manchester","maxResults":100}
"Get me architecture firms in London"Practice prospecting{"subcategory":"Architecture firm","location":"London"}
"List roofing contractors in Chicago"Trade prospecting{"searchQueries":"Roofing contractor in Chicago","maxResults":80}
"Interior designers in Mumbai, contacts only"Cheap contact list{"subcategory":"Interior designer","location":"Mumbai","advanceWebAnalysis":false}
"Which contractors have bad websites?"Agency prospecting{"advanceWebAnalysis":true} then sort on WEBSITE_HEALTH_SCORECARD.finalGrade
"Who should I call first?"Lead triage{"advanceWebAnalysis":true} then read LEAD_OVERVIEW.leadPriority
"What should I fix on this builder's site, and how do I sell it?"Proposal input{"advanceWebAnalysis":true} then read SERVICE_RECOMMENDATIONS
"Audit these firms' sites properly — 20 pages each"Deep audit{"advanceWebAnalysis":true,"maxAuditPagesPerSite":20,"maxResults":40}
"Real estate agencies in Ahmedabad"Property prospecting{"subcategory":"Real estate agency","location":"Ahmedabad"}
"Push these contractor leads into Airtable"CRM delivery{"mcpConnector":"airtable","deliveryMode":"perLead","mcpTool":"create_record","mcpArguments":{"fields":{"Name":"{name}","Email":"{email}"}}}
"Post today's construction leads to Slack"Digest delivery{"mcpConnector":"slack","deliveryMode":"summary","mcpTool":"send_message","mcpArguments":{"channel":"#leads","text":"{message}"}}
"Save a long lead list into Notion without it timing out"Chunked delivery{"deliveryMode":"chunked","mcpTool":"notion-create-pages"} with {part}/{partCount} in the title
"Contractors and architects in one run"Multi-type⚠️ subcategory is single-valued — run once per type, or use the any-industry Actor
"Find dentists / cafes / accountants"Non-construction❌ The run exits without scraping — route to the matching vertical or any-industry Actor
"Show me open tenders or planning applications"Project pipeline❌ Out of scope — Google Maps listings only
"Is this contractor licensed and bonded?"Compliance check❌ Out of scope — pair with a licensing board register
"Get the owner's personal email"Contact discovery❌ Out of scope — firm-level public emails only

Should NOT route here: any non-construction business type (the run exits without scraping) · several preset types in one run · plain listing data at lowest cost (→ Google Maps Scraper) · tenders, permits, planning applications or project pipelines · licence, bonding or insurance status · owner names or personal emails · review text, photos or coordinates · email verification/deliverability · sending outreach · more than 100 firms in one run.


🧭 Agent Execution & Routing Logic

[Input User Query]
1. Target is Google Maps business listings? NO → Route to the right platform Actor
│ YES
2. Is the target a CONSTRUCTION or PROPERTY firm? NO → Route to the any-industry / matching vertical Actor
│ YES (a non-construction query here scrapes nothing)
3. Needs tenders / permits / licences / project data? YES → Abort (not extracted)
│ NO
4. Pick the input route:
├── one of the 6 preset types? → subcategory + location
└── a specific phrase or URL? → searchQueries (must contain a construction term)
5. Several preset types needed? YES → One run per type, merge datasets
│ NO
6. Set maxResults EXPLICITLY (default is only 5; ceiling 100; free plans 20)
7. Advanced Web Analysis needed?
├── YES → advanceWebAnalysis: true
│ └─ KNOWN ISSUE: the code needs pay-per-EVENT pricing, but this listing is
│ pay-per-RESULT, so paid runs return contacts only (free-tier runs do get it)
└── NO → advanceWebAnalysis: false (same per-result price, faster run, smaller payload)
8. Tune depth vs speed: maxEmailPagesPerSite (1-25, default 4), maxAuditPagesPerSite (1-25, default 6),
batchSize (1-20, default 4)
9. Deliver to a connector? YES → mcpConnector + mcpTool + {message}
│ use SHORT placeholders: {name} {email} {rating} {mapsUrl}
│ NO → set deliveryMode "none" (it defaults to perLead)
[Execute Apify Actor]
├──► status == "SUCCEEDED" ──► itemCount == 0? YES → was the query construction-shaped? fix and re-run
│ │ NO
│ └──► read BUSINESS_PROFILE.* for contacts (NOT top level)
│ check whether the analysis blocks are populated
└──► status == "FAILED" ──► route to Error Handling Matrix above

💰 Cost Control & Pricing Transparency

Model: pay-per-result. Every firm returned in the dataset is billed at your account tier's rate. There is no separate charge for the analysis layer, and no monthly subscription.

Apify planRate per 1,000 resultsCost per firm
Free (no discount)$10.00$0.010
Starter (bronze)$9.33$0.0093
Scale (silver)$8.67$0.0087
Business (gold)$8.00$0.0080

Worked examples at the Free-tier rate:

Firms returnedCost (Free tier)Cost (Business tier)
5 firms (the default run)$0.05$0.04
20 firms (free-plan cap)$0.20$0.16
50 firms$0.50$0.40
100 firms (per-run ceiling)$1.00$0.80
1,000 firms (10 runs)$10.00$8.00

Apify platform usage is billed on top, at your plan's rates — compute units ($0.20/CU on Free down to $0.13/CU on Business) and residential proxies ($8.00/GB on Free, $7.00/GB on Business) are the two that matter here. Deep audits raise compute-unit consumption sharply, so maxAuditPagesPerSite and maxEmailPagesPerSite affect your platform bill even though they don't change the per-result price.

Cost levers: keep maxResults tight — it is the only thing that moves the per-result charge; lower the two page-depth settings to cut compute units; and set maxTotalChargeUsd on the run endpoint as a hard per-execution ceiling.

🐞 Known issue — the analysis is gated on the wrong pricing model. my_actor/main.py requires pricing_info.is_pay_per_event before enabling the premium layer, but this listing is configured pay-per-result. The practical effect today: free-tier runs get the full analysis (that branch returns before the pricing check) while paying customers get contacts only, with not running with pay-per-event pricing in the log — the opposite of the intended behaviour. Two ways out: (a) drop the pay-per-event gate so the analysis is simply part of the per-result price, or (b) switch the Store listing to pay-per-event with an advanced-web-analysis event. Until one of those is done, treat the analysis blocks as free-tier-only.


🔍 Companion machine-readable files

FilePurpose
.actor/actor.jsonIdentity, version, default run options (4096 MB, 3600s timeout), input/output/dataset wiring
.actor/input_schema.jsonAuthoritative typed input contract — custom query, 6-value business type, location, maxResults (1–100), email/audit depths, batchSize, the analysis toggle, deliveryMode enum
.actor/dataset_schema.jsonDeclares the six nested output blocks and the Console table view
.actor/output_schema.jsonDeclares where results are stored
my_actor/main.pyQuery validation, Playwright listing extraction, concurrent email crawl + website audit, charge gating, intelligence generation, MCP delivery
my_actor/connector.pyMCP connector session handling and {placeholder} rendering

Note: this Actor has no pay_per_event.json. The Store listing is configured pay-per-result, while the code still gates the analysis layer on pay-per-event pricing — see the Known issue under Cost Control.

If any table on this page disagrees with the schema files, the schema files win.


🛠️ Troubleshooting

#Symptom you seeMost likely causeFix
1SUCCEEDED but nothing scrapedsearchQueries was not recognised as a construction searchAdd a construction term, or clear it and use a preset subcategory.
2Only 5 resultsmaxResults defaults to 5Set it explicitly — up to 100.
3Results are General contractors in London you never asked forsubcategory and location silently defaultedAlways pass both explicitly from API / MCP / SDK calls.
4Input rejected for maxResults above 100The per-run ceiling is 100Send 100 or less; partition bigger jobs across runs.
5Results stop at 20Free Apify plan capUpgrade the plan; the log prints Reached free-tier limit.
6Analysis blocks are emptyThe analysis didn't runCheck the log for the three billing reasons, and that advanceWebAnalysis is true.
7Log: not running with pay-per-event pricingExpected on this listing — it is priced pay-per-result while the code requires pay-per-eventOwner action: remove the gate, or switch the listing to PPE. Contacts are still returned.
8Log: event 'advanced-web-analysis' is not configuredThe billable event is missing in ConsoleOwner action: add the event. Contacts still returned.
9Log: max charge limit does not allow the premium eventmaxTotalChargeUsd too lowRaise the cap and re-run if you need the analysis.
10item["companyEmail"] is undefinedContacts are nested under BUSINESS_PROFILERead item["BUSINESS_PROFILE"]["companyEmail"].
11companyEmail is "NA"No email discoverable within the crawled pagesRead emailStatus first; raise maxEmailPagesPerSite (up to 25); fall back to phone.
12emailStatus: "no_website"The firm has no website — nothing to crawl or auditExpected. Analysis blocks will be thin.
13emailStatus: "failed"The firm's site timed out or refused the connectionRetry later; a single slow site does not fail the run.
14Can't select two business typessubcategory is a single stringRun once per type and merge on BUSINESS_PROFILE.googleMapsUrl.
15No licence / bonding fieldsNot part of Google Maps listingsPair with a licensing board, or GOV.UK Business Scraper for UK entities.
16Emails bounce when you send outreachScraped emails are not verifiedRun them through an email-verification service first.
17googleRating won't compare numericallyIt is a string ("4.7")Cast to float before comparing.
18Run is very slowUp to 25 email pages + 25 audit pages per firmLower both depths, raise batchSize, or turn the analysis off.
19Pages time out after raising batchSizeToo many parallel pages for the current networkLower batchSize back toward the default of 4.
20HTTP 408 on run-sync-get-dataset-itemsThe synchronous endpoint has a hard 300-second ceilingUse async: POST /runs → poll → fetch dataset. Recommended above ~20 firms.
21Blank or empty listing fieldsGoogle served an empty page to the container's IPRe-run. This Actor has no proxy input — there is nothing to reconfigure.
22Log: Saved outputs to <dir>The Actor also writes JSON/CSV inside the container for local developmentIgnore it on the platform — the dataset is the real output.
23Connector message has blank fieldsYou used sibling-style placeholdersUse {name}, {email}, {rating}, {reviews}, {mapsUrl} — see the placeholder table.
24Hundreds of connector calls / connector rate-limiteddeliveryMode defaults to perLeadSwitch to summary or chunked.
25Slack / Airtable / Notion received nothingDelivery needs both mcpConnector and mcpToolSet both. The dataset is still written in full.
26Log: APIFY_MCP_PROXY_URL is not setYou ran locally; connectors only resolve on the platformDeploy with apify push and run on the platform.
27HTTP 401 / 403Missing, expired, or malformed APIFY_TOKENRegenerate in Apify Console → Settings → API & Integrations.
28HTTP 429Apify account concurrency / rate limits — not Google blockingRetry with exponential backoff (2s → 4s → 8s).

Diagnostic checklist before opening an issue

  1. Baseline run. subcategory = General contractor, location = a large city, maxResults = 5, advanceWebAnalysis: false, deliveryMode: "none".
  2. Results returned? If yes, the scraper is fine — re-add the analysis and volume one step at a time.
  3. Zero items? Read the log: an unrecognised searchQueries value ends the run before any scraping.
  4. Analysis missing? Search the log for pay-per-event, not configured, or max charge limit — those three lines explain every silent disable.
  5. Check where you're reading fields from — contacts live under BUSINESS_PROFILE.

If the issue survives all five steps, open an Issues ticket on the Actor page (or email support) with the run ID, the exact input JSON, and what you expected.

❓ FAQ

Setup & access

Do I need a Google account, API key, or Google Cloud project?

No. The Actor reads public Google Maps listings and public website content. You need an Apify account and API token only.

Is this the official Google Places API?

No. This is an independent Actor, not affiliated with, endorsed by, or sponsored by Google.

Can I configure a proxy?

No — this Actor has no proxy input and uses a direct connection. If you need proxy control, the any-industry sibling and Hospitality Actor expose a proxyConfiguration field.

Can I plug it into Claude, Cursor, or a LangChain agent?

Yes — it is a native MCP tool:

claude mcp add --transport http apify "https://mcp.apify.com?tools=techforce.global/construction-lead-intelligence-scraper"

Search & volume

Can I search a business type that isn't construction?

No. A custom query that doesn't read as construction ends the run without scraping. Use the any-industry Actor for anything else.

Can I scrape two business types in one run?

No — subcategory takes a single value. Run once per type and merge the datasets.

Can I paste a Google Maps URL?

Yes. A Google Maps place or location URL in searchQueries is accepted directly.

How many firms can one run return?

Up to 100 — the same ceiling as every sibling Actor — and 20 on free Apify plans. Note the default is only 5, so set it explicitly.

Output & data

Why is companyEmail not at the top level?

This Actor nests the contact fields inside BUSINESS_PROFILE, unlike its siblings. Read item["BUSINESS_PROFILE"]["companyEmail"].

Why are the analysis blocks empty?

Because Advanced Web Analysis didn't run — either you set advanceWebAnalysis: false, or the Actor disabled it for a billing reason (see the three log lines in Troubleshooting). The blocks are still emitted, just unpopulated.

Are the emails verified?

No. They are scraped from public website content. Run them through an email-verification service before any real outreach.

Do I get tenders, permits or licence status?

No. Google Maps listings don't carry them. Pair the output with a licensing board or planning-portal source.

Do I get owner names or personal emails?

No — firm-level public addresses only (info@, office@, contact@ and similar).

Pricing

How is this billed?

Pay-per-result: every firm in the dataset costs $0.010 on the Free tier, falling to $0.0080 on Business ($10.00 → $8.00 per 1,000). Apify platform usage — compute units and residential proxies — is billed separately at your plan's rates.

Does turning the analysis on cost more?

Not per result. It doesn't change the per-result price; it makes the run longer and the payload bigger, which raises compute-unit usage. See the Known issue below for why paid runs currently don't get the analysis at all.

How do I make a run as cheap as possible?

Keep maxResults tight — it is the only lever on the per-result charge. To cut platform usage as well, set advanceWebAnalysis: false and lower maxEmailPagesPerSite / maxAuditPagesPerSite.

What happens if my spend cap is too low?

The Actor logs a warning, skips the analysis, and still returns contacts and emails. It never aborts the run over the premium layer.


Same data family

This Actor is the construction vertical member of the family — the only one with a nested output shape and a single-value business type. Its siblings cover other verticals, any industry, and a cheap listings-only mode.

ActorBest forWhy pick it over this one
Google Maps Business Leads & Sales IntelligenceAny industry, free-text queries, several unrelated business types in one runYour target isn't construction, you need several types per run, or you want flat output fields and socialMedia (from $6.50 / 1,000)
Google Maps ScraperPlain Google Maps listings — name, address, phone, website, rating, reviews, hours, coordinates, imagesYou don't need emails or sales intelligence, and want the lowest cost per result (from $0.80 / 1,000)
Google Maps Healthcare Leads & Sales IntelligenceHealthcare — 55 preset medical categories, multi-selectClinics, dental, diagnostics, wellness instead of construction (from $4.00 / 1,000)
Google Maps Hospitality ScraperHotels, resorts, restaurants, cafes — 33 mapped typesA hospitality patch instead of construction ($9.09 / 1,000)
Finance Google Maps Lead Intelligence28 finance business types, deepest per-site auditAccounting, tax, insurance, broking, lending (from $10.00 / 1,000)

Pick by intent: contractors/architects/designers/property (this Actor) · any other industry → any-industry · listings only, cheapest → Google Maps Scraper · clinics & dental → Healthcare · hotels & restaurants → Hospitality · accounting & insurance → Finance.

ℹ️ Pricing, output shape and per-run limits differ between siblings (they are separate Store listings on separate tiers). This Actor's nested BUSINESS_PROFILE output and short delivery placeholders are unique to it — check before pointing an existing pipeline here.

Enrichment & downstream pipeline

ActorUse it for
GOV.UK Business ScraperMatch UK contractor and developer names against Companies House records, with PSC / beneficial-ownership enrichment
Advanced Website Crawling ActorCrawl a firm's whole site from BUSINESS_PROFILE.website for clean HTML/Markdown/text context beyond the audited pages

Suggested pipeline patterns

🎯 Trades agency prospecting engine One run per preset type in a city with advanceWebAnalysis: true → filter WEBSITE_HEALTH_SCORECARD.finalGrade ≤ C → deliveryMode: "perLead" into Airtable → work the queue from SERVICE_RECOMMENDATIONS.

💸 Fast contact harvest, then targeted analysis Broad advanceWebAnalysis: false runs to build the contact base quickly and cheaply in compute units → shortlist by rating/reviews → re-run just the shortlist with the analysis on and a deeper audit.

🏛️ UK contractor verification This Actor for contacts → GOV.UK Business Scraper on BUSINESS_PROFILE.businessName → attach company number, incorporation date and PSC data before outreach.

📇 CRM enrichment loop One run per city on a schedule → perLead delivery into HubSpot → dedupe on BUSINESS_PROFILE.googleMapsUrl → verify companyEmail before any sequence.

Browse all Actors by Techforce Global at apify.com/techforce.global.


🔐 Compliance & Data Privacy

This is an independent Actor. It is not affiliated with, endorsed by, or sponsored by Google. Google Maps™ is a trademark of Google LLC; all trademarks are the property of their respective owners.

This Actor collects publicly available business listing data and publicly published website content for construction and property firms. It does not log into any account, bypass authentication, or access client, contract, or project data.

Three points matter before you use the output:

  • Firm contact data is still personal data in many jurisdictions — a sole-trader builder's email or mobile number identifies a person. GDPR and CCPA can apply to it.
  • Cold outreach is regulated. Before sending anything to a scraped address, satisfy the applicable anti-spam and electronic-marketing rules (GDPR Art. 6/21, ePrivacy/PECR, CAN-SPAM, CASL). Emails here are unverified and unconsented.
  • Nothing here is licensing or vetting data. The output carries no licence, bonding, insurance or safety-record status. Do not present a scraped listing as evidence that a contractor is licensed, insured or qualified.

You are responsible for ensuring your use complies with Google's Terms of Service and all applicable law.


🆘 Support & Custom Pipeline Engineering

Need multi-type or multi-city scheduled refreshes, extra construction business types, licensing-register enrichment, email verification in-pipeline, or a full CRM / data-warehouse integration?


Made with ❤️ by Techforce Global Specialists in High-Performance Lead Generation Data Extraction and AI Automation.


🏷️ Structured data for search & AI discovery

{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
"name": "Construction Lead Intelligence Scraper — Contractor, Architect & Real Estate Leads",
"applicationCategory": "BusinessApplication",
"operatingSystem": "Cloud (Apify platform)",
"description": "Scrapes construction and property firms from Google Maps by preset business type or a construction search query, finds the company email on each firm's website, and optionally adds lead priority, pitch strategy, a website performance grade, prioritized improvement recommendations and a technical audit — with optional delivery to Airtable, HubSpot, Notion, Slack, Google Sheets, or any authorized MCP connector.",
"url": "https://apify.com/techforce.global/construction-lead-intelligence-scraper",
"offers": {
"@type": "Offer",
"price": "10.00",
"priceCurrency": "USD",
"description": "Per 1,000 results on the Free tier, falling to $8.00 per 1,000 on Business"
}
}