# Redfin Scraper - MLS Property Listings, Rentals, Market Stats (`snow_leo_data/redfin-scraper`) Actor

Redfin scraper with no pagination needed: 5876 Austin listings in one request where Redfin's own Download All export stops at 350. An unknown region answers HTTP 200 with homes in Seattle, so the state and ZIP of every row are checked against your address. Redfin property data, rentals.

- **URL**: https://apify.com/snow\_leo\_data/redfin-scraper.md
- **Developed by:** [Snow Leo Data](https://apify.com/snow_leo_data) (community)
- **Categories:** Real estate, Lead generation, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.90 / 1,000 listings

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

## Redfin Scraper: listings, rentals, property cards and market stats

Scrape Redfin by city, county, neighborhood or ZIP code and get one flat table:
price, beds, baths, living area, lot, year built, status, days on market, MLS
number, MLS description, agent, coordinates and the listing URL. Add the
property card and the same row also carries the parcel number, county tax rate,
schools, climate risk, walk and transit scores, building permits, zoning and the
MLS feature list. No proxy, no browser, no API key.

Every number on this page comes from a run you can repeat. Where a number came
from a specific Apify run, the run id is printed next to it.

#### One request returns the whole region, not one page

Redfin's search endpoint has no pagination at all. `page_number=2` returns the
first page byte for byte — checked in `tests/test_live.py`, which compares the
property ids of both responses. The only lever that changes the answer is how
many listings you ask for, and it goes far past what the website offers:

| What | Listings |
|---|---|
| Redfin's own **Download All** CSV export | **350** (asking for more returns an 86-byte error) |
| Redfin's website search pages | 9 pages |
| This Actor, one request, Austin TX | **5,876** (run `RwMCBkbuydliUVLHl`) |

Austin's whole for-sale inventory arrived in a single HTTP response and 5,876
rows were written in 11.7 seconds. That is **16.8 times** the ceiling of the
export Redfin gives you in the browser, and it costs one request, not 17.

#### Sixty-three columns, already unwrapped

Redfin wraps almost every number in an object: `{"price": {"value": 769000,
"level": 1}}`, `{"sqFt": {"value": 3081}}`, `{"latLong": {"value": {...}}}`.
Dumped straight into a spreadsheet those cells read `[object Object]`, and in
pandas every column needs unpacking by hand.

This Actor unwraps them once: `price`, `price_per_sqft`, `sqft`, `lot_size_sqft`,
`beds`, `baths`, `year_built`, `latitude`, `longitude` and the rest arrive as
plain numbers and strings. A live Austin row carries **63 columns, 47 of them
filled**; across 350 Austin listings **62 of the 63 columns** were filled on at
least one row. The untouched Redfin object is still available under `raw` if you
switch it on.

Two details that decide whether a number can be trusted:

- A price the MLS refuses to publish becomes `null`, never `0`. Redfin marks it
  with `hideSalePrice`, and turning that into a zero would quietly drag down
  every average you compute.
- `listing_remarks` — the MLS description — arrives with HTML entities expanded
  and whitespace squeezed. On a live Austin response **332 of 350 listings**
  carried a description, so you rarely need the property card just for text.

#### The property card: 97 columns instead of 63

Switch on **Fetch the full property card** and each listing is also read from
its own Redfin page. A measured Austin card row carried **97 columns, 83 of them
filled** (run `yIzgvb1E2Hd1DB7Pl`), adding data that the search response simply
does not have:

- parcel number (`apn`) and FIPS code;
- county name and the **county property tax rate** (1.6488% on the measured
  listing), plus a home insurance estimate;
- listing agent, brokerage, MLS feed name, when the listing was last updated;
- the agent's full description;
- schools serving the address with grades and distance;
- flood, fire, heat, wind and air-quality risk scores;
- walk, bike, transit, car, quiet and greenery scores;
- **building permits** on the parcel (18 on the measured listing) and zoning;
- the MLS feature list, flattened (24 entries on the measured listing);
- photo links and price history where Redfin publishes them.

The strongest Redfin Actor in the store has no property card at all: its own
README carries a commented-out line promising a detail scraper "when we get
it". That is the single biggest gap this Actor closes — with an honest ceiling:
Redfin's WAF locks the address after the first handful of pages, so 11 of 15
cards arrived in a 61-second measured run and the rest were delivered without
cards. The full story is under Limitations.

#### Rentals and regional market statistics

**Rentals** come from Redfin's separate rental feed: rent range, bedroom and
bathroom range, area range, units available, building name, the leasing
**phone number** and the feed source. The source caps this feed at 350 buildings
per region.

**Region market statistics** are one extra row per location, from Redfin's own
regional numbers rather than anything computed here: median list price, median
sale price, median list and sale price per square foot, median sale-to-list
ratio, average offers, average down payment, homes sold, homes on market,
average days on market, Redfin's compete score, the number of Redfin and partner
agents with their review rating, and today's mortgage rates (30-year fixed,
15-year fixed, FHA, VA). Measured for Austin: 4,772 homes on market, median sale
price $535K, compete score 47, 30-year fixed 7.125%.

#### The source lies when you get the region wrong, so the Actor checks

Ask Redfin for a region id that does not exist and it does not say so. It
answers `HTTP 200`, `errorMessage: "Success"` — and homes in **Seattle**.
Measured with probe run `WEi9cAcqZcKvbcaEf` and again in `tests/test_live.py`:
an unknown region id returned 20 listings, every one of them in Washington.

That is the worst kind of data corruption, because it looks like success. So
every region you paste is checked: the state and, for ZIP codes, the ZIP of the
returned listings are compared against the address you gave, and mismatched rows
are **dropped with a named reason** instead of being handed to you as your
market. The check can be switched off, and then you get exactly what Redfin
said.

#### Filters run inside the Actor, before you are charged

Redfin ignores filter parameters sent to its open search endpoint. 8 different combinations — `min_price`, `max_price`, `num_beds`, `uipt`,
`sold_within_days`, `poly`, `include=sold-3mo`, `sf` — returned a body identical
to the byte: 1,041,701 bytes each time. Sending those parameters and calling
them filters would be selling you a switch that is not wired to anything.

So every filter here runs in the Actor, on the collected rows, **before a row is
written to the dataset**. With pay-per-result pricing that is in your favour: a
row dropped by a filter is never written and never charged.

Available filters: price range, bedrooms range, minimum bathrooms, living area
range, minimum lot, year built range, property type (Redfin's own 8), max
days on market, only with an open house, only new construction, only with
photos, address contains, description contains, label contains, and three that
need the property card — minimum walk score, minimum transit score and minimum
permits.

Two rules the filters obey, each one written after a measured accident on a
neighbouring Actor:

1. **A missing field passes the filter.** Absence of data is not a mismatch. A
   listing whose price the MLS withholds is not the same thing as a listing
   priced below your minimum.
2. **The row limit counts delivered rows, not collected ones.** Ask for 30 rows
   with a narrow filter and you get 30 rows, not 30 candidates of which two
   survive.

#### Monitor mode: pay for what changed, not for the same table again

Switch on **Only new or changed listings** and the Actor remembers every listing
it has delivered in a named key-value store. On the next run it writes only the
listings that are new or whose price, status, beds, baths, area, price per
square foot, HOA, open house, agent or rent range moved. Each row carries
`change_type` (`NEW` / `UPDATED` / `UNCHANGED`) and, when something moved,
`changed_fields` with the value before and after.

Measured in the cloud on ZIP 78704: the first run delivered **358 listings**
(run `hKHGwuPHN3VQjlgLC`), the second run delivered **0 rows** and said why
(run `fPeW7fNZRcIIK6IDa`) — `nothing-changed`, written in the log and in the
REPORT record. A monitoring run that legitimately has nothing to report is not
a failure, and it should not cost you a second full table.

The fingerprint deliberately ignores noisy fields. Redfin's `timeOnRedfin`
counter grows every second; hashing the whole row would mark every listing as
changed on every run and turn monitor mode back into a plain dump.

#### An empty dataset always says why

A green run with an empty dataset is the worst outcome for a buyer: the start
was paid for and nothing explains the silence. This Actor names the reason in
the log and in the `empty_reason` field of the REPORT record, and the reasons
that can be worked out from your input alone are decided **before a single byte
is fetched**:

There are 17 named reasons in all, and 12 of them are decided from the input
alone, before the first request:

`no-location-given`, `all-locations-invalid`, `price-range-is-empty`,
`beds-range-is-empty`, `sqft-range-is-empty`, `year-range-is-empty`,
`property-type-filter-in-rental-mode`, `open-house-filter-in-rental-mode`,
`detail-only-filter-without-details`, `property-type-not-recognised`,
`property-mode-without-property-urls`, `charge-limit-reached`.

And the ones that only become visible after the fetch: `filtered-out`,
`nothing-changed`, `source-returned-nothing`, `all-locations-unreachable`,
`region-check-failed`.

The three input pairs worth naming, because each one guarantees zero rows: a
property-type filter in rental mode (Redfin's rental feed has no property type),
an open-house filter in rental mode, and a walk-score, transit-score or permit
filter with the property card switched off. Each is refused up front with a
sentence saying what to change — not after downloading several megabytes on your
time.

#### What you paste in, and what you get back

**Locations** accepts:

- a city page — `https://www.redfin.com/city/30818/TX/Austin`;
- a county page — `https://www.redfin.com/county/2866/TX/Travis-County`;
- a neighborhood page — `https://www.redfin.com/neighborhood/.../Allandale`;
- a ZIP page — `https://www.redfin.com/zipcode/78704` — or just `78704`;
- a single property — `/TX/Austin/3915-Idalia-Dr-78749/home/31804526`;
- a Redfin search URL with filters on it, such as
  `/city/30818/TX/Austin/filter/min-price=800k` — the region is taken from it;
- an explicit `type:id` pair, e.g. `6:30818`, for a region whose page you do not
  have at hand.

A bare ZIP code is resolved by reading Redfin's own ZIP page and taking the
region id out of it, because Redfin's address autocomplete endpoint answers 403
to every datacenter address — measured with browser headers and without.

You can also chain this Actor behind another one: give it a dataset id and the
field holding a URL, and every item becomes a location.

#### How to use it in three steps

1. Open Redfin in your browser, search the area you care about, and copy the
   address bar. That URL is the input.
2. Choose what to collect: homes for sale, rentals, property cards, or region
   market statistics. Set **Max rows**; leave it at 0 for everything.
3. Run it. Export to CSV, Excel, JSON or hook the dataset into your own code
   through the Apify API.

For a daily watch, set **Only new or changed listings**, put the run on a
schedule, and read `change_type` and `changed_fields`.

#### Limitations, stated plainly

- **Sold and off-market homes are not available.** Redfin's open search endpoint
  drops every filter parameter, `sold_within_days` and `include=sold-3mo`
  included — measured, identical response bytes. This Actor returns what that
  endpoint returns: homes currently on the market. It does not pretend to filter
  server-side.
- **Property cards are rate limited by Redfin, and the Actor stops rather than
  grind.** After the first handful of property pages, Redfin's WAF answers
  `HTTP 202` with a 2,448-byte challenge page and the header
  `x-amzn-waf-action: challenge`. Browser-shaped headers change nothing — 12
  header fields were tried, same refusals (probe run `Lmn01ZLPoLPCM2eFm`). The
  Actor paces itself at one page every two seconds, retries once, and after
  three refusals in a row stops asking for cards and keeps delivering listings
  with their search fields. Measured on the finished build (run
  `xJxWTKXRKWVVA7hTE`): **11 cards of 15 requested arrived in 61 seconds**, then
  the address was locked and the remaining rows were delivered without cards.
  An earlier build that kept retrying spent 537 seconds to get 6 cards (run
  `L7TsznKdX8gywSb4V`), which is why it now stops. Use the card mode for shortlists — a few dozen addresses —
  not for a whole city.
- **City by name is not supported**, because Redfin's autocomplete is closed to
  datacenter addresses (403) and so are its sitemaps. Paste the city page URL or
  a ZIP code instead.
- **Rentals are capped at 350 buildings per region** by the source, not by this
  Actor, and rental rows have no property type, no open house and no MLS number.
- **Price history and photo links appear only where Redfin publishes them.** In
  non-disclosure states much of the history is withheld, and the property card
  will show fewer fields there.
- **The region check needs a hint.** If you pass an explicit `type:id` pair
  there is no city or ZIP to compare against, so the check passes by default.
- This Actor is not affiliated with, endorsed by or connected to Redfin. It
  reads pages and endpoints that any visitor can read, and it collects no
  personal data beyond what the MLS publishes about a listing: the agent's name
  and brokerage.

#### Frequently asked questions

**How many listings can I get from one city?**
As many as Redfin has on the market there. Austin returned 5,876 in a single
request. The only cap is **Listings to ask Redfin for, per location**, which
defaults to 2,000 and goes to 20,000.

**Is there a page limit like the website's nine pages?**
No. The website's paging does not exist at the endpoint level: page two returns
page one. This Actor asks for the whole region at once.

**Why are the filters applied by the Actor and not by Redfin?**
Because Redfin ignores them. 8 filter combinations returned byte-identical
responses. Filtering here means filtering before billing, which is cheaper for
you than filtering after.

**Does it need proxies or a browser?**
No. Every endpoint it uses answers a plain HTTPS request from Apify's own
addresses. That is why the run costs cents and finishes in seconds.

**Can I monitor a ZIP code every morning?**
Yes. Switch on **Only new or changed listings** and schedule the run. A morning
with no changes writes zero rows and says `nothing-changed` in the REPORT
record.

**What happens if I paste something that is not a Redfin address?**
It is skipped, listed in the REPORT record with the reason, and the run
continues with whatever else you gave. If nothing is left, the run stops before
any request with `all-locations-invalid`.

**Can I get the agent's phone number?**
For rentals, yes — the leasing phone is part of the feed. For homes for sale
Redfin publishes the agent's name and brokerage, not a direct phone, and this
Actor does not invent one.

**How do I pull everything into my own system?**
Every run writes a dataset you can read through the Apify API in JSON, CSV,
Excel or XML, and the last row is a REPORT record with counts, the filters that
were active, the regions used and, when the dataset is empty, the reason why.

#### Output example

```json
{
  "source": "redfin",
  "mode": "for_sale",
  "property_id": 31487394,
  "url": "https://www.redfin.com/TX/Austin/2701-Richcreek-Rd-78757/home/31487394",
  "address": "2701 Richcreek Rd, Austin, TX 78757",
  "city": "Austin",
  "state": "TX",
  "zip": "78757",
  "neighborhood": "Allandale Park",
  "latitude": 30.3519645,
  "longitude": -97.7379262,
  "price": 1999000,
  "price_per_sqft": 644,
  "beds": 4,
  "baths": 3,
  "sqft": 3104,
  "year_built": 2022,
  "property_type": "House",
  "status": "Coming Soon",
  "days_on_market": 1,
  "mls_number": "2192874970196828361",
  "photo_count": 19,
  "key_facts": ["Garage", "Pool", "Built 2022"],
  "labels": ["EARLY ACCESS", "COMPASS COMING SOON"],
  "region_label": "Austin, TX"
}
```

#### What else is this called?

Other names for the fields in a row: Redfin estimate versus list price (`redfin_estimate`), income restricted housing data (`is_income_restricted`), military housing listings (`is_military_housing`), wildfire risk home data (`risk_fire_score`), lot size acreage data (`lot_size_sqft`), housing market statistics export (`includeMarketStats`), cumulative days on market, student housing and senior living listings, 3D tour listings (`has_3d_tour`), HOA monthly fee (`hoa_month`), zoning code lookup, hot home indicator (`is_hot`), garage spaces parking data, school ratings near a listing (`schools`).

# Actor input Schema

## `locations` (type: `array`):

Paste Redfin page addresses - city (https://www.redfin.com/city/30818/TX/Austin), county, neighborhood, ZIP (https://www.redfin.com/zipcode/78704) or a single property (/TX/Austin/3915-Idalia-Dr-78749/home/31804526). A bare five-digit ZIP code works too. One request returns the whole region: 5,876 Austin listings arrived in a single response, against the 350-row ceiling of Redfin's own CSV export.

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

Homes for sale, rentals, property cards for the addresses you pasted, or one market-statistics row per region (median sale price, sale-to-list, compete score, mortgage rates).

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

Stop after this many rows have been DELIVERED, not merely looked at - so a narrow filter still fills the quota. 0 means no limit.

## `maxHomesPerLocation` (type: `integer`):

Redfin's search endpoint has no pages: page\_number=2 returns the first page byte for byte (measured), and this is the only lever. 350 is what the website itself uses; 5,876 listings came back in one response when this was set high. Rentals are capped by the source at 350.

## `includeDetails` (type: `boolean`):

On: every listing is also read from its Redfin property page - parcel number, county tax rate, agent and brokerage, full agent description, schools, flood/fire/heat/wind/air risk, walk and transit scores, building permits, zoning, MLS feature list and photo links. Costs one extra request per listing (about 0.9 MB), so keep 'Property cards' below sane. Off: the search fields only.

## `maxDetails` (type: `integer`):

Hard ceiling on how many property pages are opened when the card is switched on. 0 means no ceiling.

## `includeMarketStats` (type: `boolean`):

Adds one extra row per location with Redfin's own regional numbers: median list and sale price, median sale-to-list, average offers, homes sold, homes on market, compete score and today's mortgage rates.

## `verifyRegion` (type: `boolean`):

Measured: an unknown region id answers HTTP 200, 'Success' and homes in Seattle. With this on, the state and ZIP of the returned homes are checked against the address you pasted and mismatched rows are dropped instead of being handed to you as your region.

## `minPrice` (type: `integer`):

Keep listings priced at or above this. 0 switches the filter off. Rentals are matched on the lowest advertised rent.

## `maxPrice` (type: `integer`):

Keep listings priced at or below this. 0 switches the filter off.

## `minBeds` (type: `integer`):

Keep listings with at least this many bedrooms. 0 switches the filter off.

## `maxBeds` (type: `integer`):

Keep listings with at most this many bedrooms. 0 switches the filter off.

## `minBaths` (type: `number`):

Keep listings with at least this many bathrooms, half baths included. 0 switches the filter off.

## `minSqft` (type: `integer`):

Keep listings whose living area is at least this. 0 switches the filter off.

## `maxSqft` (type: `integer`):

Keep listings whose living area is at most this. 0 switches the filter off.

## `minLotSqft` (type: `integer`):

Keep listings whose lot is at least this big. Redfin leaves the lot empty for most condos, and a listing with an empty lot passes the filter.

## `minYearBuilt` (type: `integer`):

Keep listings built in this year or later. 0 switches the filter off.

## `maxYearBuilt` (type: `integer`):

Keep listings built in this year or earlier. 0 switches the filter off.

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

Redfin's own eight types. Empty means all of them. Rentals carry no property type at all, so this filter and the rentals mode together are refused before a single request is sent.

## `maxDaysOnMarket` (type: `integer`):

Keep only listings that have been on the market no longer than this. 0 switches the filter off.

## `onlyOpenHouses` (type: `boolean`):

Keep only listings carrying an open house slot. Measured on a live Austin response: 90 of 350 listings had one.

## `onlyNewConstruction` (type: `boolean`):

Keep only listings Redfin marks as new construction.

## `onlyWithPhotos` (type: `boolean`):

Keep only listings that carry at least one photo.

## `addressContains` (type: `string`):

Plain text matched against the address, city, ZIP, neighborhood and region label.

## `descriptionContains` (type: `string`):

Plain text matched against the agent description and the MLS feature list. The MLS description ships with the search response for most listings; the feature list needs the property card, so with the card off this filter is refused before any request.

## `labelContains` (type: `string`):

Matched against Redfin's own badges - OPEN HOUSE, PRICE DROP, HOT HOME, NEW, COMING SOON - and the listing status.

## `minWalkScore` (type: `integer`):

Property-card field. With the card off this filter is refused before any request instead of silently emptying the dataset.

## `minTransitScore` (type: `integer`):

Property-card field, same rule as the walk score.

## `minPermits` (type: `integer`):

Property-card field: how many permits the county has on this parcel. Useful for spotting renovated stock.

## `onlyChanged` (type: `boolean`):

Monitor mode. The Actor remembers every listing it has delivered in a named key-value store and, on the next run, writes only the ones that are new or whose price, status, open house or agent moved. Every row carries change\_type and, when something moved, changed\_fields with the before and after value.

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

Keeps the change\_type labels but writes every listing, changed or not.

## `compactOutput` (type: `boolean`):

Twenty decision fields per row instead of sixty-three - address, price, beds, baths, size, type, status, days on market, coordinates. Made for LLM agents and for cheap storage.

## `dropEmptyFields` (type: `boolean`):

Leaves out keys whose value is empty, so a row carries only what Redfin actually published for that listing.

## `includeRawRecord` (type: `boolean`):

Attaches Redfin's untouched object under 'raw' next to the flat columns, for anything this Actor does not map.

## `concurrency` (type: `integer`):

How many property cards to fetch at once. The search itself is one request per location.

## `timeoutSeconds` (type: `integer`):

A whole-region response can be several megabytes, so this is deliberately generous.

## `inputDatasetId` (type: `string`):

Dataset id from another Actor run. Every item's url field is treated as a location, which chains this Actor after any other one.

## `urlField` (type: `string`):

Which field of that dataset holds the Redfin address. Defaults to url.

## Actor input object example

```json
{
  "locations": [
    "https://www.redfin.com/city/30818/TX/Austin"
  ],
  "mode": "forSale",
  "maxItems": 100,
  "maxHomesPerLocation": 2000,
  "includeDetails": false,
  "maxDetails": 50,
  "includeMarketStats": false,
  "verifyRegion": true,
  "minPrice": 0,
  "maxPrice": 0,
  "minBeds": 0,
  "maxBeds": 0,
  "minBaths": 0,
  "minSqft": 0,
  "maxSqft": 0,
  "minLotSqft": 0,
  "minYearBuilt": 0,
  "maxYearBuilt": 0,
  "propertyTypes": [],
  "maxDaysOnMarket": 0,
  "onlyOpenHouses": false,
  "onlyNewConstruction": false,
  "onlyWithPhotos": false,
  "addressContains": "",
  "descriptionContains": "",
  "labelContains": "",
  "minWalkScore": 0,
  "minTransitScore": 0,
  "minPermits": 0,
  "onlyChanged": false,
  "emitUnchanged": false,
  "compactOutput": false,
  "dropEmptyFields": false,
  "includeRawRecord": false,
  "concurrency": 4,
  "timeoutSeconds": 90,
  "inputDatasetId": "",
  "urlField": "url"
}
```

# Actor output Schema

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

All collected rows

# 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 = {
    "locations": [
        "https://www.redfin.com/city/30818/TX/Austin"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("snow_leo_data/redfin-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 = { "locations": ["https://www.redfin.com/city/30818/TX/Austin"] }

# Run the Actor and wait for it to finish
run = client.actor("snow_leo_data/redfin-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 '{
  "locations": [
    "https://www.redfin.com/city/30818/TX/Austin"
  ]
}' |
apify call snow_leo_data/redfin-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,snow_leo_data/redfin-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/7nnVXCVclyrrL7nBZ/builds/xPrpix3sjTdvG6xMr/openapi.json
