StreetEasy Scraper icon

StreetEasy Scraper

Scrape StreetEasy sales, rentals and in-contract listings across NYC and Jersey City. Search with filters or URLs and extract prices, GPS coordinates,…

Start using this actor on Apify ↗Need a custom scraper?Contact us ↗

StreetEasy Scraper at a glance

StreetEasy Scraper is a ready-to-run Apify actor from abotapi for collecting real estate data. Its documented output includes id, url, type, status and price, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $2.00 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify.

Runs on
Apify cloud: console, API, schedules and integrations
Data type
Real Estate, Automation, Developer Tools
Pricing
$2.00 per 1,000 results (Free plan), from $1.00 on paid plans
Output
Documented below · JSON, CSV, Excel
Inputs
30 options

Scrape StreetEasy sales, rentals and in-contract listings across NYC and Jersey City. Search with filters or URLs and extract prices, GPS coordinates, photos, amenities, building details, brokerages, agent contacts and price history.

What StreetEasy Scraper can do

  • Two ways in. Combine filters (price, beds, baths, square feet, amenities, no-fee, keywords, sort, and three listing categories) into one search, or paste StreetEasy search-result URLs, including their own price, beds, and sort path segments.
  • Big pages. Up to 500 listings per page, so a large pull needs fewer requests.
  • Coordinates included. Latitude and longitude on every listing without detail-page enrichment.
  • Full-market coverage. Auto-expand mode splits a search above roughly 1,050 matching results into price buckets and merges them.
  • Optional enrichment. Detail pages add the full description, verified amenities, building name and year, price history, agent contacts, and open house dates.
  • Rental concessions. Net effective rent, months free, lease term, and move-in date for concession-aware rental analysis.

Choose what to collect

These inputs let you configure StreetEasy Scraper - NYC Listings, Prices & Agents. Open the actor on Apify to enter your values and review the current options.

Supported input fields
InputWhat it controls
modestring · requiredUse search mode to combine filters (areas, price, beds, baths, etc.) into one query. Use url mode to paste one or more StreetEasy search-result URLs (for-sale, for-rent, in-contract) and let the actor walk pagination forward. The Filters section applies in both modes.

Choices: search, url

saleTypestringFor sale, for rent, or in contract. StreetEasy no longer serves a standalone recently-sold or off-market browse page, so past sales come back as price-history events on a listing (turn on Fetch detail pages), not as a category you can query here.

Choices: forSale, forRent, inContract

locationsarraySlugs as they appear in StreetEasy URLs. Examples: nyc (all NYC), manhattan, brooklyn, queens, bronx, staten-island, williamsburg, astoria, jersey-city, hoboken, upper-east-side, park-slope, dumbo. Multi-select supported. Defaults to all NYC.
urlsarrayExamples: • https://streeteasy.com/for-sale/manhattan • https://streeteasy.com/for-rent/williamsburg/price:3000-5000 • https://streeteasy.com/for-sale/nyc/sort:price_asc • https://streeteasy.com/for-sale/manhattan/beds:2 A URL's own price:LOW-HIGH, beds:N (or beds:MIN-MAX) and sort:KEY path segments, if present, are honored (join with | in one segment, e.g. price:3000-5000|beds:2). Unrecognized path segments are logged and ignored. Leaving this field untouched in URL mode scrapes the three examples above. Not supported (skipped with a warning): a building/single-listing detail page URL, or a /sold/... URL (StreetEasy no longer serves a standalone recently-sold browse page; see saleType above for what this actor can query). Multi-URL supported. Pagination starts at the URL's page and walks forward. The Filters section below also applies to a pasted URL, and narrows it further: property types, beds, baths, sqft, amenities, no-fee, keywords, sort order, plus Min/Max price whenever the URL itself carries no price segment. Only the Search mode fields above (Listing type, Locations) are unused here, because the pasted URL already supplies them.
propertyTypesarrayFilter by building / property type. Multi-select supported.
minPriceintegerLower bound on price. For sales: total price. For rentals: monthly rent.
maxPriceintegerUpper bound on price. For sales: total price. For rentals: monthly rent.
Show 23 more inputs
More input fields
InputWhat it controls
minBedroomsintegerUse 0 for studios.
maxBedroomsintegerUpper bound on bedroom count.
minBathroomsnumberLower bound on bathroom count. Decimal supported (1.5).
minSqftintegerLower bound on living area (square feet).
maxSqftintegerUpper bound on living area (square feet).
amenitiesarrayFilter to listings that advertise these amenities.
noFeebooleanRentals: only listings with no broker fee. Ignored when saleType is not forRent.
keywordsstringFree-text keyword filter (matches description / title).
sortBystringOrder in which results are returned.

Choices: RECOMMENDED, PRICE_ASC, PRICE_DESC, LISTED_AT_DESC, LISTED_AT_ASC, SQFT_DESC, BEDROOMS_DESC

maxPagesintegerPagination cap per query. Each page returns up to perPage listings (default 100). Leave empty to walk every result page, bounded only by maxListings.
perPageintegerUp to 500 supported. Higher values mean fewer round trips and lower cost.
maxListingsintegerHard cap across the whole run. The actor stops as soon as this many records have been pushed. Default 20 keeps small test runs cheap; bump it for production scrapes.
fetchDetailsbooleanWhen on, the actor opens each listing page to enrich amenities, building info, agent contact, full description, and price history. Adds one HTTP request per listing.
expandLargeQueriesbooleanWhen on and a query matches more than the per-query cap (~1050), the actor splits it into price buckets and merges results so you can extract the full market.
resumeFromRunIdstringPaste a previous run ID or dataset ID to continue a full-catalogue walk across separate runs. Listings already collected there (matched by listing id) are skipped, so this run only saves the new ones. Use this after an interrupted run, or to keep growing one big catalogue pull. For recurring daily/weekly monitoring of the same search, use Incremental mode below instead, the two are different things and normally not combined.
incrementalModebooleanTurn this on for daily/weekly monitoring of the same search. The first run returns every matching listing as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED listings, unchanged ones are skipped (and not billed). A listing is UPDATED when any compared field changes (price, status, address, unit, bedrooms, bathrooms, size, images, amenities, open houses, detail-page fields and so on); changedFields names them. These counters and derived fields are kept in the output but never drive UPDATED: daysOnMarket, zipCode, state, mediaAssetCount, hasTour3d, hasVideos, isNewDevelopment, priceDelta, priceChangedAt, netEffectivePrice, monthsFree, leaseTerm, availableAt. State is kept separately per search scope (mode, location/URL, filters, and the Fetch detail pages setting); use State key below to name or deliberately share a monitoring campaign. To continue one specific interrupted run instead, use Resume from a previous run above.
stateKeystringOptional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the search scope (locations/URLs, filters, and Fetch detail pages), different searches then never mix state with each other.
emitUnchangedbooleanOff by default. Turn on to also return listings that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have, so leave it off unless you specifically want the full snapshot every run.
emitExpiredbooleanOff by default. Turn on to also return listings that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search, not when Max listings/Max pages capped it, the site blocked a page, or Resume was used. This returns, and bills, extra synthetic rows, so leave it off unless you need expiry tracking.
ignoreFieldsForChangesarrayOptional list of fields that must not count as a change. They stay in the output but never make a listing UPDATED or appear in changedFields. Use a top-level name (e.g. price) or a dot path for nested fields (e.g. agents.phone; arrays are applied to every element). Applied on top of the built-in ignore list described under Incremental changes. Adding an entry does not cause a one-time wave of UPDATED rows.
mcpConnectorsarrayOptionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON, the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).
notionParentPageUrlstringURL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.
maxNotifyListingsintegerCap on items written to each connector per run. Does not affect the dataset.

Fields in the output

The documented dataset includes the fields below. Availability can depend on the source page and selected mode.

idID (text)
urlURL (link)
saleTypeType (text)
statusStatus (text)
pricePrice (number)
neighborhoodNeighborhood (text)
boroughBorough (text)
addressAddress (text)
unitUnit (text)
bedroomsBeds (number)
bathroomsBaths (number)
halfBathroomsHalf baths (number)
Show 42 more fields
squareFeetSqft (number)
pricePerSqft$/sqft (number)
propertyTypeProperty type (text)
latitudeLat (number)
longitudeLng (number)
imageUrlImage (image)
brokerageBrokerage (text)
listedAtListed at (date)
daysOnMarketDOM (number)
zipCodeZip code (text)
mediaAssetCountPhoto/video count (number)
priceDeltaLast price change ($) (number)
netEffectivePriceNet effective rent (rentals) (number)
monthsFreeMonths free (rentals) (number)
availableAtAvailable from (rentals) (date)
changeTypeChange type (incremental mode) (text)
changedFieldsChanged fields (incremental mode) (array)
firstSeenAtFirst seen (incremental mode) (date)
lastSeenAtLast seen (incremental mode) (date)
descriptionDescription (text)
amenitiesAmenities (array)
buildingNameBuilding (text)
buildingYearYear built (number)
priceHistoryPrice history (array)
agentsAgents (array)
openHouseDatesOpen houses (array)
buildingIdBuilding ID (text)
areaIdArea ID (number)
residentialUnitCountResidential units in building (number)
roomCountRooms (number)
statusDateLast status change (date)
verifiedUpToDateVerified up to date (text)
nearbySchoolsNearby schools (array)
nameAgent (text)
phonePhone (text)
emailEmail (text)
licenseLicense (text)
profileUrlProfile URL (link)
isProPro (text)
bioBio (text)
businessNameBusiness (text)
fullBusinessAddressFull business address (text)

Example output

An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.

{
  "id": "0000001",
  "url": "https://streeteasy.com/building/sample-tower/4a",
  "saleType": "forSale",
  "status": "For sale",
  "price": 1250000,
  "neighborhood": "Sample Neighborhood",
  "borough": null,
  "address": "100 Sample Street",
  "unit": "4A",
  "bedrooms": 2,
  "bathrooms": 2,
  "halfBathrooms": 0,
  "squareFeet": 1100,
  "pricePerSqft": 1136.36,
  "propertyType": "Condo",
  "latitude": 40.7,
  "longitude": -74,
  "imageUrl": "https://images.streeteasy.com/photos/sample-uncropped.webp",
  "images": [
    "https://images.streeteasy.com/photos/sample-uncropped.webp"
  ],
  "brokerage": "Sample Realty",
  "listedAt": "2026-01-01",
  "daysOnMarket": 30,
  "offMarketAt": null,
  "furnished": false,
  "noFee": null,
  "advertisedListing": false,
  "description": "Full listing description text appears here when Fetch detail pages is on.",
  "amenities": [
    "Doorman",
    "Elevator",
    "Gym"
  ],
  "buildingName": "Sample Tower",
  "buildingYear": 1990,
  "schoolDistricts": [],
  "transit": [
    "6",
    "Q"
  ],
  "priceHistory": [
    {
      "date": "2026-01-01",
      "event": "Listed",
      "price": 1250000
    }
  ],
  "agents": [
    {
      "name": "Agent Name",
      "phone": "+10000000000",
      "email": "agent@example.com",
      "license": "Licensed Real Estate Salesperson",
      "brokerage": "Sample Realty",
      "contactId": "100001",
      "profileId": "200001",
      "profileUrl": "https://streeteasy.com/200001",
      "isPro": false,
      "businessName": "Sample Realty LLC",
      "businessAddress1": "1 Example Avenue",
      "businessCity": "New York",
      "businessState": "NY",
      "businessZip": "10001",
      "fullBusinessAddress": "1 Example Avenue, New York, NY 10001"
    }
  ],
  "openHouseDates": [
    "2026-02-01"
  ],
  "virtualTourUrl": null,
  "buildingId": "10001",
  "areaId": 120,
  "residentialUnitCount": 40,
  "roomCount": 4,
  "statusDate": "2026-01-01T09:00:00.000-05:00",
  "verifiedUpToDate": false,
  "salesStartDate": null,
  "nearbySchools": [
    {
      "id": "ps-1-manhattan",
      "name": "P.S. 001 Sample School",
      "district": "2",
      "grades": [
        "PK",
        "01",
        "02"
      ]
    }
  ],
  "sourceUrl": null,
  "zipCode": "10011",
  "state": "NY",
  "mediaAssetCount": 12,
  "hasTour3d": false,
  "hasVideos": false,
  "isNewDevelopment": false,
  "priceDelta": -25000,
  "priceChangedAt": "2026-01-15T00:00:00.000Z",
  "netEffectivePrice": null,
  "monthsFree": null,
  "leaseTerm": null,
  "availableAt": null
}

Ways to use this data

  • Real estate investors and analysts: track price per square foot and price history to spot pricing trends across buildings or neighborhoods.
  • Renters and apartment hunters: filter by no-fee, amenities, and neighborhood to shortlist rentals without paging through search results.
  • PropTech and market research teams: build a recurring dataset of NYC and Jersey City listings for pricing models and market reports.
  • Brokerages and agencies: monitor a set of buildings or neighborhoods for new listings and price changes.
  • Content and news teams: source current listing data for neighborhood market coverage.

Before you run

Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.

Questions about this actor

What data does StreetEasy Scraper return?

The documented output for StreetEasy Scraper includes id, url, type, status, price, neighborhood, borough and address. Availability of each field depends on the source page and the selected mode.

How much does StreetEasy Scraper cost?

It costs $2.00 per 1,000 results on the Apify Free plan and from $1.00 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.

Why is borough sometimes null?

borough is estimated from the listing's coordinates, with or without Fetch detail pages. It is null only when the listing has no usable coordinates or they fall outside the five boroughs plus Jersey City and Hoboken. neighborhood and address always come straight from the listing. If you track a search with Incremental mode and your saved state was taken before borough was always filled in, the first run after the upgrade treats a row whose only difference is borough going from empty to a value as UNCHANGED: it is not emitted and not billed.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push a summary of each listing into Notion, Linear, or Airtable.

Ready to collect with StreetEasy Scraper?

Run it on Apify with your own input and export the results as JSON, CSV or Excel.