# Absentee Owner Lead List Builder — County Assessor Rolls (`malonestar/absentee-owner-lead-list-builder`) Actor

Build absentee-owner lead lists from county assessor rolls: Cook County IL, Philadelphia PA, NYC. Flags out-of-state and out-of-city owners by situs-vs-mailing mismatch, LLC/trust entity owners, with class and value filters. Clean JSON/CSV leads for wholesalers, flippers, direct mail and agents.

- **URL**: https://apify.com/malonestar/absentee-owner-lead-list-builder.md
- **Developed by:** [Kyle Maloney](https://apify.com/malonestar) (community)
- **Categories:** Real estate, Lead generation, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $13.75 / 1,000 results

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/platform/actors/running/actors-in-store#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

## Absentee Owner Lead List Builder — County Assessor Rolls

Build **absentee-owner lead lists** straight from official county assessor / parcel rolls — no scraping of paywalled lead vendors, no stale resold data. The actor pulls live parcel records, compares the **property (situs) address against the owner's tax-bill mailing address**, and classifies every parcel into an absentee tier, so you can pull a targeted list of out-of-state landlords, tired out-of-town owners, or LLC-held inventory in minutes.

**Covered jurisdictions (v1):**

| County key | Source | What you get |
|---|---|---|
| `cook-il` | Cook County Assessor **Parcel Universe** (Socrata, latest assessment year auto-resolved) | Full mismatch classification + owner mailing address |
| `philadelphia-pa` | Philadelphia **OPA Properties** (Carto SQL API) | Full mismatch classification + market value |
| `nyc` | NYC **PLUTO** (Socrata) | Owner-name lists only — see limitation below |

### Who this is for

- **Wholesalers & flippers** — pull every out-of-state owner of residential parcels in Cook County and start driving for dollars with a real list.
- **Direct-mail investors** — export mailing name + address columns, dedupe, and drop a campaign; the tier field lets you segment "out-of-state" vs "same city, different address."
- **Real-estate agents & farm builders** — find absentee landlords in your farm area likely to sell.
- **Data / prop-tech teams** — a clean, unified JSON schema across counties, callable as an API or MCP tool.

### Example input

```json
{
  "county": "cook-il",
  "absenteeTier": "out_of_state",
  "propertyClassPrefix": "2",
  "entityOnly": false,
  "maxResults": 100
}
```

Filters:

- `county` — `cook-il` | `philadelphia-pa` | `nyc`
- `absenteeTier` — `any` | `out_of_state` | `out_of_city` (alias `out_of_county`) | `same_area_diff_address` | `owner_occupied_likely`
- `entityOnly` — keep only LLC / trust / corp / partnership owners
- `propertyClassPrefix` — source class-code prefix (Cook `2` = residential, `5` = commercial; PLUTO `A` = one-family; OPA `1` = single family)
- `minAssessedValue` — value floor (Philadelphia `market_value`, NYC `assesstot`; not available for Cook)
- `maxResults` — cost cap, up to 10,000 rows per run

### How complete is the contact data? (measured, not claimed)

Measured on 2026-08-01 against the live sources, using each county's own
out-of-state filter, n = 100 rows per county:

| Contact / identity field | Cook County IL | Philadelphia PA | NYC |
|---|---|---|---|
| `owner_name` | **100.0%** | **100.0%** | see note |
| `owner_mailing_address` | **100.0%** | **100.0%** | **0% - not published** |
| `owner_mailing_city` | 100.0% | 100.0% | 0% |
| `owner_mailing_state` | 100.0% | 100.0% | 0% |
| `owner_mailing_zip` | 99.0% | 100.0% | 0% |
| `owner_mailing_care_of` | n/a | 6.0% | n/a |
| `owner_name_secondary` | n/a | 35.0% | n/a |
| `situs_address` / `situs_city` / `situs_state` | 100.0% | 100.0% | 100.0% |
| `situs_zip` | 97.0% | 100.0% | 100.0% |
| `entity_flag_basis` (of rows flagged as entities) | 14.0% | 35.0% | varies |
| `assessed_value` | **0% - not published** | 100.0% | published |
| `lat` / `lon` | **0% - not published** | 100.0% | published |

**There are no phone numbers or email addresses in any of these sources.** The
assessor rolls publish an owner name and an owner **mailing address**. This is
the list you feed to a skip-trace, not a replacement for one.

**Per-county coverage differs and every row says so.** `mailing_address_available`,
`assessed_value_available` and `geo_available` are published on every row:

- **Cook County IL** - full owner mailing address, but the Parcel Universe
  publishes **no value column and no coordinates at all** (verified live:
  `lat IS NOT NULL` returns 0 of 1,587,209 rows). `assessed_value`, `lat` and
  `lon` are null there and `minAssessedValue` is ignored.
- **Philadelphia PA** - full owner mailing address, market value and coordinates.
- **NYC** - PLUTO publishes owner **names only, with no owner mailing address**.
  Absentee status is therefore structurally unanswerable for NYC:
  `absentee_tier` reads `unknown` and `absentee_tier_basis` reads
  `no_mailing_data`. It is **not** a verified negative. Use NYC for the
  corporate/LLC-owner flag (`entityOnly: true`), not for absentee tiering.

### How many of the matching parcels do you actually get?

Every row carries `total_matching_rows`, `rows_scanned`, `pages_scanned`,
`scan_complete` and `selection_method`. A run reads at most 30,000 source rows
in **parcel-id order** and returns the first `maxResults` matches.

That matters because parcel ids are geographically ordered. The actor's own
prefill (Cook County, out-of-state owners, class 2) matches **42,587 parcels**
county-wide; the 100 rows it returns are all from PIN area 01 - Barrington,
Barrington Hills, South Barrington, Inverness and Hoffman Estates. Chicago
proper is never reached. Every row is a genuine out-of-state-owned class-2 Cook
County parcel, but the set is **one corner of the county, not a county-wide
sample**, and the run log now says so loudly.

To move the window, narrow the filters (`propertyClassPrefix`,
`minAssessedValue`, a tighter `absenteeTier`) until `scan_complete` reads true.

### Output fields (one row per parcel lead)

`county`, `parcel_id`, `situs_address`, `situs_city`, `situs_state`, `owner_name`, `owner_mailing_address`, `owner_mailing_city`, `owner_mailing_state`, `owner_mailing_zip`, `absentee_tier`, `entity_flag`, `assessed_value`, `property_class`, `property_class_desc`, `lat`, `lon`, `source`, `source_url`

#### The absentee-tier classifier

| Tier | Meaning |
|---|---|
| `out_of_state` | Mailing state differs from the property state — the strongest absentee/motivated-seller signal |
| `out_of_city` | Mailing city differs, same state (out-of-town landlord) |
| `same_area_diff_address` | Same city, different street address (local landlord) |
| `owner_occupied_likely` | Mailing address matches the property (street-normalized; same-building condo units count as matches) |
| `unknown` | No mailing data in the source (all `nyc` rows) |

`entity_flag` is true when the owner name matches LLC, L.L.C., LP, LLP, LTD, TRUST, TR, CORP, INC, CO, COMPANY, PARTNERS, HOLDINGS, PROPERTIES, or BANK — combine `entityOnly: true` with a tier for investor-owned absentee inventory.

#### Provenance and coverage (new in v1.1)

| Field | Meaning |
| --- | --- |
| `absentee_tier_basis` | What the tier was decided from: `mailing_address` (a full owner mailing street was compared), `city_state_only` (only the mailing city/state were published), `no_mailing_data` (nothing was published, so the tier is `unknown`) |
| `entity_flag_basis` | The token that made `entity_flag` true (LLC, LP, TRUST, TR, CORP, INC, CO, COMPANY, PARTNERS, HOLDINGS, PROPERTIES, BANK). `TR` is a trustee suffix - a real trust, but not an LLC |
| `situs_zip` | ZIP of the property itself |
| `township` | Cook County assessment township |
| `owner_mailing_care_of` | Care-of line on the owner mailing address (Philadelphia) |
| `owner_name_secondary` | Second owner of record (Philadelphia `owner_2`) |
| `assessment_year` | Assessment roll year the parcel row belongs to (Cook) |
| `source_status` | `ok` when the county source answered and its filters were proven applied by a negative control |
| `source_error` | Error text when it did not. Null on a healthy run |
| `year_status` | `ok` / `not_applicable` for the live Cook assessment-year resolution |
| `assessment_year_used` | The Cook assessment year this run actually queried |
| `total_matching_rows` | How many parcels match your filters upstream, before the scan cap |
| `rows_scanned` | How many source rows this run read |
| `pages_scanned` | How many source pages this run read |
| `scan_complete` | True only when every matching parcel upstream was examined |
| `selection_method` | How the emitted rows were chosen from that universe |
| `mailing_address_available` | False for NYC |
| `assessed_value_available` | False for Cook County |
| `geo_available` | False for Cook County |
| `data_as_of` | UTC date the run executed |

### What v1.1 fixed (2026-08-01)

All three assessor rolls were re-probed live. Nothing was removed or renamed.

- **Philadelphia: 824 genuinely absentee owners were labelled owner-occupied and
  filtered out.** v1.0 hard-coded `owner_occupied_likely` whenever
  `mailing_street` was null, *regardless of the mailing city and state on the
  same row*. Live: 3,601 Philadelphia rows have a null `mailing_street`, of which
  **208 carry an out-of-state `state_code`** and **616 carry a non-Philadelphia
  PA mailing city**. Every one of those was dropped from every `out_of_state` and
  `out_of_city` run - exactly the leads the product exists to find. A further
  **1,098 rows have no mailing data at all** and were asserting owner-occupancy
  from nothing; they now read `unknown`. Verified on real parcels: 1923 Pratt St
  (owner mailing NJ) and 1437 W Passyunk Ave 1-2 (owner mailing DE) now classify
  `out_of_state`.
- **The Cook assessment year was resolved inside a silent catch.** v1.0 fell back
  to a hard-coded `2023` on any failure. That is harmless only while the constant
  happens to match - and it does today - but the moment Cook publishes 2024, a
  transient failure would ship a year-old roll as current with no signal. The
  year is now resolved loudly, band-checked, and published as
  `assessment_year_used`.
- **The scan cap was invisible.** See the section above: the prefill returns 100
  of 42,587 matches, all from one corner of Cook County. Selection is unchanged;
  it is now disclosed on every row.
- **No filter was ever proven applied.** Each source now runs a negative control
  (a predicate that cannot match) before any row is read; a non-zero answer fails
  the run, because Socrata and Carto will both accept some malformed predicates
  and quietly return the unfiltered table.
- **A typo'd `absenteeTier` was silently coerced to `any`,** so a run asking for
  out-of-state owners quietly returned owner-occupied parcels too. It now fails
  before anything is billed.
- **`mailing_care_of` and `township_name` were fetched and discarded** in the
  mappers.
- **Cook publishes no coordinates at all** - `lat IS NOT NULL` returns 0 of
  1,587,209 rows - so `lat`/`lon` rendered permanently empty there with no
  explanation. Now flagged by `geo_available`.

### Honest limitation: the NYC leg

NYC PLUTO publishes owner **names** but **no owner mailing address**, so the situs-vs-mailing comparison is impossible for NYC in v1. The `nyc` county therefore ships as a **corporate/LLC-owner flag list** (`absentee_tier` is always `unknown`; use `entityOnly: true`). Mailing-address enrichment for NYC is on the roadmap.

Other notes: Cook County's Parcel Universe has no assessed-value column, so `assessed_value` is null and `minAssessedValue` is ignored for `cook-il`. Tiers are heuristics computed from address strings — verify before making offers.

### Use as an MCP tool

This actor is callable by AI agents (Claude, Cursor, etc.) via [mcp.apify.com](https://mcp.apify.com) — the input and output schemas are fully described at field level, so an agent can request e.g. "out-of-state entity owners of multi-family parcels in Cook County" and chain the resulting leads into skip-tracing or CRM tools.

### FAQ

**How do I find absentee owners of a property for free?**
County assessor rolls are public record. This actor automates the pull and the situs-vs-mailing comparison across Cook County IL, Philadelphia PA, and NYC, and gives you export-ready JSON/CSV.

**How do I get a list of out-of-state property owners in Chicago / Cook County?**
Run with `county: "cook-il"`, `absenteeTier: "out_of_state"`, `propertyClassPrefix: "2"` (residential). Each row includes the owner's out-of-state mailing address for direct mail.

**Can I get absentee owner leads for Philadelphia?**
Yes — `county: "philadelphia-pa"` classifies every OPA parcel by mailing mismatch and includes `market_value` so you can set a value floor.

**How do I find LLC-owned properties in NYC?**
Run `county: "nyc"` with `entityOnly: true` (optionally `propertyClassPrefix` like `"C"` for walk-up apartments). PLUTO has no mailing addresses, so NYC rows are owner-name flag lists.

**Is this data legal to use for marketing?**
The sources are official open-data portals published for public use. You are responsible for complying with local telemarketing/mail regulations (e.g. do-not-call lists).

**How fresh is the data?**
Live at run time. The Cook leg auto-resolves the latest assessment year in the Parcel Universe; Philadelphia OPA and NYC PLUTO are updated by their agencies on their own cycles.

### Pricing

Pay per result row — you only pay for the leads you pull (set `maxResults` to cap spend). Empty runs cost virtually nothing.

# Actor input Schema

## `county` (type: `string`):

Which assessor/parcel roll to build leads from. cook-il = Cook County IL (Chicago area, full mailing-address mismatch classification). philadelphia-pa = Philadelphia OPA (full classification). nyc = NYC PLUTO (owner names only — no mailing address in the source, so rows are corporate/LLC-owner flag lists with absentee\_tier=unknown).

## `absenteeTier` (type: `string`):

Keep only leads in one absentee tier. out\_of\_state = owner's mailing state differs from the property state (strongest absentee signal). out\_of\_city = mailing city differs, same state (out\_of\_county is accepted as an alias). same\_area\_diff\_address = same city but a different street address. owner\_occupied\_likely = mailing matches the property. any = no tier filter. Ignored for nyc (no mailing data).

## `entityOnly` (type: `boolean`):

Keep only parcels whose owner name looks like a legal entity (LLC, LP, LLP, LTD, TRUST, TR, CORP, INC, CO, COMPANY, PARTNERS, HOLDINGS, PROPERTIES, BANK). Great for targeting investor-owned inventory; this is the only useful filter for the nyc leg.

## `propertyClassPrefix` (type: `string`):

Filter by the source's property-class code prefix. cook-il: Cook Assessor major class, e.g. "2" = residential, "3" = multi-family, "5" = commercial/industrial. nyc: PLUTO building class, e.g. "A" = one-family, "C" = walk-up apartments. philadelphia-pa: OPA category\_code, e.g. "1" = single family (applied client-side). Leave empty for all classes.

## `minAssessedValue` (type: `integer`):

Keep only parcels at or above this value. Uses market\_value for philadelphia-pa and assesstot for nyc. The Cook County Parcel Universe dataset carries no assessed-value column, so this filter is ignored for cook-il (a warning is logged).

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

Maximum number of lead rows to emit (caps your cost — you are billed per result row). Hard cap 10,000 per run.

## Actor input object example

```json
{
  "county": "cook-il",
  "absenteeTier": "out_of_state",
  "entityOnly": false,
  "propertyClassPrefix": "2",
  "maxResults": 100
}
```

# Actor output Schema

## `results` (type: `string`):

The default dataset of classified absentee-owner leads.

# 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 = {
    "county": "cook-il",
    "absenteeTier": "out_of_state",
    "propertyClassPrefix": "2",
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("malonestar/absentee-owner-lead-list-builder").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 = {
    "county": "cook-il",
    "absenteeTier": "out_of_state",
    "propertyClassPrefix": "2",
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("malonestar/absentee-owner-lead-list-builder").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "county": "cook-il",
  "absenteeTier": "out_of_state",
  "propertyClassPrefix": "2",
  "maxResults": 100
}' |
apify call malonestar/absentee-owner-lead-list-builder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=malonestar/absentee-owner-lead-list-builder",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

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