# Property Owner, Tax & Deed Records Intel (`seibs.co/property-records-intel`) Actor

Unifies US county assessor / property-tax / recorder records into one parcel + owner schema: owner, assessed value, sale history, deed, tax status. Value layer: owner-to-parcel linking, portfolio rollups, equity/distress scoring. Public records, no skip-tracing. For investors, lenders, PropTech.

- **URL**: https://apify.com/seibs.co/property-records-intel.md
- **Developed by:** [Seibs.co](https://apify.com/seibs.co) (community)
- **Categories:** Real estate, Business, Lead generation
- **Stats:** 22 total users, 12 monthly users, 88.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 property records

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/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

## Property Owner, Tax & Deed Records Intel

> **TL;DR for real-estate investors, wholesalers, lenders, PropTech, and insurers:** Aggregates US county assessor / property-tax / recorder records - public-by-law, but scattered across thousands of county portals with no unified free API - into one normalized **parcel + owner** schema: owner name, situs + mailing address, assessed/land/improvement value, sale history, deed type, and tax status. On top of the raw records it adds the value layer the incumbents charge for: **owner-to-parcel linking** (find every property an owner controls), **portfolio rollups**, and **equity/distress scoring** (tax delinquency, absentee / out-of-state ownership, estimated equity, estate/trust, long tenure, portfolio owner). The fragmentation is exactly the moat PropStream ($99-300/mo), DataTree/RealQuest ($150-275/mo), and ListSource ($0.30-0.45/record, $50 min) monetize. **Not** another saturated Zillow/Redfin listing scraper - this is the ownership/tax graph underneath. Logged-out public records, **no skip-tracing** into private phone/email. Free Apify plan covers exploration runs on your $5 platform credit.

### Run it in 30 seconds

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("seibs.co/property-records-intel").call(run_input={
    "mode": "owner_portfolio",
    "owner_names": ["HOUSING AUTHORITY"],
    "counties": ["NYC", "DC"],
    "include_distress": True
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

Or via curl:

```bash
curl -X POST "https://api.apify.com/v2/acts/seibs.co~property-records-intel/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"mode": "property_search", "owner_names": ["ACME PROPERTIES LLC"], "counties": ["NYC","DC"]}'
```

Or click "Try for free" on this page if you prefer the no-code UI.

### What you get

Each run produces:

- A clean dataset, filterable in the Apify console and downloadable as CSV or JSON (views: `overview`, `parcels`, `owners`, `distress`)
- An OUTPUT.html dashboard preview of your top records
- A sample-output preview at [`.actor/sample-output.json`](./.actor/sample-output.json)
- An `access_notes` record up top documenting each county's access method, proxy needs, coverage, and the responsible-use note

### What does Property Records Intel do?

It queries each selected county's public property/assessor source and normalizes every result into one schema: `apn`, `owner_name`, `owner_type` (individual / entity / trust / estate / government), `situs_address`, `mailing_address`, `land_use` (residential / commercial / vacant\_land / ...), `assessed_total_value`, `last_sale_date` + `last_sale_price`, `deed_type`, `tax_status` (paid / delinquent / exempt), `year_built`, and `source_url`. Then it runs the **value layer**:

- **Owner-to-parcel linking** - groups parcels by a normalized owner key and flags **portfolio owners** (one owner holding multiple parcels - the wholesaler/investor signal). One `owner_portfolio` rollup per owner with parcel count, counties, total assessed value, and land-use mix.
- **Owner enrichment** - classifies individual vs entity vs trust/estate, and derives **owner-occupancy / absentee / out-of-state** from the tax-roll mailing address vs the situs address (both public-record fields - no skip-trace).
- **Equity / distress scoring** - from public assessor + recorder fields, derives motivation leads: tax delinquency, absentee / out-of-state owner, **estimated equity** (assessed value vs last recorded sale price), estate/trust ownership, long tenure, vacant land, and portfolio owner -> a per-parcel `distress_score` and a `distress_summary` rollup.

### Modes

| Mode | What it returns |
|---|---|
| `property_search` (default) | Every matching parcel per county for your owner / address / APN queries, plus `owner_portfolio` rollups. |
| `parcel_profile` | Deep profile (assessed value, sale history, deed, tax status) for specific parcels (`parcels=[{county, apn}]`) - charges `owner_enrichment` per parcel that yields an owner. |
| `owner_portfolio` | One `owner_portfolio` record per owner with their resolved multi-parcel footprint and a `portfolio_owner` flag. The "find every property this owner controls" view. |
| `distress_scan` | Scores the resolved parcel set for equity + motivation signals - charges `equity_distress_signal` per flagged parcel. |

### County coverage: fragmented by design, unified here

US county property data shares no schema and no unified free API - that fragmentation is the moat we unify. Two parameterized connector bases cover the two dominant public-data shapes, so adding a county is one `field_map` dict:

- **`ArcGISParcelConnector`** - the single most common county GIS pattern: an Esri **ArcGIS REST FeatureServer/MapServer** `/query` endpoint that takes a SQL `where` clause and returns `{"features":[{"attributes":{...}}]}` JSON.
- **`SocrataParcelConnector`** - counties/cities that publish parcel + sales data on a **Socrata** open-data portal (SoQL JSON).

Coverage is honestly tiered.

**Verified-live counties (3)** - request + parser implemented, fixture-validated, AND the live endpoint confirmed returning real data:

| County | Source | Access | Search axes | Notes |
|---|---|---|---|---|
| **NYC** (5 boroughs) | DOF/DCP PLUTO (Socrata, `64uk-42ks`) | `http_json` | owner, address, apn (BBL) | Owner, assessed land/total value, building class, year built. No recorded-sale price in PLUTO (NYC sales live in DOF Rolling Sales / ACRIS). |
| **DC** | Office of Tax & Revenue - Common Ownership / Integrated Tax (ArcGIS layer 40) | `http_json` | owner, address, apn (SSL) | Owner, mailing + premises address, assessment, sale date/price, deed instrument. |
| **LA\_CA** (Los Angeles) | LA County Assessor parcel layer (ArcGIS) | `http_json` | address, apn | CA redacts owner names on the public parcel layer, so owner search is unavailable; APN + address return the assessment facts (situs, use type, roll land/improvement value, year built). |

**ArcGIS connectors pending a live URL recapture (2)** - field map implemented and fixture-validated, but the documented service endpoint has moved, so they are registered as catalog until the live URL is refreshed (a one-line change): **MECK\_NC** (Mecklenburg/Charlotte) and **MARICOPA\_AZ** (Phoenix - Maricopa also publishes a public Assessor API that is a strong upgrade target).

**Catalog counties (~28)** - registered with the correct portal URL, access method, anti-bot level, and proxy tier, and wired into the escalation pipeline, but a per-county `field_map` is pending a live capture. These emit a documented `county_pending` note rather than fabricated data. Includes Cook (Chicago), Harris/Dallas/Travis/Bexar/Tarrant (TX), Miami-Dade/Broward/Hillsborough/Orange/Palm Beach (FL), King (Seattle), San Diego/Orange/Santa Clara (CA), Clark (Las Vegas), Wake (Raleigh), Fulton (Atlanta), Cuyahoga/Franklin (OH), Philadelphia/Allegheny (PA), Suffolk/Boston (MA), Denver, Salt Lake, Hennepin (Minneapolis), and the Maricopa + Tarrant recorder (deed) connectors. Pass `counties=["ALL"]` to enumerate them, or read the `access_notes.access_matrix` on any run.

Upgrading a catalog county to full is one `field_map` dict + the search-field names - the orchestrator, owner-resolution, distress-scoring, and monitor layers are all county-agnostic.

### Anti-bot escalation

County portals range from open JSON APIs to Cloudflare-fronted SPAs. The `parcel_client` runs a three-tier ladder, escalating only on a block:

1. **httpx** over the DATACENTER proxy (cheapest).
2. **curl\_cffi** with real Chrome TLS impersonation over the RESIDENTIAL proxy (defeats JA3/TLS-fingerprint WAFs).
3. **Playwright/patchright** headful browser over the RESIDENTIAL proxy (clears Cloudflare/Imperva managed challenges; calls a fronted JSON API from inside the warmed page so it carries `cf_clearance` + the real TLS). Set `browser_cdp_url` to a warm anti-detect browser for the toughest portals; the per-search-CAPTCHA portals additionally need an opt-in solver (`CAPTCHA_SOLVER_PROVIDER` + `CAPTCHA_SOLVER_KEY`, off by default).
4. **Fail-soft** - if every tier is blocked, the county emits a documented `fetch_error` and the run still finishes SUCCEEDED.

### Pricing (pay-per-event)

| Event | Price | When |
|---|---|---|
| `property_record` | $0.008 | Per normalized parcel emitted. |
| `owner_enrichment` | $0.012 | Per parcel that yields a resolved owner (profile/portfolio modes or `include_owner_enrichment`). |
| `equity_distress_signal` | $0.015 | Per parcel flagged with an equity/motivation signal (`distress_scan` or `include_distress`). |
| `scheduled_delta_run` | $0.050 | Per scheduled monitor-mode run that emits a change digest. |

A run that returns nothing costs nothing. Compare to PropStream ($99-300/mo), DataTree/RealQuest ($150-275/mo), and ListSource ($0.30-0.45/record, $50 minimum).

### Legal & responsible use

County property records (ownership, assessed value, recorded deeds) are **public-by-law**. This actor:

- Stays **logged-out** and uses **public-record fields only** - owner name, tax-roll mailing address, and the assessment + recorded-sale facts.
- Does **NOT skip-trace** into private contact data (no phone, no personal email, no SSN/DOB) - a deliberate scope line, not a missing feature. Skip-tracing is a PII minefield and out of scope.
- Labels equity and distress figures as **assessor-derived estimates and investigative leads**, not verified title, lien, or mortgage-balance determinations.
- Property data may **not** be used for FCRA-covered decisions (credit, tenant screening, employment). Use within your local fair-use rules.

### Monitor mode

Run this actor on an Apify Schedule and it switches to monitor mode: it diffs this run against the last scheduled run and emits a change digest (new parcels, ownership changes, new tax delinquencies), optionally posted to a Slack-compatible `monitor_webhook_url`. Charges one `scheduled_delta_run`. Perfect for a "new distressed properties in my county this week" watchlist.

### MCP / AI-agent use

A paired MCP server, **`mcp-property-records-intel`**, exposes five tools (`search_properties`, `get_parcel_profile`, `find_owner_portfolio`, `scan_distress`, `lookup_by_address`) for Claude, Cursor, LangChain, and any Apify-actor-as-tool host. It is **x402 (USDC on Base) and Skyfire ready** for token-less agentic payments.

### Portfolio fit

This is the **ownership/tax graph** beneath the event-driven property lead actors (Foreclosure Property Leads, Property Auction Leads, House Flipper Leads) - enrich each of those leads with a verified public-record owner + equity estimate. See the full portfolio at https://apify.com/seibs.co.

# Actor input Schema

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

property\_search = search each county by owner name / address / APN and resolve owner portfolios. parcel\_profile = deep profile (assessed value, sale history, deed, tax status) for specific parcels. owner\_portfolio = group parcels by owner and surface multi-parcel owners (find every property an owner controls). distress\_scan = score the resolved parcel set for equity/distress signals (tax delinquency, absentee, estimated equity, estate/trust, long tenure).

## `owner_names` (type: `array`):

Owner names (or name fragments) to search each selected county for, e.g. \['SMITH JOHN', 'ACME PROPERTIES LLC']. Owner names are public record on the tax roll; no skip-tracing is performed. Hard cap of 50.

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

Property (situs) addresses or address fragments to search, e.g. \['350 5 Avenue', '100 Main St']. Hard cap of 50.

## `apns` (type: `array`):

Assessor parcel numbers (APN / BBL / SSL / PIN) to search across the selected counties, e.g. \['1008350001']. Hard cap of 50.

## `parcels` (type: `array`):

Profile specific parcels directly without searching. Each item: {"county": "NYC", "apn": "1008350001"}. Use for parcel\_profile when you already have the parcel id. Hard cap of 50.

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

County codes. Verified-live connectors that return real data now: NYC (PLUTO), DC (OTR), LA\_CA (LA is address/APN only - California redacts owner names on the public parcel layer). A national catalog of ~30 more major counties (incl. Mecklenburg + Maricopa, whose ArcGIS parsers are fixture-validated but whose live service URL needs a recapture) is registered with the correct portal + access method; those return a documented county\_pending or fetch note. Pass \['ALL'] to enumerate every catalogued county. Leave empty for the default set (NYC, DC, LA\_CA).

## `all_counties` (type: `boolean`):

Shortcut to query every catalogued county (overrides the counties list). Fully-parsed counties return parcels; catalog counties return a documented county\_pending note.

## `include_owner_enrichment` (type: `boolean`):

Resolve each parcel's owner, classify individual vs entity vs trust/estate, derive owner-occupancy/absentee from the tax-roll mailing address, and link the owner to their other parcels. Charges owner\_enrichment per parcel that yields an owner. Defaults on for parcel\_profile / owner\_portfolio, off for a fast name-only property\_search.

## `include_distress` (type: `boolean`):

Score each parcel for equity + motivation signals (tax delinquency, absentee / out-of-state owner, estimated equity from assessed value vs last sale, estate/trust ownership, long tenure, portfolio owner). Charges equity\_distress\_signal per flagged parcel. Defaults on for distress\_scan mode. These are leads, not a verified title/lien determination.

## `max_results_per_county` (type: `integer`):

Hard cap on parcels returned per county per query. Default 25.

## `contact_email` (type: `string`):

Optional operator contact added to request headers. Good-citizen practice; not required.

## `monitor_webhook_url` (type: `string`):

When this actor runs under an Apify Schedule (monitor mode), post the change digest (new parcels, ownership changes, new tax delinquencies) to this Slack-compatible webhook URL.

## `use_apify_proxy` (type: `boolean`):

Route county requests through Apify Proxy. The DATACENTER tier handles the first (httpx) pass; a RESIDENTIAL tier is provisioned for the anti-bot escalation legs.

## `use_browser_fallback` (type: `boolean`):

When a county portal serves a Cloudflare/CAPTCHA/403 challenge, automatically escalate: switch to the RESIDENTIAL proxy and retry with curl\_cffi Chrome TLS impersonation, then (if available) a headless browser. Turn off to use plain httpx only.

## `browser_cdp_url` (type: `string`):

Optional. CDP/WebSocket endpoint of an already-running, anti-detect (UC-mode / real Chrome) browser. When set, the browser tier connects to it (inheriting its session + fingerprint) so it passes the Cloudflare/Imperva county portals. Without it a plain headless Chromium is launched. Can also be set as the BROWSER\_CDP\_URL env var. The per-search CAPTCHA portals additionally need an opt-in solver: set CAPTCHA\_SOLVER\_PROVIDER (2captcha|capsolver) + CAPTCHA\_SOLVER\_KEY as actor env secrets - off by default.

## `apify_proxy_groups` (type: `array`):

Override the auto-selected proxy group. Leave empty to let the actor pick DATACENTER (with RESIDENTIAL provisioned for escalation legs).

## `concurrency` (type: `integer`):

Parallel county fetches. County portals are rate-sensitive; default 4.

## Actor input object example

```json
{
  "mode": "property_search",
  "owner_names": [
    "ACME PROPERTIES LLC"
  ],
  "addresses": [],
  "apns": [],
  "parcels": [],
  "counties": [
    "NYC",
    "DC",
    "LA_CA"
  ],
  "all_counties": false,
  "include_owner_enrichment": false,
  "include_distress": false,
  "max_results_per_county": 10,
  "contact_email": "",
  "monitor_webhook_url": "",
  "use_apify_proxy": true,
  "use_browser_fallback": true,
  "browser_cdp_url": "",
  "apify_proxy_groups": [],
  "concurrency": 4
}
```

# Actor output Schema

## `datasetItems` (type: `string`):

Narrow, token-efficient slice of every record. Consumer: LLM agents (Claude, GPT, LangChain tools), MCP hosts, REI dashboards.

## `datasetItemsParcels` (type: `string`):

Full normalized parcels with owner, addresses, valuation, sale history, and tax status. Consumer: REI underwriting, CRM enrichment, RAG ingest.

## `datasetItemsOwners` (type: `string`):

One row per owner with their resolved multi-parcel footprint. Consumer: wholesalers, list-builders, skip-trace upstream (we stop at public-record owner data).

## `datasetItemsMcp` (type: `string`):

First 50 overview records as a clean JSON array. Wrap on the agent side in an MCP tool-call envelope. Consumer: MCP servers, Claude Desktop, Cursor, OpenAI Assistants tool calls.

## `datasetItemsCsv` (type: `string`):

Spreadsheet-friendly export of the overview view. Consumer: REI analysts, Excel / Google Sheets users.

# 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 = {
    "mode": "property_search",
    "owner_names": [
        "ACME PROPERTIES LLC"
    ],
    "counties": [
        "NYC",
        "DC",
        "LA_CA"
    ],
    "max_results_per_county": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("seibs.co/property-records-intel").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 = {
    "mode": "property_search",
    "owner_names": ["ACME PROPERTIES LLC"],
    "counties": [
        "NYC",
        "DC",
        "LA_CA",
    ],
    "max_results_per_county": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("seibs.co/property-records-intel").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 '{
  "mode": "property_search",
  "owner_names": [
    "ACME PROPERTIES LLC"
  ],
  "counties": [
    "NYC",
    "DC",
    "LA_CA"
  ],
  "max_results_per_county": 10
}' |
apify call seibs.co/property-records-intel --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=seibs.co/property-records-intel",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

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