Chicago, LA, Seattle & Austin Permit Monitor
Pricing
from $1.00 / 1,000 permit evidence rows
Chicago, LA, Seattle & Austin Permit Monitor
Track commercial building permits from official Chicago, Los Angeles, Seattle and Austin data. Compare saved snapshots for status and valuation changes within fixed issue-date windows. Includes source links and conservative commercial classification; no homeowner contacts.
Pricing
from $1.00 / 1,000 permit evidence rows
Rating
0.0
(0)
Developer
Felix GoldWin
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
11 days ago
Last modified
Categories
Share
Commercial Permit Change Monitor
Monitor conservatively classified commercial building-permit evidence in Chicago, Seattle, Austin, and Los Angeles. Each run reads bounded official public APIs, reports source coverage, and can compare retained fields with a caller-supplied snapshot from an earlier matching scan.
This package contains source code, Apify schemas, deterministic fixtures/tests, example inputs, and publishing instructions. Consult QA.md for the actual validation results and live-check evidence. Apify account deployment, platform runs, billing configuration, and publication have not been performed. A source package is not proof of a successful platform run.
Supported scope
| Source ID | Official dataset and trade | Commercial classification |
|---|---|---|
chicago | Chicago Building Permits: new-construction and renovation/alteration permit types | Explicit supported commercial-use terms in the published work description, without supported residential/mixed-use exclusions. Negated, former-use, and conversion wording is unknown. This is text evidence, not a zoning determination. |
seattle | Seattle Building Permits: Building type | Requires both Commercial permit class and Non-Residential mapping. Institutional, industrial, missing, and conflicting classifications remain unknown. |
austin | Austin Issued Construction Permits: BP building permits | Requires Commercial mapping plus a reviewed nonresidential class. Residential/multifamily classes remain excluded even if the source maps them Commercial. Reviewed source classes include certain institutional, religious, school, public-works, and industrial buildings; this is not a private-sector-only filter. |
los-angeles | Los Angeles Building Permits Issued from 2020 to Present: Building group with Commercial subtype | Uses the source's explicit Commercial subtype; residential conflicts and mixed-use evidence are unknown. The source reports a weekly refresh. Work descriptions and contractor companies are omitted. |
These are source-specific adapters for the general-building trade. Classification rules deliberately leave some records unknown; they are not a universal land-use classifier. The dataset contains only qualifying records and changes involving previously qualifying records. Per-city diagnostics count the residential, unknown, and out-of-scope records examined within that adapter's query. Los Angeles filters Commercial subtype on the server, so its diagnostics do not count every residential permit in the city.
The date range filters permit issue date, inclusive at both ends. Records with missing issue dates do not enter that range. This is not a feed of all modifications made during the date range: an old permit can change today and will be seen only if its issue date is inside the chosen window. Issuance does not establish a construction start. A record disappearing from a matching scan does not establish cancellation.
Input
The prefilled form and Store demonstration use a small, fixed historical Chicago window:
{"sources": ["chicago"],"dateFrom": "2026-10-02","dateTo": "2026-10-02","maxSourceRecords": 50,"maxResults": 10,"maxRequests": 8,"maxRunSeconds": 60,"maxChargeUsd": 0.02}
This demonstration reads genuine published permits; it is not a current-events window. Change the dates deliberately for your monitoring scope. The complete effective prefill is examples/store-prefill-input.json; QA.md records the actual local SDK result. Historical source records can still be corrected or removed, so future nonempty results are not guaranteed. See also examples/input.json and examples/four-cities-input.json. The input schema is .actor/input_schema.json. Unknown input keys, unsupported sources, duplicate sources, invalid dates, and unsafe nested JSON are rejected.
The table below describes runtime defaults when a field is omitted, including direct API calls with no supplied dates. Schema prefills shown above take precedence in the initial Console/Store input. They do not alter the runtime's omitted-date behavior.
| Input | Runtime default when omitted | Allowed limit / meaning |
|---|---|---|
sources | ["chicago"] | One to four unique IDs from the table above; processed in sorted order. |
dateFrom, dateTo | Seven days before the current UTC date, through today | Real ordered YYYY-MM-DD values, at most 367 inclusive days. Source issue dates retain their calendar meaning. Fix both dates for comparison runs. |
maxSourceRecords | 500 | 1–1,000 rows per city, including nonqualifying rows in the adapter query. An excessive initial count stops that city before downloading pages. |
pageSize | 100 | 1–250; sequential pages ordered by source permit identifier. |
maxResults | 300 | 1–1,000 total evidence rows, including baseline, unchanged, and disappearance observations. |
maxRequests | 32 | 1–100 across all cities, retries, metadata, and count requests. A successful city scan normally needs four verification requests plus its data pages. |
maxRunSeconds | 120 | 5–300 for source retrieval. SDK startup and dataset/storage writes are additional. |
requestTimeoutSeconds | 15 | 1–30 per attempt, including streaming the response. |
maxResponseBytes | 2,000,000 | 10,000–5,000,000 per response, measured while streaming. |
maxTotalBytes | 16,000,000 | 10,000–40,000,000 across responses. |
maxRetries | 2 | 0–3 additional attempts for transient network, 429, and server errors. Access denials are not retried. Retry-After above ten seconds, or beyond the deadline, stops the scan. |
maxChargeUsd | 0.05 | 0–10; conservative custom-event budget, with configured automatic start charges reserved and the platform event limit also consulted. It does not set a platform compute/storage budget. |
previousSnapshot | Omitted | Complete same-scope snapshot JSON from the previous run; at most 1,000 records. Overall input is capped at 3 MB and accepted nesting depth is bounded. |
No source URL, proxy, credentials, or external snapshot-storage key is accepted. Source requests use only the hardcoded registry; redirects fail. The Actor does not log into a portal or follow record-detail links.
Outputs and comparison
The default dataset contains one evidence row per retained permit observation, plus applicable observations for prior records no longer qualifying or no longer found. Each row contains sourceId, permitId, event, before, after, changedFields, classificationAfter, observedAt, and interpretation.
event | Meaning |
|---|---|
baseline | The source has no supplied previous snapshot. |
newlyObserved | The permit was not in the matching supplied snapshot. It may be an older or corrected permit. |
unchanged | Every retained normalized field equals the prior record. |
changed | One or more retained fields changed; changedFields lists them. |
noLongerCommerciallyClassifiable | A prior qualifying permit is still observed in the query, but no longer passes classification. |
noLongerObserved | A prior qualifying permit is absent from a complete matching scan. This is not a cancellation claim. |
Each non-null before or after object contains the same retained record fields: source identifier, permit number, project address, work description when retained, permit/work type, published status, published milestone when available, issue date, source value, USD currency, retained contractor companies, classification evidence, and provenance. Provenance includes the source, official record link, and field names. Missing values stay null or empty arrays. Reported/estimated project cost is not contract value or confirmed spending.
The before/after records are exact copies of the normalized fields retained by this Actor, not full raw source rows. Contact patterns are redacted, dates can be reduced to a calendar date by an adapter, and numeric strings converted to numbers. A source field exceeding its retained text bound makes the city scan incomplete instead of silently comparing truncated text. Unselected source columns cannot produce changes. The Actor does not reconstruct changes that occurred between scans. previousEvidenceOrigin labels any before record as caller-supplied: syntax and scope are validated, but authenticity cannot be established.
The default key-value store contains:
OUTPUT:complete/incomplete/failedstatus, scope, request/byte/retry counts, per-city scan and output flags, stop reasons, configured limits, pricing budget information, and reusable source IDs.SNAPSHOT: versioned source snapshots with a scope hash, complete flag, and retained records. Snapshot JSON is capped at 2 MB.
For the next comparison, copy the prior SNAPSHOT JSON into previousSnapshot and keep the same source IDs, adapter version, classification rule, and fixed issue-date range. A changed date window must start a new baseline. Do not paste OUTPUT or dataset rows as a snapshot. The Actor validates the prior snapshot, rejects duplicate records and untrusted provenance URLs, and reads no global cross-user state. The caller controls which snapshot is supplied and retained.
Complete and incomplete scans
Before each city scan, the Actor reads dataset metadata and a bounded-query count. It requests the expected pages, checks their lengths and unique IDs, and reads the count and update marker again. A schema error, changing count/update marker, missing page, access denial, or budget limit prevents that city's changes and reusable snapshot from being emitted.
complete means the bounded query passed these checks. The public APIs do not provide a transactional historical snapshot, so these checks cannot prove there were no intermediate edits that left the checks unchanged. Source observation time is not source event time.
If all of a city's evidence rows cannot fit within the result/charge capacity, its planned output and snapshot are withheld; other complete cities can still be returned. This per-city planning does not make Apify dataset writes transactional. A later storage or billing error can leave partial delivered rows; check OUTPUT, do not reuse a failed snapshot, and do not interpret a missing row as a project event.
Privacy and source restrictions
No homeowner, owner, applicant, personal phone, or personal email column is requested. Chicago's server projection retains only general-contractor names with an explicit corporate suffix. Seattle and Austin select their published contractor-company field and retain only corporate-suffix names; ambiguous personal/trading names are omitted. This heuristic is not corporate-registry verification and may omit legitimate businesses.
Chicago, Seattle, and Austin descriptions use best-effort contact redaction. Public free text can still contain names or unexpected personal details; review it before external redistribution. Los Angeles work descriptions are never requested or retained. See NOTICE.md for source attribution and terms.
Local verification and deployment
Use Node.js 22 or later. From the extracted source root:
npm ci --ignore-scriptsnpm testnpm run validatenpm audit --omit=dev
For a local source run, put an example input in storage/key_value_stores/default/INPUT.json, then run npm start. Save a reusable snapshot outside temporary SDK storage before a subsequent run. A source run contacts public APIs; tests use deterministic fixtures. npm run smoke performs the documented small public-source smoke check. node scripts/store-prefill-smoke.js derives input directly from the schema and runs the actual local SDK entry point in isolated temporary storage, without account credentials. It validates nonempty output rows and snapshot round trips and writes bounded evidence under evidence/. QA.md records what was actually run and what remains unverified.
The Docker configuration uses Node.js 22, a 128 MB V8 heap target, and a fixed 256 MB Apify memory allocation. A V8 heap setting is not a process-memory guarantee; platform feasibility still needs its own run. Dependencies pin Apify SDK 3.7.2 and override the transitive basic-ftp package to 6.2.3. FTP is not used by these adapters; the override crosses a major version and does not constitute FTP-path testing.
Follow PUBLISHING.md to import the source package, verify the first platform run, and configure the owner-approved listing rates: $0.005 per automatic start unit and $0.001 per delivered permit evidence row. No prices are configured by this package.
Hosted verification update — 2026-10-12 UTC
This dated update supersedes the original builder-only platform status above. The complete final v2 package was imported and its 52-file source tree verified against the approved archive after the Console’s outer-whitespace normalization. Apify build 0.0.2 succeeded with Node 22 at the package’s fixed 256 MB memory setting.
Two owner-account runs using the schema-generated historical Chicago demonstration (issue date 2026-10-02, max 50 source records, 10 result rows, 8 HTTP attempts, 60 source-work seconds and a $0.02 input event cap) each succeeded in about four seconds with five delivered rows. The platform run cap was $0.02 with a 120-second timeout and 256 MB memory. The baseline examined 24 published source rows and retained five commercial observations, used five requests and 442,698 response bytes, and reported complete scan/output with a reusable snapshot. The repeat accepted the baseline snapshot and reported all five observations unchanged. Peak memory across the Chicago tests was 52.5 MB; this is not a maximum-load guarantee.
Runtime confirmed pay-per-event mode with a $0.005 automatic start and $0.001 permit-evidence-row price. Baseline and unchanged observations are billable at the configured rate. The synthetic paid dataset-item event is removed. The unchanged runtime checks per-row event count increases before continuing. The owner’s Console rounded each run’s platform usage to $0.000; these owner runs are not customer invoice settlement tests. Customer pay-per-event prices include platform usage. A separate bounded hosted four-city run over the same issue-date window succeeded in 24 seconds with 54 rows: Austin 18, Chicago 5, Los Angeles 21, Seattle 10. It used 20 requests with no retries, 1,048,861 response bytes, and a 54 MB peak. All four diagnostics reported complete scan/output and reusable snapshots. This run used a $0.10 platform/input cap, max 100 source rows per city, 60 result rows, 32 requests and 90 source-work seconds. It is a small dated source check, not a guarantee of future source availability or maximum-load performance.
The platform-generated example is an historical demonstration, not a current construction feed. Do not infer construction starts, cancellation, guaranteed leads or complete city coverage from the retained observations.
A start-only platform cap of $0.005 was verified to produce zero source requests, zero rows and no reusable snapshot. A separate maxResults: 1 run with the prior Chicago snapshot completed its five-request scan, then withheld the entire five-row city because it could not fit; outputComplete was false, no rows were delivered and no snapshot was reusable. These limits did not create disappearance evidence. The saved Console example is restored to the bounded historical Chicago baseline with no previous snapshot, a $0.02 platform cap, 120-second timeout and 256 MB memory.