Los Angeles Building Permits Scraper
Pricing
Pay per event
Los Angeles Building Permits Scraper
Search official LADBS building permits issued since 2020 by date, ZIP, permit type, status, use, planning area, valuation, and project text.
Pricing
Pay per event
Rating
0.0
(0)
Developer
Stas Persiianenko
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
14 hours ago
Last modified
Categories
Share
Turn official Los Angeles building permit records into searchable construction project intelligence.
This Apify Actor queries the City of Los Angeles LADBS Building Permits Issued from 2020 to Present dataset and exports normalized permit records.
Filter by issue date, ZIP code, permit type, permit subtype, use, status, community plan area, declared valuation, or project text.
Each result can include the permit number, issue and status dates, address, ZIP and APN, planning geography, permit classification, use, valuation, work description, EV and solar flags, coordinates, and source metadata.
- 🏗️ Discover recently permitted construction projects.
- 📍 Monitor projects in a sales or service territory.
- 💵 Prioritize records by declared valuation.
- 🔎 Search project descriptions for trades or technologies.
- 📊 Refresh construction activity datasets on a schedule.
- ✅ Trace every result to the official city API request.
What does this Actor do?
The Actor uses the anonymous City of Los Angeles Socrata API for dataset pi9x-tg5x.
It does not scrape a visual page. It does not require a browser, login, API token, or proxy.
Filters run on the official source before records are transferred. Results are sorted deterministically, paginated, deduplicated by permit number, and saved to the default Apify dataset.
The v1 scope is intentionally limited to LADBS building permits issued from 2020 to present. It does not combine electrical, plumbing, mechanical, inspection, LA County, or contact-enrichment datasets.
Who is it for?
Contractors and subcontractors
Search recent permit descriptions for roofing, solar, renovation, demolition, additions, pools, grading, or other relevant work.
Use ZIP codes and planning areas to keep results inside a service territory.
Building-material and job-site suppliers
Find projects that may need materials, rentals, waste services, insurance, financing, or other project support.
Sort by valuation or schedule a daily query for recent permits.
Construction intelligence teams
Build a repeatable feed for project discovery, territory analysis, and market monitoring without maintaining a SoQL integration.
Property and market researchers
Measure permit volume by issue date, location, project classification, use, and declared value.
Civic-data developers
Receive typed JSON, CSV, Excel, XML, RSS, or Parquet exports through Apify datasets and integrations.
Why use it?
- Official data: records come from the City of Los Angeles open-data API.
- Focused coverage: one documented LADBS dataset with a clear 2020-present scope.
- Useful source-side filters: transfer only records relevant to the workflow.
- Typed output: valuations and coordinates are numbers; flags are booleans.
- Stable pagination: fixed allowlisted sort expressions prevent arbitrary SoQL input.
- Auditable provenance: every row includes the dataset ID, request URL, and extraction time.
- Automation ready: run manually, on a schedule, through API, webhook, integration, or MCP.
- Low overhead: no browser or proxy configuration is needed.
What data can you extract?
| Data group | Output fields | Example use |
|---|---|---|
| Identity | permitNumber | Deduplicate or verify a permit |
| Dates and status | issueDate, status, statusDate, refreshTime | Monitor new or changing records |
| Property | address, zipCode, assessorParcelNumber, zone | Route and enrich project records |
| Planning geography | councilDistrict, areaPlanningCommission, communityPlanArea, neighborhoodCouncil, censusTract | Aggregate local activity |
| Classification | permitGroup, permitType, permitSubType | Segment project categories |
| Use | useCode, useDescription | Separate residential and commercial uses |
| Project | valuation, workDescription | Qualify scope and declared value |
| Flags | solar, electricVehicle | Identify source-marked technologies |
| Location | latitude, longitude, geolocation | Map permits and calculate territory proximity |
| Provenance | sourceDataset, sourceUrl, scrapedAt | Audit extraction and source query |
Source fields are nullable.
A missing value remains null rather than being guessed.
Input parameters
All filters are optional and combine with logical AND.
| Parameter | Type | Default | Description |
|---|---|---|---|
startDate | string | none | Issue date on or after YYYY-MM-DD |
endDate | string | none | Issue date on or before YYYY-MM-DD |
zipCodes | string[] | none | Up to 50 exact five-digit ZIP codes |
permitGroups | string[] | none | Exact permit groups, such as Building |
permitTypes | string[] | none | Exact values such as Bldg-New |
permitSubTypes | string[] | none | Exact permit subtype values |
uses | string[] | none | Exact use descriptions |
statuses | string[] | none | Exact statuses such as Issued |
planningAreas | string[] | none | Exact Community Plan Area names |
minValuation | number | none | Minimum declared US-dollar valuation |
maxValuation | number | none | Maximum declared US-dollar valuation |
textSearch | string | none | Case-insensitive text in description, address, use, or permit number |
sort | string | newest | newest, oldest, valuationDesc, or valuationAsc |
maxItems | integer | 100 | Save 1 to 10,000 unique permits |
Exact categorical values follow the source dataset.
Common permit types include Bldg-Alter/Repair,
Bldg-Addition,
Bldg-New,
Grading,
Swimming-Pool/Spa,
and Bldg-Demolition.
Getting started
- Open the Actor input page.
- Keep the prefilled recent date and ZIP code or replace them.
- Add only the filters needed for your workflow.
- Choose a result limit.
- Click Start.
- Open the Dataset tab when the run finishes.
- Export JSON, CSV, Excel, XML, RSS, or Parquet.
- Save the task or schedule it if the query should repeat.
A good first test is:
{"startDate": "2026-01-01","zipCodes": ["90012"],"sort": "newest","maxItems": 25}
High-value project example
{"permitTypes": ["Bldg-New"],"minValuation": 500000,"sort": "valuationDesc","maxItems": 100}
This returns only records whose source permit type and declared valuation satisfy both filters.
Text-monitoring example
{"startDate": "2026-01-01","textSearch": "solar","statuses": ["Issued"],"sort": "newest","maxItems": 250}
textSearch checks the work description,
primary address,
use description,
and permit number.
It does not perform fuzzy matching or infer a trade that is absent from source text.
Output example
A current prefilled local run produced a record shaped like this:
{"permitNumber": "26016-10000-18824","issueDate": "2026-07-16T00:00:00.000","status": "Issued","statusDate": "2026-07-16T00:00:00.000","address": "916 N CENTENNIAL ST","zipCode": "90012","assessorParcelNumber": "5406025009","zone": "[LM2-MU2-5] [RG1-FA] [CPIO]","councilDistrict": "1","areaPlanningCommission": "Central","communityPlanArea": "Downtown","permitGroup": "Building","permitType": "Bldg-Alter/Repair","permitSubType": "Apartment","useDescription": "Apartment","valuation": 8000,"workDescription": "Re-roof with Class A or B material...","electricVehicle": false,"solar": false,"businessUnit": "Express Permit","latitude": 34.06732,"longitude": -118.2454,"geolocation": {"type": "Point","coordinates": [-118.2454, 34.06732]},"refreshTime": "2026-07-19T00:00:00.000","sourceDataset": "pi9x-tg5x","sourceUrl": "https://data.lacity.org/resource/pi9x-tg5x.json?...","scrapedAt": "2026-07-25T04:21:00.663Z"}
The description is shortened here for readability. Dataset output preserves the complete source text.
How pagination and limits work
The Actor requests up to 1,000 source rows per page. It uses fixed deterministic ordering with permit number as a tie-breaker.
maxItems controls accepted unique records,
not the number of HTTP requests.
The Actor stops when it reaches the limit or the source returns no more matching rows.
Duplicate permit numbers are not charged or saved twice in one run. Malformed source rows without a permit number are ignored.
Pricing
This Actor uses pay-per-event pricing:
- one
$0.005run-start event; - one permit-saved event for every unique output record.
Current formula-driven permit prices are:
| Apify tier | Price per permit |
|---|---|
| FREE | $0.00001 |
| BRONZE | $0.00001 |
| SILVER | $0.00001 |
| GOLD | $0.00001 |
| PLATINUM | $0.00001 |
| DIAMOND | $0.00001 |
FREE-tier examples including the start event:
| Results | Charge calculation |
|---|---|
| 100 | $0.005 + (100 × $0.00001) |
| 1,000 | $0.005 + (1,000 × $0.00001) |
| 10,000 | $0.005 + (10,000 × $0.00001) |
Apify displays the applicable price before a run. Platform compute is included in PPE billing rather than added as a separate Actor charge to the customer.
Scheduling a recurring feed
Create a saved task with a recent startDate,
territory filters,
and a useful maxItems.
Then add an Apify schedule.
For strict incremental workflows,
store the newest processed issueDate and permitNumber downstream,
then discard records already seen by the receiving database or CRM.
The source may refresh or correct previously published records. A repeat query can therefore be useful even when permit numbers are already known.
Integrations and workflows
CRM project discovery
- Run recent permits for target ZIP codes.
- Filter or score by permit type and valuation.
- Send dataset items to a webhook, Make, Zapier, or custom integration.
- Enrich only projects that match your responsible-use policy.
Territory dashboard
Schedule daily or weekly runs. Export to Google Sheets, BigQuery, Snowflake, or a data warehouse. Aggregate by ZIP, Community Plan Area, permit type, or issue week.
Mapping
Use latitude and longitude for points.
Preserve permitNumber and sourceUrl in map popups so analysts can trace records.
Market research
Group records by issue date, use, permit type, and valuation bands. Remember that permit counts and declared value are not the same as completed construction spending.
Run through the Apify API with cURL
curl -X POST \"https://api.apify.com/v2/acts/automation-lab~los-angeles-building-permits-scraper/runs?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"startDate": "2026-01-01","zipCodes": ["90012"],"maxItems": 25}'
Wait for the run or use the synchronous dataset endpoint when appropriate for your application. Never commit an Apify token to source control.
JavaScript API example
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('automation-lab/los-angeles-building-permits-scraper').call({startDate: '2026-01-01',permitTypes: ['Bldg-New'],minValuation: 500000,maxItems: 100,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
Install the client with:
$npm install apify-client
Python API example
import osfrom apify_client import ApifyClientclient = ApifyClient(os.environ['APIFY_TOKEN'])run = client.actor('automation-lab/los-angeles-building-permits-scraper').call(run_input={'startDate': '2026-01-01','textSearch': 'solar','statuses': ['Issued'],'maxItems': 100,})for item in client.dataset(run['defaultDatasetId']).iterate_items():print(item)
Install the client with:
$pip install apify-client
Use with MCP and AI assistants
Add this Actor to Claude Code through the Apify MCP server:
claude mcp add --transport http apify \"https://mcp.apify.com?tools=automation-lab/los-angeles-building-permits-scraper"
Claude Desktop setup
Add the following HTTP MCP server in Claude Desktop.
Cursor setup
Use the same JSON in Cursor’s MCP settings.
VS Code setup
Use the same server URL in a VS Code MCP configuration.
{"mcpServers": {"apify": {"url": "https://mcp.apify.com?tools=automation-lab/los-angeles-building-permits-scraper"}}}
Example prompts:
- “Find up to 100 Los Angeles new-building permits issued since 2026-01-01 with valuation above $500,000.”
- “Export recent issued permits in ZIP 90012 whose description mentions solar.”
- “Summarize permit counts and total declared valuation by Community Plan Area from this dataset.”
AI-generated conclusions should be checked against the source records.
Limits and data caveats
- Coverage is the City dataset
pi9x-tg5x, described as 2020 to present. - It is not an LA County permit search.
- It covers the building-permit dataset only.
- It does not promise electrical, plumbing, mechanical, inspection, or other permit trades.
- Owner, applicant, contractor, phone, and email fields are not exposed by this source dataset.
- Records are project-discovery signals, not contact-enriched sales leads.
- Source records and timestamps may be corrected after initial publication.
- Declared valuation may be absent and is not necessarily final project cost.
- Text search is literal case-insensitive containment, not semantic search.
- Categorical filters require exact source values.
- Coordinates and planning fields may be null.
maxItemsis capped at 10,000 per run.
Failure behavior and troubleshooting
Input is validated before requests begin. Invalid dates, ZIP codes, valuation ranges, sort modes, or limits fail the run with a non-zero status.
Transient network errors, HTTP 429 responses, and server errors are retried with bounded exponential backoff. Deterministic client errors are not retried blindly.
Why did my run return no records?
The filters may be too narrow or exact category spelling may differ from the source. Remove filters one at a time, check the date window, and try a small broad query.
Why is a field null?
The official source did not publish that value for the permit. The Actor does not infer missing data.
Why are there fewer results than maxItems?
maxItems is a ceiling.
The source may contain fewer matching unique permits.
Why does text search miss a concept?
It searches literal text in four fields.
Try a shorter source term such as solar,
roof,
or a street fragment.
Do I need a proxy or Socrata token?
No. The Actor uses the public anonymous resource API and handles transient throttling with retries.
Responsible and legal use
The Actor accesses a public government dataset. You are responsible for using results in compliance with applicable laws, Apify terms, the source portal terms, and your organization’s policies.
Do not treat a permit as proof that work started, finished, or requires a particular vendor. Do not use project records for harassment, discrimination, unsafe site visits, or misleading outreach.
Apply appropriate retention, security, and human review when combining permits with other data.
FAQ
Is this real-time?
No guarantee is made.
Freshness follows the City dataset’s own refresh process.
Use refreshTime and scrapedAt to understand provenance.
Can it search one permit number?
Yes.
Put the complete or distinctive permit number in textSearch.
The search also checks other documented fields.
Can it return every matching permit?
A run can save up to 10,000 records. For larger historical exports, split work into non-overlapping date windows.
Does it include contractor or owner contacts?
No. This dataset does not expose those fields, and the Actor does not invent or enrich them.
Can I schedule it?
Yes. Create a task and attach an Apify schedule. Use downstream permit-number deduplication for a durable incremental feed.
Does it charge for duplicates or rejected source rows?
No. The item event is emitted only for unique normalized permits accepted into output.
Related automation-lab Actors
- Chicago Building Permits & Contractor Leads Scraper — Chicago permit records with the fields published by that city.
- NYC DOB NOW Building Permits Scraper — New York City DOB NOW permit coverage.
Use each regional Actor independently because source schemas, coverage, and update behavior differ by city.