# US Construction Permit Intelligence (`marielise.dev/us-construction-permit-intelligence`) Actor

Find high-value US construction permits from official city data and turn them into ranked sales opportunities. The actor normalizes trades, scores leads, adds AI insight, and tells contractors, suppliers, and investors which permits to call now, qualify, monitor, or skip.

- **URL**: https://apify.com/marielise.dev/us-construction-permit-intelligence.md
- **Developed by:** [Marielise](https://apify.com/marielise.dev) (community)
- **Categories:** Lead generation, Automation, AI
- **Stats:** 21 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $40.00 / 1,000 permit leads

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

## Construction Permit Intelligence

Turn official US permit feeds into ranked construction signals your team can actually use.

This actor pulls live permit records from official US open-data sources, normalizes them, and scores each construction signal for outreach or market monitoring. Instead of dumping raw rows, it prioritizes the records most likely to matter based on recency, estimated project value, trade relevance, property type, available contact data, and optional built-in AI review.

### Why this actor

Permit data is valuable, but raw permit feeds are noisy:

- Contractors need to know which jobs look worth calling on.
- Suppliers need to spot active markets and higher-value work fast.
- Investors and service businesses need a leading indicator for neighborhood-level construction activity.
- Existing permit tools often stop at retrieval, with little ranking or qualification.

This actor is built around that gap: **official permit data + practical prioritization + AI-assisted lead review**.

### Coverage

This is a **US-only** actor and it does **not** claim nationwide coverage yet. Coverage is explicit and metro-based.

| Source | Jurisdiction | Coverage type | Key strengths |
|--------|--------------|---------------|---------------|
| `los_angeles` | Los Angeles, CA | Building permits | Good descriptions, valuation, permit metadata |
| `chicago` | Chicago, IL | Building permits | Strong contact fields, reported cost, rich work descriptions |
| `new_york_city` | New York City, NY | DOB NOW approved permits | Issued dates, applicant/owner info, estimated job costs |
| `san_francisco` | San Francisco, CA | Building permits | Clean issued-date stream, estimated cost, use and reroof signals |
| `austin` | Austin, TX | Permit applications issued | Trade-specific contractor fields, permit class, active issued permits |
| `miami` | Miami, FL | Building permits | Official issued-date feed, total cost, scope-of-work, contractor company |
| `seattle` | Seattle, WA | Issued building permits | Clean issued stream, estimated cost, strong new-build and residential signals |

The source architecture is modular, so more US cities can be added without changing the output contract.

### What it returns

Each run produces:

- A **summary record** with high-priority counts, average signal score, dominant trade, top ZIP codes, and total estimated value
- An **AI market insight** summary when `OPENAI_API_KEY` is available
- A **ranked permit dataset** with normalized addresses, permit type, trade tags, valuation, score, reason, and optional AI lead notes
- `OUTPUT` JSON in the key-value store
- `permits.csv` for spreadsheet workflows
- `REPORT.md` for quick review or sharing

### Inputs

#### Core filters

- `sources`: `["los_angeles", "chicago", "new_york_city", "san_francisco", "austin", "miami", "seattle"]`
- `tradeFocus`: optional list of trade priorities like `solar`, `roofing`, `electrical`, `fire_suppression`, `renovation`
- `buyerPersona`: `general`, `contractor`, `supplier`, or `investor`
- `searchQuery`: free-text query across descriptions, permit types, addresses, and available party names
- `focusKeywords`: extra include keywords to strengthen relevance
- `excludeKeywords`: keywords to drop
- `zipCodes`: optional 5-digit ZIP filter
- `propertyTypes`: `residential`, `commercial`, `mixed_or_other`
- `issuedFrom` / `issuedTo`: date range in `YYYY-MM-DD` (defaults to last 30 days through today)
- `minReportedCost` / `maxReportedCost`: valuation filter where available
- `minSignalScore`: drop weak matches
- `aiMode`: `auto` or `off`. `auto` uses built-in OpenAI review if `OPENAI_API_KEY` is present in the runtime
- `aiMaxItems`: maximum number of top permits to review with AI
- `aiMinRuleScore`: minimum rule-based score before AI review is attempted

#### Output controls

- `maxItemsPerSource`: raw permits fetched before ranking
- `maxItems`: final permits returned
- `sortBy`: `signal_desc`, `issue_date_desc`, `valuation_desc`
- `outputFormat`: `full`, `summary_only`, `permits_only`

### AI intelligence

The actor now has a built-in AI layer:

- It reads `OPENAI_API_KEY` from the environment, not from actor input.
- In `auto` mode, it sends only the strongest rule-ranked permits to OpenAI for structured review.
- AI can refine trade classification, adjust score modestly, add outreach guidance, and generate a short market insight.
- If no `OPENAI_API_KEY` is available, the actor still works in rule-based mode.

The default built-in model is `gpt-5-mini`, chosen as a balance of cost and structured-inference quality for short JSON permit reviews.

Buyer personas change the ranking logic:

- `contractor`: favors fresh, contactable work with clear execution scope
- `supplier`: leans harder on valuation, commercial property, and likely materials demand
- `investor`: favors larger commercial / mixed permits and lower-noise market signals

### Example inputs

#### Roofing and renovation leads in Los Angeles

```json
{
  "sources": ["los_angeles"],
  "tradeFocus": ["roofing", "renovation"],
  "zipCodes": ["90011", "90012", "90015"],
  "issuedFrom": "2026-02-01",
  "minReportedCost": 25000,
  "minSignalScore": 45,
  "maxItems": 100
}
```

#### Chicago electrical and signage permits

```json
{
  "sources": ["chicago"],
  "tradeFocus": ["electrical", "signage"],
  "searchQuery": "panel upgrade",
  "issuedFrom": "2026-01-15",
  "focusKeywords": ["generator", "service upgrade"],
  "maxItemsPerSource": 200,
  "maxItems": 75
}
```

#### NYC fire suppression and tenant-space work

```json
{
  "sources": ["new_york_city"],
  "tradeFocus": ["fire_suppression", "renovation"],
  "searchQuery": "tenant space",
  "propertyTypes": ["commercial"],
  "issuedFrom": "2026-02-06",
  "maxItems": 50
}
```

#### Multi-city commercial renovation watchlist

```json
{
  "sources": ["los_angeles", "chicago", "miami"],
  "buyerPersona": "supplier",
  "tradeFocus": ["renovation", "general_construction"],
  "searchQuery": "tenant improvement",
  "propertyTypes": ["commercial"],
  "minReportedCost": 100000,
  "aiMode": "auto",
  "sortBy": "valuation_desc",
  "maxItems": 150
}
```

#### Austin residential mechanical and plumbing work

```json
{
  "sources": ["austin"],
  "tradeFocus": ["hvac", "plumbing"],
  "searchQuery": "replacement",
  "issuedFrom": "2026-03-01",
  "zipCodes": ["78759", "78757"],
  "maxItems": 50
}
```

#### San Francisco roofing watchlist

```json
{
  "sources": ["san_francisco"],
  "tradeFocus": ["roofing", "solar"],
  "issuedFrom": "2026-03-01",
  "minReportedCost": 5000,
  "maxItems": 50
}
```

#### Seattle and Miami new-construction watchlist

```json
{
  "sources": ["seattle", "miami"],
  "tradeFocus": ["new_construction", "electrical", "plumbing"],
  "issuedFrom": "2026-03-01",
  "minReportedCost": 10000,
  "sortBy": "issue_date_desc",
  "maxItems": 100
}
```

### Output shape

#### Summary record

```json
{
  "type": "summary",
  "summary": {
    "quickTake": "12 high-priority permits surfaced across 2 source(s), led by renovation activity.",
    "aiMarketInsight": "Fresh higher-value renovation permits are clustering around commercial interiors, which is useful for specialty subs and supplier outreach.",
    "averageOpportunityScore": 68.4,
    "highPriorityPermits": 12,
    "dominantTrade": "renovation",
    "totalEstimatedValue": {
      "amount": 4825000,
      "currency": "USD",
      "display": "$4,825,000"
    },
    "topSignals": [
      { "label": "renovation", "count": 34 }
    ],
    "topZipCodes": [
      { "zipCode": "90012", "count": 11 }
    ]
  },
  "meta": {
    "sourcesAttempted": 2,
    "sourcesWithResults": 2,
    "permitsAnalyzed": 287,
    "permitsReturned": 150,
    "issuedFrom": "2026-02-06",
    "issuedTo": "2026-03-07",
    "processingMs": 1823,
    "buyerPersona": "supplier",
    "aiMode": "auto",
    "aiModelUsed": "gpt-5-mini",
    "aiEnhancedPermits": 15
  }
}
```

#### Permit record

```json
{
  "type": "permit",
  "source": "chicago",
  "permitId": "101072844",
  "issueDate": "2025-10-14",
  "status": "ACTIVE",
  "address": {
    "full": "2219 S OAKLEY AVE Chicago, IL",
    "city": "Chicago",
    "state": "IL",
    "zipCode": "60608"
  },
  "valuation": {
    "amount": 20000,
    "currency": "USD",
    "display": "$20,000"
  },
  "permitType": "PERMIT - RENOVATION/ALTERATION",
  "permitSubType": "SELF CERT",
  "propertyType": "residential",
  "primaryTrade": "renovation",
  "tradeTags": ["renovation", "general_construction"],
  "description": "BUILD A DORMER ON THE SOUTH SIDE OF THE EXISTING 8-UNIT RESIDENTIAL BUILDING ROOF...",
  "contacts": [
    {
      "type": "CONTRACTOR-GENERAL CONTRACTOR",
      "name": "ALL TECH BUILDERS & RESTORATION INC",
      "city": "WHEELING",
      "state": "IL",
      "zipCode": "60090"
    }
  ],
  "opportunityScore": 71,
  "priority": "medium",
  "recommendedAction": "qualify",
  "reason": "renovation match, $20,000 valuation, contactable parties available",
  "aiIntelligence": {
    "model": "gpt-5-mini",
    "reviewedAt": "2026-03-07T14:22:01.000Z",
    "scoreDelta": 4,
    "confidence": "high",
    "commercialIntent": "medium",
    "refinedTrade": "renovation",
    "refinedPropertyType": "residential",
    "summary": "Fresh interior alteration with a named contractor and a clear renovation scope.",
    "outreachAngle": "Lead with renovation support and close-in execution capacity.",
    "buyerSignals": ["named contractor", "clear scope", "recent issue date"],
    "risks": ["mid-sized valuation"]
  },
  "sourceUrl": "https://data.cityofchicago.org/resource/ydr8-5enu.json?$where=permit_='101072844'"
}
```

### How scoring works

Each permit gets a `0-100` opportunity score based on:

- **Recency**: newer permits rank higher
- **Value**: higher reported cost / valuation increases priority
- **Trade fit**: matches against requested `tradeFocus`, `searchQuery`, and `focusKeywords`
- **Property fit**: rewards the requested property type
- **Contactability**: Chicago records with contractor / owner details score higher

When AI is enabled, the actor keeps the rule-based score as the baseline and applies a bounded AI review only to top permits. That review can:

- refine trade and property classification
- adjust the score modestly
- add permit-level commercial notes and outreach guidance
- generate a short market insight for the report summary

Each permit also gets a deterministic `recommendedAction`:

- `call_now`
- `qualify`
- `monitor`
- `skip`

### Development

```bash
npm install
npm run build
npm start
```

Local runs can use a `.env` file or shell environment variable. Apify runs should set `OPENAI_API_KEY` in **Actor Settings > Environment Variables**.

### Notes

- This actor uses **official public datasets**, not scraped private systems.
- Coverage is **major US markets first**, not “all states”.
- Valuation and descriptive richness vary by source, so score composition is normalized but not identical across cities.
- Miami does not publish a site ZIP in the official open dataset, so ZIP filtering is strongest on the other supported metros.
- AI review is built in and uses the actor runtime environment, so users do not pass API keys in actor input.

# Actor input Schema

## `sources` (type: `array`):

Choose which official US city datasets to search.

## `tradeFocus` (type: `array`):

Optional trade filters used to score and rank the most relevant permits.

## `searchQuery` (type: `string`):

Optional free-text search across descriptions, permit types, addresses, and available party names. Example: tenant improvement, restaurant, panel upgrade, dormer.

## `focusKeywords` (type: `array`):

Additional keywords that increase ranking relevance.

## `excludeKeywords` (type: `array`):

Drop permits containing these keywords in the normalized searchable text.

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

Optional list of 5-digit ZIP codes to narrow the results.

## `propertyTypes` (type: `array`):

Optional property type filter after normalization.

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

Start date in YYYY-MM-DD. Defaults to 30 days ago when left empty.

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

End date in YYYY-MM-DD. Defaults to today when left empty.

## `minReportedCost` (type: `number`):

Minimum reported cost / valuation in USD where available.

## `maxReportedCost` (type: `number`):

Maximum reported cost / valuation in USD where available.

## `minSignalScore` (type: `integer`):

Drop permits below this opportunity score.

## `maxItemsPerSource` (type: `integer`):

Maximum raw permits to fetch from each official source before scoring.

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

Maximum ranked permits returned after scoring and filtering.

## `sortBy` (type: `string`):

How to sort the ranked permits.

## `outputFormat` (type: `string`):

Choose whether to return full results, only the summary, or only permit records.

## `aiMode` (type: `string`):

Use built-in OpenAI permit review when OPENAI\_API\_KEY is available in the actor environment. No API key is accepted in input.

## `aiMaxItems` (type: `integer`):

Maximum number of top rule-ranked permits to send to OpenAI for deeper review.

## `aiMinRuleScore` (type: `integer`):

Only permits at or above this rule-based score are considered for AI review.

## Actor input object example

```json
{
  "sources": [
    "los_angeles",
    "chicago",
    "new_york_city",
    "san_francisco",
    "austin",
    "miami",
    "seattle"
  ],
  "tradeFocus": [],
  "focusKeywords": [],
  "excludeKeywords": [],
  "zipCodes": [],
  "propertyTypes": [],
  "minSignalScore": 35,
  "maxItemsPerSource": 150,
  "maxItems": 200,
  "sortBy": "signal_desc",
  "outputFormat": "full",
  "aiMode": "auto",
  "aiMaxItems": 15,
  "aiMinRuleScore": 60
}
```

# Actor output Schema

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

High-level permit opportunity analytics and hotspot signals

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

Normalized permit records scored for outreach or market monitoring

## `keyValueStore` (type: `string`):

Actor run key-value store for JSON, CSV, and Markdown artifacts

# 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("marielise.dev/us-construction-permit-intelligence").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("marielise.dev/us-construction-permit-intelligence").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 marielise.dev/us-construction-permit-intelligence --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,marielise.dev/us-construction-permit-intelligence"
        }
    }
}

```

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/QEIP3kgJHYxawbwen/builds/cfUQ34jkrZNTKwQpH/openapi.json
