# US Building Permits Scraper: New Permit & Contractor Leads (`radiant_opuntia/us-building-permits-alerts`) Actor

Search and monitor new building permits in NYC, Chicago, LA, San Francisco, Seattle, Austin and more from official city open-data portals, no API key. Filter by keyword, work type (roofing, solar...), ZIP and cost. Flat JSON with address, cost, contractor, owner. 'Only new' mode for alerts.

- **URL**: https://apify.com/radiant_opuntia/us-building-permits-alerts.md
- **Developed by:** [GovData Feeds](https://apify.com/radiant_opuntia) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.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?

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

**Get new US building permits from nine city open-data portals in one format: address, category, estimated cost, contractor and owner, ready for lead lists and alerts.**

**Rate your experience:** if you have used this Actor, you can tell us how it went on the [reviews page](https://apify.com/radiant_opuntia/us-building-permits-alerts/reviews). Honest feedback of any kind helps us improve it.

### What it does and who it is for

This Actor reads the **official open-data portals** of **New York City, Chicago, Los Angeles, San Francisco, Seattle, Austin, Cincinnati, Baton Rouge and Mesa** and returns one flat record per permit: **city, permit number and type, an automatically detected category (new construction, roofing, solar, electrical, plumbing, HVAC, pool and more), status, description, address, ZIP, issue and application dates, estimated cost, contractor name, license and phone, applicant and owner, use type, units, latitude/longitude and a link**.

Filter by city, keyword, category, ZIP code, minimum project cost and issue date range. Turn on **Only new** for a daily lead feed.

#### Use cases

- **Roofers, solar installers, electricians, HVAC and pool companies:** find properties where work was just permitted.
- **Building-materials suppliers and subcontractors:** reach contractors with active projects.
- **Real-estate investors and appraisers:** track construction activity by area.
- **Lenders, insurers and analysts:** monitor new construction and renovations.
- **AI agents:** answer "which solar permits were issued in Austin this week?".

### Why use this instead of the free official site or API

The underlying data is public and the official sources are free. What this Actor adds is convenience: nine different city feeds become one consistent format.

| What you need | Official site / API | This Actor |
|---|---|---|
| Covering several cities | Each city has its own portal, column names and quirks | One input, one record format for all nine cities |
| Finding a type of job | Free-text search per portal | A `category` field (roofing, solar, electrical and others) detected from the permit text |
| Lead lists | Export each portal and merge by hand | Contractor, owner and cost columns in the same place for every city |
| Only newly issued permits | Compare exports yourself | **Only new** mode with a named alert |

If you only need a single lookup now and then, the official site is fine. If you want the same data on a schedule, as flat rows you can feed to a spreadsheet, CRM or agent, this saves the glue work.

### Data fields

| Field | Type | What it contains |
|---|---|---|
| `city` | text | City that issued the permit. |
| `state` | text | State. |
| `permitNumber` | text | Permit number from the city. |
| `permitType` | text | Permit type as named by the city. |
| `category` | text | Category detected by the Actor from the permit text (new_construction, roofing, solar and so on). |
| `status` | text | Permit status as published by the city. |
| `description` | text | Description of the work. |
| `address` | text | Property address. |
| `zip` | text | ZIP code, when the city publishes it. |
| `issuedDate` | date | Date the permit was issued. |
| `appliedDate` | date | Date the permit application was filed, when published. |
| `estimatedCost` | integer | Estimated project cost in USD, when published. |
| `contractorName` | text | Contractor name, when published. |
| `contractorLicense` | text | Contractor license number, when published. |
| `contractorPhone` | text | Contractor phone, when published. |
| `applicantName` | text | Applicant name, when published. |
| `ownerName` | text | Owner name, when published. |
| `useType` | text | Use type (for example Residential). |
| `units` | integer | Number of dwelling units, when published. |
| `latitude` | number | Latitude, when published. |
| `longitude` | number | Longitude, when published. |
| `url` | text | Link to the permit record or the city portal. |
| `source` | text | The open-data dataset the record came from. |
| `scrapedAt` | datetime | When the Actor collected the record (UTC). |

Fields a source does not publish are `null`. Cities publish different columns, so contractor, cost, owner and ZIP are only filled where the city provides them.

### "New since yesterday" alerts

Turn on **Only new** and the Actor remembers what it has already returned, so each scheduled run delivers only records you have not seen before.

1. Open the Actor in Apify Console and set the input, with **Only new since last run** switched on and a fixed alert name (`stateKey`). Example input:

```json
{
  "cities": ["nyc", "chicago", "la", "sf", "seattle", "austin"],
  "categories": ["roofing", "solar"],
  "issuedWithinDays": 7,
  "maxResultsPerCity": 200,
  "maxResults": 1000,
  "onlyNew": true,
  "stateKey": "daily-roofing-solar-permits"
}
```

2. Click **Save as task**, then open **Schedules**, create a schedule (for example the cron expression `0 7 * * *` for every day at 7:00 in the time zone you pick) and add the task to it.
3. Under the task's **Integrations**, send the results to Slack, email, Google Sheets, a webhook or your own system.

Cities update their portals at different speeds. A 7-day window with Only new keeps late-posted permits from being missed.

The first run returns everything that matches your window (all matching permits issued in the last 7 days); later runs return only unseen records. Use a different alert name for each task so each keeps its own memory. A run with nothing new returns no results.

### Cost per run

This Actor uses **pay-per-result pricing: $3.00 per 1,000 results ($0.003 per result)**, with the Apify platform fee included. You are charged for the records a run returns and nothing is added on top for platform usage. A run that finds nothing new returns no results, so it has no per-result charge. The **Max results** input caps what a run can return (and so what it can cost).

**Worked example:** a daily alert that returns 60 new permits costs 60 × $0.003 = $0.18 per run, about $5.40 for a 30-day month. A pull of 10,000 permits costs $30.00.

The pricing is configured in Apify Console; the Pricing tab on this page is the authoritative source if it ever differs from this text.

### Example input and output

The output below comes from real test runs of this Actor. Email addresses are masked and very long text is shortened here; the Actor returns the full values.

Input used for the example:

```json
{
  "cities": ["austin", "seattle", "chicago", "nyc"],
  "keyword": "solar",
  "categories": ["solar"],
  "issuedWithinDays": 14,
  "minProjectCost": 0,
  "onlyNew": true,
  "stateKey": "solar-permits",
  "maxResultsPerCity": 3,
  "maxResults": 50
}
```

Output (the first 2 records of a test run):

```json
[
  {
    "city": "Austin",
    "state": "TX",
    "permitNumber": "2026-132984 EP",
    "permitType": "Electrical Permit - Auxiliary Power",
    "category": "solar",
    "status": "Active",
    "description": "Tindall 40-25134 - Install new _6.9__kW rooftop solar system to existing residential only using backfed breaker only.",
    "address": "6637 QUINTON DR",
    "zip": "78747",
    "issuedDate": "2026-10-21",
    "appliedDate": "2026-10-08",
    "estimatedCost": null,
    "contractorName": "Power Home Remodeling",
    "contractorLicense": null,
    "contractorPhone": "(610) 874-5000",
    "applicantName": null,
    "ownerName": null,
    "useType": "Residential",
    "units": 1,
    "latitude": 30.1525935,
    "longitude": -97.74191386,
    "url": "https://abc.austintexas.gov/web/permit/public-search-other?t_detail=1&t_selected_folderrsn=13786332",
    "source": "data.austintexas.gov dataset 3syk-w9eu",
    "scrapedAt": "2026-10-23T12:12:08.244Z"
  },
  {
    "city": "Austin",
    "state": "TX",
    "permitNumber": "2026-052150 EP",
    "permitType": "Electrical Permit - Auxiliary Power",
    "category": "solar",
    "status": "Active",
    "description": "Solar installation at 5973 Hi Line Rd SHM Emerald Point.",
    "address": "5973 HI LINE RD",
    "zip": "78734",
    "issuedDate": "2026-10-21",
    "appliedDate": "2026-04-27",
    "estimatedCost": null,
    "contractorName": "RENERGY SOLAR LLC",
    "contractorLicense": null,
    "contractorPhone": "(830) 570-3214",
    "applicantName": null,
    "ownerName": null,
    "useType": "Commercial",
    "units": 1,
    "latitude": 30.43181507,
    "longitude": -97.94133438,
    "url": "https://abc.austintexas.gov/web/permit/public-search-other?t_detail=1&t_selected_folderrsn=13694144",
    "source": "data.austintexas.gov dataset 3syk-w9eu",
    "scrapedAt": "2026-10-23T12:12:08.253Z"
  }
]
```

### Limits worth knowing

- Each city updates its portal on its own schedule, usually daily or weekly. Use a window of 7 days or more with Only new.
- **Chicago and Mesa do not publish a permit ZIP code**, so they return nothing when you filter by ZIP.
- Cost, contractor, owner and applicant fields are only filled where the city publishes them.
- The category is detected from permit text by rules, so some permits land in `other` or an unexpected category.
- With a small **Max results** and Only new on, each run returns the next unseen batch.
- Anonymous access is enough for alerts. A free city app token only raises rate limits for very large pulls.

### FAQ

#### Which cities are covered?

New York City, Chicago, Los Angeles, San Francisco, Seattle, Austin, Cincinnati, Baton Rouge and Mesa.

#### Can you add my city?

We only add cities with a public, current, keyless open-data feed. Tell us the city you need.

#### Does it include contractor contact information?

Only what the city publishes, which for some cities includes a contractor name, license and phone.

#### Do I need an API key?

No.

#### How do I find only roofing or solar permits?

Use the **Categories** filter.

### Related Actors

More Actors from GovData Feeds, all on Apify:

- [grants-gov-alerts](https://apify.com/radiant_opuntia/grants-gov-alerts): US federal grant opportunities (Grants.gov): ceilings, deadlines, eligibility
- [sec-form-d-alerts](https://apify.com/radiant_opuntia/sec-form-d-alerts): SEC Form D filings: companies that just raised money
- [usaspending-awards-alerts](https://apify.com/radiant_opuntia/usaspending-awards-alerts): New federal contract, grant and loan awards (USAspending)
- [sec-form4-insider-alerts](https://apify.com/radiant_opuntia/sec-form4-insider-alerts): SEC Form 4 insider buys and sells, one row per transaction
- [fda-recall-alerts](https://apify.com/radiant_opuntia/fda-recall-alerts): FDA food, drug and medical device recalls
- [fda-compliance-alerts](https://apify.com/radiant_opuntia/fda-compliance-alerts): FDA 510(k) clearances, MAUDE adverse events and warning letters
- [cpsc-recall-alerts](https://apify.com/radiant_opuntia/cpsc-recall-alerts): CPSC consumer product safety recalls
- [clinical-trials-alerts](https://apify.com/radiant_opuntia/clinical-trials-alerts): New ClinicalTrials.gov studies by condition, sponsor and phase
- [federal-register-alerts](https://apify.com/radiant_opuntia/federal-register-alerts): Federal Register rules, proposed rules and notices
- [contractor-license-alerts](https://apify.com/radiant_opuntia/contractor-license-alerts): New contractor licenses in WA, OR and NY with bond and insurance
- [ofac-sanctions-alerts](https://apify.com/radiant_opuntia/ofac-sanctions-alerts): OFAC sanctions screening and change alerts
- [new-business-registrations-alerts](https://apify.com/radiant_opuntia/new-business-registrations-alerts): New LLC and corporation registrations (NY, CO, OR, CT)
- [epa-echo-enforcement-alerts](https://apify.com/radiant_opuntia/epa-echo-enforcement-alerts): EPA ECHO facilities with new environmental penalties
- [restaurant-inspections-alerts](https://apify.com/radiant_opuntia/restaurant-inspections-alerts): Restaurant health inspections from seven US jurisdictions
- [code-violations-alerts](https://apify.com/radiant_opuntia/code-violations-alerts): Building, housing and property code violations from six cities

*Data comes from city open-data portals and is public record. This Actor is not affiliated with any city. Permit data can be delayed, incomplete or corrected later.*

# Actor input Schema

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

Which city building-permit datasets to search. Each one is the city's official open-data feed.

## `keyword` (type: `string`):

Full-text match on the permit record (description, type, address, contractor, owner). Examples: 'solar', 'roof', 'swimming pool', 'tesla', 'restaurant'.

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

Only keep permits in these automatically detected categories. Leave empty for all. Great for roofers, solar installers, electricians and HVAC companies.

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

Only permits at these 5-digit ZIP codes. Chicago and Mesa don't publish a permit ZIP, so they return nothing when this is set. Leave empty for all.

## `minProjectCost` (type: `integer`):

Skip permits with an unknown or lower estimated cost. 0 = no minimum.

## `issuedWithinDays` (type: `integer`):

Permits issued in the last N days. Ignored if a start date is set.

## `startDate` (type: `string`):

Earliest issue date, YYYY-MM-DD. Overrides 'Issued within last N days'.

## `endDate` (type: `string`):

Latest issue date, YYYY-MM-DD. Defaults to today.

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

Remember which permits were already returned and output only newly issued ones. Ideal with a daily Schedule + email/Slack/webhook integration.

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

Separate memory for 'only new' mode. Defaults to a key derived from your filters.

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

Not needed. Anonymous access is enough for alerts. A free app token from the city's data portal raises rate limits for very large pulls.

## `maxResultsPerCity` (type: `integer`):

Stop after this many permits per city.

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

Stop after this many permits in total.

## Actor input object example

```json
{
  "cities": [
    "nyc",
    "chicago",
    "la",
    "sf",
    "seattle",
    "austin"
  ],
  "keyword": "roof",
  "categories": [],
  "zipCodes": [],
  "minProjectCost": 0,
  "issuedWithinDays": 7,
  "onlyNew": false,
  "maxResultsPerCity": 25,
  "maxResults": 50
}
```

# Actor output Schema

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

All building permit records returned by this run (flat JSON items in the default dataset).

## `runSummary` (type: `string`):

Counts of items pushed and items skipped as already seen (only-new mode).

# 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": [
        "nyc",
        "chicago",
        "la",
        "sf",
        "seattle",
        "austin"
    ],
    "keyword": "roof",
    "minProjectCost": 0,
    "issuedWithinDays": 7,
    "onlyNew": false,
    "maxResultsPerCity": 25,
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("radiant_opuntia/us-building-permits-alerts").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": [
        "nyc",
        "chicago",
        "la",
        "sf",
        "seattle",
        "austin",
    ],
    "keyword": "roof",
    "minProjectCost": 0,
    "issuedWithinDays": 7,
    "onlyNew": False,
    "maxResultsPerCity": 25,
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("radiant_opuntia/us-building-permits-alerts").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": [
    "nyc",
    "chicago",
    "la",
    "sf",
    "seattle",
    "austin"
  ],
  "keyword": "roof",
  "minProjectCost": 0,
  "issuedWithinDays": 7,
  "onlyNew": false,
  "maxResultsPerCity": 25,
  "maxResults": 50
}' |
apify call radiant_opuntia/us-building-permits-alerts --silent --output-dataset

```

## MCP server setup

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

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/3dHFg0Sg4FI47L4y1/builds/riUqX6ny3u4XHLiFN/openapi.json
