# US Building Permits Scraper - Construction Leads, 13 Cities (`burn98/building-permits-scraper`) Actor

Fresh building permits from official city open-data APIs: Chicago, NYC, LA, Austin, Seattle, SF, Philadelphia, Boston + more. Normalized permit type, status, address, valuation and contractor name. Construction leads, pay per result.

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

## Pricing

from $2.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

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

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

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

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

# README

## US Building Permits Scraper — Construction Leads from 13 Major Cities

Get fresh building permits straight from official city open-data APIs, normalized into one clean schema: permit number, type, status, issue date, address, project valuation, and **contractor name where the city publishes it**. Type a city name, get permits. No proxies, no brittle HTML scraping — every source is a government JSON API.

### Supported cities

| City | Contractor names | Valuation | Source |
|---|---|---|---|
| Chicago, IL | ✅ | ✅ | data.cityofchicago.org |
| New York, NY (DOB NOW) | ✅ | ✅ | data.cityofnewyork.us |
| Los Angeles, CA | — | ✅ | data.lacity.org |
| Austin, TX | ✅ | partial | datahub.austintexas.gov |
| Seattle, WA | — | ✅ | data.seattle.gov |
| San Francisco, CA | — | ✅ | data.sfgov.org |
| Philadelphia, PA | ✅ | — | phl.carto.com (L\&I) |
| Boston, MA | ✅ (applicant) | ✅ | data.boston.gov |
| New Orleans, LA | ✅ | ✅ | data.nola.gov |
| Cincinnati, OH | ✅ | ✅ | data.cincinnati-oh.gov |
| Baton Rouge, LA (EBR Parish) | ✅ | ✅ | data.brla.gov |
| Norfolk, VA | — | — | data.norfolk.gov |
| Montgomery County, MD | — | ✅ | data.montgomerycountymd.gov |

**Bonus:** any other city on a Socrata open-data portal works too — paste the dataset's resource URL (`https://<portal>/resource/<id>.json`) and the actor auto-maps the common permit fields.

### Why this actor

- **Construction leads with purchase intent.** A freshly issued permit is a project that is funded and about to start. Filter by issue date, sort by valuation, call the contractor.
- **Official sources only.** Government open-data APIs — stable, legal, no anti-bot arms race, no proxy costs passed to you.
- **One schema across all cities.** No per-city CSV wrangling; `permitNumber`, `issuedDate`, `valuation`, `contractor` mean the same thing everywhere.
- **Honest field coverage.** The table above tells you exactly which cities publish contractor names and valuations. Cities that don't publish a field return `null` — we don't fabricate or "enrich" data.
- **Built-in quality guard.** If a city changes its data schema, the actor flags it and skips the garbage instead of filling your dataset with empty rows.
- **Pay per result.** You pay only for permits actually delivered.

### Who uses this

- **Building-material suppliers** — new permits by ZIP = who needs lumber, roofing, HVAC equipment this month.
- **Contractor & subcontractor sales teams** — solar, HVAC, plumbing, electrical subs prospecting the GCs pulling permits.
- **Market researchers & PropTech** — construction activity, valuations, and permit velocity by city and neighborhood.
- **Real-estate investors** — track renovation and development activity block by block.

### Input

```json
{
    "cities": ["chicago", "austin", "philadelphia", "baton-rouge"],
    "issuedAfter": "2026-06-01",
    "maxPermitsPerCity": 500
}
```

- `cities` — city names (`chicago`, `nyc`, `la`, `sf`, `philly`, …), portal URLs, or raw Socrata resource URLs.
- `issuedAfter` (optional) — only permits issued on/after this date. For lead generation, the last 7–30 days is the sweet spot.
- `maxPermitsPerCity` — cap per city, newest first (default 500).

### Output

One dataset item per permit:

```json
{
    "city": "Chicago, IL",
    "permitNumber": "B200476664",
    "permitType": "PERMIT - EXPRESS PERMIT PROGRAM",
    "status": "ACTIVE",
    "issuedDate": "2026-07-10T00:00:00.000",
    "address": "9764 S LOOMIS ST",
    "description": "INSTALL SOLAR PANELS ON ROOF OF ACCESSORY BUILDING",
    "valuation": 5130,
    "contractor": "SUNRUN INSTALLATION SERVICES",
    "latitude": 41.716239,
    "longitude": -87.657705,
    "url": null,
    "source": "chicago"
}
```

Export as JSON, CSV, or Excel from the dataset tab, or pull via the Apify API into your CRM.

### FAQ

**Is this legal?**
Yes. All data comes from official government open-data portals that cities publish explicitly for public use, via their documented APIs (Socrata, Carto, CKAN). No scraping of protected or private systems.

**What about homeowner privacy?**
This actor deliberately does **not** output homeowner/owner name fields, even where cities publish them. Lead generation needs the contractor and the project — not the resident. Contractor and business names are included because they are commercial actors on public commercial records.

**Why isn't my city listed?**
Many cities (Miami, Denver, DC, Phoenix, …) run their permits on ArcGIS or Accela portals that need per-city integration — they're on the roadmap. If your city has a Socrata portal, paste the dataset resource URL and it will likely work today. Unsupported cities are logged in the run, never silently dropped.

**How fresh is the data?**
Each supported city's dataset is refreshed by the city itself, typically daily. The actor always returns the newest permits first.

**A city returned fewer permits than my cap — why?**
Either the `issuedAfter` window contains fewer permits, or the city published fewer records. The run log shows per-city counts.

# Actor input Schema

## `cities` (type: `array`):

City names (chicago, nyc, la, austin, seattle, sf, philadelphia, boston, new-orleans, cincinnati, baton-rouge, norfolk, montgomery-county-md), open-data portal URLs, or any Socrata resource URL (https://<domain>/resource/<id>.json).

## `issuedAfter` (type: `string`):

Only permits issued on or after this date. Leave empty for the newest permits up to the per-city cap. For fresh construction leads use the last 7-30 days.

## `maxPermitsPerCity` (type: `integer`):

Cap on permits returned per city (newest first).

## Actor input object example

```json
{
  "cities": [
    "chicago",
    "austin",
    "philadelphia",
    "baton-rouge"
  ],
  "maxPermitsPerCity": 500
}
```

# 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 = {
    "cities": [
        "chicago",
        "austin",
        "philadelphia",
        "baton-rouge"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("burn98/building-permits-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 = { "cities": [
        "chicago",
        "austin",
        "philadelphia",
        "baton-rouge",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("burn98/building-permits-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "cities": [
    "chicago",
    "austin",
    "philadelphia",
    "baton-rouge"
  ]
}' |
apify call burn98/building-permits-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=burn98/building-permits-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/8yXcQOgOgPunkg8fi/builds/jBNaTYrqj6qK3Kvn7/openapi.json
