# US Building Permits: Daily New Permits from 14 City Portals (`alpine-data/us-building-permits`) Actor

No-code: daily new US building permits from 14 official city open-data portals (NYC, LA, Chicago, SF, Seattle, Austin, Dallas...). One clean table: type, value, address, contractor. Filter by type, value and ZIP in a simple form.

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

## Pricing

from $1.55 / 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

## US Building Permits Data: New Permits from 14 City Open-Data Portals

Get **new US building permits every day** from 14 official city and county open-data portals: New York City, Los Angeles, Chicago, San Francisco, Seattle, Austin, Dallas, Philadelphia, Boston, Cincinnati, Mesa, Baton Rouge, Montgomery County (MD) and Marin County (CA). Each city publishes its data in a different format. This actor puts all of it into **one clean table**: permit number, type, description, status, issue date, address, ZIP, coordinates, estimated value, and the **contractor's business name and license** where the city publishes them. Filter by permit type (roofing, solar, pool, new construction…), minimum value, keywords or ZIP code. Run it on a schedule to get **only the new permits**, which makes it a good source of **construction leads and building permit leads**.

### How to use it (no code needed)

Everything works in the Apify input form. You never need to write code or JSON.

1. **Pick your cities** from the dropdown. Leave the field empty to search all 14.
2. **Pick a time window and permit types**, for example the last 7 days of *Roofing* and *Solar* permits. Optional filters (minimum value, words in the description, ZIP codes) are in the sections below.
3. **Click Start.** The pre-filled example costs at most $0.32 (100 permits × $0.0032). When the run is done, open the **Output** tab and click **Export** to download **Excel, CSV or JSON**.
4. **Optional, get new permits automatically:** turn on *Only new permits since my last run* and click **Schedule** (e.g. daily). Under *Integrations* you can send each run's results to Google Sheets, Slack, email, Make, Zapier or n8n without code.

### What you get

![US building permits data example output: new permits with city, type, value and issue date](https://api.apify.com/v2/key-value-stores/jVsR1fgZbtwc50gQM/records/us-building-permits-example-output)

Real rows from a test run on 23 Oct 2026, issued 19–21 Oct 2026:

| City | Permit | Category | Description | Value | ZIP | Contractor |
|---|---|---|---|---|---|---|
| Seattle, WA | 7168557-RR | roofing | Reroof | $15,000 | 98115 | Integrity Roofing & Construction |
| New York City, NY | Q01476940-I1-SL | solar | Rooftop solar installation | $27,400 | 11001 | KAMTECH RESTORATION CORP (GC 616224) |
| Austin, TX | 2024-155910 BP | pool | New swimming pool | $48,000 | 78741 | Southern Pools Service & Spas |

Each row also has the full address, latitude and longitude, status, application date, the original permit type and work class, a link to the source record, and the dataset ID. The dataset has three views: **Overview**, **Leads** (contractor-focused) and **Map** (coordinates). The run's key-value store also holds a free **CITY_SUMMARY**: rows per city, rows filtered out, and the latest issue date the city has published.

### Get only new permits (schedule tip)

Turn on **Only new permits** and schedule the actor daily or weekly (Console → Schedules). Each run returns only permits you have not received before, and **already-seen permits are free**. Give each monitor its own **Monitor name** (for example `roofing-tx` and `solar-nyc`).

### Use cases

- **Roofing, solar, HVAC, pool and remodeling leads:** find homeowners' projects and the contractors who just pulled permits in your area.
- **Suppliers and subcontractors:** see which general contractors are starting new construction, and the job value.
- **Real estate and investors:** track new construction, additions and demolitions by ZIP code.
- **Market research:** count building permits by city, type and value over time.
- **Insurance, lending and proptech:** enrich addresses with recent permit activity.

### Input fields

![US building permits data input form: cities, permit types, dates and minimum value](https://api.apify.com/v2/key-value-stores/jVsR1fgZbtwc50gQM/records/us-building-permits-input-form)

| Field | What it does |
|---|---|
| 1. Cities | Which portals to search. Empty means all 14. |
| 2. Days back | Permits issued in the last N days (1–365, default 7). |
| 3. Permit types | Optional: new construction, addition/alteration, roofing, solar, electrical, plumbing, mechanical/HVAC, demolition, pool, other. Empty means all types. |
| 4. Max permits | Stops after this many rows, newest first, across all cities (default 100). You never pay for more than this. |
| Minimum project value (USD) | Only permits with an estimated job value at or above this. Permits without a value are excluded. |
| Description contains (any of) | Only permits whose type or description contains one of these words, e.g. `ADU, solar, kitchen`. |
| ZIP codes | Only these ZIP codes or prefixes, e.g. `78704, 941`. |
| Only new permits since my last run / Monitor name | Monitor mode: skip permits delivered in earlier runs (free). |
| Issued from / Issued to | An exact date range instead of "Days back", up to 366 days. |
| Include owner business name | Off by default. When on, adds the owner name only if it is clearly a business (LLC, Inc, Corp…). Private persons are never shown. |

### Pricing

Pay per result: **$0.0032 per permit** delivered, which is **$3.20 per 1,000 permits**. There is no start fee.

- **Cheaper on bigger Apify plans:** Scale plan users pay 10% less (**$0.00288 per permit**, $2.88 per 1,000) and Business plan users (and above) pay 20% less (**$0.00256 per permit**, $2.56 per 1,000). Free and Starter plans pay the standard $0.0032. Apify applies the discount automatically.
- Example: 7 days of roofing permits in Austin, Dallas and NYC, about 150 rows, costs about **$0.48**.
- The prefilled input (4 cities, 7 days, max 100) costs at most **$0.32**. If you clear every field and click Start, all cities are searched with the default cap of 100, also at most $0.32.
- **Free:** invalid input, cities that are temporarily unavailable, permits removed by your filters, and already-seen permits in "Only new" mode.
- Use **Max permits** or the run's maximum cost setting to cap your spend. The actor stops cleanly at the limit.

### FAQ and common mistakes

**Where can I find building permits data by ZIP code?** Enter one or more ZIP codes, or a prefix like `787`, in *ZIP codes*. Chicago does not publish ZIP codes, so use *Description contains* keywords there, or filter the exported table yourself (e.g. by address).

**Is there a building permits API?** Yes. You can use the form only, or call this actor through the Apify API, webhooks, Make, Zapier or n8n (see *For developers* at the end). You get one schema for all cities instead of 14 different portals.

**Do I need to write code or JSON?** No. Every option is a field in the form: dropdowns, checkboxes, date pickers and lists.

**How do I get roofing or solar permit leads?** Choose permit type *Roofing* or *Solar / PV / battery storage*, add your cities and turn on *Only new permits* with a daily schedule.

**Why did I get fewer rows than I expected?** Check the status message and CITY_SUMMARY. Common reasons are a high *Minimum value* (some cities publish no values) and Los Angeles' upload delay. Rows your filters removed are free.

**Are homeowner names included?** No. Private individuals' names, phone numbers and emails are never output. Contractor and owner fields only contain business names.

**Can I open the CSV in Excel safely?** Yes. Text fields that start with `=`, `+`, `-` or `@` get a leading `'`, so spreadsheet apps never run them as formulas. The XLSX export is also safe.

**Can I get permits older than a year?** Use *Issued from / to* for any 366-day window. For longer periods, run the actor once per year.

### Limits

- Data is only as fresh as each city's upload. On 23 Oct 2026 most cities had permits through 21–22 Oct 2026, Cincinnati through 20 Oct and **Los Angeles through 17 Oct** (LA uploads with a delay of about 5–6 days).
- Not every city publishes every field:
  - **Dallas:** no contractor, value or coordinates.
  - **Chicago:** no ZIP code.
  - **Philadelphia:** no job value, so a *Minimum value* filter excludes Philadelphia.
  - **Boston and San Francisco:** no contractor.
- Permit categories are normalized from each city's own type and description text, so a few permits may land in a neighboring category. The original `permitType` and `workType` are always included.
- At most 366 days per run and 100,000 permits per run.

### Data source and legal notes

All data comes from **official public government open-data portals** (Socrata, CKAN and Carto APIs) published for reuse by each city or county. The actor reads only public data through the portals' documented public APIs and respects their usage. Private individuals' names, phone numbers and emails are removed. Check your local rules (e.g. telemarketing and CAN-SPAM) before contacting anyone. City names and trademarks belong to their owners; this actor is not affiliated with or endorsed by any city or county.

### Related tools from Alpine Data Labs

- [EU Tenders (TED): Tender Alerts](https://apify.com/alpine-data/ted-tender-monitor): public construction and service tenders from the EU's TED database.
- [Career Page Job Scraper](https://apify.com/alpine-data/career-site-jobs): see which contractors and builders are hiring, from Greenhouse, Lever, Workday and other career pages.
- [Zefix Swiss Company Register](https://apify.com/alpine-data/swiss-company-register): company lists from the Swiss commercial register.
- [All tools from Alpine Data Labs](https://apify.com/alpine-data): no-code data tools for public data, business research and monitoring.

### Support

Found a bug or want another city added? Open an issue in the **Issues** tab. Built and maintained by **Alpine Data Labs**.

### For developers / API & integrations (optional)

You do **not** need anything in this section to use the Actor: the form does everything. It is for developers who want to start runs from their own code, website or workflow. **The input is the same JSON that the form creates.** Every field name in the form is also the API field name, and the form never changes them, so existing API calls, tasks, schedules and integrations keep working. Replace `<YOUR_APIFY_TOKEN>` with your own token from *Apify Console → Settings → API & Integrations*, and never put it in public code.

**Example input (JSON):**

```json
{
  "cities": [
    "austin",
    "dallas",
    "nyc"
  ],
  "daysBack": 7,
  "permitTypes": [
    "roofing",
    "solar"
  ],
  "minValuation": 10000,
  "maxResults": 200,
  "onlyNew": true,
  "stateKey": "roof-solar-leads"
}
```

**cURL: run it and get the results in one call** (for small runs; a run with a few hundred permits usually takes well under a minute):

```bash
curl -X POST "https://api.apify.com/v2/acts/alpine-data~us-building-permits/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"cities": ["austin", "dallas", "nyc"], "daysBack": 7, "permitTypes": ["roofing", "solar"], "minValuation": 10000, "maxResults": 200, "onlyNew": true, "stateKey": "roof-solar-leads"}'
```

**JavaScript (apify-client):**

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('alpine-data/us-building-permits').call({
    "cities": [
        "austin",
        "dallas",
        "nyc"
    ],
    "daysBack": 7,
    "permitTypes": [
        "roofing",
        "solar"
    ],
    "minValuation": 10000,
    "maxResults": 200,
    "onlyNew": true,
    "stateKey": "roof-solar-leads"
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

**Python (apify-client):**

```python
from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("alpine-data/us-building-permits").call(run_input={'cities': ['austin', 'dallas', 'nyc'], 'daysBack': 7, 'permitTypes': ['roofing', 'solar'], 'minValuation': 10000, 'maxResults': 200, 'onlyNew': True, 'stateKey': 'roof-solar-leads'})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

**Where the results are:** one dataset row per permit, with the same fields in every city. The key-value store holds a free `CITY_SUMMARY`. City IDs for `cities`: `chicago`, `nyc`, `los-angeles`, `san-francisco`, `seattle`, `austin`, `dallas`, `philadelphia`, `boston`, `cincinnati`, `mesa`, `baton-rouge`, `montgomery-county-md`, `marin-county`. Permit type IDs: `new_construction`, `addition_alteration`, `roofing`, `solar`, `electrical`, `plumbing`, `mechanical`, `demolition`, `pool`, `other`.

**Example output (one permit row, JSON):**

```json
{
  "city": "New York City",
  "state": "NY",
  "permitNumber": "Q01476940-I1-SL",
  "issueDate": "2026-10-21",
  "applicationDate": "2026-10-21",
  "category": "solar",
  "categories": ["solar"],
  "permitType": "Solar",
  "workType": "Initial Permit",
  "description": "ROOFTOP SOLAR INSTALLATION. NO CHANGE TO USE, OCCUPANCY OR EGRESS.",
  "status": "Permit Issued",
  "estimatedValue": 27400.0,
  "address": "264-16 85 AVENUE Queens",
  "zip": "11001",
  "fullAddress": "264-16 85 AVENUE Queens, New York City, NY 11001",
  "latitude": 40.736096,
  "longitude": -73.703627,
  "contractorName": "KAMTECH RESTORATION CORP",
  "contractorLicense": "GC 616224",
  "sourceUrl": "https://data.cityofnewyork.us/resource/rbx6-tga4.json?work_permit=Q01476940-I1-SL",
  "dataset": "data.cityofnewyork.us/rbx6-tga4",
  "datasetUrl": "https://data.cityofnewyork.us/d/rbx6-tga4",
  "portal": "NYC Open Data - DOB NOW: Build - Approved Permits",
  "recordKey": "nyc:Q01476940-I1-SL:2026-10-21",
  "scrapedAt": "2026-10-23T03:54:10Z"
}
```

**Integrations without code:**

- **Schedules:** run it daily or weekly (Console → Schedules).
- **Webhooks:** call your URL when a run finishes (event `ACTOR.RUN.SUCCEEDED`). The payload contains the run ID and the `defaultDatasetId`.
- **Make, Zapier, n8n:** use the official Apify app or node: "Run Actor", then "Get dataset items".
- **Google Sheets, Slack, email:** these are under the *Integrations* tab.
- **AI agents:** the Actor can be called through the [Apify MCP server](https://mcp.apify.com).

# Actor input Schema

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

Which city or county open-data portals to search. Leave empty to search all of them. Each is the official government API, updated daily.

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

Permits issued in the last N days (today included). 7 = the last week. Ignored if you set 'Issued from' below.

## `permitTypes` (type: `array`):

Only these kinds of work. Leave empty for all. Detected from the city's permit type, work class and description, so one permit can match several types (e.g. a solar install is also electrical).

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

Stop after this many permits (newest first across all cities). You pay only for permits delivered, so this is your cost cap: the pre-filled 100 costs at most $0.32 (100 × $0.0032). Raise it (e.g. 5000) for full exports.

## `minValuation` (type: `integer`):

Only permits whose declared value / estimated cost is at least this. 0 = no minimum. Permits without a value are skipped when you set a minimum.

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

Only permits whose description or type contains at least one of these words, e.g. 'kitchen', 'ADU', 'EV charger', 'tenant improvement'. Not case-sensitive.

## `zipCodes` (type: `array`):

Only permits in these ZIP codes. A prefix works too: '787' = all ZIPs starting with 787. Leave empty for the whole city.

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

Turn on for scheduled runs: each permit is delivered (and charged) only once. Already-delivered permits are skipped for free.

## `stateKey` (type: `string`):

Optional. Give each monitor its own name if you run several 'only new' schedules with the same cities and filters.

## `issuedFrom` (type: `string`):

First issue date (YYYY-MM-DD). Overrides 'Days back'. Max range is 366 days.

## `issuedTo` (type: `string`):

Last issue date (YYYY-MM-DD). Empty = today.

## `includeOwnerBusinessName` (type: `boolean`):

Adds ownerBusinessName where the city publishes the property owner AND it is a company (LLC, Inc., trust, developer...). Names of private individuals are never included.

## Actor input object example

```json
{
  "cities": [
    "chicago",
    "nyc",
    "austin",
    "seattle"
  ],
  "daysBack": 7,
  "permitTypes": [],
  "maxResults": 100,
  "minValuation": 0,
  "keywords": [],
  "zipCodes": [],
  "onlyNew": false,
  "stateKey": "",
  "includeOwnerBusinessName": false
}
```

# Actor output Schema

## `permits` (type: `string`):

City, issue date, category, permit type, description, value, address, contractor and source link.

## `leads` (type: `string`):

The same permits with the columns sales teams use.

## `citySummary` (type: `string`):

CITY_SUMMARY: permits delivered per city, latest issue date seen, filtered or skipped counts and any portal errors.

# 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",
        "nyc",
        "austin",
        "seattle"
    ],
    "daysBack": 7,
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("alpine-data/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 = {
    "cities": [
        "chicago",
        "nyc",
        "austin",
        "seattle",
    ],
    "daysBack": 7,
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("alpine-data/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 '{
  "cities": [
    "chicago",
    "nyc",
    "austin",
    "seattle"
  ],
  "daysBack": 7,
  "maxResults": 100
}' |
apify call alpine-data/us-building-permits --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,alpine-data/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/iSPm1f48XN5DdnQj5/builds/uNn1CekC7RIb7O8tG/openapi.json
