Building Permit Monitor - Construction Leads
Pricing
from $1.60 / 1,000 baseline permits
Building Permit Monitor - Construction Leads
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.
Pricing
from $1.60 / 1,000 baseline permits
Rating
0.0
(0)
Developer
Lowland Data
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Building Permit Monitor — Construction Leads
Watches US city building-permit portals — Chicago, Austin, San Francisco, Seattle and New York City — for newly issued permits matching your profile: keywords, permit types, minimum project valuation. It alerts the moment a matching permit is issued, and it remembers what it has already told you — so an alert always means a genuinely new project, never a re-scrape of last week's list.
It reads each city's official open-data API (the access route the cities publish for exactly this), and the output is clean by construction: project, address, valuation and contractor business — never homeowner or applicant identities. Safe to store, share with your sales team, or import into a CRM.
Quick start (30 seconds, no account keys needed)
- Run the actor with the prefilled input (Seattle, last 14 days) — it finishes in a few seconds and shows a baseline of recent permits.
- Replace the demo profile with your own: your cities, your trade's keywords or permit types, your minimum project size.
- Add a daily schedule (Actor page → Schedule). From then on, runs are quiet until a permit you care about is actually issued.
Who uses this
- A roofing contractor in Chicago monitors
keywords: ["roof", "reroof"]daily. When a permit is issued two neighborhoods over, the alert lands with theaddress,valuationUsdandissuedDate— a lead the same week the project goes live, not after the crews are already on site. - A solar installer in Austin watches
keywords: ["solar", "photovoltaic"]— every new solar permit shows whichcontractorNamewon the job, mapping both leads and competitors in one feed. - A building-materials supplier runs
permitTypes: ["new construction"]withminValuationUsd: 500000across all five cities — only projects big enough to supply, straight into the CRM via the API. - A market analyst tracks permit volumes and valuations per city as a construction-economy indicator — the baseline plus daily deltas is a clean time series.
- An HVAC company pairs
permitTypes: ["mechanical"]withalertOn: "new-and-updated"to also see status changes on projects it quoted.
What you get
One JSON item per event: a baseline snapshot per permit on the first run, then only transitions — newly issued matching permits, and (opt-in) status changes on permits you have already seen. A new-permit alert looks like:
{"portal": "austin","permitNumber": "2026-091811 EP","permitType": "Electrical Permit","permitClass": "Residential","workClass": "New","description": "Install rooftop solar array, 24 panels, 9.6 kW","status": "Active","address": "8316 ROBERT ZION WAY","city": "Austin","state": "TX","zip": "78744","valuationUsd": 48500,"appliedDate": "2026-07-16","issuedDate": "2026-07-17","expiresDate": "2027-01-13","contractorName": "Powerhouse Electrical Services, Inc.","contractorTrade": "Electrical Contractor","url": "https://abc.austintexas.gov/web/permit/public-search-other","isBaseline": false,"isUpdate": false}
Field honesty notes:
- Every portal has its own vocabulary —
permitType,permitClassandworkClasscarry the city's own labels, unnormalized, and every item's labels are reusable as yourpermitTypesfilter. valuationUsdappears only when the city publishes a project cost — many permits carry none, and absence does not mean small.contractorNameis the business on the permit where the city publishes one (Chicago and Austin do; San Francisco and Seattle mostly don't).addressis the project site the city publishes for public accountability. Who lives there is deliberately not in the data — see the compliance section.
How much does permit monitoring cost?
Pay per outcome — checking costs nothing; you pay when the monitor tells you something new:
- New matching permit (the alert): $0.02 — also for status-change alerts.
- Baseline item (first run only): $0.002.
- Actor start: $0.005. Everything included - there are no separate platform-usage charges, and higher Apify plans get automatic unit-price discounts.
Cost feel: a focused trade profile in two cities sees a handful of new permits per working day → roughly $2–8/month for complete coverage, with the one-time baseline (say 100 permits) costing about $0.20. A run with zero new matches costs $0.005 all-in. Lead-gen services sell the same permit leads for $50–300/month.
Why an alert costs more than a scraped row
The store's headline ("from $2.00 / 1,000 baseline results") is what a trial costs: a 100-permit baseline ≈ $0.20. Apify displays every event per 1,000, so in the pricing table the alert event reads "$20.00 / 1,000" next to raw permit scrapers at $2–30 per 1,000 rows — but that comparison is between different things:
- A raw permit scraper sells rows: to monitor with rows you re-download each city's recent permits every day and diff them yourself.
- This monitor sells the transition: it remembers state in your account and charges $0.02 exactly when a permit you have not seen matches your profile. Nobody buys 1,000 alerts a month.
Not technical? Let your AI assistant set it up
Paste this prompt together with a line about your trade and cities:
Set up the Apify actor lowlanddata/building-permit-monitor to watch US buildingpermits for me. Build the input JSON from my business description:- portals: which of ["chicago","austin","san-francisco","seattle","nyc"] I can serve- keywords: 3-8 words my kind of project's description would contain(e.g. ["roof","reroof"] for roofing, ["solar"] for solar installers)- permitTypes: my trade's permit labels if I named any (e.g. ["electrical"])- minValuationUsd: only if I gave a minimum project sizeLeave alertOn, emitBaseline and maxItems at their defaults. Run it once andshow me the baseline as a table (description, address, city, valuation,contractor, issued date). Then create a daily schedule for it and set up anotification so I get an email when a run produces items.
Coverage — measured, not promised
- Sources: each city's official open-data permit dataset (Socrata APIs) — Chicago, Austin, San Francisco, Seattle and New York City (DOB NOW). Keyless, sanctioned access; together several thousand permits/week unfiltered (measured July 2026, NYC alone ~3,000/week).
- More cities are on the roadmap; each city ships only after its dataset passes the same field-level privacy verification.
- Cities update their datasets on their own cadence — typically daily with a small lag after issuance. The monitor alerts when the dataset publishes the permit; that is as fast as official data allows.
- Permit-type vocabularies differ per city —
permitTypesis an honest substring match over each city's own labels, not a fake universal taxonomy. - A portal outage or dataset migration never fails the run: the affected city is reported in the run status (uncharged) and its permits alert once it recovers.
How the monitor thinks
- First run = baseline. It fetches your profile's matches from the last
lookbackDays(default 14), pushes them flaggedisBaseline: trueat the low baseline price, and memorizes them.emitBaseline: falseseeds silently. - After that, only transitions. Each run queries from the previous run (one
day of overlap; the memory absorbs duplicates) and pushes only permits it has
never alerted. Status changes alert as
isUpdate: truewhenalertOn: "new-and-updated"; with the default they stay silent but are remembered. - Editing the profile starts a fresh baseline — matching-relevant inputs
are the profile's identity, so a changed profile can never flood you with
alerts computed against another profile's memory.
maxItems,emitBaselineand schedule changes do not restart anything. - Memory lives in a named key-value store (
stateStoreName, defaultpermit-monitor-state) in your account. Run several profiles on separate schedules against the same store — they never interfere.resetState: truewipes the current profile's memory. - A capped baseline samples every selected city round-robin instead of exhausting the first one.
- Re-running after a crash or overlap re-alerts at most the last few unsaved items — state is checkpointed during the run.
Input reference
| Field | Type | Default | Notes |
|---|---|---|---|
portals | array | all five | chicago, austin, san-francisco, seattle, nyc. |
keywords | array | [] | OR, case-insensitive, over description + type labels. |
permitTypes | array | [] | Substring match over the city's type/class labels only. |
minValuationUsd | integer | — | Permits without a published valuation always pass. |
lookbackDays | integer | 14 | Baseline reach on the first run (max 60). |
alertOn | string | "new" | "new-and-updated" adds status-change alerts. |
emitBaseline | boolean | true | false = silent seeding. |
resetState | boolean | false | One-shot: wipe this profile's memory. |
maxItems | integer | 500 | Overflow alerts on the next run, never lost. |
stateStoreName | string | "permit-monitor-state" | Only change to fully isolate monitor instances. |
Scheduling and API use
Run it daily and pair the schedule with a Monitoring alert on "dataset items
0" to get an email exactly when a permit matched.
curl -X POST \"https://api.apify.com/v2/acts/lowlanddata~building-permit-monitor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"portals": ["austin"], "keywords": ["solar"]}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('lowlanddata/building-permit-monitor').call({portals: ['chicago', 'austin'],keywords: ['roof', 'reroof'],});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items); // only new permits since the last run
from apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("lowlanddata/building-permit-monitor").call(run_input={"portals": ["seattle"],"permitTypes": ["mechanical"],})items = client.dataset(run["defaultDatasetId"]).list_items().items
Daily runs finish in well under a minute, comfortably inside the 300s sync-call wall; a 60-day four-city baseline is the one case that can take a couple of minutes — run it async once.
Use it with AI agents (MCP)
Claude, Cursor and other MCP-capable agents can run this monitor as a tool through Apify's hosted MCP server: the agent builds the profile from a plain-language brief, runs it, and reads the leads back — no glue code.
Claude Code:
$claude mcp add apify --transport http "https://mcp.apify.com?actors=lowlanddata/building-permit-monitor"
Cursor or Claude Desktop (add a custom connector / MCP server with this URL):
https://mcp.apify.com?actors=lowlanddata/building-permit-monitor
Sign in with your Apify account when prompted — runs are billed to it. Setup details per client: Apify MCP docs, or start from this actor's own MCP page: apify.com/lowlanddata/building-permit-monitor/api/mcp.
Prompts that work once connected:
- "Watch Chicago and Austin for new roofing permits and show me today's leads."
- "What solar permits over $30k were issued in Austin this week, and which contractors got them?"
- "Track new-construction permits over $1M across all five cities and alert me daily."
Is it legal to monitor building permits?
Yes — building permits are public records, and these five cities publish them through official open-data APIs exactly so they can be reused. No login walls, no anti-bot bypass — if a portal is unreachable, the run reports it rather than fighting it. And the output is safe by construction: homeowner and applicant identities are never extracted (see below).
How you contact a lead is on you — this tool gives you the public project record, not marketing-law advice for your state.
Compliance: safe to store, safe to CRM-import
Permit records as published by the cities can contain personal data — owner and
applicant names, phone numbers, even the applicant's own address. This actor's
guarantee is structural: each city's mapper whitelists fields IN (project,
address, valuation, dates, contractor business name/trade), so person-fields
never map at all, and an automated test proves it against each city's real
column names. The project address stays — it is the publicly published
project site and the lead's core value; who lives there is deliberately
unreachable. One honest limit: description is text the applicant wrote — on
rare occasions someone writes a name into free text. We cannot rewrite public
records; everything structured is guaranteed clean.
FAQ
Why did my second run return nothing? Because nothing new matched — that is the product working. The first run is the baseline; afterwards you only pay for permits you have not seen. The run status says how many permits were checked.
Does the output contain homeowner names or phone numbers? No — by design. The city mappers never touch owner/applicant fields. You get the project, the address, the valuation and the contractor business.
Which cities are covered? Chicago, Austin, San Francisco, Seattle and New York City — cities with official open-data permit APIs. More follow; tell us which city you need via the Issues tab.
Can I monitor several trades or cities separately? Yes — one schedule per profile, same actor, same state store. Each profile keeps its own memory.
How fresh are the alerts? As fresh as the city's dataset — typically the permit appears within a day or two of issuance. The monitor can't be faster than the official data, and doesn't pretend to be.
What does a status-change alert mean? With alertOn: "new-and-updated",
a seen permit whose status moves (e.g. Active → Finaled) alerts once as
isUpdate: true — useful for tracking projects you quoted.
How do I get construction leads from building permits? Set your trade's
keywords (e.g. ["roof", "reroof"]) or permit types, pick your cities, and put
the actor on a daily schedule. Every newly issued matching permit arrives with
the address, valuation and issue date — a lead the week the project starts.
What does permit monitoring cost? $0.02 per new-permit or status-change alert, $0.002 per baseline item, $0.005 per run start — nothing else. A focused trade profile in two cities usually lands at $2–8/month; permit lead-gen services sell the same leads for $50–300/month.
Do I need API keys for the city portals? No. All five cities publish their permits through keyless open-data APIs, so there is nothing to register, renew or pay for on the city side.
What does the first run load? The last lookbackDays of issued permits
(default 14, up to 60) as a baseline, each flagged isBaseline: true at the
low baseline rate. Turn emitBaseline off to seed the memory without pushing
anything.
Can the same permit trigger two alerts? Not for being new — runs overlap by
a day on purpose and the monitor's memory swallows the duplicates. The only
second event a permit can produce is an opt-in isUpdate status change.
How do I only see large projects? Set minValuationUsd, e.g. 500000 for
half-million-plus jobs. Note that many permits publish no valuation at all;
those always pass, because absence does not mean small.
How do I filter by trade or permit type? permitTypes does a
case-insensitive substring match over each city's own type and class labels —
there is no universal taxonomy. Every dataset item carries its city's labels,
so you can copy them straight back into the filter.
Can I see which contractor got the job? Where the city publishes it, yes:
contractorName and contractorTrade are filled for Chicago and Austin; San
Francisco and Seattle mostly leave them empty.
Can I pipe the leads into my CRM? Yes — pull the run's dataset over the API or download it from the Console in CSV, Excel or JSON. The fields are flat and stable, and homeowner identities are structurally absent, so the import needs no privacy scrub.
How often should the monitor run? Daily. Cities refresh their datasets roughly once a day with a small lag after issuance, so running more often just buys extra $0.005 run starts without finding permits sooner.
What if one city's portal goes down? The run keeps going: the affected city is reported in the run status (uncharged) and its permits alert once the dataset recovers. Only when every portal fails does the run fail.
Can I drive it from an AI agent? Yes — via Apify's hosted MCP server, agents like Claude or Cursor can turn a plain-language brief into a profile, start the run and summarize the new leads.
Troubleshooting
- "Every portal failed" — the open-data platforms are down or unreachable; re-run later. Single-portal failures never fail the run.
- " — the lookback window matched
more than ~10,000 permits; lower
lookbackDaysor narrow the profile. - "Monitor state record … is not readable" — the state was written by a
newer version; run once with
resetState: trueto start a fresh baseline.
Something else off? Open an issue on the actor's Issues tab — reports are read and answered. And if the alerts are earning their keep, a rating on this page takes ten seconds and helps other buyers find a GDPR-clean monitor among the lookalikes.