# City Building Permits: Chicago, NYC, Austin, Seattle, LA (`yzy001/city-building-permits`) Actor

Building permits issued in Chicago, New York, Austin, Seattle and Los Angeles, from each city's official open data: work type, cost, contractor company, address, coordinates. Filter by category, cost, ZIP or keyword, and track only new permits.

- **URL**: https://apify.com/yzy001/city-building-permits.md
- **Developed by:** [宗諭 楊](https://apify.com/yzy001) (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 $2.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.

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

## City Building Permits: Chicago, New York, Austin, Seattle, Los Angeles

Building permits issued in five large US cities, read straight from each city's official open-data portal and put into one table: what work was permitted, its category, the estimated cost, the contractor company, the address and coordinates, and a link to the record. Filter by category, cost, ZIP code, keyword or contractor, and schedule it daily with change tracking to get only permits you have not received yet.

A run over the latest 7 days of all five cities is about 5,000 permits (New York about 2,000, Los Angeles and Austin about 1,200 each, Chicago about 600, Seattle about 120).

### What you get for each permit

| Field | Meaning |
|---|---|
| `city`, `permitNumber` | City and the city's own permit number |
| `issuedDate`, `appliedDate`, `expiresDate` | Dates as the city publishes them (New York gives no application date) |
| `category` | One of `NEW_CONSTRUCTION`, `ALTERATION_ADDITION`, `DEMOLITION`, `ELECTRICAL`, `PLUMBING`, `MECHANICAL`, `SIGN`, `SITE_SAFETY`, `OTHER` |
| `categories` | All categories of the permit (a New York permit can cover several work types) |
| `permitType`, `workType`, `propertyClass` | The city's own permit type, work type and residential/commercial class, unchanged |
| `description` | The city's description of the work |
| `estimatedCost`, `costBasis` | The city's cost or valuation figure in USD, and which column it came from |
| `housingUnits`, `squareFeet` | Where the city publishes them |
| `address` | Street, city, state, ZIP |
| `contractors` | Contractor company name and trade |
| `status` | The city's permit status |
| `isRenewal`, `filingNumber` | New York renewal flag and job filing number |
| `latitude`, `longitude` | Coordinates as the city publishes them |
| `cityRecordUrl`, `sourceRecordUrl` | The city's own permit page (Austin, Seattle) and the exact record on the open-data portal |
| `changeStatus`, `firstSeen` | With tracking: `FIRST_RUN`, `NEW` or `SEEN` |

### Categories

Each city names its permits differently, so `category` is mapped from the city's own permit and work types (built from every value the portals used over the last 120 days; `permitType` and `workType` keep the originals):

- **Chicago**: new construction, renovation/alteration, wrecking/demolition and sign permits by type; Express Permit Program permits by their work type (electrical work, solar, plumbing, masonry, reroofing, porches, garages and so on). Elevator permits and reinstated permits are `OTHER`.
- **New York** (DOB NOW: Build): by work type. General construction, structural and foundation work are `ALTERATION_ADDITION`, because these permits do not say whether the job is a new building; full demolitions are `DEMOLITION`; solar is `ELECTRICAL`; sprinklers and standpipes are `PLUMBING`; sidewalk sheds, scaffolds and construction fences are `SITE_SAFETY`.
- **Austin**: electrical, plumbing and mechanical permits by type; building permits by work class (new and shell = new construction, demolition, everything else = alteration).
- **Seattle** and **Los Angeles**: by permit type. Grading, pools and non-building structures in Los Angeles are `OTHER`.

### Date window

`daysBack` counts back from the newest issue date each city has published, so every city returns its latest days even when its portal is behind: Chicago, New York, Austin and Seattle trail issuance by about one to two days, and Los Angeles refreshes weekly and trails by about a week. With `fromDate`/`toDate` you get the same calendar dates for every city instead. The status message and the run summary show each city's window.

Some permits reach the portals later than that: in September and October 2026, 9% of New York permits appeared more than 7 days after their issue date. For daily monitoring, use `daysBack` 31 with `trackChanges` and `onlyNew`, so late additions are still returned once.

### Costs

`estimatedCost` is each city's own figure: Chicago's reported cost, New York's estimated job cost, Austin's total job valuation, Seattle's estimated project cost and Los Angeles' valuation. Austin fills the job valuation for few permits, so for repair, remodel and addition permits that leave it blank the remodel valuation is used (`costBasis` says which). A cost of 0 or 1 is returned as empty: the cities enter those when the cost is not given or is on another filing (New York lists new buildings at 0), and real costs between 2 and 10 dollars do not occur. Most Austin trade permits and new buildings carry no cost, so `minEstimatedCost` leaves them out.

### Personal data

No owner, tenant, applicant or filing representative names, addresses or phone numbers are collected; those columns are not even requested. `contractors` lists the contracting company only: Chicago's contacts whose type names a contractor (owners acting as their own contractor are left out), New York's permittee business name, Austin's and Seattle's contractor company. Los Angeles publishes no contractor, and Chicago publishes no ZIP code for the permit address, so `contractorKeywords` with Los Angeles and `zipPrefixes` with Chicago are refused rather than silently returning nothing for that city.

### Filters

`cities`, `daysBack` or `fromDate`/`toDate`, `categories`, `minEstimatedCost`, `zipPrefixes`, `keywords` (description, permit type and work type), `contractorKeywords`, `includeRenewals` (New York), `trackChanges`, `onlyNew`, `allowPartial`, `maxItems`. Rows alternate between the cities, newest first within each city, so when `maxItems` cuts the list every city keeps an equal share.

### Things to know

- If one city's portal fails, the other cities are returned and the failed one is named in the status message and summary (turn `allowPartial` off to fail the whole run instead).
- If a portal has not been refreshed for longer than usual (7 days, 14 for Los Angeles), that city fails instead of returning stale permits as current.
- A New York permit that covers several work types is listed once per work type by the city; here it is one row with the work types joined.

### Data

The cities' own open-data portals, read through their public APIs with one request per second as the portals ask: City of Chicago Building Permits; NYC Department of Buildings DOB NOW: Build Approved Permits; City of Austin Issued Construction Permits; Seattle Department of Construction and Inspections Building Permits; Los Angeles Department of Building and Safety Building Permits Issued from 2020 to Present. No login and no scraping of search pages.

# Actor input Schema

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

Which cities to read. Each comes from that city's official open-data portal.

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

The latest N days of permits each city has published (1-31), counted back from that city's newest issue date, so a city whose portal is a few days behind still returns its latest days. For daily monitoring use 31 with change tracking. Ignored when a from date is set.

## `fromDate` (type: `string`):

Optional. First issue date to include (YYYY-MM-DD), the same for every city. The range can cover at most 31 days.

## `toDate` (type: `string`):

Optional. Last issue date to include. Defaults to today.

## `categories` (type: `array`):

Keep permits in any of these categories, mapped from each city's own permit and work types. Empty = all.

## `minEstimatedCost` (type: `integer`):

Optional. Keep permits whose estimated cost is at least this. Permits without a cost are left out (most Austin trade permits and new buildings carry none).

## `zipPrefixes` (type: `array`):

Optional. Keep permits whose address ZIP starts with any of these, for example 10011 or 787. Chicago publishes no ZIP for the permit address, so remove Chicago from cities when you use this.

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

Optional. Keep permits whose description, permit type or work type contains any of these words (case-insensitive), for example solar, roof, accessory dwelling, restaurant.

## `contractorKeywords` (type: `array`):

Optional. Keep permits whose contractor company name contains any of these. Los Angeles publishes no contractor, so remove Los Angeles from cities when you use this.

## `includeRenewals` (type: `boolean`):

New York reissues a permit when it is renewed. Off = only initial permits.

## `trackChanges` (type: `boolean`):

Remember which permits were returned before (in your own key-value store) and mark each row NEW, SEEN or FIRST_RUN.

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

With tracking on, return only permits not returned by an earlier run.

## `allowPartial` (type: `boolean`):

If a city's portal fails, return the other cities and name the failed one. Off = the run fails.

## `maxItems` (type: `integer`):

Upper limit on rows. Rows alternate between the cities, newest first within each city, so a limit gives every city an equal share.

## Actor input object example

```json
{
  "cities": [
    "CHICAGO",
    "NEW_YORK",
    "AUSTIN",
    "SEATTLE",
    "LOS_ANGELES"
  ],
  "daysBack": 3,
  "categories": [],
  "zipPrefixes": [],
  "keywords": [],
  "contractorKeywords": [],
  "includeRenewals": false,
  "trackChanges": false,
  "onlyNew": false,
  "allowPartial": true,
  "maxItems": 1000
}
```

# Actor output Schema

## `items` (type: `string`):

Normalised permits from the five cities.

## `summary` (type: `string`):

Each city's window, freshness, counts by category, rows filtered out and why, caveats.

# 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",
        "NEW_YORK",
        "AUSTIN",
        "SEATTLE",
        "LOS_ANGELES"
    ],
    "daysBack": 3,
    "maxItems": 1000
};

// Run the Actor and wait for it to finish
const run = await client.actor("yzy001/city-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",
        "NEW_YORK",
        "AUSTIN",
        "SEATTLE",
        "LOS_ANGELES",
    ],
    "daysBack": 3,
    "maxItems": 1000,
}

# Run the Actor and wait for it to finish
run = client.actor("yzy001/city-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",
    "NEW_YORK",
    "AUSTIN",
    "SEATTLE",
    "LOS_ANGELES"
  ],
  "daysBack": 3,
  "maxItems": 1000
}' |
apify call yzy001/city-building-permits --silent --output-dataset

```

## MCP server setup

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