# Parcel Data API - Boundaries, Owners, Zoning, Land Use (`nabeelbaghoor/parcel-boundary-data-api`) Actor

Look up land parcel records by address, assessor parcel number, owner name, coordinate or map polygon, and read the full record: boundary geometry, owner and mailing address, zoning and land use, acreage, assessed value, sale history and flood zone. Bring your own key.

- **URL**: https://apify.com/nabeelbaghoor/parcel-boundary-data-api.md
- **Developed by:** [Nabeel Hassan](https://apify.com/nabeelbaghoor) (community)
- **Categories:** Business, Developer tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $12.00 / 1,000 parcel record returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Parcel Data API - Boundaries, Owners, Zoning, Land Use

Turn an address, an assessor parcel number, an owner name, a coordinate or a map polygon into the full land parcel record: the boundary itself, who owns it, how it is zoned, what it is worth and what it last sold for.

This actor calls a parcel data API on your behalf and stores one row per parcel. Bring your own key: paste your account token into the input and the run uses your own plan and your own contract.

### What you get

- **Nine ways in.** Street address, assessor parcel number, owner name, latitude and longitude, GeoJSON polygon, the provider's parcel path, its stable parcel id, a nationwide field search, and a cheap typeahead that ranks address suggestions.
- **The boundary, not just the attributes.** Every parcel row carries its GeoJSON geometry and a computed centroid, so the output drops straight into a map, a spatial join or a GIS.
- **Ownership as recorded.** Owner name plus the tax mailing address, which is what separates an owner occupier from an absentee landlord or a holding company.
- **Zoning twice over.** The county's own zoning code and description, plus the standardised zoning type that means the same thing across state lines.
- **Land use twice over.** The county use code and description, plus the Land Based Classification Standards activity code and its description.
- **Value and sale history.** Assessed total, land and improvement values, the value type behind them, and the last sale amount, sale date and ownership transfer date.
- **Risk and context.** FEMA flood zone and subtype, USPS vacancy and residential delivery flags, census tract, unified school district and qualified opportunity zone status.
- **Structures.** Building count, total footprint area, year built, number of stories and structure style, plus matched building footprint rows when your account carries that dataset.
- **A nationwide field search.** Filter every parcel in the country by owner name, state, county, postal code, zoning, standard land use, acreage, year built, sale price, sale date, land value, building count, vacancy or opportunity zone status.
- **Every county column kept.** The curated columns sit at the top level for sorting and filtering; the provider's whole field bag rides along in `fields` so nothing is thrown away.

### Pay per result

You are charged per record, never per request, and only for rows that carry real data. An address the provider has no parcel for is stored with the reason and costs nothing.

| Event | Price | What it covers |
| --- | --- | --- |
| Parcel record returned | $0.012 | One parcel with boundary, ownership, zoning, land use, assessment, sale history and risk context |
| Address suggestion returned | $0.002 | One ranked typeahead suggestion with the parcel id, path, address and centroid |

Matched building footprints are stored but never charged for, because the parcel they belong to already was.

### Quick start

1. Generate an API token in the API section of your provider account profile.
2. Paste it into **API token**.
3. Pick a **What this run does** mode. Address mode with one address in **Addresses** is the fastest way to see a real row.
4. Set **Maximum rows** to the most you want to pay for.
5. Run it.

### FAQ

#### What is a parcel data API?

A parcel data API returns the record a county assessor holds for one piece of land: its legal boundary, its assessor parcel number, its owner and their mailing address, its zoning and land use, its assessed value and its last recorded sale. This actor reads a nationwide parcel dataset assembled from those county records and standardised into one schema, so a parcel in Wayne County, Michigan and a parcel in Dallas County, Texas come back with the same column names.

#### How do I find a parcel when I only have an address?

Use address mode, and set **Restrict to a state or county** when the street name is common. If your addresses are messy, run typeahead mode first: it returns ranked suggestions with the provider's stable parcel id for a fifth of the price, and you then spend a full lookup only on the ids you keep.

#### What is an assessor parcel number?

An assessor parcel number, also written APN or PIN, is the identifier a county assessor assigns to a parcel for tax purposes. It is unique inside its county but not between counties, so parcel number mode also takes a county path to say which county you mean. Punctuation is ignored when matching, so 02001069-71 and 0200106971 find the same parcel.

#### Can I find every property one owner holds?

Yes. Owner mode searches by owner name and returns every parcel recorded to that name, which is how portfolio research, due diligence and skip tracing usually start. Names are matched from the beginning, so a last name or the start of a company name works and at least four characters are needed. Owner search covers the United States only.

#### Can I search a whole neighbourhood or flood zone?

Yes. Area mode takes a GeoJSON Feature Collection, Feature or bare geometry and returns every parcel inside it. Polygons, points, lines and their multi variants all work, a radius in metres buffers the shape, and the provider caps a single search area at 80 square miles.

#### How do I search the whole country by attribute?

Query mode filters the nationwide dataset by the fields the provider indexes for it: owner name, state, county, postal code, zoning code, standardised zoning type, land use activity, acreage, year built, sale price, sale date, land value, building count, postal vacancy and residential flags, and qualified opportunity zone status. The provider allows at most four distinct fields in one search. A minimum and a maximum on the same measure count as one field, not two, and this actor checks the count before the first request rather than letting the provider refuse it mid run.

#### Does this return the parcel boundary?

Yes. Every parcel row carries the GeoJSON polygon or multipolygon in `geometry`, plus a computed `latitude` and `longitude` centroid. Turn **Include boundary geometry** off when you only want attributes and want smaller rows.

#### What about buildings on the parcel?

When your account carries the matched building footprints dataset, footprint rows come back alongside the parcels they sit on, each carrying the footprint geometry and the parcel ids it overlaps. Every parcel row also carries the building count, total footprint square footage, year built, stories and structure style from the assessor record.

#### Which countries are covered?

The United States and Puerto Rico by default. Set **Country** to `ca` for Canada or to a European country code your plan covers. Coverage is enabled per account, so the provider rather than this actor decides which codes work. Owner search is United States only.

#### What happens if my key is missing or rejected?

The run ends cleanly with the reason as its status message rather than failing with a stack trace. A missing token, an empty input, a token the provider will not accept and an exhausted record allowance are all treated as answers, not faults.

#### Is my API key stored anywhere?

No. It is read from the run input or from the `DATA_API_KEY` environment secret, used for that run's requests, and never written to the dataset or the log. On a POST it travels in the request body rather than the URL, so it does not end up in a proxy log.

### Example output

```json
{
  "recordType": "address",
  "requested": "440 Burroughs St, Detroit, MI",
  "found": true,
  "parcelId": "83cf8982-b8f8-415e-8cba-f388978f7367",
  "parcelPath": "/us/mi/wayne/detroit/364491",
  "parcelNumber": "02001069-71",
  "address": "440 BURROUGHS ST",
  "city": "DETROIT",
  "county": "wayne",
  "state": "MI",
  "postalCode": "48202-3429",
  "fipsCode": "26163",
  "owner": "TECHONE DEVELOPMENT LLC",
  "ownerMailingAddress": "440 BURROUGHS, DETROIT, MI, 48202",
  "landUseCode": "22320",
  "landUseDescription": "OFFICE BLDG-3 STORIES OR MORE",
  "standardLandUse": "Office",
  "zoning": "SD2",
  "zoningDescription": "Special Development District Mixed Use",
  "zoningType": "Mixed",
  "acres": 0.66,
  "buildingCount": 1,
  "buildingSquareFeet": 28713,
  "yearBuilt": 1926,
  "stories": 5,
  "assessedValue": 0,
  "valueType": "ASSESSED",
  "saleAmount": 0,
  "lastTransferDate": "2019-07-31",
  "floodZone": "X",
  "floodZoneDescription": "AREA OF MINIMAL FLOOD HAZARD",
  "vacancy": "N",
  "schoolDistrict": "Detroit Public Schools Community District",
  "latitude": 42.3650758,
  "longitude": -83.0730601,
  "geometry": { "type": "Polygon", "coordinates": [] }
}
```

### Keyword map

parcel data API, property boundary API, land parcel API, assessor parcel number lookup, APN lookup API, property owner search API, parcel ownership data, GIS parcel boundaries, GeoJSON parcel API, zoning data API, land use data API, property assessment data, county assessor data API, reverse geocoding to parcel, property records by address, owner portfolio search, vacant land search, opportunity zone parcels, flood zone by parcel, building footprint data, real estate data API, land data for site selection

# Actor input Schema

## `mode` (type: `string`):

A run answers one question. Address, parcel number, owner name, coordinate, path and parcel id look up parcels you already have an identifier for. Area returns every parcel inside a map polygon. Query filters the nationwide dataset by indexed fields. Typeahead returns ranked address suggestions and is the cheap way to turn a messy address list into stable parcel ids first. Fields belonging to another mode are ignored rather than causing an error.

## `apiKey` (type: `string`):

Your own account's API token, generated in the API section of your account profile. Bring your own key: nothing is shared between runs and the token is never written to the dataset or the log.

## `addresses` (type: `array`):

Street addresses to look up, one per line. Used by address mode and by typeahead mode. A partial address works, matched from the beginning, so narrow the search with the county path below when an address is common.

## `parcelNumbers` (type: `array`):

Assessor parcel numbers, also called PINs, one per line. Punctuation is ignored when matching. The same number can exist in more than one county, so set the county path below to be sure which parcel you get.

## `ownerNames` (type: `array`):

Owner names to search, one per line, individuals in Last, First order and entities by their registered name. Matched from the start of the name, so Jones finds Jones, Festus while Festus does not, and at least four characters are needed. Owner search covers the United States only.

## `coordinates` (type: `array`):

Latitude and longitude pairs, one per line, written latitude first, for example 42.36511, -83.073107. An exact point sometimes falls just outside a boundary, so set a search radius below when a point comes from a geocoder or a device.

## `paths` (type: `array`):

The provider's readable parcel paths, one per line, in the form /country/state/county/place/id. These come back on every parcel row, so this is how you re-read a parcel you stored earlier.

## `parcelIds` (type: `array`):

The provider's stable parcel identifiers, one per line. Unlike a county parcel number these never change, so they are the right key to store against your own records.

## `geojson` (type: `string`):

A GeoJSON Feature Collection, Feature or bare geometry to search inside, used by area mode. Polygon, MultiPolygon, Point, MultiPoint, LineString and MultiLineString are all accepted. The provider caps a search area at 80 square miles, and a radius widens it further.

## `radiusMeters` (type: `integer`):

Widens a coordinate or an area into a circle of this radius, up to 32000 metres. A small radius is what rescues a point that a geocoder placed in the road rather than on the lot.

## `scopePath` (type: `string`):

Narrows an address, parcel number, owner or field search to one place, written as the provider's path: /us/mi for a state, /us/mi/wayne for a county, /us/mi/wayne/detroit for a city. This is the fix for a common street name or a parcel number that repeats across counties.

## `ownerContains` (type: `string`):

Query mode only. Keeps parcels whose owner name contains this text, matched anywhere in the name and ignoring case. Unlike owner mode this is a contains match rather than a prefix one. For example HOLDINGS.

## `states` (type: `array`):

Query mode only. Keeps parcels in any of these states, one two letter code per line.

## `counties` (type: `array`):

Query mode only. Keeps parcels in any of these counties, one per line, written the way the provider spells them in lower case, such as wayne.

## `postalCodes` (type: `array`):

Query mode only. Keeps parcels with any of these situs postal codes, one per line.

## `zoningCodes` (type: `array`):

Query mode only. Keeps parcels with any of these county zoning codes, one per line, matched exactly as the county writes them.

## `zoningTypes` (type: `array`):

Query mode only. Keeps parcels in any of these standardised zoning types. This is the cross jurisdiction classification rather than the county's own code, so it is the one that works across state lines. Special covers uses no other zone reflects, such as parks and universities; Planned covers a zone created for one development; Overlay adds conditions on top of another zone; NZ marks a jurisdiction confirmed to have no zoning at all.

## `landUseActivity` (type: `integer`):

Query mode only. Keeps parcels with this standardised land use activity code, the Land Based Classification Standards activity dimension, for example 1100 for household activities and 2300 for office.

## `vacancy` (type: `string`):

Query mode only. Keeps parcels the postal service marks vacant or occupied. Vacancy is one of the strongest signals of a distressed or abandoned property.

## `residentialIndicator` (type: `string`):

Query mode only. Keeps parcels the postal service classes as a residential delivery point or not. It answers whether somebody lives there, and does not separate the non-residential kinds from each other.

## `minAcres` (type: `number`):

Query mode only. Keeps parcels of at least this measured acreage. A minimum and a maximum on acreage together count as one field against the provider's four field limit, not two.

## `maxAcres` (type: `number`):

Query mode only. Keeps parcels of at most this measured acreage.

## `minYearBuilt` (type: `integer`):

Query mode only. Keeps parcels whose main structure was built in this year or later.

## `maxYearBuilt` (type: `integer`):

Query mode only. Keeps parcels whose main structure was built in this year or earlier.

## `minSalePrice` (type: `integer`):

Query mode only. Keeps parcels whose recorded sale price is at least this much, in dollars.

## `maxSalePrice` (type: `integer`):

Query mode only. Keeps parcels whose recorded sale price is at most this much, in dollars.

## `soldFrom` (type: `string`):

Query mode only. Keeps parcels last sold on or after this date, written as YYYY-MM-DD or as a year. For example 2020-01-01.

## `soldTo` (type: `string`):

Query mode only. Keeps parcels last sold on or before this date, written as YYYY-MM-DD or as a year. For example 2024-12-31.

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

Query mode only. Keeps parcels whose assessed land value is at least this much, in dollars. Land value separated from improvement value is what identifies an underbuilt lot.

## `minBuildings` (type: `integer`):

Query mode only. Keeps parcels with at least this many matched building footprints. Set it to 0 to find vacant land.

## `opportunityZone` (type: `string`):

Query mode only. Keeps parcels inside or outside a qualified opportunity zone, the federal tax designation.

## `includeGeometry` (type: `boolean`):

Return the parcel boundary polygon on every row. Turning it off makes each row far smaller, which is worth doing when you only want the attributes.

## `includeBuildings` (type: `boolean`):

Return building footprints alongside the parcels they sit on, when your account has that dataset. Footprint rows are stored but never charged for, because the parcel they belong to already was.

## `includeExtraAddresses` (type: `boolean`):

Return the unit level addresses matched to each parcel, when your account has that dataset. This is what turns one apartment building parcel into its individual units.

## `includeOwnership` (type: `boolean`):

Return the provider's enhanced ownership records, when your account has that dataset: additional owner names, mailing addresses and entity classification beyond what the county supplies.

## `includeZoning` (type: `boolean`):

Return zoning normalised across jurisdictions, when your account has that dataset, rather than only the county's own code.

## `includeCountyFields` (type: `boolean`):

Pass through the county's own extra columns beyond the standard schema. These vary county by county, which is exactly why they are off by default.

## `countryCode` (type: `string`):

Which country's parcel dataset to read, as a two letter code. Leave empty or set us for the United States, ca for Canada, or a European country code your plan covers. Coverage is enabled per account, so the provider rather than this actor decides which codes work.

## `pageSize` (type: `integer`):

How many parcel records to ask for per request, up to the provider's maximum of 1000. Billing counts records rather than requests, so a larger page is not cheaper, it just means fewer round trips.

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

The most rows this run may store, and so the most it can charge for. A county wide field search can match millions of parcels, so this is the cap that keeps a run predictable.

## `requestsPerMinute` (type: `integer`):

How fast this run calls the provider. The documented ceiling is about 200 a minute, so lower this if your plan is rate limited more tightly.

## `baseUrl` (type: `string`):

Overrides the API host. Only needed if the provider has given your account a different endpoint.

## Actor input object example

```json
{
  "mode": "address",
  "addresses": [
    "440 Burroughs St, Detroit, MI"
  ],
  "geojson": "{\"type\":\"Feature\",\"properties\":{},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-83.074472,42.365423],[-83.073946,42.364478],[-83.071878,42.365108],[-83.072403,42.366061],[-83.074472,42.365423]]]}}",
  "includeGeometry": true,
  "includeBuildings": true,
  "includeExtraAddresses": true,
  "includeOwnership": true,
  "includeZoning": true,
  "includeCountyFields": false,
  "pageSize": 100,
  "maxResults": 100,
  "requestsPerMinute": 120
}
```

# Actor output Schema

## `records` (type: `string`):

One row per record, alongside the address, parcel number, owner name or search that produced it.

# 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 = {
    "addresses": [
        "440 Burroughs St, Detroit, MI"
    ],
    "geojson": "{\"type\":\"Feature\",\"properties\":{},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-83.074472,42.365423],[-83.073946,42.364478],[-83.071878,42.365108],[-83.072403,42.366061],[-83.074472,42.365423]]]}}"
};

// Run the Actor and wait for it to finish
const run = await client.actor("nabeelbaghoor/parcel-boundary-data-api").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 = {
    "addresses": ["440 Burroughs St, Detroit, MI"],
    "geojson": "{\"type\":\"Feature\",\"properties\":{},\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[[[-83.074472,42.365423],[-83.073946,42.364478],[-83.071878,42.365108],[-83.072403,42.366061],[-83.074472,42.365423]]]}}",
}

# Run the Actor and wait for it to finish
run = client.actor("nabeelbaghoor/parcel-boundary-data-api").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 '{
  "addresses": [
    "440 Burroughs St, Detroit, MI"
  ],
  "geojson": "{\\"type\\":\\"Feature\\",\\"properties\\":{},\\"geometry\\":{\\"type\\":\\"Polygon\\",\\"coordinates\\":[[[-83.074472,42.365423],[-83.073946,42.364478],[-83.071878,42.365108],[-83.072403,42.366061],[-83.074472,42.365423]]]}}"
}' |
apify call nabeelbaghoor/parcel-boundary-data-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,nabeelbaghoor/parcel-boundary-data-api"
        }
    }
}

```

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/S4zxfcGV3KwYt3trH/builds/GDJgFSt3OTb9cbzrj/openapi.json
