# Apartment List Scraper - US Rentals by City (`s-r/apartmentlist-scraper`) Actor

Scrape rental listings from apartmentlist.com. Rent range, beds, baths, floor plans, square footage, amenities, availability, coordinates and phone for any US city, filtered search or property URL.

- **URL**: https://apify.com/s-r/apartmentlist-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Real estate, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 per-run start fees

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

## Apartment List Scraper

Rental listings from apartmentlist.com as a clean table. Give it a US city and
get back every property on the market there: the name, the full address with
ZIP code, the coordinates, the rent range, the bed and bath counts, every floor
plan with its square footage and price, the amenities, how many units are open
and from when, and the leasing office phone.

It takes a city in either form, `tx/austin` or `Austin, TX`, and walks the
result pages for you. It also takes a full apartmentlist.com search URL, so if
you have already narrowed a search in the browser to two bedrooms under $1,500,
paste that URL and the filters in it are respected. Or set the filters here:
`beds`, `baths` and `maxRent` are passed straight to the site's own search.

Property pages work too. Paste property URLs into `listingUrls` (or into the
search box; the scraper tells them apart) and each comes back as a richer row
with the description, year built, total unit count, pet policy and the
property's own website.

### What you get per property

- `name`, `address`, `street`, `city`, `state`, `zip`, `neighborhood`
- `lat`, `lng`
- `rent_min`, `rent_max`, and `rent_by_beds` (the range per bedroom count)
- `beds` (every count on offer, `0` is a studio), `baths`, `sqft_min`, `sqft_max`
- `floorplans`: per plan the name, beds, baths, square feet, rent, units
  available and earliest move-in date
- `units_available`, `available_from`, `has_rent_special`
- `amenities`, `phone`, `image`, `url`, `updated_at`
- `search`, `search_page`, `result_count`, `position`

Property-page rows add `description`, `year_built`, `total_units`,
`pets_allowed`, `pets`, `rental_type` and `website`. The `_type` column says
`listing` or `property` so a mixed run stays sortable.

`result_count` is the total the search itself matched, which is far larger
than any single run returns. Austin reports over two thousand properties on an
unfiltered search and 355 with two bedrooms under $1,500, so use the filters
to cut a city down to the slice you want before you raise `maxItems`.

### Why scrape Apartment List

Apartment List covers the large multi-family market in the United States: the
managed communities with a leasing office, published floor plans and unit-level
availability. That is the data a rent analysis needs and the data an
individual-landlord site does not have. Every row here carries the rent per
floor plan rather than one headline number, so the same property can be
compared on a one-bedroom against a one-bedroom across a whole city.

The listings refresh often. `updated_at` is stamped on every row, most of them
within the last day, and `available_from` is the earliest move-in date the
property advertises, so a weekly run tracks concessions, price moves and
vacancy without any guesswork.

### Input

| Field | Type | Required | Notes |
|---|---|---|---|
| `search` | list | no | Cities as `tx/austin` or `Austin, TX`, or full search URLs. |
| `listingUrls` | list | no | Property pages, one per line. |
| `beds` | integer | no | Keep properties with a floor plan of this many bedrooms. |
| `baths` | integer | no | Keep properties with a floor plan of at least this many bathrooms. |
| `maxRent` | integer | no | Keep properties whose lowest rent is at or under this, USD per month. |
| `maxItems` | integer | no | Across all cities, default 50, up to 5,000. |
| `maxPages` | integer | no | Per city, default 10, up to 100. |

Give at least one of `search` or `listingUrls`. A run with neither fails with
`bad_input`.

### Output

One row per property in the dataset:

```json
{
  "_type": "listing",
  "listing_id": "p43719",
  "name": "SoNa",
  "address": "7900 San Felipe blvd, Austin, TX 78729",
  "street": "7900 San Felipe blvd",
  "city": "Austin",
  "state": "TX",
  "zip": "78729",
  "lat": 30.438271,
  "lng": -97.767799,
  "rent_min": 875,
  "rent_max": 1204,
  "rent_by_beds": {"1": {"min": 875, "max": 953}, "2": {"min": 879, "max": 1204}},
  "beds": [1, 2],
  "baths": [1, 2],
  "sqft_min": 550,
  "sqft_max": 917,
  "units_available": 11,
  "available_from": "2026-10-24",
  "amenities": ["Dogs allowed", "Pet friendly", "Gym", "Pool", "In unit laundry"],
  "floorplans": [
    {"name": "A1", "beds": 1, "baths": 1, "sqft": 550, "rent": 875,
     "units_available": 3, "available_from": "2026-08-01"}
  ],
  "url": "https://www.apartmentlist.com/tx/austin/sona--2",
  "image": "https://cdn.apartmentlist.com/image/upload/f_auto,q_auto,t_web-base/b0965f33a0c81c7983fc759b5bda437d.jpg",
  "phone": "(512) 866-8102",
  "updated_at": "2026-09-19T14:06:54.402Z",
  "search": "tx/austin",
  "search_page": 1,
  "result_count": 2234,
  "position": 1
}
```

The key-value store holds `summary` (cities walked, rows returned, how many
requests were made and how many were refused) and `errors` (pages that could
not be read, with a code and a short message).

### Use cases

**Rent benchmarking.** Pull a city with `beds` set and compare `rent_by_beds`
across properties, or go one level down and compare `floorplans` on square
footage. Because every property carries its coordinates, the rows drop
straight onto a map or into a distance-to-office calculation.

**Vacancy and concession tracking.** Run the same cities weekly.
`units_available`, `available_from` and `has_rent_special` move before the
headline rent does, and `updated_at` tells you which rows actually changed.

**Lead lists for property services.** Every row carries the property name,
the address and, on nearly every one, the leasing office phone. Property-page
rows add the management company's own website.

**Relocation and market research.** A handful of cities with `maxRent` set
gives a like-for-like picture of what a budget buys in each, with the
amenities listed so the comparison is not on price alone.

### Pricing

Pay per event: one `run_start` event per run and one `listing` event per
property returned. Nothing is charged for pages that could not be read.

### Limits and gotchas

- US cities only; that is the site's coverage.
- `beds` matches properties that *have* a plan with that count, so a
  `beds: 2` row can also list one- and three-bedroom plans. Read `rent_by_beds`
  for the two-bedroom price.
- Page one of a search holds twenty properties, later pages sixteen. A property
  featured at the top of page one is not returned twice.
- `maxItems` is applied across all cities in the run, in the order given.
- Free-plan Apify accounts are capped at ten rows per run.
- If the site refuses every request, the run fails with a clear status message
  and `summary.refused` says how many attempts were made. Rerun a little later.
- Property pages are fetched one at a time, so a long `listingUrls` list is
  slower than the same properties reached through a search.

### FAQ

**Can I filter by neighbourhood?** Not directly. Filter by city and then by the
`neighborhood` column, which the site fills in for the larger metros.

**Does it return individual units?** Floor plans, with the count of units
available per plan and the earliest date. Unit numbers are not returned.

**Why is `rent_max` sometimes far above `rent_min`?** Because the property
spans several floor plans. `rent_by_beds` and `floorplans` break it down.

**Why does `result_count` say 2,234 but I got 50?** `result_count` is what the
search matched; `maxItems` is what you asked for. Raise `maxItems` and
`maxPages` to get more.

**Can I search by ZIP code?** Not yet. Search the city and filter the `zip`
column, or paste a search URL from the site that already has the ZIP applied.

### Related Actors

- [Apartments.com Scraper](https://apify.com/s-r/apartments-scraper)
- [Homes.com Scraper](https://apify.com/s-r/homes-com-scraper)
- [Redfin Scraper](https://apify.com/s-r/redfin-scraper)

# Actor input Schema

## `search` (type: `array`):

One per line. A city as state/city (tx/austin) or as City, ST (Austin, TX), or a full apartmentlist.com search URL with filters already applied.

## `listingUrls` (type: `array`):

Optional. Individual property pages to read, one per line, for example https://www.apartmentlist.com/tx/austin/sona--2. These rows carry the description, year built, pet policy and website as well.

## `beds` (type: `integer`):

Optional. Keep properties that have a floor plan with this many bedrooms. 0 means studio.

## `baths` (type: `integer`):

Optional. Keep properties that have a floor plan with at least this many bathrooms.

## `maxRent` (type: `integer`):

Optional. Keep properties whose lowest rent is at or under this amount.

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

Across all cities. Result pages hold sixteen to twenty properties each, so this trims the last page rather than shortening it.

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

The safety rail on a large city. Austin alone has over a hundred pages.

## Actor input object example

```json
{
  "search": [
    "tx/austin",
    "Denver, CO",
    "https://www.apartmentlist.com/ca/san-francisco?beds=2&price_max=3500"
  ],
  "listingUrls": [
    "https://www.apartmentlist.com/tx/austin/sona--2"
  ],
  "maxItems": 50,
  "maxPages": 10
}
```

# Actor output Schema

## `listings` (type: `string`):

One row per property.

## `summary` (type: `string`):

Cities walked, listings returned and how many requests were refused.

## `errors` (type: `string`):

Pages that could not be read.

# 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 = {
    "search": [
        "tx/austin"
    ],
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/apartmentlist-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 = {
    "search": ["tx/austin"],
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("s-r/apartmentlist-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 '{
  "search": [
    "tx/austin"
  ],
  "maxItems": 50
}' |
apify call s-r/apartmentlist-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,s-r/apartmentlist-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/76Jk1kaQkAFkLfqIC/builds/ikJQyTcwnl7Dhc6kk/openapi.json
