Building Permit Monitor - Construction Leads

Get alerted the moment a matching building permit is issued in Chicago, Austin, San Francisco, Seattle or NYC.

Get alerted the moment a matching building permit is issued in Chicago, Austin, San Francisco, Seattle or NYC. Filter by keywords, permit type and valuation; alerts only on never-seen permits via official city open-data APIs. Project and contractor business data, no homeowner identities.

$3.00 / 1,000 · 100.0% success over 27 public runs in the last 30 days.

Run it on Apify → Free to try - runs bill per result on your own account.

What you give it

Every field is optional unless marked; sensible defaults do the rest.

FieldTypeWhat it doesDefault
portals array Which city permit portals to monitor. All five are official open-data APIs - no keys needed. ["chicago", "austin", "san-francisco", "seattle", "nyc"]
keywords array Alert on permits whose description or type contains ANY of these words (case-insensitive). Example: ["solar", "roof", "HVAC"]. Leave empty to match everything and filter by permit type or valuation instead. []
permitTypes array Only alert on permits whose type or class label contains any of these (case-insensitive substring - portal vocabularies differ). Example: ["electrical", "demolition", "new construction"]. Every dataset item carries its portal's own labels, reusable here. []
minValuationUsd integer Only alert on permits with a reported project cost of at least this many dollars. Permits without a published valuation always pass - portals make the field optional, and dropping them would hide real leads. -
lookbackDays integer How many days of already-issued permits the FIRST run of a profile loads as its baseline. Later runs automatically query from the previous run with one day of overlap - re-alerting a seen permit is impossible. 14
alertOn string "new" alerts once per permit. "new-and-updated" also alerts when a seen permit's status changes (marked isUpdate: true), e.g. issued to finaled. new
emitBaseline boolean On the very first run of a profile, push the currently matching permits (flagged isBaseline: true, charged at the lower baseline price) so you start with the recent picture. Turn off to seed silently and only ever receive new alerts. True
resetState boolean Discard this profile's memory of already-seen permits and start over with a fresh baseline run. One-shot switch: turn it back off afterwards. False
maxItems integer Upper bound on items pushed per run (baseline or alerts). On an alert run, matches beyond the cap alert on the next run. On the very first (baseline) run they are recorded as already seen instead, so raise this before the first run if you need the whole baseline. 500
stateStoreName string Named key-value store holding the monitor's seen-permit memory. Only change this to run fully isolated monitor instances. permit-monitor-state
reportFailures boolean When a run fails, send the developer the actor name and build, an error category, the error message (truncated) and a one-way hash of your input - so a bug can be fixed without anyone asking you to reproduce it. Your input itself, your results and your identity are never sent, and successful runs send nothing at all. Switch this off and the actor behaves exactly the same. True

What you get back

One JSON object per result, with exactly these fields - no seller identities, no contact data, ever.

A real result row from a recent run:

{
  "address": "1526 M L KING JR WAY",
  "appliedDate": "2025-12-23",
  "city": "SEATTLE",
  "description": "Construct new two family dwelling  per plan. (Establish use as single family residences  one with an attached accessory dwelling unit per la...",
  "expiresDate": "2028-04-12",
  "isBaseline": false,
  "isUpdate": false,
  "issuedDate": "2026-10-12",
  "latitude": 47.61492124,
  "longitude": -122.29568016,
  "permitClass": "Residential",
  "permitNumber": "7116062-CN",
  "permitType": "Building",
  "portal": "seattle",
  "state": "WA",
  "status": "Issued",
  "url": "https://services.seattle.gov/portal/customize/LinkToRecord.aspx?altId=7116062-CN",
  "valuationUsd": 447600,
  "workClass": "New",
  "zip": "98122"
}
FieldTypeMeaning
portal string Which city portal issued the permit.
permitNumber string The permit's number on its portal - its stable public identifier.
permitType string The portal's permit-type label, unnormalized. Reusable in the permitTypes input.
permitClass string Residential/commercial class where the portal publishes one.
workClass string The portal's work-class or review-type label.
description string Work description as filed with the city.
status string Current permit status on the portal.
address string Project address - where the work happens. Owner and applicant identities are never included (see the compliance section).
city string Project city.
state string Project state, two-letter code.
zip string Project ZIP code.
latitude number Project latitude where the portal publishes coordinates.
longitude number Project longitude where the portal publishes coordinates.
valuationUsd number Reported project cost in USD, when published. Absence does not mean small.
appliedDate string Date the permit was applied for, YYYY-MM-DD.
issuedDate string Date the permit was issued, YYYY-MM-DD.
expiresDate string Permit expiry date where published, YYYY-MM-DD.
contractorName string Contractor's business name, where the portal publishes one. Organization-level data only - no person names, phones or emails.
contractorTrade string Contractor's trade or role label.
contractors array All contractor parties on the permit ({trade, name}), where the portal lists several (Chicago).
url string Link to the permit record on its portal, where one exists.
isBaseline boolean True on items from a profile's first run (the recent baseline). False on real new-permit alerts.
isUpdate boolean True when the alert is a status change on an already-seen permit (alertOn: new-and-updated).

Health

100.0% success over 27 public runs in the last 30 days. Live record, failures included: status page.

Full documentation, examples and the AI-assistant prompt live on the store page.