# Texas County Appraisal Records - Owner, Address & Value Search (`j0401/tx-county-appraisal`) Actor

Texas county appraisal-district property rolls - Harris (Houston), Dallas, Tarrant (Fort Worth) and Travis (Austin): owner name and mailing address, situs address, land/improvement/total values, year built, exemptions. Free public data. Search by owner, city, ZIP, class or value.

- **URL**: https://apify.com/j0401/tx-county-appraisal.md
- **Developed by:** [Wenhao Yang](https://apify.com/j0401) (community)
- **Stats:** 2 total users, 1 monthly users, 57.1% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.03 / 1,000 texas appraisal 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

## Texas County Appraisal Records - Owner, Address & Value Search

Every Texas county has an **appraisal district** that values all taxable property and publishes its **certified roll as a free public bulk download**. This actor turns those rolls into a **charged-per-record lookup and screening tool** for the four largest counties - **Harris (Houston), Dallas, Tarrant (Fort Worth) and Travis (Austin)** - selected with the `county` input.

Each record carries the **owner name and mailing address**, the **situs (property) address**, the **land / improvement / total / assessed values**, the **year built**, the **legal description**, the **neighborhood code**, the **class code** and the **exemptions** - wherever that county publishes it.

**Built for:** real-estate due diligence, title and ownership research, absentee-owner and farm-and-ranch identification, exemption and homestead screening, comparable-value analysis, and county-wide value/ownership analytics.

### What it covers

**4,353,771 parcels across four counties** (free public data; each refreshed by the county):

| County | District | Parcels |
|---|---|---|
| Harris (Houston) | HCAD | 1,628,377 |
| Dallas | DCAD | 827,412 |
| Tarrant (Fort Worth) | TAD | 1,404,658 |
| Travis (Austin) | TCAD | 493,324 |

Fields are the **union** across counties - every request returns the same schema, with a field left empty where a county does not publish it:

| Field | Harris | Dallas | Tarrant | Travis |
|---|---|---|---|---|
| Owner name + mailing address | yes | yes | yes | yes |
| Situs address / city / ZIP | yes | yes | yes (address/city ~55%, ZIP ~48% in source) | yes (city often blank in source) |
| Land / improvement / total value | yes | yes | yes | yes |
| Assessed value | yes | - | yes | yes |
| Year built | yes | yes | yes | yes |
| Legal description | yes | yes | yes | yes |
| Neighborhood code | yes | yes | yes | yes |
| School district | yes | yes | - | - |
| Exemptions | - | yes | yes | yes |

### Typical questions

- "Who **owns** this parcel, and at what **mailing address**?"
- "Show every parcel on **Lamar Blvd in Austin** valued over $10 million."
- "Find **homestead-exempt** homes built after 2015 in Dallas."
- "Which **owners** hold property in Fort Worth?"
- "How are Harris County parcels **distributed by city, class and value**?"

### Inputs

| Input | What it does |
|---|---|
| `county` | which appraisal roll - `harris` / `dallas` / `tarrant` / `travis` (default `harris`) |
| `accountNumber` | exact account / parcel number (leading zeros ignored) -> that parcel |
| `ownerName` | owner name substring, case-insensitive |
| `city` / `zipCode` | situs location |
| `propertyType` | coarse class label (Residential, Commercial, Vacant Land, Mineral, ) or the raw class code |
| `schoolDistrict` | school district substring (Harris and Dallas) |
| `stateClass` | the county's raw class code, exact (`A1`, `F1`, `C1`, `RES`, `COM`, `R` ) |
| `yearBuiltFrom` / `yearBuiltTo` | build-year window (only returns parcels that record a year) |
| `valueMin` / `valueMax` | total-value range |
| `hasExemption` | only parcels with (or without) a recorded exemption |
| `aggregate` / `groupBy` | one summary row per group - city / ZIP / property type / year built |
| `maxResults` | cap records (default 200). The `aggregate` mode returns every group in full and is **not** cut by this cap. |

**Default run = a tiny aggregate** (property-type mix for Harris) - fast and safe for the daily auto-test, never a surprise full dump.

### Example inputs

**Look up one parcel** (Harris) -

```json
{ "county": "harris", "accountNumber": "0010020000001" }
```

**Owners named Leonard in Dallas** -

```json
{ "county": "dallas", "ownerName": "LEONARD", "maxResults": 10 }
```

**Fort Worth parcels valued at $500,000 or more** -

```json
{ "county": "tarrant", "city": "FORT WORTH", "valueMin": 500000, "maxResults": 10 }
```

**The property-type mix** (Tarrant) -

```json
{ "county": "tarrant", "aggregate": true, "groupBy": "propertyType", "maxResults": 10 }
```

### Low cost

**From $0.00005 per record, down to $0.00003 at Gold** - billed only for the rows you use, and each record is metered individually.

None of these rolls has a query server behind it: HCAD is a **212 MB zip**, DCAD a **198 MB zip of 18 cross-referenced CSVs**, TAD a **748 MB zip** whose main table is a **13.9 GB fixed-width file**, TCAD a **557 MB zip** of the same fixed-width family. There is no way to ask a county for "just the Lamar Blvd parcels over $10M". Rather than make every lookup pay for a multi-gigabyte download, each roll is **mirrored and normalized once**, and a run streams only its county's shard through the filter in a single pass. Every mirror is **integrity-checked** (parcel-count floor, key-column coverage, class vocabulary), so a degraded or restructured source **fails loudly** instead of returning bad rows.

### Example output

**`county=harris`, `accountNumber=0010020000001`**:

```json
{
 "platform": "tx-county-appraisal",
 "source": "tx-county-appraisal",
 "state": "TX",
 "county": "Harris",
 "accountNumber": "0010020000001",
 "propertyType": "Commercial/Industrial",
 "stateClass": "F1",
 "ownerName": "CURRENT OWNER",
 "ownerAddress": "510 BERING DR STE 680",
 "ownerCity": "HOUSTON",
 "ownerState": "TX",
 "ownerZip": "77057",
 "situsAddress": "907 COMMERCE ST",
 "situsCity": "HOUSTON",
 "situsZip": "77002",
 "landValue": "300060",
 "improvementValue": "10105",
 "totalValue": "310165",
 "assessedValue": "310165",
 "yearBuilt": "",
 "legalDescription": "TR 15 BLK 2 SSBB",
 "neighborhoodCode": "5900.05",
 "schoolDistrict": "01",
 "exemptions": "",
 "refreshed": "2026-10-13",
 "mode": "record",
 "groupKey": "",
 "groupCount": "",
 "groupBy": ""
}
```

**`county=tarrant`, `aggregate=true`, `groupBy=situsCity`** (top):

```
(blank)         627,610
FORT WORTH      337,332
ARLINGTON       122,880
```

> The blank group is real: Tarrant's mineral and personal-property accounts carry no
> situs city.

### Source

- Harris County Appraisal District (HCAD) - `hcad.org` public data downloads.
- Dallas Central Appraisal District (DCAD) - `dallascad.org` data products.
- Tarrant Appraisal District (TAD) - `tad.org` data download.
- Travis Central Appraisal District (TCAD) - `traviscad.org` public information.

All four are official free public datasets published by the county appraisal districts themselves.

# Actor input Schema

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

Which county appraisal roll to query. Blank = harris. harris = Harris County (Houston, HCAD) ~1.63M parcels; dallas = Dallas County (DCAD) ~827k; tarrant = Tarrant County (Fort Worth, TAD) ~1.40M; travis = Travis County (Austin, TCAD).

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

lookup = one account number. aggregate = one row per group. Leave blank to auto-route: a bare accountNumber -> lookup, otherwise search (or aggregate when aggregate=true).

## `accountNumber` (type: `string`):

Exact account number (leading zeros ignored). Harris: e.g. "0010020000001"; Dallas: "65076543010030300"; Tarrant/Travis: the property id, e.g. "51".

## `ownerName` (type: `string`):

Owner name substring, case-insensitive (e.g. "HOUSTON", "SMITH").

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

Property city substring, case-insensitive (e.g. "HOUSTON", "DALLAS", "FORT WORTH").

## `zipCode` (type: `string`):

Property ZIP prefix, digits only (e.g. "77002", "75201").

## `propertyType` (type: `string`):

Coarse property classification, substring match. Values are derived from each county's own class code: Residential, Commercial, Multi-Family, Vacant Land, Qualified Open-Space, Commercial/Industrial, Special/Exempt, Mineral, Personal, Mobile Home. You may also pass the raw class code (e.g. "A1", "F1", "RES", "COM", "R").

## `schoolDistrict` (type: `string`):

School district substring (Harris and Dallas only, e.g. "DALLAS ISD", "GARLAND ISD"). Tarrant and Travis do not publish this field, so this filter is rejected there.

## `stateClass` (type: `string`):

The county's raw class code, exact match: Harris state class (e.g. "A1", "F1", "C1"), Dallas division ("RES", "COM", "BPP"), Tarrant/Travis property type ("R", "P", "MN", "MH").

## `yearBuiltFrom` (type: `string`):

Earliest year built (inclusive, 4 digits). A year-built filter only returns parcels that record a year (Harris 'yr_impr', Dallas ResDetail, Tarrant/Travis improvement detail).

## `yearBuiltTo` (type: `string`):

Latest year built (inclusive, 4 digits).

## `valueMin` (type: `number`):

Lowest total appraised value (USD). A value filter only returns parcels that record a value.

## `valueMax` (type: `number`):

Highest total appraised value (USD).

## `hasExemption` (type: `boolean`):

true = only parcels with a recorded exemption; false = only parcels with none; leave unset for all. Exemption detail is available for Dallas, Tarrant and Travis.

## `aggregate` (type: `boolean`):

When on, returns one summary record per group (with a count) instead of individual parcels.

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

propertyType -> the property-type mix; situsCity -> city distribution; situsZip -> ZIP distribution; yearBuilt -> parcels by build year.

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

Cap the number of records pushed (0 = a reasonable ceiling of 200). The aggregate mode returns every group and is not cut by this cap.

## Actor input object example

```json
{
  "county": "",
  "aggregate": false,
  "groupBy": "propertyType",
  "maxResults": 200
}
```

# Actor output Schema

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

Texas county appraisal parcel records - 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/tx-county-appraisal").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/tx-county-appraisal").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/tx-county-appraisal --silent --output-dataset

```

## MCP server setup

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

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/ockmlLqxdH1O7vIoz/builds/1x6y2pjeQAs6NmyMY/openapi.json
