# US Building Permits Scraper: Contractor Leads (`greatwork/us-building-permits`) Actor

Newly issued building permits from Austin, San Francisco, Seattle, Chicago, Cincinnati, New Orleans and Montgomery County MD in one clean table: address, work description, job value and contractor. Filter by keyword (solar, roof, pool, ADU) and value.

- **URL**: https://apify.com/greatwork/us-building-permits.md
- **Developed by:** [Great Work](https://apify.com/greatwork) (community)
- **Categories:** Lead generation, Real estate, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 permits

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

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

### What does US Building Permits Scraper do?

**US Building Permits Scraper pulls newly issued building permits from 7 US city and county open-data portals into one clean table**: address, work description, **job value**, permit type, status and the **contractor company** on the job. A permit is a public signal that money is about to be spent at a specific address: a new roof, a kitchen remodel, a pool, solar panels, a tenant build-out, a teardown. Filter by **keyword** (solar, roof, pool, ADU, HVAC), job value, property type and date instead of learning seven different portals.

**Try it now:** click **Start**. The prefilled input returns up to 40 recent roof, solar, remodel, addition and pool permits worth $10,000 or more across every covered city, in about 30 seconds, for about $0.49.

### Who uses building permit leads?

- **Contractors and subcontractors** looking for jobs in progress: roofers, electricians, HVAC, plumbers, pool and solar installers, landscapers, painters, cleaners.
- **Building material suppliers and equipment rental** selling to the contractor named on the permit.
- **Home services and insurance** (security systems, home warranties, insurance agents) reaching properties with fresh work.
- **Real estate investors, lenders and market analysts** tracking renovation and new construction by ZIP code.
- **Proptech and data teams** that want a normalized permit feed without maintaining city-specific parsers.

### Which cities are covered?

| Key | Jurisdiction | Permits in a recent week | Contractor company | Job value |
|---|---|---|---|---|
| `austin` | Austin, TX | ~650 | yes, with phone | on building permits |
| `chicago` | Chicago, IL | ~400 | yes, all trades | yes |
| `new-orleans` | New Orleans, LA | ~300 | yes | yes |
| `san-francisco` | San Francisco, CA | ~200 | no | yes |
| `cincinnati` | Cincinnati, OH | ~110 | yes | yes |
| `montgomery-county-md-residential` | Montgomery County, MD | ~100 | no | yes |
| `seattle` | Seattle, WA | ~35 | rarely | yes |
| `montgomery-county-md-commercial` | Montgomery County, MD | ~20 | no | yes |

Counts are for September 23 to 29, 2026, and include each city's publishing lag of one to three days. We add a jurisdiction only when its open-data license clearly allows redistribution. Want a city? Open an issue.

### What data do you get?

| Field | Example |
|---|---|
| `jurisdiction`, `jurisdictionName` | austin, Austin, TX |
| `permitNumber`, `id` | 2026-122424 BP, austin:2026-122424 BP |
| `permitType`, `workType`, `category` | Building Permit, Addition and Remodel, commercial |
| `description` | 372 SF addition to an existing restaurant and remodel of existing building. |
| `status` | Active |
| `appliedDate`, `issuedDate` | 2026-03-31, 2026-09-17 |
| `address`, `city`, `state`, `zip` | 2159 S LAMAR BLVD, AUSTIN, TX, 78704 |
| `latitude`, `longitude` | 30.2474, -97.7726 |
| `estimatedCost`, `squareFeet`, `housingUnits` | 48000, 1772, 1 |
| `contractorCompany`, `contractorPhone`, `contractorTrade` | 2400 Construction LLC, General Contractor |
| `otherCompanies` | other trade contractors, applicants, architects and engineers on the permit |
| `sourceUrl`, `dataset`, `attribution` | links to the city record and dataset |

#### Sample output

Real permits issued in September 2026, filtered to roof, solar, remodel and addition work of $10,000 or more:

| City | Issued | Work | Job value | Contractor |
|---|---|---|---|---|
| Chicago, IL | 2026-09-25 | Reroofing, 16,400 sq ft | $262,809 | ADVANCED ROOFING SYSTEMS, INC. |
| Chicago, IL | 2026-09-25 | Small-scale solar PV system | $23,810 | SUNRUN INSTALLATION SERVICES |
| San Francisco, CA | 2026-09-25 | Interior remodel and horizontal addition | $223,000 | (not published by SF) |
| Seattle, WA | 2026-09-22 | Roof tear-off and replacement | $21,152 | Four Seasons Roof |
| Austin, TX | 2026-09-17 | Restaurant addition and remodel | $48,000 | 2400 Construction LLC |

One full record:

```json
{
  "id": "austin:2026-122424 BP",
  "jurisdiction": "austin",
  "jurisdictionName": "Austin, TX",
  "permitNumber": "2026-122424 BP",
  "permitType": "Building Permit",
  "workType": "Addition and Remodel",
  "category": "commercial",
  "description": "372 SF addition to an existing restaurant and remodel of existing building.",
  "status": "Active",
  "appliedDate": "2026-03-31",
  "issuedDate": "2026-09-17",
  "address": "2159 S LAMAR BLVD",
  "city": "AUSTIN",
  "state": "TX",
  "zip": "78704",
  "latitude": 30.24740108,
  "longitude": -97.7726128,
  "estimatedCost": 48000,
  "squareFeet": 1772,
  "housingUnits": 1,
  "contractorCompany": "2400 Construction LLC",
  "contractorPhone": "5126562163",
  "contractorTrade": "General Contractor",
  "otherCompanies": [{ "role": "Applicant", "name": "2400 Construction LLC" }],
  "sourceUrl": "https://abc.austintexas.gov/web/permit/public-search-other?t_detail=1&t_selected_folderrsn=13774130",
  "dataset": "https://data.austintexas.gov/d/3syk-w9eu",
  "attribution": "City of Austin Open Data Portal"
}
```

In Apify Console the Output tab has three views: **Permits**, **Contractors** (for supplier and B2B outreach) and **Property** (address, coordinates and job value for mapping). Download any run as CSV, Excel, JSON or XML.

### How to get building permit leads

1. Click **Start** with the prefilled input, or pick **cities**, **keywords** (for example `solar`, `roof`, `pool`, `ADU`, `HVAC`, `tenant improvement`), a **minimum job value** and **residential or commercial**.
2. Pick a window: permits issued in the last N days, or an exact date range.
3. Open the **Output** tab and export the table, or send it to your CRM or a spreadsheet.
4. Save the input as a task and **schedule it daily** with **Only permits not delivered before** switched on, so each morning's run has only new permits.

#### Input examples

**Everything issued in the last 7 days, capped per city:**

```json
{ "daysBack": 7, "maxResultsPerJurisdiction": 200 }
```

**Solar installs in Austin and San Francisco this month:**

```json
{ "jurisdictions": ["austin", "san-francisco"], "daysBack": 30, "keywords": ["solar", "photovoltaic", "PV"] }
```

**Commercial jobs over $250,000 with a named contractor, for a supplier's sales team:**

```json
{ "daysBack": 14, "category": "commercial", "minCost": 250000, "requireContractor": true }
```

**Daily roofing feed that never repeats a permit:**

```json
{ "daysBack": 3, "keywords": ["roof", "reroof"], "onlyNew": true, "feedName": "roofing" }
```

### How much does it cost?

You pay per permit returned. Filters run before you are charged, and there is no subscription or platform usage fee on top.

| Event | Free and Starter plans | Scale plan | Business plan |
|---|---|---|---|
| Permit | $0.012 | $0.011 | $0.01 |
| Run start | $0.01 | $0.01 | $0.01 |

What that looks like in practice:

| Use | Permits | Cost |
|---|---|---|
| The prefilled first run | up to 40 | about $0.49 |
| Daily feed: solar permits, every city | about 300 a month | about $4 a month |
| Daily feed: roofing permits, every city | about 800 a month | about $10 a month |
| Daily feed: every permit, every city | about 7,800 a month | about $94 a month |

Set **Max results in total**, or a maximum cost per run in the run options, to cap any single run. Apify's free plan includes monthly credit you can spend on this Actor.

### Run it as a daily permit feed

- **Only permits not delivered before** (`onlyNew`) skips permits the same feed already returned in the last 60 days. The list lives in a key-value store in your own account, so overlapping windows never bill you twice.
- **Feed name** (`feedName`) keeps separate lists for separate schedules, for example `austin-solar` and `chicago-roofing`.
- Cities publish with a lag of one to three days, so `"daysBack": 3` plus `onlyNew` on a daily schedule catches late arrivals without duplicates.
- A per-city summary of each run (rows read, permits saved, any source errors) is saved in the run's key-value store under `SUMMARY`.

### Integrations and API

- **Google Sheets, HubSpot, Salesforce, Slack, email:** through Apify integrations, **Make**, **Zapier** or **n8n**.
- **Webhooks:** fire on every finished run to push permits into a CRM, dialer or map.
- **AI agents over MCP:** add `https://mcp.apify.com?tools=greatwork/us-building-permits` to Claude, ChatGPT, Cursor or any MCP client and ask for "solar permits issued in Chicago this week".
- **REST API, Python and JavaScript clients:**

```bash
curl -X POST "https://api.apify.com/v2/acts/greatwork~us-building-permits/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"jurisdictions": ["seattle"], "daysBack": 7, "keywords": ["ADU", "accessory dwelling"]}'
```

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("greatwork/us-building-permits").call(run_input={"daysBack": 7, "keywords": ["solar"]})
for permit in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(permit["jurisdictionName"], permit["address"], permit["estimatedCost"], permit["contractorCompany"])
```

### FAQ

#### How fresh is the data?

Cities publish on their own schedules, usually daily with a lag of one to three days. The Actor reads each portal live on every run.

#### Why is the job value sometimes missing or $1?

Job value is whatever the applicant declared. Austin publishes value only on building permits, not on trade permits, and some express permits carry placeholder values like $1. **Minimum job value** drops permits with no value.

#### Do you return homeowner names?

No. Owner and individual applicant names are never returned. Only contractor, architect and engineer companies are kept.

#### Can you add my city?

Probably, if its permits are on an open-data portal with a license that allows redistribution. Open an issue with the city name.

#### Is it legal to use building permit data?

Every source is an official government open-data portal, and each dataset's license allows reuse (see the table below). Chicago's terms ask for an attribution notice, which every Chicago record carries. When you contact contractors, follow the rules that apply to you, such as CAN-SPAM and TCPA.

### How it works and limits

- Reads each city's official open-data portal through its public Socrata API. No login, no browser and no scraping of permit-search websites.
- If one portal is down, the run continues with the others and reports which one failed. If every selected source fails, or a full week returns nothing, the run fails on purpose so you notice.

### Data sources and terms

| Source | License |
|---|---|
| City of Austin Open Data | Public Domain (U.S. Government) |
| DataSF | Open Data Commons Public Domain Dedication and License |
| City of Seattle Open Data | Public Domain |
| City of Chicago Data Portal | City of Chicago Data Terms of Use |
| City of Cincinnati Open Data | Public Domain |
| City of New Orleans Open Data | CC0 1.0 Public Domain Dedication |
| Montgomery County, MD dataMontgomery | Public Domain |

Chicago records carry the City's required notice in their `attribution` field: this site provides applications using data that has been modified for use from its original source, www.cityofchicago.org, the official website of the City of Chicago. The City of Chicago makes no claims as to the content, accuracy, timeliness, or completeness of any of the data provided at this site. The data provided at this site is subject to change at any time. It is understood that the data provided at this site is being used at one's own risk.

This Actor is independent and is not affiliated with or endorsed by any of these governments.

### More lead feeds by Great Work

| Actor | What you get |
|---|---|
| [SEC Form D Scraper](https://apify.com/greatwork/sec-form-d-leads) | Companies that just raised private money, with phone, amount raised and investors |
| [FMCSA New Carrier Leads](https://apify.com/greatwork/fmcsa-new-carriers) | Trucking companies registered in the last few days, with phone, email and fleet size |

### Support

Found a bug or need a city? Open an issue on the **Issues** tab and we usually reply within one business day. For a custom feed or a bulk historical export, email hello@greatwork.company.

# Changelog

This Actor's version history is a separate document: https://apify.com/greatwork/us-building-permits/changelog.md

# Actor input Schema

## `jurisdictions` (type: `array`):

Which permit sources to read. Leave empty for all of them.

## `daysBack` (type: `integer`):

Permits issued in the last N days (including today). Ignored when 'Issued from' is set.

## `dateFrom` (type: `string`):

First issue date (YYYY-MM-DD).

## `dateTo` (type: `string`):

Last issue date (YYYY-MM-DD). Defaults to today.

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

Keep permits whose description contains ANY of these words, e.g. solar, roof, pool, ADU, kitchen, HVAC, demolition, tenant improvement. Empty = all.

## `minCost` (type: `integer`):

Keep permits with a reported job value at or above this. Permits with no value are dropped when this is set. 0 = no minimum.

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

Residential or commercial, where the city reports it.

## `requireContractor` (type: `boolean`):

Keep only permits that name a contractor company (available in Austin, Seattle, Chicago, Cincinnati and New Orleans).

## `maxResultsPerJurisdiction` (type: `integer`):

Cap per source so one big city does not use the whole run.

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

Stop after this many permits. You pay per permit returned, so this is also your cost cap.

## `onlyNew` (type: `boolean`):

For scheduled runs: skip permits this feed already returned in the last 60 days. Tracked in a key-value store in your own account.

## `feedName` (type: `string`):

Keeps separate 'already delivered' lists per schedule, e.g. 'austin-solar'.

## `socrataAppToken` (type: `string`):

Only needed for very large pulls.

## Actor input object example

```json
{
  "daysBack": 7,
  "keywords": [
    "roof",
    "solar",
    "remodel",
    "addition",
    "pool"
  ],
  "minCost": 10000,
  "category": "any",
  "requireContractor": false,
  "maxResultsPerJurisdiction": 5,
  "maxResults": 40,
  "onlyNew": false,
  "feedName": "default"
}
```

# Actor output Schema

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

Every record from this run. Open it as a table in the Output tab, or download JSON, CSV or Excel from the dataset API.

# 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 = {
    "daysBack": 7,
    "keywords": [
        "roof",
        "solar",
        "remodel",
        "addition",
        "pool"
    ],
    "minCost": 10000,
    "maxResultsPerJurisdiction": 5,
    "maxResults": 40
};

// Run the Actor and wait for it to finish
const run = await client.actor("greatwork/us-building-permits").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 = {
    "daysBack": 7,
    "keywords": [
        "roof",
        "solar",
        "remodel",
        "addition",
        "pool",
    ],
    "minCost": 10000,
    "maxResultsPerJurisdiction": 5,
    "maxResults": 40,
}

# Run the Actor and wait for it to finish
run = client.actor("greatwork/us-building-permits").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 '{
  "daysBack": 7,
  "keywords": [
    "roof",
    "solar",
    "remodel",
    "addition",
    "pool"
  ],
  "minCost": 10000,
  "maxResultsPerJurisdiction": 5,
  "maxResults": 40
}' |
apify call greatwork/us-building-permits --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,greatwork/us-building-permits"
        }
    }
}
```

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/6Bw3grnzsHdgycLpD/builds/5cTb0AJcbR614Ot06/openapi.json
