Los Angeles Building Permits Scraper avatar

Los Angeles Building Permits Scraper

Pricing

Pay per event

Go to Apify Store
Los Angeles Building Permits Scraper

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

Stas Persiianenko

Maintained by Community

Actor 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 groupOutput fieldsExample use
IdentitypermitNumberDeduplicate or verify a permit
Dates and statusissueDate, status, statusDate, refreshTimeMonitor new or changing records
Propertyaddress, zipCode, assessorParcelNumber, zoneRoute and enrich project records
Planning geographycouncilDistrict, areaPlanningCommission, communityPlanArea, neighborhoodCouncil, censusTractAggregate local activity
ClassificationpermitGroup, permitType, permitSubTypeSegment project categories
UseuseCode, useDescriptionSeparate residential and commercial uses
Projectvaluation, workDescriptionQualify scope and declared value
Flagssolar, electricVehicleIdentify source-marked technologies
Locationlatitude, longitude, geolocationMap permits and calculate territory proximity
ProvenancesourceDataset, sourceUrl, scrapedAtAudit 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.

ParameterTypeDefaultDescription
startDatestringnoneIssue date on or after YYYY-MM-DD
endDatestringnoneIssue date on or before YYYY-MM-DD
zipCodesstring[]noneUp to 50 exact five-digit ZIP codes
permitGroupsstring[]noneExact permit groups, such as Building
permitTypesstring[]noneExact values such as Bldg-New
permitSubTypesstring[]noneExact permit subtype values
usesstring[]noneExact use descriptions
statusesstring[]noneExact statuses such as Issued
planningAreasstring[]noneExact Community Plan Area names
minValuationnumbernoneMinimum declared US-dollar valuation
maxValuationnumbernoneMaximum declared US-dollar valuation
textSearchstringnoneCase-insensitive text in description, address, use, or permit number
sortstringnewestnewest, oldest, valuationDesc, or valuationAsc
maxItemsinteger100Save 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

  1. Open the Actor input page.
  2. Keep the prefilled recent date and ZIP code or replace them.
  3. Add only the filters needed for your workflow.
  4. Choose a result limit.
  5. Click Start.
  6. Open the Dataset tab when the run finishes.
  7. Export JSON, CSV, Excel, XML, RSS, or Parquet.
  8. 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.005 run-start event;
  • one permit-saved event for every unique output record.

Current formula-driven permit prices are:

Apify tierPrice 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:

ResultsCharge 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

  1. Run recent permits for target ZIP codes.
  2. Filter or score by permit type and valuation.
  3. Send dataset items to a webhook, Make, Zapier, or custom integration.
  4. 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 os
from apify_client import ApifyClient
client = 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.
  • maxItems is 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.

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.

Use each regional Actor independently because source schemas, coverage, and update behavior differ by city.