Building Permits Scraper: 12 Cities, Contractor Leads
Pricing
Pay per usage
Building Permits Scraper: 12 Cities, Contractor Leads
Building permits from 12 US and Canadian city open data portals in ONE schema: contractor name, phone, licence, owner, valuation and a derived project class (solar, roofing, HVAC, new build). Plus a contractor rollup. No API key, no proxy.
Pricing
Pay per usage
Rating
0.0
(0)
Developer
The Mine Works
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
2 days ago
Last modified
Categories
Share
๐๏ธ Building Permits Scraper: 12 Cities, Contractor Leads
โก Public municipal open data over plain HTTP. No API key, no proxy, no browser, no login.
๐ธ You are charged only for a permit that actually lands in your dataset. Contractor rollup rows and the run summary are free.
Overview
Every US city publishes its building permits. Almost none of them publish it the same way. Chicago calls the scope of work work_description, Seattle calls it description, Philadelphia calls it approvedscopeofwork, and Boston writes the job value as the string "$45,000.00" while Austin writes it as a number spread across five different valuation columns depending on the trade. Chicago does not have a contractor column at all: it has contact_1_type through contact_15_type, and the contractor is whichever one has the word CONTRACTOR in its role.
That is the actual work, and it is what this actor does. It pulls permits from twelve municipal portals across three different open data platforms, normalises them into one row shape, and derives the two fields that make a permit useful commercially: a project class and a contractor identity.
โ 12 cities, one schema ยท โ Contractor name, phone and licence where published ยท โ Derived project class ยท โ Free contractor rollup ยท โ MCP ready for AI agents
Cities covered
| Key | City | Platform | Contractor published |
|---|---|---|---|
new_york_ny | New York, NY (DOB NOW) | Socrata | โ business name + licence |
chicago_il | Chicago, IL | Socrata | โ name + trade + city |
austin_tx | Austin, TX | Socrata | โ name + phone + trade |
philadelphia_pa | Philadelphia, PA | Carto | โ name + city |
new_orleans_la | New Orleans, LA | Socrata | โ name + trade + licence |
baton_rouge_la | Baton Rouge, LA | Socrata | โ name + owner |
seattle_wa | Seattle, WA | Socrata | โ when the city fills it |
boston_ma | Boston, MA | CKAN | applicant name only |
san_francisco_ca | San Francisco, CA | Socrata | not published |
cincinnati_oh | Cincinnati, OH | Socrata | not published |
montgomery_county_md | Montgomery County, MD (residential) | Socrata | not published |
edmonton_ab | Edmonton, AB | Socrata | not published |
The last column is stated plainly rather than implied, because a permit dataset that does not name the contractor cannot be turned into a contractor lead by any amount of scraping. Set contractorLeadsOnly to true and the run keeps only rows that actually carry a company name.
The derived project class
A raw permit type reads EXPRESS PERMIT PROGRAM or OTC alterations permit. Nobody buys leads on that. The actor classifies every permit from its combined type, work class and description text into one of: solar, ev_charger, battery_storage, roofing, pool_spa, hvac, new_construction, adu, demolition, fence_deck, sign, electrical, plumbing, fire_safety, elevator, addition, remodel, other.
Order matters in the classifier. Solar is tested before electrical because a residential solar install is almost always filed as an electrical permit, and pools before plumbing for the same reason. So a search for solar returns the rooftop PV jobs rather than three thousand service upgrades.
Input
{"cities": ["austin_tx", "chicago_il", "philadelphia_pa"],"daysBack": 30,"projectClasses": ["solar", "roofing"],"minValuation": 5000,"contractorLeadsOnly": true,"contractorRollup": true,"maxPermitsPerCity": 500}
| Field | What it takes |
|---|---|
cities | One or more city keys from the table above. Unknown keys are reported and skipped rather than silently ignored. |
daysBack | How far back to look, counted from the permit issue date. |
projectClasses | Keep only these derived classes. Empty means every class. |
keywords | Keep only permits whose type, work class, description or contractor name contains one of these words. |
minValuation | Drop permits below this declared job value. Permits with no published value are dropped when this is set. |
contractorLeadsOnly | Keep only permits that name a contractor company. |
contractorRollup | Append one aggregated row per contractor at the end of the run. |
maxPermitsPerCity | Hard cap per city, and your main cost control. |
Output
Every permit row:
{"city": "austin_tx","city_name": "Austin, TX","state": "TX","permit_number": "2026-102151 EP","permit_type": "Electrical Permit","work_class": "Residential Repair","work_description": "Installation of a new residential roof-mounted solar photovoltaic system with battery energy storage...","project_class": "solar","status": "Active","issued_date": "2026-08-12T00:00:00","valuation_usd": 20000,"address": "14016 TYBURN TRL","postal_code": "78717","latitude": 30.48875096,"longitude": -97.79060856,"contractor_name": "roofio LLC","contractor_phone": "5129223034","contractor_trade": "Electrical Contractor","has_contractor": true,"source": "City of Austin issued construction permits"}
And one free rollup row per contractor:
{"_type": "contractor","contractor_name": "LS CONTRACTING GROUP, INC.","permit_count": 2,"total_valuation_usd": 315840,"avg_valuation_usd": 157920,"cities": ["Chicago, IL"],"trades": ["GENERAL CONTRACTOR", "MASON CONTRACTOR"],"project_classes": ["addition", "remodel"],"first_permit_date": "2026-07-28T00:00:00","last_permit_date": "2026-08-11T00:00:00"}
Rollup grouping normalises legal suffixes, so ROOFIO LLC, Roofio, L.L.C. and roofio llc are one contractor while Roofio Austin stays separate.
Common use cases
Solar, roofing and HVAC lead generation. Filter to your class and city, get the job site address, the owner and the contractor who won the job. New permits appear within a day or two of issue.
Contractor prospecting. Sell to contractors instead of homeowners. The rollup ranks every contractor by total job value in the window, so your list is ordered by who is actually building.
Construction market intelligence. Count permits and dollars by class, city and month to size a market or track where activity is moving.
Supplier and manufacturer territory planning. Permit valuations and volumes are a leading indicator of material demand by postal code.
Property and investment research. New construction, ADU and demolition permits flag parcels in transition before they reach a listing site.
AI agents. Point an agent at it through MCP and ask which contractors pulled the most solar permits in Austin last month.
Cost control built in
Three guards run on every job, because a run that returns nothing should also cost nothing.
- Run level spend cap. A per city page cap is not a cost guard while the city count is unbounded, so the ceiling applies to the whole run rather than to any one city.
- Zero yield abort. Two consecutive pages that add nothing new and the city is dropped. One productive page resets the counter, so a healthy run never trips it.
- No transport escalation. A portal that does not answer is skipped and reported in the summary. There is no retry through a paid proxy or a browser, because escalating on a run that is already failing costs many times more and recovers almost nothing.
Pricing
| Event | Price | You pay when |
|---|---|---|
| Permit delivered | $0.001 | A permit row lands in your dataset |
$1.00 per 1,000 permits. Contractor rollup rows, the summary row and empty runs are free.
Run it on a schedule
- Run once with the cities and classes you want, then click Save as a task.
- In the Apify Console go to Schedules โ Create new.
- Pick a frequency and attach the saved task.
- Wire the dataset to Sheets, Slack, a CRM or a webhook from the Integrations tab.
Set daysBack to slightly more than your schedule interval and deduplicate on permit_number so a daily run never reprocesses the same permit.
FAQ
Is this data public? Yes. Every source is an official municipal open data portal, published by the city itself for reuse. No login, no key, no scraping of a protected site.
Why only twelve cities? Because these are the twelve that were probed live and returned real permit rows. Los Angeles requires a login, and San Diego, San Antonio, Denver, Nashville, Raleigh and Charlotte returned 404 or non JSON on their published endpoints. Dallas answers, but publishes its issue date as free text and has not been updated since 2019, so a date filtered query returns zero rows while looking healthy. A city listed here and returning nothing would cost you compute to discover, so those were left out rather than counted.
How fresh is it? Most portals publish daily. In testing, permits issued the previous day were already present in Austin, Chicago, Philadelphia, Boston and New Orleans.
Why is valuation missing on some rows? Because that city does not publish it, or published it as zero. It is left empty rather than guessed. Philadelphia and New Orleans zoning permits frequently have no value at all.
Can you add my city? If it has a public open data portal with a permits dataset, yes. Reach out through the Apify profile with the city and dataset link.
Use from Claude, ChatGPT and any MCP agent
https://mcp.apify.com/?tools=themineworks/building-permits-construction-leads
Or call it programmatically:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });const run = await client.actor('themineworks/building-permits-construction-leads').call({cities: ['austin_tx', 'chicago_il'],daysBack: 30,projectClasses: ['solar'],contractorLeadsOnly: true,maxPermitsPerCity: 500,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
Questions, or need a city or field we do not return yet? Reach out through the Apify profile.