# US Building Permit Leads — Scored (Chicago, Austin) (`vov4ikr/my-actor-1`) Actor

Turn official city building-permit records into scored, deduplicated leads — Chicago, Austin, more cities over time.

- **URL**: https://apify.com/vov4ikr/my-actor-1.md
- **Developed by:** [Volodymyr Ruskykh](https://apify.com/vov4ikr) (community)
- **Categories:** Lead generation, Other, Open source
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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

## 🏗️ Permit Alert Monitor — Deduplicated Construction Leads with Lead Scoring

**Turn official city building-permit records into scored, deduplicated leads.** This actor pulls directly from city open-data APIs (Socrata), scores every new permit HOT/WARM/COLD based on freshness and project value, and — unlike every one-off permit scraper on the Store — remembers what it already showed you, so a scheduled run only ever surfaces what's genuinely new.

> A new building permit means a project is about to start. Typical lead window is **1-6 weeks before construction begins** — exactly when roofers, solar installers, HVAC companies, electricians, and remodelers want to reach the homeowner or contractor before someone else does.

No proxies. No CAPTCHAs. No blocks. **100% public government records.**

***

### Why this instead of a typical permit scraper

| | This actor | Typical permit scraper |
|---|---|---|
| **Lead scoring** (🔥 HOT / 🟡 WARM / ⚪ COLD) | ✅ | ❌ raw dump |
| **Deduplication across runs** | ✅ — only genuinely new permits | ❌ re-exports everything every time |
| **Multiple cities, one Actor** | ✅ (Chicago, Austin — more added over time) | Usually one Actor per city |
| **Trade filter** | ✅ Roofing, Solar, Pool & Spa, HVAC, Electrical, Fencing, Decks & Porches | Sometimes |
| **Contractor contact info** | ✅ name + phone where the city publishes it | Partial |
| **Minimum project value filter** | ✅ | Rarely |
| **Optional email digest** | ✅ one clean email per run, not one per permit | Rarely offered |

***

### What you get

Every genuinely new permit, deduplicated against everything seen in previous runs:

```json
{
  "permit_number": "2016-012795 BP",
  "issue_date": "2026-08-20T00:00:00.000",
  "address": "7213 ALTIDORE DR",
  "description": "New 1-story single-family residence, attached garage, covered porch and patio",
  "reported_cost": "116480",
  "contractor_name": "Sondra Allison",
  "contractor_phone": "5126518100",
  "lead_score": 85,
  "lead_grade": "HOT"
}
```

Plus, if you set an email, one digest per run covering everything new — never one email per permit, so volume stays sane no matter how many matches show up:

```
Subject: New permit: 7213 ALTIDORE DR ($116,480)

🔥 Lead: HOT (85/100)
Address: 7213 ALTIDORE DR
Map: https://www.google.com/maps/search/?api=1&query=7213+ALTIDORE+DR
Date issued: 2026-08-20
Work: New 1-story single-family residence, attached garage, covered porch and patio
Permit #: 2016-012795 BP
Reported cost: $116,480
Contractor on file: Sondra Allison
Contractor phone: 5126518100
```

***

### Supported cities

Chicago (IL) · Austin (TX) — more added over time, verified against each city's real schema before going live (no guessed field names).

***

### Who uses this

Roofers · Solar installers · HVAC & electrical contractors · Fencing & deck companies · Remodelers & general contractors · Lead-gen agencies · Real-estate & proptech researchers · Anyone building a CRM feed via API, n8n, or Make

***

### Input

| Field | What it does | Default |
|---|---|---|
| `city` | Which city's permits to pull | `chicago` |
| `trade` | Roofing / Solar / Pool & Spa / HVAC / Electrical / Fencing / Decks & Porches / Everything | `everything` |
| `alertEmail` | Optional — where to send the digest email. Leave empty to just use the Dataset/API | — |
| `minCost` | Optional — only alert on permits at or above this project value | — |

To force a clean-slate test run (see all matching permits as "new" again), don't use an input flag — manually delete the memory instead: Apify Console → your Actor → **Storage → Key-value stores → find the store named `permit-alert-state-<city>-<trade>` → delete the "STATE" key**.

***

### Use it from code / n8n / Make

Run it via the [Apify API](https://docs.apify.com/api/v2) and pull results from the Dataset, or wire it into **n8n, Make, or Zapier** to drip fresh, scored leads into your CRM every run.

***

### FAQ

**Is this legal?** Yes — building permits are public records, published by each city's own official open-data portal.

**How fresh is the data?** Cities update their open-data portals roughly daily. Nobody in this space is truly real-time despite the marketing — even large commercial permit-data platforms refresh their bulk feeds on a multi-week cycle. Pulling directly from each city's own portal keeps this Actor about as fresh as the data gets.

**Why are some fields empty?** Each city publishes a different raw schema. Chicago splits an address into street number/direction/name; Austin gives one combined address string. Austin publishes a contractor phone number; Chicago doesn't. The Dataset keeps every original field the city publishes, unmodified — blank fields just mean that city doesn't publish that particular detail.

**How does lead scoring work?** A simple, explainable formula — not a black box: freshness (days since issued), project value, and whether there's a contact to actually call. Full transparency: it's meant as a quick triage signal, not a guarantee.

**Why deduplication instead of a raw export?** Most permit scrapers give you the same records again on every run, leaving you to figure out what's actually new. This Actor remembers what it already surfaced (per city/trade combination) and only alerts on genuinely new matches.

# Actor input Schema

## `city` (type: `string`):

Which city's permit data to pull. Both cities share this one Actor/dataset — no need to run separate Actors per city.

## `trade` (type: `string`):

New permits matching this trade will trigger an alert.

## `alertEmail` (type: `string`):

Where new-permit alerts will be sent. Leave empty if you just want the raw leads in the Dataset (e.g. pulling results via the API or n8n/Make) without an email digest.

## `minCost` (type: `integer`):

Only alert on permits with a reported cost at or above this amount, e.g. 5000 to skip small repairs. Leave empty for no filter. Lower-cost permits are still remembered internally so you won't see them later either.

## Actor input object example

```json
{
  "city": "chicago",
  "trade": "everything"
}
```

# Actor output Schema

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

Every genuinely new permit found this run, matching your trade filter.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("vov4ikr/my-actor-1").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("vov4ikr/my-actor-1").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 '{}' |
apify call vov4ikr/my-actor-1 --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vov4ikr/my-actor-1"
        }
    }
}

```

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/O5kvQ9GWbv6u5Q5jd/builds/lgNmbC3kucm7hTAu4/openapi.json
