# StreetEasy Scraper \[$1.50/1K💰] | NYC Rentals | Broker Data (`ahmed_jasarevic/streeteasy-scraper`) Actor

Scrape StreetEasy NYC rental listings into structured data: price, net-effective rent, beds, baths, sqft, neighborhood, broker, no-fee status and price history. Ideal for NYC rental market research, price monitoring and lead generation.

- **URL**: https://apify.com/ahmed_jasarevic/streeteasy-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 results

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

## StreetEasy Scraper: NYC Rental Listings & Brokerage Data

Scrape **streeteasy.com** NYC rental listings across all five boroughs and export address, neighborhood, ZIP, latitude/longitude, price, net-effective rent, beds/baths, square footage, building type, broker, no-fee status, photos and full price history as clean structured JSON. It calls StreetEasy's own internal GraphQL endpoint server-side with no browser, so a run is fast and cheap even at scale.

Built for NYC real-estate investors, relocation and rental agencies, buy-box and comp analysts, and lead-generation teams who want StreetEasy coverage alongside Zillow/Redfin data.

### Main use cases

- **NYC rental market research**: track asking rents, net-effective rents and inventory across boroughs and neighborhoods.
- **Rental price monitoring**: schedule recurring snapshots to catch price drops (`priceDelta`), concessions (`monthsFree`) and no-fee (`noFee`) listings.
- **Real estate lead generation**: pull the broker/brokerage label from active listings for outreach and partner research.
- **Build a NYC rental database / property dataset**: warehouse StreetEasy rentals with geo-coordinates, building type and price history.
- **Buy-box and comps analysis**: filter by price, beds and baths to line up comparables across Manhattan, Brooklyn, Queens and more.
- **Relocation and apartment search tooling**: power your own apartment-search UI with fresh StreetEasy listings and photos.

### How it works

StreetEasy's Next.js frontend queries its own internal GraphQL endpoint, and this actor calls that same endpoint server-side. There is **no browser and no HTML scraping**: search pages and detail records come back as clean JSON.

- **Endpoint:** `POST https://api-v6.streeteasy.com/`
- **Search:** `searchRentals(input: {...})`, paged with `perPage` / `page`, filtered by numeric `areas` codes plus price, beds and baths.
- **Details:** `rentalByListingId(id: ...)` for description, amenities, all photo and floor-plan keys, the building record (ZIP) and `propertyHistory.rentalEventsOfInterest` (price history).
- **Photos:** `https://photos.zillowstatic.com/fp/{key}-se_large_800_400.webp` (public CDN, not bot-walled).

Rentals are fully supported. Sales are a best-effort probe of a mirrored endpoint; if the server rejects it, the run logs a warning and continues rentals-only.

### Extract NYC Rental Listings For Market Research

Every rental search returns listing cards that the actor maps into one dataset row each: listing id and URL, street address and unit, neighborhood and borough, city/state/ZIP (with detail enrichment), latitude/longitude, current price and net-effective rent, concession months free and no-fee flag, last price change, bedrooms, full and half bathrooms, square feet, building type, broker label, status, availability date, photos and (with enrichment) description, amenities, floor plans and price history.

You provide one or more areas (`areas`, e.g. `MANHATTAN`, `Williamsburg`, `park-slope-brooklyn`, or numeric area ids) plus optional price/bed/bath filters.

### Build A NYC Rental Database Without A StreetEasy API

StreetEasy has **no public rental API**, and its `www.streeteasy.com` HTML pages sit behind **PerimeterX** (a plain HTTP fetch gets a `403` challenge page). This actor sidesteps both by calling the internal `api-v6.streeteasy.com` GraphQL endpoint the site's own frontend uses, carrying the frontend's headers (`Origin: https://streeteasy.com`, `Apollographql-Client-Name: srp-frontend-service`, a browser User-Agent) and valid PerimeterX cookies (`_px3`, `_pxvid`).

A critical quirk: enum values are sent as plain JSON strings inside `variables.input` (for example `"rentalStatus": "ACTIVE"`, `"attribute": "LISTED_AT"`), which is exactly how the current StreetEasy frontend calls api-v6.

**Anti-bot handling (PerimeterX):** PX signs its `_px3` cookie to the egress IP and User-Agent. On fresh **residential** exit IPs the API accepts requests without cookies; datacenter IPs get a `403` challenge regardless. The actor therefore:

1. **Rotates the session (fresh exit IP) on every blocked response** and retries.
2. If the API starts returning `403`, attempts a **one-shot PX cookie bootstrap** by loading the public StreetEasy HTML page through the same exit IP with `got-scraping`; if PX blocks the HTML too, it falls back to IP rotation only.
3. Optionally accepts **manually pasted browser cookies** (`cookies`) as a fallback.

For reliable runs, enable **Apify Proxy (residential group)** in the input and raise `maxRequestRetries` if needed.

**Known limitations**

- Rentals are fully supported; sales depend on an undocumented endpoint and may fall back to rentals-only.
- Broker contact details (phone/email) are not exposed by the internal API, only the brokerage label.
- `api-v6.streeteasy.com` is an internal, unpublished endpoint with no stability guarantee; if StreetEasy changes the schema, the actor's GraphQL layer is the single place to update.

### Input Parameters

| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
| `areas` | array (stringList) | **Yes** | `["MANHATTAN"]` | StreetEasy neighborhoods or boroughs, e.g. `Manhattan`, `Williamsburg`, `Chelsea`, `Astoria`, `Park Slope`. Numeric area ids are also accepted. |
| `listingType` | string (enum) | No | `rentals` | `rentals` (full support), `sales` or `both` (best-effort probe; falls back to rentals-only). |
| `maxItems` | integer | No | `100` | Maximum listings to return (1 to 5000). Free users are capped at 10 items per run. |
| `minPrice` | integer | No | - | Minimum monthly rent (or sale price) filter. |
| `maxPrice` | integer | No | - | Maximum monthly rent (or sale price) filter. |
| `minBeds` | integer | No | - | Minimum bedroom count (`0` = studio). |
| `maxBeds` | integer | No | - | Maximum bedroom count. |
| `minBaths` | integer | No | - | Minimum bathroom count. |
| `maxBaths` | integer | No | - | Maximum bathroom count. |
| `enrichDetails` | boolean | No | `false` | Fetch each listing's detail record (ZIP code, description, amenities, all photos, floor plans, price history). One extra request per listing, roughly triples run time. |
| `listingIds` | array (stringList) | No | - | Specific rental ids or URLs (e.g. `4808197` or `https://streeteasy.com/rental/4808197`) to enrich directly. |
| `maxRequestsPerCrawl` | integer | No | `500` | Safety cap on total API requests (search pages plus detail fetches). |
| `maxRequestRetries` | integer | No | `10` | Retries per request (0 to 100). Each retry rotates to a fresh proxy session/IP and re-acquires PX cookies. Raise if runs return little data. |
| `cookies` | string | No | - | Optional fallback: paste the full `Cookie` header from a working streeteasy.com browser session. The actor normally self-bootstraps PX cookies per proxy IP. |
| `proxy` | object (proxy) | No | Apify proxy, RESIDENTIAL group | Residential proxy strongly recommended. PerimeterX blocks datacenter IPs regardless of cookies. |

### Output Fields

One dataset item per listing. The default `overview` view shows Address, Neighborhood, Price, Beds, Baths, Sqft, Broker and URL.

| Field | Type | Description |
|---|---|---|
| `listingId` | string | StreetEasy numeric listing id. |
| `listingType` | string | `rental` or `sale`. |
| `listingUrl` | string / null | Canonical StreetEasy listing URL. |
| `urlPath` | string / null | Listing path on streeteasy.com. |
| `address` | string / null | Street plus unit, e.g. `160 West 24th Street #3N`. |
| `unit` | string / null | Unit / apartment number. |
| `street` | string / null | Street address. |
| `neighborhood` | string / null | StreetEasy area name, e.g. `Chelsea`. |
| `borough` | string / null | Borough derived from the area code. |
| `city` | string / null | City (detail enrichment only). |
| `state` | string / null | State (detail enrichment only). |
| `zipCode` | string / null | ZIP code (detail enrichment only). |
| `latitude` | number / null | Listing latitude. |
| `longitude` | number / null | Listing longitude. |
| `price` | number / null | Current list price ($/mo for rentals). |
| `netEffectivePrice` | number / null | Net-effective rent after concessions. |
| `noFee` | boolean / null | Whether the listing is no-fee. |
| `monthsFree` | number / null | Concession months free, if any. |
| `priceDelta` | number / null | Last price change amount. |
| `bedrooms` | number / null | Bedroom count (0 = studio). |
| `bathroomsFull` | number / null | Full bathrooms. |
| `bathroomsHalf` | number / null | Half bathrooms. |
| `sqft` | number / null | Living area in square feet (null when not listed). |
| `buildingType` | string / null | Building type, e.g. `RENTAL`, `CONDO`, `CO_OP`. |
| `broker` | string / null | Brokerage/agent label from the listing source. |
| `sourceType` | string / null | Listing source type. |
| `status` | string / null | Listing status (ACTIVE, ...). |
| `availableAt` | string / null | Availability date. |
| `description` | string / null | Full listing description (detail enrichment only). |
| `amenities` | array | Amenity and feature codes (detail enrichment only). |
| `photos` | array | Photo URLs (Zillow CDN). |
| `floorPlans` | array | Floor-plan image URLs (detail enrichment only). |
| `priceHistory` | array | Price/status events `{date, price, event}` (detail enrichment only). |
| `areaName` | string / null | Raw StreetEasy area name. |
| `scrapedAt` | string | Row timestamp (ISO). |

Fields that require detail enrichment (`zipCode`, `description`, `amenities`, `floorPlans`, `priceHistory` and the extra photos) are `null`/empty when `enrichDetails` is false or the detail fetch fails; the search-level row is still returned.

### Example Input And Output

**Input**

```json
{
  "areas": ["Williamsburg", "Astoria"],
  "listingType": "rentals",
  "maxItems": 100,
  "maxPrice": 5000,
  "minBeds": 1,
  "enrichDetails": true
}
```

**Output (one dataset row)**

```json
{
  "listingId": "4808197",
  "listingType": "rental",
  "listingUrl": "https://streeteasy.com/rental/4808197",
  "urlPath": "/rental/4808197",
  "address": "160 West 24th Street #3N",
  "unit": "3N",
  "street": "160 West 24th Street",
  "neighborhood": "Chelsea",
  "borough": "Manhattan",
  "city": "New York",
  "state": "NY",
  "zipCode": "10011",
  "latitude": 40.74419,
  "longitude": -73.99374,
  "price": 5200,
  "netEffectivePrice": 4766,
  "noFee": true,
  "monthsFree": 1,
  "priceDelta": -200,
  "bedrooms": 1,
  "bathroomsFull": 1,
  "bathroomsHalf": 0,
  "sqft": 720,
  "buildingType": "RENTAL",
  "broker": "Corcoran Group",
  "sourceType": "broker",
  "status": "ACTIVE",
  "availableAt": "2026-11-01",
  "description": "Sunny one-bedroom with southern exposure ...",
  "amenities": ["ELEVATOR", "LAUNDRY_IN_UNIT", "GYM"],
  "photos": ["https://photos.zillowstatic.com/fp/....-se_large_800_400.webp"],
  "floorPlans": [],
  "priceHistory": [{ "date": "2026-10-01", "price": 5400, "event": "LISTED" }],
  "areaName": "chelsea",
  "scrapedAt": "2026-10-11T09:00:00.000Z"
}
```

### Integrations & Automation

Every Apify actor is reachable through the **Apify API**, and this one plugs into **webhooks**, **Zapier** and **Make** so results can flow into a Google Sheet, Airtable base, CRM or data warehouse. For rental price monitoring and market research, run it on a **schedule**: a daily or weekly snapshot of your target neighborhoods is enough to catch new listings, price drops and concessions, and recurring runs also improve the actor's Store recommendation signals.

### Related Actors

- [zillow-scraper](https://apify.com/maxcopell/zillow-scraper): the largest US listings scraper; pairs StreetEasy rentals with broad national coverage.
- [zillow-detail-scraper](https://apify.com/maxcopell/zillow-detail-scraper): adds full Zillow detail pages for listings StreetEasy does not expose.
- [zumper-scraper](https://apify.com/ahmed_jasarevic/zumper-scraper): US rental listings to complement StreetEasy's NYC inventory.
- [century21-scraper](https://apify.com/ahmed_jasarevic/century21-scraper): another US real-estate source for a multi-portal property database.
- [coldwellbanker-scraper](https://apify.com/ahmed_jasarevic/coldwellbanker-scraper): brokerage-level US listings with agent and office data.

### FAQ

#### Is there an official StreetEasy API?

No. StreetEasy (a Zillow brand) does not publish a public rental API, and its HTML pages are protected by PerimeterX. This actor reads StreetEasy's own internal GraphQL endpoint directly, so you get structured rentals without an API key and without a browser.

#### What are the alternatives to this actor / this data source?

For NYC rental data you can combine this with Zillow, Zumper, Realtor.com or HotPads scrapers. StreetEasy is the most NYC-focused of these, so it is worth having alongside the national portals to widen coverage of active rentals, brokerages and price history.

#### How do I get NYC rental price history and no-fee data at scale?

Set `enrichDetails` to true and provide your `areas` plus any price/bed/bath filters. The actor follows search pagination automatically, then enriches each listing to return `priceHistory`, `netEffectivePrice`, `monthsFree`, `noFee` and `priceDelta` alongside price, size and geo-coordinates.

#### Does StreetEasy block scrapers?

StreetEasy uses PerimeterX, which blocks datacenter IPs with a `403` challenge even with valid cookies. This actor avoids that by rotating to fresh residential exit IP sessions and optionally bootstrapping PX cookies, so enable the **residential** Apify proxy group in production runs.

#### Best way to monitor NYC rent prices by neighborhood?

Schedule this actor daily or weekly against your target neighborhoods and store each run's dataset. Comparing runs over time gives you new-listing, rent-change and concession trends without manual checks.

#### Why are `zipCode`, `description` and price history null?

Those fields live on the per-listing detail record. They are returned only when `enrichDetails` is true (roughly one extra request per listing, which triples run time). Leave it off for fast basic rows.

### SEO Keywords

streeteasy scraper, streeteasy api, nyc apartments, nyc rental data, nyc real estate data, rental listings, apartment scraper, zillow scraper, nyc apartments for rent, rental price monitoring, real estate lead generation, no-fee apartments, manhattan rentals, brooklyn apartments, new york city rental market, price history, brokerage data, streeteasy alternative, nyc rental market, property database

### For AI Agents & LLM Apps

Purpose: return one structured NYC rental-listing row per StreetEasy listing for a given set of areas and optional price/bed/bath filters.

Minimal working input:

```json
{ "areas": ["MANHATTAN"], "maxItems": 20 }
```

Variant input (enrich a specific listing, or search sales):

```json
{ "listingIds": ["4808197"], "enrichDetails": true }
```

Output fields: `listingId, listingType, listingUrl, urlPath, address, unit, street, neighborhood, borough, city, state, zipCode, latitude, longitude, price, netEffectivePrice, noFee, monthsFree, priceDelta, bedrooms, bathroomsFull, bathroomsHalf, sqft, buildingType, broker, sourceType, status, availableAt, description, amenities, photos, floorPlans, priceHistory, areaName, scrapedAt`.

Behaviors an agent should know:

- `areas` is the only required field; it accepts neighborhood or borough names, or numeric StreetEasy area ids.
- `listingType` defaults to `rentals`. `sales`/`both` are best-effort and may fall back to rentals-only; an unsupported sales probe does not fail the run.
- `maxItems` defaults to **100**; free-plan runs are capped at **10** listings regardless.
- Detail-only fields (`zipCode`, `description`, `amenities`, `floorPlans`, `priceHistory`, extra `photos`) are `null`/empty unless `enrichDetails` is `true`. Do not treat their absence as a failure.
- `listingIds`, when set, enriches those specific listings directly and does not require `areas`.
- Enable the residential proxy for production; without residential IPs PerimeterX returns `403`.

Billing: pay-per-event: **$0.0015 per result** ($1.50 / 1,000 listings) via the `apify-default-dataset-item` event, an additional **$0.001 per listing** ($1.00 / 1,000) `full-details` event when `enrichDetails` is on, plus a $0.00005 actor-start event.

### Legal & Compliance Disclaimer

This actor is an independent tool and is **not affiliated with, endorsed by, or sponsored by StreetEasy or Zillow Group**. It accesses only publicly available StreetEasy / StreetEasy API surfaces; it does not log in, bypass authentication, or solve CAPTCHAs on anyone's behalf. Users are responsible for ensuring their use complies with StreetEasy's Terms of Service and with applicable data-protection law.

# Actor input Schema

## `areas` (type: `array`):

StreetEasy neighborhoods or boroughs to search, e.g. Manhattan, Williamsburg, Chelsea, Astoria, Park Slope. Numeric area ids are also accepted.

## `listingType` (type: `string`):

Rentals are fully supported via the internal API. Sales is a best-effort probe of a mirrored endpoint; if unsupported the run continues rentals-only.

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

Maximum listings to return. Free users are capped at 10 items per run.

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

Minimum monthly rent (or sale price) filter.

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

Maximum monthly rent (or sale price) filter.

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

Minimum bedroom count (0 = studio).

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

Maximum bedroom count.

## `minBaths` (type: `integer`):

Minimum bathroom count.

## `maxBaths` (type: `integer`):

Maximum bathroom count.

## `enrichDetails` (type: `boolean`):

Fetch each listing's detail record (ZIP code, description, amenities, all photos, floor plans, price history). Uses one extra request per listing and roughly triples run time. Leave off for fast basic rows.

## `listingIds` (type: `array`):

Optional: specific rental IDs or URLs (e.g. 4808197 or https://streeteasy.com/rental/4808197) to enrich directly.

## `maxRequestsPerCrawl` (type: `integer`):

Safety cap on total API requests (search pages + detail fetches).

## `maxRequestRetries` (type: `integer`):

Retries per request. StreetEasy's PerimeterX rate-limits aggressively — each retry rotates to a fresh proxy session/IP and re-acquires PX cookies. Raise (up to 100) if runs return little data.

## `cookies` (type: `string`):

Optional: paste the full Cookie header from a working streeteasy.com browser session (DevTools → Network → any request → Request Headers → cookie). The actor normally self-bootstraps PX cookies per proxy IP; paste cookies only as a fallback.

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

Residential proxy strongly recommended — PerimeterX blocks datacenter IPs regardless of cookies.

## Actor input object example

```json
{
  "areas": [
    "MANHATTAN"
  ],
  "listingType": "rentals",
  "maxItems": 100,
  "enrichDetails": false,
  "maxRequestsPerCrawl": 500,
  "maxRequestRetries": 10,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (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 = {
    "areas": [
        "MANHATTAN"
    ],
    "cookies": "",
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/streeteasy-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 = {
    "areas": ["MANHATTAN"],
    "cookies": "",
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/streeteasy-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 '{
  "areas": [
    "MANHATTAN"
  ],
  "cookies": "",
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call ahmed_jasarevic/streeteasy-scraper --silent --output-dataset

```

## MCP server setup

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