# County Property Records API — Owner, Tax, Assessor, Appraisal (`muhammadafzal/county-property-records-api`) Actor

Search public county assessor records by address, parcel number, or owner name. Return normalized ownership, tax, appraisal, and property data.

- **URL**: https://apify.com/muhammadafzal/county-property-records-api.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 property records

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## County Property Records API — Owner, Tax, Assessor, Appraisal

Search public county assessor parcel data by property address, parcel number, or owner name and receive one consistent JSON schema for real-estate research, lead qualification, appraisal review, and tax workflows.

This Actor queries the public ArcGIS REST services published for the selected jurisdiction. It includes built-in field mappings for Denton County, Texas and Los Angeles County, California, plus an automatic adapter for other public ArcGIS FeatureServer and MapServer parcel layers.

### What it extracts

| Group | Fields |
| --- | --- |
| Parcel identity | `recordId`, `parcelNumber`, `alternateParcelNumber`, `county`, `state` |
| Ownership | `ownerName`, `ownerMailingAddress` when the public source exposes them |
| Property | `propertyAddress`, `legalDescription`, `propertyUse`, `yearBuilt`, `squareFeet`, land area, bedrooms, bathrooms, units |
| Assessment | assessed land, improvement, and total values; appraised value; taxable value; roll year |
| Tax | `taxAmount`, `taxArea`, and `exemption` when available from the source |
| Provenance | `sourceName`, `sourceUrl`, and `retrievedAt` |

Unavailable public fields are returned as `null`, never guessed. Los Angeles County's built-in assessor roll does not publish owner names, owner mailing addresses, or tax-bill amounts through this source. Denton County's public parcel layer includes owner names and mailing fields but may not represent the newest certified roll; verify time-sensitive facts with the county office.

### When to use it

Use this Actor for public-record research, appraisal comparisons, tax-area analysis, property lead enrichment, and normalized exports across supported county GIS layers. It is especially useful when downstream code or an AI agent needs stable field names instead of county-specific abbreviations.

Do not use it as a title report, legal boundary survey, ownership certification, tax-payment confirmation, or nationwide completeness guarantee. County publication policies vary. Some counties redact owner names, publish delayed rolls, omit tax bills, or do not expose a compatible public ArcGIS layer.

### Input

| Field | Required | Description |
| --- | --- | --- |
| `source` | Yes | `dentonCountyTx`, `losAngelesCountyCa`, or `customArcgis` |
| `searchMode` | Yes | `address`, `parcelNumber`, or `ownerName` |
| `query` | Yes | Address text, parcel identifier, or owner name; 2–160 characters |
| `customLayerUrl` | For custom | Public HTTPS ArcGIS layer URL ending in `/FeatureServer/{id}` or `/MapServer/{id}` |
| `maxResults` | Yes | Result and billing cap from 1 to 500; default 25 |

#### Address search

```json
{
  "source": "dentonCountyTx",
  "searchMode": "address",
  "query": "5 WOODHAVEN CT",
  "maxResults": 10
}
```

#### Parcel-number search

```json
{
  "source": "losAngelesCountyCa",
  "searchMode": "parcelNumber",
  "query": "2004013020",
  "maxResults": 1
}
```

#### Custom public ArcGIS layer

```json
{
  "source": "customArcgis",
  "searchMode": "address",
  "query": "MAIN ST",
  "customLayerUrl": "https://example.gov/arcgis/rest/services/Parcels/FeatureServer/0",
  "maxResults": 25
}
```

The custom adapter inspects field names and aliases for common parcel, situs, owner, assessment, appraisal, tax, and building fields. If it cannot identify the field required by the selected search mode, the run stops with an actionable diagnostic and does not fabricate results.

### Output example

```json
{
  "recordId": "dentonCountyTx:R111625",
  "county": "Denton County",
  "state": "TX",
  "parcelNumber": "R111625",
  "alternateParcelNumber": "111625",
  "propertyAddress": "5 WOODHAVEN CT",
  "ownerName": "MITCHELL, JUNIOR R",
  "ownerMailingAddress": "5 WOODHAVEN CT, KRUGERVILLE, TX 76227",
  "legalDescription": "TIMBER MESA BLK C LOT 5",
  "propertyUse": "Real, Residential, Single Family",
  "yearBuilt": 1986,
  "squareFeet": 1547,
  "landAreaSqFt": 15008,
  "landAreaAcres": 0.344536,
  "assessedLandValue": 25656,
  "assessedImprovementValue": 106320,
  "assessedTotalValue": 131976,
  "appraisedValue": 131976,
  "taxableValue": null,
  "taxAmount": null,
  "taxArea": "C18, CAD, G01, S02",
  "exemption": "HS",
  "rollYear": null,
  "latitude": null,
  "longitude": null,
  "sourceName": "Denton County public parcel layer",
  "sourceUrl": "https://services.arcgis.com/9dTWrhPzuDPnUVXr/ArcGIS/rest/services/County_Parcels/FeatureServer/0",
  "retrievedAt": "2026-09-07T12:00:00.000Z"
}
```

The default dataset contains only normalized property records. `OUTPUT` in the default key-value store records whether the run returned `DATA`, a truthful `EMPTY` result, a user-input `REJECTED` diagnostic, or a source `BLOCKED`/`FAILED` diagnostic.

### Pricing

This Actor uses transparent pay-per-event pricing.

| Event | Price |
| --- | ---: |
| Search start | $0.0001 per run |
| Normalized property record | $0.002 per default-dataset item |

A 10-record run costs $0.0201 in events. A valid no-match run costs only the $0.0001 start event. `maxResults` is both a work limit and a result-charge limit. The platform may enforce a lower charge cap configured by the caller; the Actor writes and charges one result through Apify's synthetic dataset-item event, with no duplicate manual result charge.

### Reliability and limits

The Actor uses direct public ArcGIS metadata and query endpoints, bounded 30-second requests, three attempts with exponential backoff for transient failures, source pagination, record normalization, and stable-ID deduplication. HTTP access denials, upstream failures, unsupported field mappings, and honest no-match results are classified separately in `OUTPUT`.

The Actor does not bypass authentication, CAPTCHAs, paywalls, access controls, or county publication restrictions. A custom layer must allow anonymous HTTPS queries. Large wildcard exports are intentionally not offered; searches require a specific query and return at most 500 records.

### Data use and privacy

Property records may contain personal information that is lawful to access but sensitive in context. Use the data only for a legitimate purpose and follow applicable privacy, fair-housing, consumer-reporting, solicitation, and public-record laws. Do not use this Actor to make eligibility, credit, housing, employment, insurance, or other high-impact decisions without appropriate legal review and authoritative verification. Source data is informational and can be stale, incomplete, or incorrect; confirm material facts with the relevant assessor, appraisal district, or tax office.

### Support

For a failed custom layer, include the public layer URL, selected search mode, and redacted `OUTPUT` diagnostic. Do not send private tokens, cookies, or personal credentials.

# Actor input Schema

## `source` (type: `string`):

Use this to choose a built-in county source or a public ArcGIS parcel layer. Denton includes owner names; Los Angeles does not. Default: Denton County, Texas.

## `searchMode` (type: `string`):

Use this to choose how query is matched. Owner name works only when the selected public source exposes an owner field. Default: property address.

## `query` (type: `string`):

Use this for an address, parcel number, or owner name according to searchMode. Example: `5 WOODHAVEN CT`. Enter at least 2 visible characters; this is not raw SQL.

## `customLayerUrl` (type: `string`):

Use this only with customArcgis. Enter a public ArcGIS FeatureServer or MapServer layer URL ending in a numeric layer ID, for example `https://example.gov/arcgis/rest/services/Parcels/FeatureServer/0`.

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

Use this to cap normalized records and result-event charges. Accepted range: 1–500. Default: 25.

## Actor input object example

```json
{
  "source": "dentonCountyTx",
  "searchMode": "address",
  "query": "5 WOODHAVEN CT",
  "maxResults": 25
}
```

# Actor output Schema

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

Normalized owner, tax, assessor, appraisal, parcel, and property records returned by the selected public county source.

## `summary` (type: `string`):

Outcome, record count, source details, warnings, and billing notes for this run.

# 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 = {
    "query": "5 WOODHAVEN CT"
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/county-property-records-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 = { "query": "5 WOODHAVEN CT" }

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/county-property-records-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 '{
  "query": "5 WOODHAVEN CT"
}' |
apify call muhammadafzal/county-property-records-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/county-property-records-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/pX0ZoAun3WVdMjDLt/builds/gdICSsxx56AdKKoiZ/openapi.json
