# LA County Parcel Data (Assessor Roll) (`j0401/la-county-parcels`) Actor

LA County assessor parcel roll (public data, 2.43M parcels): AIN/APN, situs address, use class & code, year built, units, square footage, and the full assessment roll values with exemptions for every parcel.

- **URL**: https://apify.com/j0401/la-county-parcels.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Categories:** Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.03 / 1,000 la county parcel records

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## LA County Parcel Data - Assessor Roll

### Low cost

**From $0.00005 per record, down to $0.00003 at Gold** - pay per record delivered, and nothing for the query. A whole-county roll of 2.4 million parcels, billed by the parcel.

Los Angeles County's assessor parcel layer: the county's parcels with the assessor's own record on each - identity, situs address, use, structure, and the assessment roll figures behind the tax bill.

### What you get

| Field group | What it holds |
|---|---|
| identity | AIN (10-digit assessor id) and APN (12-digit parcel number) |
| situs | house number, fraction, direction, unit, street, city, ZIP, and the full assembled address |
| tax | tax-rate area and tax-rate city |
| use | assessor use code, the broad use class, and the finer use description |
| structure | design type, year built, effective year, units, bedrooms, bathrooms, main square footage and quality class for the primary structure |
| roll values | roll year, land value, improvement value, personal-property value, fixture value - and the homeowner, real-estate, personal-property and fixture exemptions |
| basis | land and improvement base years |
| dates | parcel creation date, and the assessor's last-change timestamp where the assessor recorded one (~31% of parcels) |
| legal | five legal-description lines |

2,432,949 rows, one per assessor parcel record, drawn from a 92-field source layer; 44 fields are delivered per parcel. Residential is ~2.17M of them; commercial ~101k, industrial ~52k, irrigated farm ~52k. Roughly 49 assessor IDs appear on more than one row, so AIN identifies a parcel in practice without being a strict primary key.

### Modes

- **parcels** (default) - individual parcels, most recently added first
- **aggregate** - one count row per group: by use class, use description, roll year, parcel type, or tax-rate city

Filter by AIN, APN, address, city, ZIP, use class, use code, roll year, parcel type, year built, land value, or the assessor's last-change window.

### Example inputs

**One parcel by AIN** - `ain` is a substring match; the full 10-digit AIN returns the single parcel.

```json
{ "ain": "8765001013" }
```

**Every parcel on a street** - `address` matches the situs address.

```json
{ "address": "PATHFINDER RD", "maxResults": 25 }
```

**Offices in one city** - combine the assessor's `useType` with a city.

```json
{ "useType": "Commercial", "city": "DIAMOND BAR", "maxResults": 25 }
```

**The county's use mix** - `aggregate=true` returns one count row per group, every group of the dimension.

```json
{ "aggregate": true, "groupBy": "useType" }
```

### What this is - and what it is not

This is the **assessor roll**: what the parcel is, how it is built, and what it is assessed at. It does **not** carry owner names - LA County publishes owner information through its own per-parcel lookup, not as an open bulk table. If your use case is "who owns this parcel", this dataset will not answer it; if it is "what is this parcel, what is on it, and what is it worth on the roll", it is the whole county in one place.

### Why this is hard

Three things fight you on this layer.

The **city column is free text**, not a controlled list. Los Angeles County's roughly 88 cities come back as 967 distinct strings - `LOS ANGELES CA`, `LOS ANGELES, CA`, `LOS ANGELES  CA`, `LOS ANGELE CA` and on. Treating it as an enumerated dimension produces a breakdown of typos rather than a breakdown of cities, so it is handled as a text match and kept out of the aggregations.

**Two date encodings live in the same table.** The parcel creation date is an integer `YYYYMMDD`; the assessor's last-change timestamp is epoch milliseconds. Read one with the other's parser and you get 1970, or the year 20260827.

The **change date is mostly absent**. 1,685,945 of the 2,432,949 parcels - 69% - carry no last-change timestamp at all, so a change-date window returns roughly a third of the county, not all of it. That subset is real and useful (it is the parcels the assessor touched), but it is a subset, and a query that treats it as the whole roll will be wrong.

And the **roll year is not a single value**. Roughly 61,000 parcels in the layer carry no roll year at all - they sit in the layer but not on the current assessment roll - so "the latest roll" is a filter you have to state, not one you can assume.

### Output

One schema in every mode: each record carries the full field set, empty where the source has nothing, and dates arrive as `YYYY-MM-DD`. Aggregate rows use the same schema, with `groupKey` / `groupCount` filled.

### Example output

**One parcel** - `ain=8765001013` returns the assessor's record for that parcel:

```json
{
 "ain": "8765001013",
 "apn": "8765-001-013",
 "situsHouseNo": "20955",
 "situsFraction": "",
 "situsDirection": "",
 "situsUnit": "",
 "situsStreet": "PATHFINDER RD",
 "situsCity": "DIAMOND BAR CA",
 "situsZip": "91765-4028",
 "situsFullAddress": "20955 PATHFINDER RD DIAMOND BAR CA 91765",
 "taxRateArea": "10101",
 "taxRateCity": "DIAMOND BAR",
 "useCode": "1703",
 "useType": "Commercial",
 "useDescription": "Office Buildings",
 "yearBuilt1": "1984",
 "effectiveYear1": "1984",
 "designType1": "1700",
 "units1": "0",
 "bedrooms1": "0",
 "bathrooms1": "0",
 "sqftMain1": "68715",
 "qualityClass1": "CX",
 "rollYear": "2026",
 "rollLandValue": "7000000",
 "rollImpValue": "8300000",
 "rollPersPropValue": "0",
 "rollFixtureValue": "0",
 "rollHomeOwnersExemp": "0",
 "rollRealEstateExemp": "0",
 "rollPersPropExemp": "0",
 "rollFixtureExemp": "0",
 "rollLandBaseYear": "2006",
 "rollImpBaseYear": "2006",
 "parcelTypeCode": "0",
 "assrMap": "8765-001",
 "assrIndexMap": "8765-NDX",
 "parcelCreateDate": "",
 "spatialChangeDate": "2007-01-02",
 "legalDescLine1": "*TR=PARCEL MAP",
 "legalDescLine2": "",
 "legalDescLine3": "",
 "legalDescLine4": "",
 "legalDescLine5": "",
 "platform": "ca-la-parcels",
 "source": "la-county-assessor-roll",
 "groupKey": "",
 "groupCount": "",
 "groupBy": ""
}
```

**`aggregate=true`, `groupBy=useType`** - one count row per use class:

```
Residential        2,172,850
Commercial           100,513
Industrial            52,314
Irrigated Farm        51,936
Government            23,828
Miscellaneous         10,435
Institutional          9,689
Recreational           2,651
```

### Notes

- Public open data from LA County. No login, no scraping.
- Charges are metered per record delivered, so a single parcel lookup costs a fraction of a cent.

# Actor input Schema

## `ain` (type: `string`):

Assessor Identification Number (10-digit), substring match. Example: 2067 (a substring) or the full AIN.

## `apn` (type: `string`):

Assessor Parcel Number (12-digit), substring match.

## `address` (type: `string`):

Situs (property) address substring, case-insensitive, e.g. a street name like SHEPHERD HILLS.

## `city` (type: `string`):

Situs city substring, case-insensitive, e.g. DIAMOND BAR. This column is free text in the source (the same city appears in several spellings), so it is a substring match rather than an exact list.

## `zip` (type: `string`):

Situs ZIP prefix, e.g. 900 or 91765.

## `useType` (type: `string`):

The assessor's broad use class. Residential covers ~2.17M of the 2.43M parcels.

## `useCode` (type: `string`):

Exact assessor use code, 4 digits, e.g. 0100 (single-family residence) or 4000 (commercial).

## `rollYear` (type: `string`):

Assessment roll year, e.g. 2026 (the current roll for ~2.37M parcels). Blank = any year.

## `parcelTypeCode` (type: `string`):

Assessor parcel-type class: 0 = standard parcel (~2.08M), 1 = ~352k, 2 = ~2.6k. Blank = any.

## `yearBuilt` (type: `string`):

Exact year built of the primary structure, e.g. 1952. Blank = any.

## `minLandValue` (type: `integer`):

Only parcels with a rolled land value at or above this amount. Parcels with no land value on the roll are excluded by a bound here.

## `maxLandValue` (type: `integer`):

Only parcels with a rolled land value at or below this amount.

## `changedFrom` (type: `string`):

Only parcels the assessor last changed on/after this date (YYYY-MM-DD). Note: 69% of parcels carry no last-change date, so a window here selects only the ~31% the assessor has a change timestamp for.

## `changedTo` (type: `string`):

Only parcels the assessor last changed on/before this date (YYYY-MM-DD).

## `aggregate` (type: `boolean`):

When on, returns one summary record per group (see groupBy) with count - instead of individual parcels.

## `groupBy` (type: `string`):

Which dimension to aggregate over. useType -> the broad use mix (residential / commercial / industrial / ...); useDescription -> finer detail (single family, two units, five or more apartments, desert, ...); taxRateCity -> where the parcels are.

## `maxResults` (type: `integer`):

Cap the number of parcel records pushed (0 = up to ~10k per run; each record is metered individually, so there is no per-run charge cap). Does not apply in aggregate mode, which returns every group of the chosen dimension (at most ~90).

## Actor input object example

```json
{
  "ain": "",
  "apn": "",
  "address": "",
  "city": "",
  "zip": "",
  "useType": "",
  "useCode": "",
  "rollYear": "",
  "parcelTypeCode": "",
  "yearBuilt": "",
  "changedFrom": "",
  "changedTo": "",
  "aggregate": false,
  "groupBy": "useType",
  "maxResults": 50
}
```

# Actor output Schema

## `recordsUrl` (type: `string`):

LA County assessor parcel records or aggregates - as JSON

## `datasetUrl` (type: `string`):

No description

## `runUrl` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("j0401/la-county-parcels").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("j0401/la-county-parcels").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call j0401/la-county-parcels --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,j0401/la-county-parcels"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/Nq5WHHSEMTgNvgilU/builds/UfWA8GWoi4TXlaqqg/openapi.json
