# US Distressed Property Scraper - Violations & Foreclosures (`abotapi/distressed-us-scraper`) Actor

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.

- **URL**: https://apify.com/abotapi/distressed-us-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Real estate, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.80 / 1,000 distressed 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.
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

## 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.

| Field | Example |
| --- | --- |
| `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` / `postalCode` | top-level address parts, `"123"` / `"Sample St"` / `"Chicago"` / `"IL"` / `"60601"` |
| `latitude` / `longitude` | `41.73` / `-87.61` |
| `sourceDomain` / `datasetId` / `sourceRecordId` | `"data.cityofchicago.org"` / `"22u3-xenr"` / `"7000000"` |
| `deadlineAt` | compliance or hearing deadline where published |
| `attachments` | links published with the record, when the source has any |
| `valueAmount` / `valueCurrency` / `valueText` | `2500` / `"USD"` / `"$2,500"` |
| `status` | `"OPEN"`, `"sold"`, `"Pending"` |
| `parties` | `[{ "role": "respondent", "name": "Sample Respondent" }]` |
| `description` | violation text, ordinance, sale caption |
| `details` | dataset id, metro, coordinates, codes, inspections, fines, hearings |
| `changeType` / `changedFields` / `firstSeenAt` / `lastSeenAt` | incremental-mode metadata |
| `url` | source 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:**

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

**Single-dataset override:**

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

**URL mode:**

```json
{
  "mode": "url",
  "urls": [
    "https://data.cityofchicago.org/resource/22u3-xenr.json?$limit=2&$order=:id"
  ],
  "maxItems": 20
}
```

##### URL mode: supported link shapes

| # | Shape | Example | Notes |
|---|-------|---------|-------|
| 1 | Resource JSON | `https://data.cityofnewyork.us/resource/9rz4-mjek.json?$limit=2` | Reads rows from the JSON API. |
| 2 | Resource JSON with `$order` and `$offset` | `https://data.cityofchicago.org/resource/22u3-xenr.json?$limit=2&$offset=2&$order=:id` | Your `$order` and `$offset` are honoured. |
| 3 | Resource JSON with a `$where` filter | `https://data.cityofchicago.org/resource/22u3-xenr.json?$where=violation_date>'2026-01-01'&$limit=1` | Your `$where` is combined with the dataset's own filter. |
| 4 | `.gov` domain | `https://datacatalog.cookcountyil.gov/resource/55ju-2fs9.json?$limit=1` | Any `.gov` Socrata domain works. |
| 5 | County open-data portal | `https://data.kingcounty.gov/resource/nx4x-daw6.json?$limit=1` | Same API, different domain. |
| 6 | City open-data portal | `https://data.nola.gov/resource/d52w-8nva.json?$limit=1` | Same API, different domain. |
| 7 | Resource CSV form | `https://data.cityofchicago.org/resource/22u3-xenr.csv?$limit=2` | Read through the JSON API; rows are identical. |
| 8 | Human dataset page `/d/<id>` (also `/dataset/<name>/<id>`) | `https://data.cityofchicago.org/d/22u3-xenr` | Mapped to the JSON API for that dataset. |
| 9 | Legacy `/api/views/<id>/rows.json` | `https://data.cityofchicago.org/api/views/22u3-xenr/rows.json?$limit=1` | Mapped 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:**

```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:**

```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.

| Field | What it does |
|---|---|
| `mcpConnectors` | Selected MCP connectors (empty = no export). |
| `notionParentPageUrl` | Notion parent page URL or ID; required for Notion exports. |
| `maxNotifyListings` | Maximum records sent to each selected connector (default `50`, maximum `1000`). |

### Input Parameters

All parameters are optional unless noted.

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `search` | `search` walks the metro registers (or the dataset override); `url` reads only the pasted links. |
| `metros` | array | all 4 metros | Metro registers to walk, in order: `chicago`, `nyc`, `seattle`, `new-orleans`. Search mode only. |
| `datasetId` | string | (none) | Walk exactly one Socrata dataset id instead of the metro lists. Search mode only. |
| `datasetDomain` | string | (none) | Socrata domain for the dataset override. |
| `sinceDays` | integer | `30` | Only rows newer than this many days ago (date-filtered sets); `0` = no cutoff. |
| `dateFrom` | string | (none) | Absolute start of the date window on each dataset's date column. Replaces `sinceDays` when set. Undated datasets (King County foreclosures) ignore it. |
| `dateTo` | string | (none) | Absolute end of the date window (inclusive). Undated datasets ignore it. |
| `soqlWhere` | string | (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. |
| `sortOrder` | string | `newest` | `newest` or `oldest`: which end of each dataset is walked first. |
| `maxItemsPerDataset` | integer | `0` | Stop each dataset after this many rows so one big register cannot use up **Max items**; `0` = no per-dataset cap. |
| `urls` | array | one example of each of the 9 link shapes | Pasted Socrata links (API, CSV, dataset page, legacy rows); each is walked as its own scope. Read in url mode. |
| `maxItems` | integer | `50` | Total 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). |
| `maxPages` | integer | `0` | Page cap per dataset walk; `0` = until natural end. |
| `proxy` | object | standard pool | Connection settings (see Plan Requirement). |
| `resumeFromRunId` | string | (none) | Continue a previous run; only unpushed records are saved. |
| `incrementalMode` | boolean | `false` | Track changes across scheduled runs; only NEW/UPDATED returned. Mutually exclusive with `resumeFromRunId`. |
| `stateKey` | string | (none) | Named incremental baseline; derived from the scope when empty. |
| `emitUnchanged` | boolean | `false` | Also return UNCHANGED records in incremental mode. |
| `emitExpired` | boolean | `false` | Also return EXPIRED records in incremental mode. |
| `ignoreFieldsForChanges` | array | (none) | Extra fields that never count as a change. |
| `mcpConnectors` | array | (none) | Optional MCP connectors to receive returned record summaries after the run. |
| `notionParentPageUrl` | string | (none) | Parent page URL or ID required for Notion page creation. |
| `maxNotifyListings` | integer | `50` | Maximum 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):**

```json
{
  "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.

#### Is it legal to scrape this data?

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:

<table>
<tr><td>🧩 <a href="https://apify.com/abotapi/distressed-au-nz-scraper"><b>Distressed Property Scraper</b></a><br>Find mortgagee-sale and distressed-property listings in Australia and New Zealand. NZ...</td><td>🏠 <a href="https://apify.com/abotapi/distressed-eu-scraper"><b>Europe Distressed Property Scraper</b></a><br>Distressed-property leads across Europe: German ZVG foreclosure auctions, Polish KRZ...</td></tr>
<tr><td>🏠 <a href="https://apify.com/abotapi/distressed-ca-scraper"><b>Canada Distressed Property Scraper</b></a><br>Canadian tax-sale properties from taxsales.ca: tender and auction listings across 9...</td><td>🧩 <a href="https://apify.com/abotapi/homes-com-scraper"><b>Homes.com Scraper</b></a><br>Scrape US property records from Homes.com. Pick a city, state or ZIP and a channel (for...</td></tr>
<tr><td>🧩 <a href="https://apify.com/abotapi/propwire-property-leads-scraper"><b>Propwire Scraper</b></a><br>Scrape Propwire.com: 157M+ US MLS &amp; off-market properties with owner names, mailing...</td><td>🏠 <a href="https://apify.com/abotapi/streeteasy-scraper"><b>StreetEasy Scraper</b></a><br>Scrape StreetEasy sales, rentals and in-contract listings across NYC and Jersey City...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/distressed-us-scraper/issues/open). 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.

# Actor input Schema

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

How to discover records. 'search' walks the selected metros (or the dataset override) with your filters. 'url' reads only the links you paste into urls. Pasted links are ignored in search mode; the run log tells you when that happens.

## `metros` (type: `array`):

Which metro registers to walk, in order. Chicago = building violations, vacant buildings and Cook County tax sales. NYC = building, housing and ECB violations plus tax-lien sales. Seattle = King County foreclosure parcels. New Orleans = sheriff lien-foreclosure sales. Empty = all four metros.

## `datasetId` (type: `string`):

Walk exactly one Socrata dataset id (e.g. 22u3-xenr) instead of the metro lists. Pair with Dataset domain when it lives outside New York.

## `datasetDomain` (type: `string`):

Socrata domain for the dataset override, e.g. data.cityofchicago.org.

## `sinceDays` (type: `integer`):

Date-filtered datasets return only rows newer than this many days ago. 0 = no cutoff (walk from the newest row). Small sets (foreclosures, tax sales) ignore fine cutoffs and walk whole.

## `soqlWhere` (type: `string`):

Optional raw SoQL $where clause, ANDed with every walked dataset's own filter, e.g. violation_status = 'OPEN'. Column names are dataset-specific, so with several metros pick a dataset override or a single metro.

## `dateFrom` (type: `string`):

Absolute start of the date window on each dataset's date column. Replaces 'newer than N days' when set. Undated datasets (King County foreclosures) ignore it.

## `dateTo` (type: `string`):

Absolute end of the date window (inclusive). Undated datasets ignore it.

## `sortOrder` (type: `string`):

Which end of each dataset to walk first: newest rows first (default) or oldest rows first.

## `maxItemsPerDataset` (type: `integer`):

Stop each dataset after this many rows, so one big register cannot use up Max items. 0 = no per-dataset cap.

## `urls` (type: `array`):

Pasted Socrata links: the API resource (https://<domain>/resource/<id>.json or .csv), the dataset page (/d/<id>, /dataset/<name>/<id>) or the legacy /api/views/<id>/rows.json. Pasted $order, $where, $offset and $limit are honoured. Each link is walked as its own scope. Read in url mode only. The field is pre-filled with one example of every supported shape, so URL mode with the field untouched scrapes those examples.

## `maxItems` (type: `integer`):

Stop after this many results total across all metros. Default 50; 0 = no limit (a wide metro can hold hundreds of thousands of rows, so set a number you are happy to pay for).

## `maxPages` (type: `integer`):

Stop each dataset walk after this many API pages. 0 = walk until the natural end. Max items always applies too.

## `proxy` (type: `object`):

Connection used for requests. The open data API serves the standard pool; residential exits are used automatically when selected.

## `resumeFromRunId` (type: `string`):

Continue a previous run: only records not already in that run’s dataset are pushed. Leave empty for a fresh run.

## `incrementalMode` (type: `boolean`):

Track records across scheduled runs with the same scope: only NEW or UPDATED records are returned (UNCHANGED suppressed), and records that disappear are marked EXPIRED. Mutually exclusive with Resume.

## `emitUnchanged` (type: `boolean`):

In incremental mode, also return records that did not change (marked UNCHANGED).

## `emitExpired` (type: `boolean`):

In incremental mode, also return records seen previously that no longer appear (marked EXPIRED).

## `stateKey` (type: `string`):

Name for the incremental baseline when you want to share one baseline across different filter variants. Leave empty to derive it from the scope automatically.

## `ignoreFieldsForChanges` (type: `array`):

Advanced: record fields that should never count as a change (in addition to the built-in ignore list). Example: \["status"].

## `mcpConnectors` (type: `array`):

Optionally send a summary of each returned property to connected apps. Authorize a connector under Apify > Settings > Integrations, then select it here. Notion creates a page per record; other connectors receive a best-effort write or digest. Leave empty to skip. Dataset results are unaffected.

## `notionParentPageUrl` (type: `string`):

URL or ID of the Notion page where record pages should be created. Required for Notion; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Maximum number of records written to each connector. Does not affect dataset output.

## Actor input object example

```json
{
  "mode": "search",
  "metros": [
    "chicago"
  ],
  "sinceDays": 30,
  "sortOrder": "newest",
  "maxItemsPerDataset": 0,
  "urls": [
    "https://data.cityofnewyork.us/resource/9rz4-mjek.json?$limit=2",
    "https://data.cityofchicago.org/resource/22u3-xenr.json?$limit=2&$offset=2&$order=:id",
    "https://data.cityofchicago.org/resource/22u3-xenr.json?$where=violation_date>'2026-01-01'&$limit=1",
    "https://datacatalog.cookcountyil.gov/resource/55ju-2fs9.json?$limit=1",
    "https://data.kingcounty.gov/resource/nx4x-daw6.json?$limit=1",
    "https://data.nola.gov/resource/d52w-8nva.json?$limit=1",
    "https://data.cityofchicago.org/resource/22u3-xenr.csv?$limit=2",
    "https://data.cityofchicago.org/d/22u3-xenr",
    "https://data.cityofchicago.org/api/views/22u3-xenr/rows.json?$limit=1"
  ],
  "maxItems": 20,
  "proxy": {
    "useApifyProxy": true
  },
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `changes` (type: `string`):

No description

## `overview` (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 = {
    "mode": "search",
    "metros": [
        "chicago"
    ],
    "sinceDays": 30,
    "maxItemsPerDataset": 0,
    "urls": [
        "https://data.cityofnewyork.us/resource/9rz4-mjek.json?$limit=2",
        "https://data.cityofchicago.org/resource/22u3-xenr.json?$limit=2&$offset=2&$order=:id",
        "https://data.cityofchicago.org/resource/22u3-xenr.json?$where=violation_date>'2026-01-01'&$limit=1",
        "https://datacatalog.cookcountyil.gov/resource/55ju-2fs9.json?$limit=1",
        "https://data.kingcounty.gov/resource/nx4x-daw6.json?$limit=1",
        "https://data.nola.gov/resource/d52w-8nva.json?$limit=1",
        "https://data.cityofchicago.org/resource/22u3-xenr.csv?$limit=2",
        "https://data.cityofchicago.org/d/22u3-xenr",
        "https://data.cityofchicago.org/api/views/22u3-xenr/rows.json?$limit=1"
    ],
    "maxItems": 20,
    "maxPages": 0,
    "proxy": {
        "useApifyProxy": true
    },
    "incrementalMode": false,
    "emitUnchanged": false,
    "emitExpired": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/distressed-us-scraper").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": "search",
    "metros": ["chicago"],
    "sinceDays": 30,
    "maxItemsPerDataset": 0,
    "urls": [
        "https://data.cityofnewyork.us/resource/9rz4-mjek.json?$limit=2",
        "https://data.cityofchicago.org/resource/22u3-xenr.json?$limit=2&$offset=2&$order=:id",
        "https://data.cityofchicago.org/resource/22u3-xenr.json?$where=violation_date>'2026-01-01'&$limit=1",
        "https://datacatalog.cookcountyil.gov/resource/55ju-2fs9.json?$limit=1",
        "https://data.kingcounty.gov/resource/nx4x-daw6.json?$limit=1",
        "https://data.nola.gov/resource/d52w-8nva.json?$limit=1",
        "https://data.cityofchicago.org/resource/22u3-xenr.csv?$limit=2",
        "https://data.cityofchicago.org/d/22u3-xenr",
        "https://data.cityofchicago.org/api/views/22u3-xenr/rows.json?$limit=1",
    ],
    "maxItems": 20,
    "maxPages": 0,
    "proxy": { "useApifyProxy": True },
    "incrementalMode": False,
    "emitUnchanged": False,
    "emitExpired": False,
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/distressed-us-scraper").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 '{
  "mode": "search",
  "metros": [
    "chicago"
  ],
  "sinceDays": 30,
  "maxItemsPerDataset": 0,
  "urls": [
    "https://data.cityofnewyork.us/resource/9rz4-mjek.json?$limit=2",
    "https://data.cityofchicago.org/resource/22u3-xenr.json?$limit=2&$offset=2&$order=:id",
    "https://data.cityofchicago.org/resource/22u3-xenr.json?$where=violation_date>'\''2026-01-01'\''&$limit=1",
    "https://datacatalog.cookcountyil.gov/resource/55ju-2fs9.json?$limit=1",
    "https://data.kingcounty.gov/resource/nx4x-daw6.json?$limit=1",
    "https://data.nola.gov/resource/d52w-8nva.json?$limit=1",
    "https://data.cityofchicago.org/resource/22u3-xenr.csv?$limit=2",
    "https://data.cityofchicago.org/d/22u3-xenr",
    "https://data.cityofchicago.org/api/views/22u3-xenr/rows.json?$limit=1"
  ],
  "maxItems": 20,
  "maxPages": 0,
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false
}' |
apify call abotapi/distressed-us-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/distressed-us-scraper"
        }
    }
}
```

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/XUAGkBYD4rHCsrEcS/builds/mj79No19JYOPZNpme/openapi.json
