# Cook County Parcel Owners - Names & Mailing Addresses (`j0401/cook-parcel-owners`) Actor

Cook County Assessor parcel address file (public open data, 1.86M parcels per roll, 1999-2026): the owner of record AND the taxpayer of record, each with its full mailing address - they differ on 32.9% of parcels. Search by owner, taxpayer, city, ZIP or mailing state; find absentee owners.

- **URL**: https://apify.com/j0401/cook-parcel-owners.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.06 / 1,000 cook 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

## Cook County Parcel Owners - Names & Mailing Addresses

Every parcel in Cook County has an address the Assessor's office mails assessment notices to - and the party that mail goes to is frequently **not** the owner on title. This actor turns that file into a **charged-per-record search, filter and aggregate tool** over the county's parcel address roll: find a parcel by PIN, search the owner of record or the taxpayer of record, filter by city, ZIP or mailing state, or aggregate a whole roll.

**Built for:** title and lien research, absentee-owner and out-of-state-holder work, skip tracing against a county's own mailing record, portfolio and servicer mapping, and anyone who needs **the county's parcel-to-name mapping** without paging a viewer one PIN at a time.

### What it covers

**1,863,562 parcels** in the newest roll (2026), drawn from a **50,671,416-row** file that stacks **28 assessment years, 1999 through 2026** (1.62M-1.86M parcels per year, the roll growing over time). Query one year by default; ask for another, or aggregate across the whole stack.

Each record carries two parties and two addresses:

- the **owner of record** - name plus full mailing address (street, city, state, ZIP)
- the **taxpayer of record** - the party the assessment notice is addressed to, plus its own full mailing address
- the **property** - situs street address, city, state, ZIP
- both **PIN forms** (14-digit and 10-digit) for the same parcel

### The fine print that matters

**The owner and the taxpayer are two different parties, and collapsing them would misdescribe a third of the county.** Measured on the 2026 roll, they differ on **612,891 of 1,863,562 parcels (32.9%)** - because the notice goes to whoever services the loan or holds it in trust, not necessarily to the person on title. Both are returned, each with its own address block.

That difference is the point: because the mailing address travels with the **taxpayer**, the two blocks together answer what the situs address alone cannot - **where the party on title actually receives mail**. On the 2026 roll, **65,391 parcels** are mailed outside Illinois; searching `mailState=FL` returns Barrington parcels whose notices go to Delray Beach and Ponte Vedra Beach.

Two data notes. The taxpayer of record is blank on **113,800 parcels** - a situs address with no mailing party on record, which is a real state, not a defect. And a **PIN is unique within a year**: the year is part of the parcel's identity in this file, so the same PIN appears once per roll across the 28-year stack.

### Typical questions

- "Every parcel **owned by** a given name or entity."
- "Parcels whose **taxpayer of record** is a bank or trust - the serviced and trust-held inventory."
- "Parcels in **Evanston** or ZIP prefix **60010**."
- "**Absentee owners**: parcels whose mail goes to Florida (or any out-of-state address)."
- "A single parcel by **PIN**."
- "Aggregate by **city**, **ZIP**, **taxpayer mailing state**, or across **all 28 tax years**."

### Inputs

| Input | What it does |
|---|---|
| `mode` | `rows` (default) / `aggregate` |
| `owner` | owner-of-record name substring |
| `taxpayer` | taxpayer-of-record name substring (servicers, trusts, estates) |
| `pin` / `pin10` | exact parcel id, 14- or 10-digit form |
| `city` / `zip` | situs city substring / ZIP prefix |
| `mailCity` / `mailState` | where the taxpayer's mail goes - set a non-IL state for absentee owners |
| `year` | 1999-2026; blank = newest roll |
| `groupBy` | aggregate over city / zip / taxYear / taxpayerState |
| `maxResults` | cap records (default 50) |

**Default run = 50 parcels from the newest roll** - fast for the daily auto-test, and it does not scan the 28-year stack. For a targeted query add a filter; for a broad view use `aggregate`.

### Example inputs

**One parcel by PIN** - the exact 14-digit parcel index number.

```json
{ "pin": "01011000020000" }
```

**Absentee owners** - `mailState` is where the taxpayer's notice is mailed, so a
state other than IL surfaces parcels whose notices are sent out of state.

```json
{ "mailState": "FL", "maxResults": 5 }
```

**Parcels in Evanston**

```json
{ "city": "EVANSTON", "maxResults": 5 }
```

**How the roll splits by city** - one row per situs city.

```json
{ "mode": "aggregate", "groupBy": "city" }
```

### Low cost

**From $0.0001 per record, down to $0.00006 at Gold** Pay-per-event: you are charged per record delivered, and nothing for the query. Cost scales with what you pull, not with the size of the file, and each record is metered individually - pulling a ZIP's worth of parcels costs a fraction of a cent.

### Example output

**One parcel** - `pin=01011000020000` returns the owner of record, the taxpayer
of record and the property address below:

```json
{
  "platform": "cook-parcel-owners",
  "source": "cook-county-parcel-addresses",
  "mode": "rows",
  "groupKey": "",
  "groupCount": "",
  "groupBy": "",
  "pin": "01011000020000",
  "pin10": "0101100002",
  "taxYear": "2026",
  "propertyAddress": "231 W MAIN ST",
  "propertyCity": "BARRINGTON",
  "propertyState": "IL",
  "propertyZip": "60010",
  "ownerName": "ACCNZ LLC",
  "ownerAddress": "5277 TRILLIUM BLVD",
  "ownerCity": "HOFFMAN ESTS",
  "ownerState": "IL",
  "ownerZip": "60192",
  "taxpayerName": "ACCNZ LLC",
  "taxpayerAddress": "5277 TRILLIUM BLVD",
  "taxpayerCity": "HOFFMAN ESTS",
  "taxpayerState": "IL",
  "taxpayerZip": "60192",
  "sourceUpdatedAt": "2026-09-15"
}
```

# Actor input Schema

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

rows = parcels matching your filters (default). aggregate = one count row per group (see groupBy).

## `owner` (type: `string`):

Owner-of-record name substring. Distinct from the taxpayer - see the taxpayer input. Blank = any.

## `taxpayer` (type: `string`):

Taxpayer-of-record name substring - the party the assessment notice is mailed to, which is often a mortgage servicer, trust or estate rather than the owner. This is how you find parcels held by a bank or trust. Blank = any.

## `pin` (type: `string`):

Exact 14-digit parcel index number, e.g. '24091100230000'. Blank = any.

## `pin10` (type: `string`):

Exact 10-digit PIN form of the same parcel, e.g. '2409110023'. Blank = any.

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

Situs (property) city substring, e.g. 'CHICAGO' (883,473), 'EVANSTON'. Blank = any.

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

Situs ZIP prefix - '60010' matches 60010 and 60010-1234. Blank = any.

## `mailCity` (type: `string`):

Taxpayer mailing city substring - use with mailState to find owners who receive mail elsewhere. Blank = any.

## `mailState` (type: `string`):

Two-letter taxpayer mailing state, e.g. 'IL', 'FL', 'TX'. Set a state other than IL to surface absentee owners and out-of-state lienholders. Blank = any.

## `year` (type: `string`):

Roll year between 1999 and 2026. Blank = the newest roll (the 28-year stack is not scanned unless you ask for it).

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

Which dimension to aggregate over. city = situs city (~241 values); zip = situs ZIP; taxYear = the whole 28-year stack; taxpayerState = where the mail goes.

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

Cap the number of records pushed in rows mode (0 = up to ~10k per run; each record is metered individually, so there is no per-run charge cap). Aggregate mode returns every group.

## Actor input object example

```json
{
  "mode": "rows",
  "owner": "",
  "taxpayer": "",
  "pin": "",
  "pin10": "",
  "city": "",
  "zip": "",
  "mailCity": "",
  "mailState": "",
  "year": "",
  "groupBy": "city",
  "maxResults": 50
}
```

# Actor output Schema

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

Cook County parcel-owner 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/cook-parcel-owners").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/cook-parcel-owners").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/cook-parcel-owners --silent --output-dataset

```

## MCP server setup

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

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/eaMuRJYw92UhfMI3X/builds/AckHa8AeDBHl9PWp7/openapi.json
