# Property Owner Lookup & Absentee Owner List (PA, SF, CT, DC) (`hanielazevedo/property-details-by-address`) Actor

Property owner lookup and absentee owner lists for Allegheny County (Pittsburgh) and San Francisco, plus CT and DC: beds, baths, sqft, year built, assessed value by address, and motivated seller leads. Official open assessor data. $0.008/lookup, misses free.

- **URL**: https://apify.com/hanielazevedo/property-details-by-address.md
- **Developed by:** [Haniel Azevedo](https://apify.com/hanielazevedo) (community)
- **Categories:** Real estate, Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 lead rows

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?

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

## Property Owner Lookup & Absentee Owner Lists: Pittsburgh (Allegheny), San Francisco, CT, DC

**Property owner lookup and absentee owner lists for Allegheny County (Pittsburgh, PA) and San Francisco**, the two big markets no dedicated Apify Actor covers, plus **Connecticut and Washington DC**. Look up **beds, baths, sqft, year built, assessed value and last sale by address**, or build **absentee-owner, out-of-state-owner and recent-sale lists** (motivated seller leads). Everything comes from **official county and state open-data assessor rolls**: no Zillow, Redfin or Realtor.com scraping, no logins, no paid data brokers. Every row says which public dataset it came from, under which licence, and how current it is.

- **Pittsburgh / Allegheny County, PA:** absentee-owner and recent-sale lists by municipality or ward (owner type, owner mailing address, last sale) **and** property lookup by address.
- **San Francisco, CA:** property owner lookup by address (parcel / block-lot, beds, baths, sqft, year built, assessed value). SF publishes no owner mailing address, so SF is lookup only.
- **Connecticut (all 169 towns) and Washington DC:** lists with owner names, plus lookup.

**Price:** **$0.02 per list row** and **$0.008 per matched lookup**; misses are free. For comparison, [shelvick/county-property-records](https://apify.com/shelvick/county-property-records) charges $0.05 per record.

- **List mode (absentee owners + recent sales):** filter by municipality / ward / town, owner mailing address ≠ property address, out-of-state owners, sale date range, minimum sale price and property type. You get the site address, owner type (Allegheny) or owner name (CT, DC), owner mailing address, last sale date and price, assessed value and property facts. **$0.02 per row.**
- **Property owner lookup by address:** beds, baths, living sqft, lot size, year built, assessed value, parcel ID, last sale, source and as-of date, with a match-confidence score. **$0.008 per matched address; misses are free.**

> Coverage: **Allegheny County, PA (Pittsburgh)**, **San Francisco, CA** (lookup only), **Connecticut (all 169 towns)** and **Washington, DC**, about 2.9 million housing units, roughly 2% of the US. Addresses elsewhere come back as `UNSUPPORTED_COUNTY` and are free. New counties are added only where the data licence clearly allows commercial reuse.

### Who it's for

- **Wholesalers and real-estate investors** building absentee-owner, out-of-state-owner and recently-sold lists for direct mail.
- **Agents, lenders and insurers** who need property facts by address with a citable, licence-clean source.
- **Data and CRM teams** enriching address lists with parcel IDs and assessed values.

### Example input

The Console form is prefilled with this real property owner lookup (a DC two-unit rowhouse and a Pittsburgh house). Click **Start** without changing anything:

```json
{
  "mode": "lookup",
  "addresses": [
    "3100 16th St NW, Washington, DC 20010",
    "7224 Upland St, Pittsburgh, PA 15208"
  ]
}
```

### Example output

That input returns 2 `MATCHED` rows in about 4 seconds and costs $0.016 (2 lookups × $0.008) plus the $0.00005 start fee. The Pittsburgh row from a run on 1 Nov 2026, trimmed:

```json
{
  "input": "7224 Upland St, Pittsburgh, PA 15208",
  "status": "MATCHED",
  "matchConfidence": 1,
  "normalizedAddress": "7224 UPLAND ST, PITTSBURGH, PA 15208",
  "county": "Allegheny County",
  "parcelId": "0174B00120000000",
  "bedrooms": 3,
  "bathrooms": 1,
  "livingAreaSqft": 1520,
  "lotSizeSqft": 2325,
  "yearBuilt": 1930,
  "propertyUse": "SINGLE FAMILY",
  "assessedValue": 35100,
  "assessedValueYear": 2026,
  "lastSaleDate": "2026-03-06",
  "lastSalePrice": 80000,
  "source": {
    "id": "allegheny-pa-assessments",
    "license": "CC0 1.0 (public domain dedication)",
    "asOf": "2026-10-30"
  }
}
```

The DC row, trimmed:

```json
{
  "input": "3100 16th St NW, Washington, DC 20010",
  "status": "MATCHED",
  "parcelId": "2595    1048",
  "bedrooms": 3,
  "bathrooms": 2.5,
  "livingAreaSqft": 2016,
  "yearBuilt": 1978,
  "units": 2,
  "propertyUse": "Residential-Flats (2 Units)",
  "assessedValue": 995590,
  "lastSaleDate": "2021-12-08",
  "source": {
    "id": "dc-otr-itspe-cama",
    "license": "CC BY 4.0"
  }
}
```

### More inputs to try

Out-of-state owners of Pittsburgh residential property sold since August, skipping $1 deed transfers:

```json
{
    "mode": "leads",
    "jurisdiction": "ALLEGHENY_PA",
    "towns": ["Pittsburgh"],
    "outOfStateOnly": true,
    "saleDateFrom": "2026-08-01",
    "minSalePrice": 1000,
    "propertyTypes": ["Residential"]
}
```

Property owner lookup for a Pittsburgh and a San Francisco address:

```json
{
    "mode": "lookup",
    "addresses": ["7224 Upland St, Pittsburgh, PA 15208", "246 2nd Street #1102, San Francisco, CA 94105"]
}
```

Absentee owners in Danbury CT who bought this year:

```json
{
    "mode": "leads",
    "jurisdiction": "CT",
    "towns": ["Danbury"],
    "absenteeOnly": true,
    "saleDateFrom": "2026-01-01",
    "maxResults": 100
}
```

### How it works

- **List mode:** queries the official dataset for your area with your filters, compares the owner mailing address to the property address (`absentee`) and the mailing state (`outOfStateOwner`), drops duplicate parcels and stops at `maxResults` or your maximum charge per run.
- **Lookup mode:** normalizes the address (USPS suffixes, directions, units), finds the county with the free US Census Bureau geocoder, routes it to that county's open-data adapter, then matches the parcel by house number + street + unit + city/ZIP with a 0-1 confidence score. Below `minConfidence` → `NOT_FOUND`; two equally good parcels → `AMBIGUOUS` with the candidates listed. One row per input address, in input order.

### Sample output (list mode, CT)

```json
{
    "jurisdiction": "CT",
    "parcelId": "34-A06001",
    "sourceAddress": "MILLTOWN RD",
    "siteCity": "Danbury",
    "siteZip": "06810",
    "propertyUse": "Residential",
    "lastSaleDate": "2026-01-20",
    "lastSalePrice": 304100,
    "saleType": "QUALIFIED",
    "ownerName": "(owner name as recorded by the town)",
    "mailingAddress": "11 CLARK PLACE",
    "mailingCity": "MAHOPAC",
    "mailingState": "NY",
    "mailingZip": "10541",
    "absentee": true,
    "outOfStateOwner": true,
    "bedrooms": 1,
    "bathrooms": 1,
    "livingAreaSqft": 580,
    "lotSizeAcres": 2.01,
    "yearBuilt": 1940,
    "assessedValue": 156590,
    "assessedValueYear": 2025,
    "marketValue": 223700,
    "source": {
        "id": "ct-statewide-cama",
        "publisher": "State of Connecticut, Office of Policy and Management (data.ct.gov)",
        "license": "Connecticut Open Data (CGS §4-67o: no restrictions on use)"
    }
}
```

### Sample output (lookup)

```json
{
    "input": "135 Longvue Drive, Pittsburgh, PA 15237",
    "status": "MATCHED",
    "matchConfidence": 1,
    "normalizedAddress": "135 LONGVUE DR, PITTSBURGH, PA 15237",
    "county": "Allegheny County",
    "parcelId": "0430F00021000000",
    "bedrooms": 3,
    "bathrooms": 1.5,
    "livingAreaSqft": 1114,
    "lotSizeSqft": 21080,
    "lotSizeAcres": 0.4839,
    "yearBuilt": 1950,
    "propertyUse": "SINGLE FAMILY",
    "assessedValue": 129000,
    "assessedValueYear": 2026,
    "lastSaleDate": "1999-09-17",
    "lastSalePrice": 72500,
    "matchReasons": ["house number exact", "street name exact", "zip"],
    "source": {
        "id": "allegheny-pa-assessments",
        "publisher": "Allegheny County Office of Property Assessments via WPRDC (data.wprdc.org)",
        "license": "CC0 1.0 (public domain dedication)",
        "asOf": "2026-09-30"
    }
}
```

Leads rows add `ownerName` (CT, DC) or `ownerType` (Allegheny), `mailingAddress/City/State/Zip`, `absentee`, `outOfStateOwner`, `lastSaleDate`, `lastSalePrice` and the site address.

### Fields

| Field                                                                                                                       | Notes                                                                                               |
| --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `status`                                                                                                                    | `MATCHED`, `NOT_FOUND`, `AMBIGUOUS`, `UNSUPPORTED_COUNTY`, `ADDRESS_NOT_RECOGNIZED`, `SOURCE_ERROR` |
| `matchConfidence`                                                                                                           | 0-1. 1 = exact number, street and locality                                                          |
| `parcelId`                                                                                                                  | The county's own parcel / PID / SSL / block-lot                                                     |
| `bedrooms`, `bathrooms` (+ full/half), `livingAreaSqft`, `lotSizeSqft`, `lotSizeAcres`, `yearBuilt`, `units`, `propertyUse` | As recorded by the assessor; `null` when the source has no value                                    |
| `assessedValue`, `assessedValueYear`, `marketValue`                                                                         | CT assessed value is 70% of market by law; other places publish their own basis                     |
| `lastSaleDate`, `lastSalePrice`                                                                                             | Where the source publishes them                                                                     |
| `source`                                                                                                                    | Dataset, publisher, licence, licence URL, attribution, update cadence and **as-of date**            |
| `errorCode`, `errorMessage`, `candidates`                                                                                   | Why a row was not matched, and the nearest parcels                                                  |

What each source has: beds/baths in Allegheny, SF, CT and DC (condo units in DC included). Allegheny lists give owner *type* (not names); CT and DC lists include owner names. San Francisco has no owner mailing address, so it has no list mode.

### Pricing (pay per event)

| Event                                      | Price                     |
| ------------------------------------------ | ------------------------- |
| `property-lookup`: one **matched** address | **$0.008** ($8 per 1,000) |
| `lead-row`: one list-mode row              | **$0.02** ($20 per 1,000) |
| Actor start                                | $0.00005                  |

Unmatched, ambiguous, unsupported and unreadable addresses are **free**. Duplicate addresses in one run are looked up once. The run stops cleanly at your *maximum charge per run* (`CHARGE_LIMIT_REACHED`) and never charges past it. Example: 1,000 addresses with 850 matches cost $6.80.

### Error codes

| Code                                                                                    | Meaning                                                       | Charged? |
| --------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------- |
| `UNSUPPORTED_COUNTY`                                                                    | Address is outside the covered areas                          | No       |
| `NOT_FOUND`                                                                             | Covered county, but no parcel scored above `minConfidence`    | No       |
| `AMBIGUOUS`                                                                             | Two or more parcels matched equally well (see `candidates`)   | No       |
| `ADDRESS_NOT_RECOGNIZED`                                                                | No house number / street / city could be read                 | No       |
| `SOURCE_ERROR`                                                                          | The public data service failed after retries; try again later | No       |
| Run-level: `INVALID_INPUT`, `CHARGE_LIMIT_REACHED`, `MAX_RESULTS_REACHED`, `NO_RESULTS` | Shown in the status message and the `SUMMARY` record          | —        |

### Data sources, freshness and terms

| Area          | Dataset                                                                                                | Licence                                           | Refresh                                      |
| ------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------- | -------------------------------------------- |
| Allegheny PA  | [WPRDC Property Assessments](https://data.wprdc.org/dataset/property-assessments)                      | CC0                                               | Monthly                                      |
| San Francisco | [Assessor Secured Property Tax Rolls](https://data.sf.gov/d/wv5m-vpq2)                                 | PDDL 1.0                                          | Annual closed roll                           |
| Connecticut   | [CT OPM CAMA and Parcel Layer](https://data.ct.gov/d/ibe8-9i3q)                                        | CT Open Data, CGS §4-67o                          | Annual grand list; sale data per town varies |
| Washington DC | [OTR ITS Public Extract + CAMA](https://opendata.dc.gov/datasets/integrated-tax-system-public-extract) | CC BY 4.0 (Source: Office of Tax and Revenue, DC) | Daily / periodic                             |
| County lookup | [US Census Geocoder](https://geocoding.geo.census.gov/)                                                | US federal public data                            | —                                            |

Assessor data is a tax record, not a listing: beds and baths may be missing or out of date after renovations, and condos may be recorded per building or per unit. Always check `source.asOf`. This Actor does **no skip tracing** and never looks up owner phone numbers or emails. If you contact owners, follow the TCPA, CAN-SPAM, Do-Not-Call and state rules that apply to you.

### FAQ

**Why not nationwide?** Most counties either don't publish beds/baths as open data or restrict commercial reuse. We only add sources whose terms clearly allow it.
**Why did a valid address come back NOT_FOUND?** It may be a government or exempt building missing from the roll, a new build, or written differently on the roll. Turn on `includeCandidates` to see the nearest parcels.
**Do I pay for errors?** No. Only `MATCHED` lookups and delivered list rows are charged.
**How fresh are CT sales?** Each town reports on its own schedule. Some towns' 2026 sales stop months earlier than others; a narrow recent date range can return `NO_RESULTS`.
**Can I use the data commercially?** All four sources are open data that allow commercial reuse; DC requires attribution (included in every record's `source.attribution`).

### Other Actors by Haniel

- [Rent Roll to Excel: Yardi, AppFolio & RealPage Normalizer](https://apify.com/hanielazevedo/rent-roll-normalizer): Normalize Yardi, AppFolio, RealPage, Entrata and Buildium rent rolls (XLSX, CSV, PDF) into one validated Excel with occupancy and loss-to-lease. $0.02 per unit.
- [Floor Plan Takeoff: PDF Room Areas, Wall LF & Door Counts](https://apify.com/hanielazevedo/floor-plan-takeoff): Construction takeoff from vector floor-plan PDFs: room square footage, wall linear feet and door counts, with a scale self-check. $2.50 per sheet.
- [Insurance Loss Run Extractor: Loss Run PDF to Excel & CSV](https://apify.com/hanielazevedo/insurance-loss-run-extractor): Extract claims and policy-year totals from carrier loss run PDFs into Excel, CSV and JSON, each row checked against the report totals. $0.04 per validated claim.
- [PDF to Markdown Converter & PDF Text Extractor (OCR, DOCX)](https://apify.com/hanielazevedo/document-to-markdown-ocr): PDF, scanned PDF, DOCX, HTML and images to clean Markdown or text for RAG and AI agents. $3 per 1,000 documents.

# Actor input Schema

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

<b>lookup</b>: property facts for your list of addresses ($0.008 per matched address; unmatched, ambiguous and unsupported addresses are free). <b>leads</b>: a list of properties with absentee owners and/or recent sales from the public assessor record ($0.02 per row).

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

One US street address per line, with city and state (ZIP helps). Units: <code>Apt 4</code>, <code>Unit 4</code> or <code>#4</code>. Covered: Connecticut (all 169 towns), Allegheny County PA (Pittsburgh), Washington DC, San Francisco CA. Other addresses come back as <code>UNSUPPORTED_COUNTY</code> and are free. Up to 10,000 per run.

## `minConfidence` (type: `number`):

Address-to-parcel match score (0.5-1) needed to return a record. Below it the address is <code>NOT_FOUND</code> (free). 0.75 accepts suffix/abbreviation differences; 0.95 needs near-exact addresses.

## `includeCandidates` (type: `boolean`):

Add the closest parcels (ID, county address, score) to NOT_FOUND rows, to help fix addresses. AMBIGUOUS rows always list them.

## `maxConcurrency` (type: `integer`):

Addresses looked up at once (1-10). Kept low out of courtesy to the public open-data services.

## `jurisdiction` (type: `string`):

Where to build the list. San Francisco is not offered: its open data has no owner mailing address.

## `towns` (type: `array`):

Connecticut: 1-25 town names (required), e.g. <code>Hartford</code>. Allegheny: municipality names, e.g. <code>Pittsburgh</code>, <code>Mt. Lebanon</code> (empty = whole county). DC: wards, e.g. <code>Ward 3</code> (empty = whole city).

## `absenteeOnly` (type: `boolean`):

Keep only properties whose owner mailing address differs from the property address (as recorded by the assessor).

## `outOfStateOnly` (type: `boolean`):

Keep only owners whose mailing address is in another state.

## `saleDateFrom` (type: `string`):

Last recorded sale on or after this date (YYYY-MM-DD).

## `saleDateTo` (type: `string`):

Last recorded sale on or before this date (YYYY-MM-DD).

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

Skip nominal transfers (e.g. $1 deeds) by setting e.g. 1000.

## `propertyTypes` (type: `array`):

Case-insensitive words matched against the assessor's use / class text, e.g. <code>Residential</code>, <code>Condo</code>, <code>Single Family</code>, <code>Vacant</code>.

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

Leads mode: maximum list rows (default 100, max 50,000). Lookup mode: maximum addresses processed. The run also stops at your maximum charge per run.

## Actor input object example

```json
{
  "mode": "lookup",
  "addresses": [
    "3100 16th St NW, Washington, DC 20010"
  ],
  "minConfidence": 0.75,
  "includeCandidates": false,
  "maxConcurrency": 4,
  "absenteeOnly": true,
  "outOfStateOnly": false
}
```

# Actor output Schema

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

No description

## `summary` (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 = {
    "addresses": [
        "3100 16th St NW, Washington, DC 20010",
        "7224 Upland St, Pittsburgh, PA 15208"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("hanielazevedo/property-details-by-address").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": [
        "3100 16th St NW, Washington, DC 20010",
        "7224 Upland St, Pittsburgh, PA 15208",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("hanielazevedo/property-details-by-address").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": [
    "3100 16th St NW, Washington, DC 20010",
    "7224 Upland St, Pittsburgh, PA 15208"
  ]
}' |
apify call hanielazevedo/property-details-by-address --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hanielazevedo/property-details-by-address"
        }
    }
}
```

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/SykZue7CnTMZIFDVS/builds/DU4tdSzq9IffXUGiz/openapi.json
