# 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/actors/running/actors-in-store.md#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

Fresh building permits from official city open-data APIs. One clean schema, 13 cities, ready for lead generation. Get permit number, type, status, issue date, address, valuation, and contractor name where the city publishes it.

No proxies. No HTML scraping. Every source is a government JSON API.

### Supported cities

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

Honest coverage: if a city does not publish a field, the actor returns `null` for that field. No fabricated data, no enrichment.

**Any other Socrata city works too.** Paste the dataset resource URL (`https://<portal>/resource/<id>.json`) and the actor auto-maps the common permit fields. Ideal if your city runs on Socrata.

### Why this actor

**Built for construction lead generation.** A newly issued permit means a funded project that is about to start. Filter by date, sort by valuation, contact the contractor while the job is still open.

- **Official sources only.** Direct from city open-data portals (Socrata, Carto, CKAN). Stable, legal, and no proxy costs.
- **One schema across all cities.** `permitNumber`, `issuedDate`, `valuation`, `contractor` mean the same thing everywhere. No per-city cleanup.
- **Honest field coverage.** The table above shows exactly which cities publish contractor names and valuations. You know what you will get before you run.
- **Privacy safe by design.** The actor never outputs homeowner or owner names, even when a city publishes them. You get the contractor and the project, not personal data on residents. Better for compliance and deliverability.
- **Quality guard built in.** If a city changes its schema, the actor flags the issue and skips bad rows instead of filling your dataset with blanks.
- **Pay for what you get.** You are charged only for permits actually delivered.

### Use cases

- **Building material suppliers** - Find new projects by ZIP code and reach buyers for lumber, roofing, HVAC, and fixtures this month.
- **Contractor and subcontractor sales** - Solar, HVAC, plumbing, and electrical teams prospecting the GCs who just pulled permits.
- **Market research and PropTech** - Track construction volume, valuation trends, and permit velocity by city and neighborhood.
- **Real estate investors** - Monitor renovation and development activity block by block.

### Pricing

**$2 per 1,000 permits** ($0.002 per permit, charged via `apify-default-dataset-item`).

You pay only for permits returned. No setup fee, no charge for empty runs.

### Input

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

- `cities` - Required. City names (`chicago`, `nyc`, `la`, `sf`, `philly`, `boston`, etc.), portal URLs, or raw Socrata resource URLs. Case insensitive.
- `issuedAfter` - Optional. `YYYY-MM-DD`. Only permits issued on or after this date. For fresh leads, use the last 7 to 30 days.
- `maxPermitsPerCity` - Optional. Maximum permits per city, newest first. Default 500.

### Output

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

```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"
}
```

Fields:

| Field | Description |
|---|---|
| `city` | Normalized city label, e.g. `Chicago, IL` |
| `permitNumber` | City permit or filing number |
| `permitType` | Permit or work type |
| `status` | Current permit status |
| `issuedDate` | Issue date (ISO). For Norfolk, `application_date` is used as no issue date is published |
| `address` | Street address |
| `description` | Work description |
| `valuation` | Project valuation in USD, or `null` if not published |
| `contractor` | Contractor or applicant business name, or `null` if not published |
| `latitude` / `longitude` | Coordinates where published |
| `url` | Permit detail link where published |
| `source` | Internal registry key for the city |

### FAQ

**Is this legal?**

Yes. All data comes from official government open-data portals that cities publish for public use, accessed through their documented APIs (Socrata, Carto, CKAN). No scraping of protected or private systems.

**Do you include homeowner or owner names?**

No. This actor deliberately excludes owner and homeowner name fields even where a city publishes them. Lead buyers need the contractor and the project, not resident personal data. Contractor and business names are included because they are commercial records.

**Why is my city not listed?**

Many cities run permits on ArcGIS Hub or Accela, which require per-city integration. Miami, Denver, DC, and Phoenix are examples. If your city has a Socrata portal, try pasting the dataset resource URL directly, it will often work today. Unsupported cities are logged in the run, never silently dropped.

**How fresh is the data?**

Data is refreshed by each city, typically daily. The actor always returns the newest permits first.

**Why did I get fewer permits than my cap?**

Either the `issuedAfter` window contained fewer permits, or the city published fewer records in total. The run log shows per-city counts.

**Can I use this for any Socrata dataset?**

Yes. Paste any `https://<domain>/resource/<id>.json` URL into `cities`. The actor samples the schema and maps the common permit fields automatically.

# 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(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 '{
  "cities": [
    "chicago",
    "austin",
    "philadelphia",
    "baton-rouge"
  ]
}' |
apify call burn98/building-permits-scraper --silent --output-dataset

```

## MCP server setup

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

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

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