US Distressed Property Scraper - Violations & Foreclosures avatar

US Distressed Property Scraper - Violations & Foreclosures

Pricing

from $1.80 / 1,000 distressed property records

Go to Apify Store
US Distressed Property Scraper - Violations & Foreclosures

US Distressed Property Scraper - Violations & Foreclosures

Scrape US distressed property leads from Socrata open data across Chicago, New York, Seattle and New Orleans. Extract building violations, vacant properties, tax sales and foreclosure records. Supports resume and incremental change tracking for ongoing property monitoring.

Pricing

from $1.80 / 1,000 distressed property records

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Share

US Distressed Property Scraper

US municipal distressed property signals in one run: building violations, vacant buildings, tax sales and foreclosures across Chicago, New York City, Seattle and New Orleans, read from Socrata open data. Pick metros or paste dataset links, and track what changed between scheduled runs.

Why This Scraper?

  • Four metros, one actor. Walk Chicago building violations, vacant buildings and Cook County tax sales; New York building, housing and ECB violations plus tax-lien sales; King County foreclosure parcels; New Orleans sheriff lien-foreclosure sales. Every record comes back normalized to one schema.
  • Signal-level rows. Each violation, lien and sale row is its own record with native identity, dates, status, parties where published, fines and balances - the same granularity distress buyers work with.
  • Open data, no walls. Every lane reads the municipalities' own public JSON APIs at a polite pace, most recent first, with an optional recency cutoff.
  • Made for recurring monitoring. Resume an interrupted run from its ID, or let incremental mode remember what you already scraped and return only NEW and UPDATED records, with EXPIRED markers when a record leaves the source.
  • Search by metro or paste links. Walk whole metros, override with any Socrata dataset id, or paste Socrata API links and let URL mode sort them out.
  • Honest by design. If a source refuses every request the run fails loudly instead of returning an empty dataset that looks like "no results". A genuine empty search says so.

Use Cases

  • Who: Investors and buyers hunting below-market property across US code-enforcement and tax-sale channels.
  • Who: Compliance and risk teams monitoring building violations and vacant stock by metro on a schedule.
  • Who: Lead-generation teams feeding distressed-property signals into CRM systems and alerting pipelines.
  • Who: Analysts comparing municipal distress volumes across Chicago, New York, Seattle and New Orleans from one dataset.

Data You Get

Sample shape: values are illustrative placeholders, not from a live record.

FieldExample
recordId"us:socrata:22u3-xenr:7000000"
country"us"
source"chicago-violations", "nyc-taxlien", "nola-sheriff" and 7 more
title"123 Sample St MAINTAIN WINDOW"
distressType"violation", "vacant", "tax-sale" or "foreclosure"
portalId"7000000"
publishedAt"2026-10-09T00:00:00.000"
auctionDate"2026-10-30T10:00:00.000"
location.address / location.city / location.region / location.zip"123 Sample St" / "Chicago" / "IL" / "60601"
streetNumber / streetName / city / state / postalCodetop-level address parts, "123" / "Sample St" / "Chicago" / "IL" / "60601"
latitude / longitude41.73 / -87.61
sourceDomain / datasetId / sourceRecordId"data.cityofchicago.org" / "22u3-xenr" / "7000000"
deadlineAtcompliance or hearing deadline where published
attachmentslinks published with the record, when the source has any
valueAmount / valueCurrency / valueText2500 / "USD" / "$2,500"
status"OPEN", "sold", "Pending"
parties[{ "role": "respondent", "name": "Sample Respondent" }]
descriptionviolation text, ordinance, sale caption
detailsdataset id, metro, coordinates, codes, inspections, fines, hearings
changeType / changedFields / firstSeenAt / lastSeenAtincremental-mode metadata
urlsource dataset API URL

How to Use

  1. Pick a Mode: search (default) walks the selected metros (or the dataset override); url reads only the links you paste. Links you paste are ignored in search mode, and the run log says so (the untouched pre-filled examples are not warned about).
  2. In search mode, pick your metros (or leave the default walk of all four) and optionally set a recency cutoff in days. In url mode, paste Socrata API links.
  3. Set Max items, then click Start.
  4. Download the dataset as JSON, CSV or Excel, or read it through the API.

Chicago walk, recent signals:

{
"mode": "search",
"metros": ["chicago"],
"sinceDays": 7,
"maxItems": 50
}

Single-dataset override:

{
"mode": "search",
"datasetDomain": "data.cityofnewyork.us",
"datasetId": "9rz4-mjek",
"maxItems": 50
}

URL mode:

{
"mode": "url",
"urls": [
"https://data.cityofchicago.org/resource/22u3-xenr.json?$limit=2&$order=:id"
],
"maxItems": 20
}
#ShapeExampleNotes
1Resource JSONhttps://data.cityofnewyork.us/resource/9rz4-mjek.json?$limit=2Reads rows from the JSON API.
2Resource JSON with $order and $offsethttps://data.cityofchicago.org/resource/22u3-xenr.json?$limit=2&$offset=2&$order=:idYour $order and $offset are honoured.
3Resource JSON with a $where filterhttps://data.cityofchicago.org/resource/22u3-xenr.json?$where=violation_date>'2026-01-01'&$limit=1Your $where is combined with the dataset's own filter.
4.gov domainhttps://datacatalog.cookcountyil.gov/resource/55ju-2fs9.json?$limit=1Any .gov Socrata domain works.
5County open-data portalhttps://data.kingcounty.gov/resource/nx4x-daw6.json?$limit=1Same API, different domain.
6City open-data portalhttps://data.nola.gov/resource/d52w-8nva.json?$limit=1Same API, different domain.
7Resource CSV formhttps://data.cityofchicago.org/resource/22u3-xenr.csv?$limit=2Read through the JSON API; rows are identical.
8Human dataset page /d/<id> (also /dataset/<name>/<id>)https://data.cityofchicago.org/d/22u3-xenrMapped to the JSON API for that dataset.
9Legacy /api/views/<id>/rows.jsonhttps://data.cityofchicago.org/api/views/22u3-xenr/rows.json?$limit=1Mapped to the JSON API; the large legacy payload is never downloaded.

A pasted $limit caps the rows read from that link. An unsupported link gets a loud warning in the run log and the remaining links continue; the run fails only when no link is usable.

Behaviour change: the URLs field now ships pre-filled with one example of each shape above as its default. In URL mode with the field untouched, the run scrapes those nine examples (capped by Max items). Search mode ignores the field, so existing search runs are unchanged. Clear the field and paste your own links to scrape something else.

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("abotapi/distressed-us-scraper").call(run_input={
"metros": ["chicago"],
"sinceDays": 7,
"maxItems": 50,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["recordId"], item["title"], item.get("valueAmount"))

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('abotapi/distressed-us-scraper').call({
metros: ['nyc'],
sinceDays: 7,
maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) console.log(item.recordId, item.title);

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

Resume and recurring updates

  • Resume (resumeFromRunId) continues one interrupted run: paste its run ID and the actor skips everything already collected there, so you don't pay twice.
  • Incremental mode (incrementalMode) is for scheduled runs over the same scope. Each record is classified NEW, UPDATED (with changedFields), UNCHANGED (suppressed and not billed unless emitUnchanged is on) or EXPIRED (only after a run that scanned the whole scope, and only with emitExpired). Use stateKey to share one baseline across slightly different filter variants, and ignoreFieldsForChanges to exclude noisy fields from the comparison. The two features are mutually exclusive; pick one per run.

Send results into your apps (MCP connectors)

Optionally send a summary of each returned record into an app connected through Apify MCP integrations. Select one or more MCP connectors and, for Notion, provide the parent page URL or ID. The actor creates a Notion page per record; other connectors receive a best-effort write or digest. Exports are capped by Max items to export per connector (50 by default), and connector failures do not change dataset output.

FieldWhat it does
mcpConnectorsSelected MCP connectors (empty = no export).
notionParentPageUrlNotion parent page URL or ID; required for Notion exports.
maxNotifyListingsMaximum records sent to each selected connector (default 50, maximum 1000).

Input Parameters

All parameters are optional unless noted.

ParameterTypeDefaultDescription
modestringsearchsearch walks the metro registers (or the dataset override); url reads only the pasted links.
metrosarrayall 4 metrosMetro registers to walk, in order: chicago, nyc, seattle, new-orleans. Search mode only.
datasetIdstring(none)Walk exactly one Socrata dataset id instead of the metro lists. Search mode only.
datasetDomainstring(none)Socrata domain for the dataset override.
sinceDaysinteger30Only rows newer than this many days ago (date-filtered sets); 0 = no cutoff.
dateFromstring(none)Absolute start of the date window on each dataset's date column. Replaces sinceDays when set. Undated datasets (King County foreclosures) ignore it.
dateTostring(none)Absolute end of the date window (inclusive). Undated datasets ignore it.
soqlWherestring(none)Raw SoQL $where clause, combined with every walked dataset's own filter, e.g. violation_status = 'OPEN'. Column names are dataset-specific, so use it with a single metro or a dataset override.
sortOrderstringnewestnewest or oldest: which end of each dataset is walked first.
maxItemsPerDatasetinteger0Stop each dataset after this many rows so one big register cannot use up Max items; 0 = no per-dataset cap.
urlsarrayone example of each of the 9 link shapesPasted Socrata links (API, CSV, dataset page, legacy rows); each is walked as its own scope. Read in url mode.
maxItemsinteger50Total result cap across all metros and links (0 = no limit; wide metros hold hundreds of thousands of rows, so set a number you are happy to pay for).
maxPagesinteger0Page cap per dataset walk; 0 = until natural end.
proxyobjectstandard poolConnection settings (see Plan Requirement).
resumeFromRunIdstring(none)Continue a previous run; only unpushed records are saved.
incrementalModebooleanfalseTrack changes across scheduled runs; only NEW/UPDATED returned. Mutually exclusive with resumeFromRunId.
stateKeystring(none)Named incremental baseline; derived from the scope when empty.
emitUnchangedbooleanfalseAlso return UNCHANGED records in incremental mode.
emitExpiredbooleanfalseAlso return EXPIRED records in incremental mode.
ignoreFieldsForChangesarray(none)Extra fields that never count as a change.
mcpConnectorsarray(none)Optional MCP connectors to receive returned record summaries after the run.
notionParentPageUrlstring(none)Parent page URL or ID required for Notion page creation.
maxNotifyListingsinteger50Maximum records sent to each connector (1-1000).

Output Example

The Output tab offers two tables: Overview (one row per record) and Changes (change type, changed fields, first and last seen, for incremental runs).

Sample shape: values are illustrative placeholders, not from a live record.

Example record (Chicago building violation):

{
"recordId": "us:socrata:22u3-xenr:7000000",
"country": "us",
"source": "chicago-violations",
"title": "123 Sample St MAINTAIN WINDOW",
"distressType": "violation",
"portalId": "7000000",
"publishedAt": "2026-10-09T00:00:00.000",
"location": { "address": "123 Sample St", "city": "Chicago", "region": "IL", "country": "US" },
"valueAmount": 2500,
"valueCurrency": "USD",
"valueText": "$2,500",
"status": "OPEN",
"description": "MAINTAIN WINDOW Failed to maintain windows in sound condition and good repair.",
"details": {
"dataset": "22u3-xenr",
"metro": "chicago",
"lat": 41.73,
"lng": -87.61,
"violation_code": "CN000000",
"inspection_number": "14000000",
"inspection_status": "FAILED"
},
"url": "https://data.cityofchicago.org/resource/22u3-xenr.json",
"raw": {}
}

Plan Requirement

The open data APIs are public and the actor reads them through the Apify datacenter connection, so the default proxy setting works on any plan that includes proxy access; no residential proxy is needed. If the default connection is refused for your account (a CONNECT-level refusal, as on free plans), the actor switches to a backup connection and logs: "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable." Pages served that way are noted in the log as "Served over the backup connection". If every connection is refused, the run fails with a message that names the cause ("The proxy connection was refused for this account ... a paid plan is required"); if the backup also cannot load the pages, it fails with "No results: residential proxies are unavailable on this run ... Upgrade ... or supply your own proxy URLs". If no page loads for any other reason, the run fails with "Could not load any results page ... This is a connection problem, not an empty search." Your own proxy URLs are used as given, with no backup. A run never reports an empty dataset when nothing could be read.

Very large unfiltered Socrata queries can be slow upstream; the actor always orders its queries and reads pages of up to 500 rows, with a per-request time limit.

FAQ

How much does it cost?

You pay per record returned plus the actor start. There is no detail-enrichment surcharge: every row ships complete from the source API. The events are the actor start and each dataset item; there are no monthly fees, and UNCHANGED records in incremental mode are suppressed and not billed unless emitUnchanged is on (then each returned record is a billed dataset item). See the Pricing tab for the current per-event prices.

These are public municipal open-data APIs published for unrestricted reuse. The actor reads the same JSON endpoints a browser or script would, at a polite pace with paging, and links every record back to its source dataset.

Can I get only new or changed records on a schedule?

Yes. Use incremental mode: the actor remembers its baseline per scope and returns only what changed (NEW, UPDATED), with optional EXPIRED markers for records that left the source. Use stateKey to share one baseline across slightly different filter variants.

Why does a run return fewer records than I expected?

Max items (50 by default) stops the run once the cap is reached, walking the selected metros in order; raise it or set it to 0 to collect everything. The recency cutoff (sinceDays) also hides older rows on date-filtered datasets; raise it or set it to 0 for the full history.

How current is each source?

Chicago violations, New York housing, building and ECB violations are updated daily. Chicago vacant buildings and New York tax-lien sales are updated a few times a year, so a short recency cutoff can return nothing for them. The Cook County tax-sale lists (last sale year 2014 and 2015) and the New Orleans sheriff lien-foreclosure sales (cases up to 2018) are historical archives their cities no longer update, and the King County foreclosure list holds parcel numbers only, with no address or date. Use a larger recency cutoff, or 0, to see them.

Why did my run fail instead of returning an empty dataset?

A source refused every request in that run, or no page could be loaded (rate limiting, an outage, or a proxy refusal; the error message says which). The run is failed loudly rather than returning an empty dataset that would look like "no results". Wait and rerun.

Can I use it with AI agents or MCP?

Yes, the run output is a clean JSON dataset that works with MCP connectors and any AI workflow. Use the mcpConnectors input to send results straight into your apps after each run.

🔗 Want more Distressed data?

Pair this actor with these related scrapers from the same team:

🧩 Distressed Property Scraper
Find mortgagee-sale and distressed-property listings in Australia and New Zealand. NZ...
🏠 Europe Distressed Property Scraper
Distressed-property leads across Europe: German ZVG foreclosure auctions, Polish KRZ...
🏠 Canada Distressed Property Scraper
Canadian tax-sale properties from taxsales.ca: tender and auction listings across 9...
🧩 Homes.com Scraper
Scrape US property records from Homes.com. Pick a city, state or ZIP and a channel (for...
🧩 Propwire Scraper
Scrape Propwire.com: 157M+ US MLS & off-market properties with owner names, mailing...
🏠 StreetEasy Scraper
Scrape StreetEasy sales, rentals and in-contract listings across NYC and Jersey City...

👉 Browse all abotapi scrapers

💬 Support

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • 🛠️ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.