# Apartments.com Scraper By Rent, Beds & Pet Policy Filter (`scrapio/apartments-com-scraper`) Actor

🏢 Apartments.com Scrape extracts listings, rent prices, amenities, and availability from Apartments.com with ease. 🚀 Perfect for market research, lead generation, and property analytics. 📊 Fast, reliable, and data-ready!

- **URL**: https://apify.com/scrapio/apartments-com-scraper.md
- **Developed by:** [Scrapio](https://apify.com/scrapio) (community)
- **Categories:** Real estate, Lead generation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### Apartments.com Scraper — Filtered Rentals, Location and Media

Apartments.com Scraper By Rent, Beds & Pet Policy Filter turns Apartments.com's own bedroom, rent and pet-policy filter paths into simple Actor inputs, then returns every matching rental as typed JSON — property details, exact address and coordinates, nearby transit, and photo or virtual-tour links. Unlike scraping frameworks that hand back raw HTML, it returns structured data ready for your model, database or pipeline with no parsing step. Because the filters run server-side on Apartments.com's own index, and a card-level pass discards non-matching properties before any detail page is fetched, most rejected candidates never cost a request. This guide covers every input, every output field, and how teams deploy it for rent tracking, relocation search and pet-friendly inventory monitoring.

### 🧭 What Does Apartments.com Scraper By Rent, Beds & Pet Policy Filter Do?

Apartments.com Scraper By Rent, Beds & Pet Policy Filter is an Apify Actor that crawls Apartments.com's location-based rental listings and returns each matching property as a structured row: identity and address, rent and unit specs, location and nearby transit, and — on request — the full photo gallery and video/3D tour links. Instead of paging the site's unfiltered results and discarding most of what comes back, it compiles bedrooms, maximum rent, pet policy and an advanced filter segment into Apartments.com's own filtered URL path, so the site itself narrows its inventory before the Actor ever loads a page.

No Apartments.com account, login or cookie is required. Every field returned is visible to an anonymous visitor on the public listing and search pages.

Key capabilities:

- Compile `bedrooms`, `maxRent` and `petPolicy` into Apartments.com's own filtered index path, verified live against known-good and known-bad path segments
- Pre-filter the 40-card search payload on rent, specials, pets and amenities before any property-detail page is fetched
- Run post-fetch guard filters (`minRating`, `verifiedOnly`, `minSqft`, `minBaths`) for criteria Apartments.com has no URL segment for at all
- Return exact address, coordinates and nearby transit for every matching property
- Return the full photo gallery and video/3D tour links on request, with no extra page load
- Carry Apartments.com's own matched-result count and the exact filtered URL on every row, so the filter is provable, not just applied
- Clear Apartments.com's Akamai Bot Manager challenge with a real Firefox browser on Apify US Residential proxy

### Features & Capabilities

Apartments.com Scraper By Rent, Beds & Pet Policy Filter's feature set breaks into three layers: the server-side filter compiler, the zero-cost card pre-filter, and the post-fetch guard filters for criteria the site can't filter on at all.

#### Core features

- **Filter-segment URL builder** — `bedrooms`, `maxRent` and `petPolicy` compile into a single Apartments.com path segment (`2-bedrooms-under-3000-pet-friendly-dog`), applied to the whole location index rather than to a slice of unfiltered pages
- **Known-bad segment rejection** — syntax that 404s (`min-X-max-Y`, singular `studio`, `max-N`, `over-N`) or silently no-ops (`0-bedrooms`) is refused before the request is ever sent, and the rejection reason is reported in `appliedFilters.rejected`
- **Card pre-filter** — `cardMinRent`, `cardMaxRent`, `requireSpecials`, `requirePetsOnCard` and `requiredCardAmenities` run against the search-result card, so a non-matching property costs nothing beyond the search page itself
- **Post-fetch guard filters** — `minRating`, `verifiedOnly`, `minSqft` and `minBaths` enforce criteria Apartments.com exposes on the property page but not as a URL segment
- **Filter telemetry on every row** — `matchedResultCount` (Apartments.com's own count for that filtered URL), `filteredSearchUrl` and `appliedFilters` so a run's filter can be audited, not just trusted
- **Location and transit data** — `location`, `coordinates` and `transportation` (nearby transit stop, drive time, distance) on every successful row
- **Media on request** — `images` (full gallery) and `virtualTours` (video and 3D tour links) add no extra request; both are read from data already present on the fetched page
- **Typed, uncharged failure rows** — a property that can't be fetched or parsed produces a row with `errorReason` set and no charge, instead of vanishing silently or billing for nothing

#### How Apartments.com Scraper compares to other Apartments.com scrapers

| Feature | This Actor | `pro100chok/apartments-scraper-usage` | `sian.agency/apartments-com-property-scraper` |
| ----- | ----- | ----- | ----- |
| Filter mechanism | Server-side URL path segments, compiled from plain inputs | User supplies a pre-filtered search URL | Search-mode parameters (location/zip/coordinates/URL) |
| Pet-policy filter | ✅ dedicated `petPolicy` param, mapped to verified site segments | Not documented as a dedicated parameter | Pet policy returned as a paid enrichment field, not a search filter |
| Zero-cost pre-filter before detail fetch | ✅ card-level rent/specials/pets/amenity guards | Not documented | Not documented |
| Post-fetch guard filters (rating/verified/sqft/baths) | ✅ four dedicated guard parameters | Not documented | Rating returned as data; not documented as a filter |
| Uncharged failure/error rows | ✅ typed `errorReason`, no charge | Not documented | ✅ "zero charge for empty runs or failed lookups" (their listing) |
| Contact email extraction | Not offered | ✅ Action 3 extracts emails from property websites | Not offered |
| Walk/transit/bike score data | Not offered | ✅ documented in the 90+ field detail output | ✅ walk score API in the enrichment bundle (paid) |
| Anti-bot engine | Playwright Firefox + Apify US Residential (source-verified) | "primp" native async TLS client (their claim) | "Direct apartments.com API — not a fragile browser scraper" (their claim) |
| Output format | Typed JSON | Typed JSON | Typed JSON |

Feature rows reflect what each Actor's own listing documented on the Apify Store as of 26 July 2026; capabilities not stated in a competitor's README are marked "not documented" rather than assumed absent.

If your use case is feeding structured data to an LLM or an automation pipeline, the filter-mechanism row is the decision-maker: a URL you already had to build by hand versus plain inputs the Actor compiles and validates for you, with the invalid combinations rejected instead of silently ignored.

#### When another tool might suit you better

If you need leasing-office contact emails pulled from property websites, or walk/transit/bike scores, renter review text, or school ratings, this Actor doesn't return them — `pro100chok/apartments-scraper-usage` documents email extraction as a dedicated step, and `sian.agency/apartments-com-property-scraper` documents a walk-score and schools enrichment bundle as a paid add-on. This Actor's job is narrower and more mechanical: compile a rent/beds/pet-policy search the way the site itself filters, discard non-matches before they cost a fetch, and guard on the criteria that have no URL segment. If your workflow needs those enrichment fields, pair this Actor with one of the above rather than expecting it to cover everything.

#### Apartments.com Scraper within the Scrapio data stack

Apartments.com Scraper By Rent, Beds & Pet Policy Filter is Scrapio's only Apartments.com Actor today, so it is the account's full coverage of this platform's rental listings, location data and media. For a different real-estate entity on Apartments.com's sister platforms or adjacent sources, use **Realtor.com Agent Scraper** for agent profiles and specialties. For ratings and review context on any property or business, including apartment communities, **Google Maps Scraper** covers that adjacently rather than duplicating it here.

### Why do developers and data teams scrape Apartments.com?

Rental-listing data supports a narrower set of buyers than a general e-commerce platform, but each one has a specific, recurring use for it.

#### 🏢 Property managers, PropTech builders and relocation services

Feed `searchLocations` and your client's bedroom/rent/pet criteria straight into a run, and get back `matchedResultCount`, `cardRentMin`/`cardRentMax`, `cardHasSpecials` and `cardAmenities` for every qualifying property — the same signals a leasing agent would read off the search results page. A relocation concierge can turn a client brief ("2 bed, under $3,000, dog-friendly, Brookline") directly into a run's `bedrooms`/`maxRent`/`petPolicy` inputs and get a shortlist back in one pass, with `location.neighborhood` and `transportation` ready to drop into a client-facing shortlist.

#### 📊 AI training data and RAG indexing

`propertyName`, `location.fullAddress` and `breadcrumbs` are the high-information text fields for RAG — they give a model the identity and geographic context needed to answer "what's available near X" without a separate geocoding step. For training data, `rent.min`/`rent.max`, `maxUnitBeds`, `maxUnitBaths`, `maxUnitSqft` and `petsAllowed` are the structurally consistent fields across every record — typed numbers and booleans, not free text, so no normalization pass is needed before the values reach a model's context window.

#### 📱 Competitive and market intelligence

Property managers and multifamily operators use `cardRentMin`/`cardRentMax` alongside `matchedResultCount` to track how a submarket's advertised price band and inventory count move over time, and `cardHasSpecials` to see which competing properties are running concessions right now. Because `filteredSearchUrl` and `appliedFilters` are on every row, a comparison across runs is reproducible — you can point to exactly which filtered search produced a given count.

#### 🔬 Research and academic use

A filtered Apartments.com search is a defensible, reproducible sampling frame for rental-market research: the same `searchLocations`, `bedrooms`, `maxRent` and `petPolicy` inputs, run again, describe the same population, and `matchedResultCount` documents the sampling universe's size at collection time. Only public listing data is collected — no renter accounts, no leasing applications, no private communications.

#### 🎥 Product and SaaS development

`id` is a stable per-property key drawn from the canonical listing URL, so repeat collections deduplicate cleanly. That makes a rent-tracking product, a pet-friendly-housing directory, or an internal underwriting feed straightforward to build on top of: one Actor call in, one row schema out, every run.

### 🍚 Input Parameters

All 21 parameters are optional — there are no required fields. Location can come from `searchLocations`, `startUrls`, or both.

| Parameter | Type | Description | Example Value |
| ----- | ----- | ----- | ----- |
| `searchLocations` | array | Cities, neighborhoods or ZIP codes to search, one per line. Each becomes an Apartments.com location index the filters below are applied to. Default `["Brookline MA"]`. | `["Miami Beach FL", "10001"]` |
| `startUrls` | array | Apartments.com URLs — a location index (`/brookline-ma/`), a map search (`?bb=…`), or an individual property page. Filter segments are inserted into location-index URLs; map and property URLs are crawled unchanged. Default `[]`. | `["https://www.apartments.com/miami-fl/"]` |
| `propertyLimit` | integer | Stop queuing properties once this many have passed the card pre-filter. `0` = no cap. Minimum `0`, maximum `10000`. Default `10`. | `20` |
| `lastSearchPage` | integer | Stop paginating the filtered index after this page (40 cards per page). `0` = crawl until results run out. Minimum `0`, maximum `28` — Apartments.com's own ceiling, values above it are clamped. Default `0`. | `5` |
| `bedrooms` | string (select) | `any` (no filter) · `studios` (`/studios/`) · `1` (`/1-bedrooms/`) · `2` (`/2-bedrooms/`) · `3` (`/3-bedrooms/`) · `4` (`/4-bedrooms/`, the site's 4-or-more ceiling bucket). Default `"any"`. | `"2"` |
| `maxRent` | integer | Compiles to the `/under-N/` segment. Minimum `0`, maximum `100000`. `0` = off. Default `0`. Unit: USD/month. | `3000` |
| `petPolicy` | string (select) | `any-policy` (no filter) · `dog` (`/pet-friendly-dog/`) · `cat` (`/pet-friendly-cat/`) · `any` (`/pet-friendly/`, any species). Default `"any-policy"`. | `"dog"` |
| `extraFilterSegment` | string | One additional Apartments.com path segment (e.g. `furnished`, `luxury`). Syntax-checked and rejected if it matches a known-bad pattern. No default. | `"furnished"` |
| `cardMinRent` | integer | Drop a property whose highest advertised card price is below this. Minimum `0`, maximum `100000`. `0` = off. Default `0`. | `2000` |
| `cardMaxRent` | integer | Drop a property whose lowest advertised card price is above this. Minimum `0`, maximum `100000`. `0` = off. Default `0`. | `3500` |
| `requireSpecials` | boolean | Keep only cards carrying the Apartments.com Specials badge. Default `false`. | `true` |
| `requirePetsOnCard` | boolean | Keep only cards whose amenity chips mention pets. Default `false`. | `true` |
| `requiredCardAmenities` | array | Case-insensitive substrings that must ALL appear in a card's amenity chips. Default `[]`. | `["In Unit Washer", "Pool"]` |
| `minRating` | integer | Drop properties rated below this, checked after the detail page is fetched. Minimum `0`, maximum `5`. `0` = off. Default `0`. | `4` |
| `verifiedOnly` | boolean | Keep only properties carrying the Apartments.com Verified Listing badge. Default `false`. | `true` |
| `minSqft` | integer | Drop a property whose largest published unit is smaller than this. Minimum `0`, maximum `20000`. `0` = off. Default `0`. | `700` |
| `minBaths` | integer | Drop a property whose largest published unit has fewer bathrooms than this. Minimum `0`, maximum `10`. `0` = off. Default `0`. | `2` |
| `includeAllImages` | boolean | Add an `images` array with every gallery photo URL published for the property. Default `false`. | `true` |
| `includeVirtualTours` | boolean | Add a `virtualTours` array with video tours and 3D tour links. Default `false`. | `true` |
| `requestDelay` | integer | Seconds to pause before each page load, plus random jitter. Minimum `0`, maximum `30`. Default `1`. | `2` |
| `proxyConfiguration` | object | Proxy configuration. Default `{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}`. | `{"useApifyProxy": true}` |

#### Example input

```json
{
  "searchLocations": ["Brookline MA"],
  "bedrooms": "2",
  "maxRent": 3000,
  "petPolicy": "dog",
  "requireSpecials": true,
  "propertyLimit": 20,
  "includeAllImages": true,
  "includeVirtualTours": true
}
```

#### Supported URL types and input formats

`searchLocations` and `startUrls` can be used together or alone, and `startUrls` accepts three distinct shapes:

```json
{ "startUrls": ["https://www.apartments.com/brookline-ma/"] }
```

A location index. Filter segments from `bedrooms`, `maxRent`, `petPolicy` and `extraFilterSegment` are inserted into the path.

```json
{ "startUrls": ["https://www.apartments.com/the-during-brookline-ma/wqc416h/"] }
```

A direct property URL. Fetched as-is — no filter segment is inserted, and no search page is crawled.

```json
{ "startUrls": ["https://www.apartments.com/brookline-ma/?bb=..."] }
```

A map/bounding-box search. Crawled unchanged; if a filter segment was also requested, a warning is logged that it cannot be applied to a map URL.

URLs that don't start with `http://`/`https://` or don't contain `apartments.com` are skipped with a logged warning rather than causing the run to fail.

### 📦 Output Format

Every successful run produces typed, normalized JSON — one row per matching property, plus an uncharged diagnostic row for any property that couldn't be fetched or parsed. The dataset ships four preset views in the Apify Console: **Filtered results** (the default), **Filter telemetry**, **Location**, and **Media** — the last three are the field groups documented below.

#### Output for a rental property row

```json
{
  "id": "wqc416h",
  "propertyName": "Emerson Place Apartments",
  "url": "https://www.apartments.com/emerson-place-apartments-brookline-ma/wqc416h",
  "breadcrumbs": ["Massachusetts", "Norfolk County", "Brookline", "Emerson Place Apartments"],
  "lastUpdated": "2026-07-18T00:00:00-04:00",
  "location": {
    "fullAddress": "165 Freeman St, Brookline, MA 02446",
    "state": "Massachusetts",
    "city": "Brookline",
    "neighborhood": "Washington Square",
    "neighborhoodSource": "ldjson",
    "postalCode": "02446",
    "streetAddress": "165 Freeman St"
  },
  "coordinates": { "latitude": 42.3336, "longitude": -71.1211 },
  "rating": 4.4,
  "reviewCount": 27,
  "isVerified": true,
  "rent": { "min": 2650, "max": 2950 },
  "transportation": [
    { "name": "Coolidge Corner", "drive": "3 min", "distance": "0.6 mi", "url": "https://www.apartments.com/transportation/..." }
  ],
  "lastUpdatedIso": "2026-07-18",
  "petsAllowed": true,
  "unitCount": 42,
  "maxUnitBeds": 2.0,
  "maxUnitBaths": 2.0,
  "minUnitSqft": 650,
  "maxUnitSqft": 980,
  "matchedResultCount": 41,
  "filteredSearchUrl": "https://www.apartments.com/brookline-ma/2-bedrooms-under-3000-pet-friendly-dog/",
  "searchPage": 1,
  "appliedFilters": {
    "bedrooms": "2",
    "maxRent": 3000,
    "petPolicy": "dog",
    "extraSegment": null,
    "urlSegment": "2-bedrooms-under-3000-pet-friendly-dog",
    "segmentParts": ["2-bedrooms", "under-3000", "pet-friendly-dog"],
    "rejected": []
  },
  "cardRentMin": 2650,
  "cardRentMax": 2950,
  "cardBedLabels": ["1 Bed", "2 Beds"],
  "cardHasSpecials": true,
  "cardPetsAllowed": true,
  "cardAmenities": ["In Unit Washer & Dryer", "Fitness Center", "Pool"],
  "cardPlusFees": false,
  "images": ["https://images1.apartments.com/i2/example-1/floorplan.jpg"],
  "virtualTours": [
    { "type": "video", "name": "Property tour", "url": "https://www.youtube.com/embed/example", "contentUrl": "https://www.youtube.com/watch?v=example", "thumbnailUrl": "https://images1.apartments.com/i2/example-thumb.jpg", "uploadDate": "2026-05-02" },
    { "type": "3d_tour", "name": "3D Tour", "url": "https://my.matterport.com/show/?m=example", "contentUrl": null, "thumbnailUrl": "https://images1.apartments.com/i2/example-3d.jpg", "uploadDate": null }
  ],
  "errorReason": null,
  "scrapedAt": "2026-07-26T14:03:21Z"
}
```

`images` and `virtualTours` only appear on the row when `includeAllImages` / `includeVirtualTours` are enabled — both are read from data already present on the fetched property page, so turning them on costs no extra request.

#### Output for location & transit data

The **Location** dataset view isolates the geographic fields for mapping or distance calculations:

```json
{
  "id": "wqc416h",
  "propertyName": "Emerson Place Apartments",
  "location": {
    "fullAddress": "165 Freeman St, Brookline, MA 02446",
    "state": "Massachusetts",
    "city": "Brookline",
    "neighborhood": "Washington Square",
    "neighborhoodSource": "ldjson",
    "postalCode": "02446",
    "streetAddress": "165 Freeman St"
  },
  "coordinates": { "latitude": 42.3336, "longitude": -71.1211 },
  "transportation": [
    { "name": "Coolidge Corner", "drive": "3 min", "distance": "0.6 mi", "url": "https://www.apartments.com/transportation/..." },
    { "name": "Cleveland Circle", "drive": "8 min", "distance": "2.1 mi" }
  ],
  "breadcrumbs": ["Massachusetts", "Norfolk County", "Brookline", "Emerson Place Apartments"]
}
```

`location.neighborhood` is read from the property page's authoritative structured data when present, falling back to the positional breadcrumb value — `neighborhoodSource` records which one was used (`"ldjson"` or `"breadcrumb"`).

#### Output for media — photos & virtual tours

The **Media** view is only populated when the corresponding input toggle was on for that run:

```json
{
  "id": "wqc416h",
  "propertyName": "Emerson Place Apartments",
  "images": [
    "https://images1.apartments.com/i2/example-1/floorplan.jpg",
    "https://images1.apartments.com/i2/example-2/kitchen.jpg",
    "https://images1.apartments.com/i2/example-3/exterior.jpg"
  ],
  "virtualTours": [
    { "type": "video", "name": "Property tour", "url": "https://www.youtube.com/embed/example", "contentUrl": "https://www.youtube.com/watch?v=example", "thumbnailUrl": "https://images1.apartments.com/i2/example-thumb.jpg", "uploadDate": "2026-05-02" }
  ]
}
```

#### Schema stability and export options

Field names are held stable across Actor updates — version 0.3 added support for a second property-page template (condos and individual units) without renaming or removing a single existing field, and the changelog documents every field-level fix by version. Export is JSON by default, with CSV and Excel available from the Apify dataset console, and the dataset is readable through the Apify API for programmatic pipelines.

### 💡 Apartments.com Scraper By Rent, Beds & Pet Policy Filter Strategy Guide

#### 🎯 Strategy 1: Real-time enrichment pipeline

Use case: turn a client's rental brief into a shortlist the moment it comes in. Workflow: a relocation-concierge or leasing-agent tool receives a request (city, bedrooms, budget, pet situation) → triggers a run with `searchLocations`, `bedrooms`, `maxRent` and `petPolicy` set from that brief → reads back `cardRentMin`/`cardRentMax`, `location.neighborhood`, `transportation` and `cardAmenities` for every matching row → appends them to the client's CRM record or shortlist document. `matchedResultCount` on each row tells the agent how tight or loose the filter was, so a zero-result search is visibly a filter problem, not a data problem.

#### 🎯 Strategy 2: Scheduled monitoring and alerting

Use case: watch a fixed search for price drops or new pet-friendly inventory. Workflow: an Apify Schedule reruns the same `searchLocations`/`bedrooms`/`maxRent`/`petPolicy` input daily or weekly → the new dataset is diffed against the previous run, keyed on `id` → an alert fires on a new `id` appearing, on `cardRentMin` dropping for an existing `id`, or on `cardHasSpecials` flipping to `true`. An Apify webhook on run completion can push the finished dataset ID to your alerting service instead of polling the Console.

#### 🎯 Strategy 3: Bulk dataset build

Use case: build a market-wide rental inventory dataset across many cities. Workflow: list your target cities in `searchLocations` (or run one Actor call per city for isolation), set `propertyLimit` to `0` for no per-run cap, and leave `lastSearchPage` at its default so each search crawls until it runs out of pages or hits Apartments.com's own 28-page ceiling → aggregate the resulting datasets to CSV or a database, keyed on `id`. Because the Actor fetches one page at a time through a single sticky browser session per run, a multi-city build is scaled by running more Actor calls in parallel on Apify — not by raising a concurrency setting inside one run, which this Actor does not expose.

#### Strategy comparison at a glance

| Strategy | Best for | Run pattern | Output format |
| ----- | ----- | ----- | ----- |
| Real-time enrichment | Client intake, lead shortlists | Single on-demand run, narrow filters | JSON row appended to CRM/shortlist |
| Scheduled monitoring | Price and specials tracking | Apify Schedule, diffed on `id` | JSON dataset diffed run-over-run |
| Bulk dataset build | Market-wide inventory | One run per location, aggregated | CSV/database keyed on `id` |

### 🌴 Related Apartments.com Scrapers & Tools

Apartments.com Scraper By Rent, Beds & Pet Policy Filter is Scrapio's only Apartments.com Actor today. For adjacent real-estate and location data in the same account:

| Scraper Name | What it extracts |
| ----- | ----- |
| Realtor.com Agent Scraper | Real-estate agent experience, specialties and contact details |
| Google Maps Scraper | Ratings, reviews and open-status filtering for any business or address |
| Booking.com Scraper | Short-term lodging listings by amenity and board filter |

### How to integrate Apartments.com Scraper By Rent, Beds & Pet Policy Filter with your stack

Apartments.com Scraper By Rent, Beds & Pet Policy Filter works with any language or tool that can call the Apify API.

#### Python

```python
from apify_client import ApifyClient
import csv

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run = client.actor("<YOUR_USERNAME>/apartments-com-scraper-by-rent-beds-pet-policy-filter").call(
    run_input={
        "searchLocations": ["Brookline MA"],
        "bedrooms": "2",
        "maxRent": 3000,
        "petPolicy": "dog",
        "propertyLimit": 50,
    }
)

rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())

## only charged, successfully scraped rows — drop diagnostic error rows
matched = [r for r in rows if r.get("errorReason") is None]

with open("apartments_matched.csv", "w", newline="", encoding="utf-8") as fh:
    w = csv.writer(fh)
    w.writerow(["id", "propertyName", "rentMin", "rentMax", "neighborhood", "matchedResultCount"])
    for r in matched:
        w.writerow([
            r["id"], r["propertyName"],
            (r.get("rent") or {}).get("min"), (r.get("rent") or {}).get("max"),
            (r.get("location") or {}).get("neighborhood"), r.get("matchedResultCount"),
        ])

print(f"{len(matched)} matching properties written, {len(rows) - len(matched)} error rows skipped")
```

#### Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });

const run = await client.actor('<YOUR_USERNAME>/apartments-com-scraper-by-rent-beds-pet-policy-filter').call({
  searchLocations: ['Miami Beach FL'],
  bedrooms: 'studios',
  maxRent: 2500,
  petPolicy: 'any',
  requireSpecials: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();

const withSpecials = items
  .filter(i => i.errorReason === null && i.cardHasSpecials)
  .map(i => ({ id: i.id, name: i.propertyName, rent: `${i.cardRentMin}-${i.cardRentMax}` }));

console.table(withSpecials);
```

#### Async and scheduled pipelines

Apify Schedules run this Actor on a cron expression with fixed input, and an Apify webhook fires when the run finishes, delivering the dataset ID to an endpoint you control — the fire-and-forget pattern for a recurring rent-monitoring job. For a large multi-city build, split the city list across several scheduled runs rather than one long run, so a single Apartments.com block doesn't cost the whole sweep.

### 🎯 Who Needs Apartments.com Scraper? (Use Cases & Industries)

#### 🏢 Property managers and relocation concierges

Turn a client's criteria into `bedrooms`/`maxRent`/`petPolicy` inputs and get back `cardAmenities`, `cardHasSpecials` and `transportation` for every qualifying property — enough to build a client-ready shortlist in one run, without manually paging Apartments.com's filtered search by hand.

#### 📊 PropTech and rental-app builders

`id` is a stable per-property key, so a tenant-search app or rent-tracking product can run this Actor on a schedule and deduplicate cleanly on repeat collections, using `rent.min`/`rent.max` and `maxUnitBeds`/`maxUnitBaths` as the core filterable fields in the product's own UI.

#### 📱 Market and competitive intelligence teams

Track `cardRentMin`/`cardRentMax` and `matchedResultCount` for a fixed filtered search over time to see a submarket's advertised price band and inventory count move, and `cardHasSpecials` to see which competing properties are running concessions this week.

#### 🔬 Researchers

A filtered Apartments.com search is a reproducible sampling frame — the same `searchLocations`, `bedrooms`, `maxRent` and `petPolicy` inputs describe the same population on a later run, and `matchedResultCount` documents the sampling universe's size at collection time. Public listing data only.

### Is it legal to scrape Apartments.com?

Scraping publicly accessible Apartments.com listing pages is generally lawful — courts have distinguished scraping public web data from unauthorized computer access. In *hiQ Labs, Inc. v. LinkedIn Corp.* (9th Cir. 2019, cert. denied 2022), the Ninth Circuit held that accessing and scraping publicly available web pages does not violate the U.S. Computer Fraud and Abuse Act.

Three separate questions are worth keeping apart. **Scraping public data:** collecting listing pages that render to any anonymous visitor, with no login bypassed, is broadly treated as permissible. **Terms of service:** Apartments.com's terms restrict automated access; violating them is a contractual and civil-risk matter, not a criminal one, but it is a real consideration separate from legality. **Data protection:** this Actor returns property, pricing and leasing data — property names, addresses, rent ranges, unit specs and site-published transit info. It does not collect renter identities, leasing applications or other individuals' personal data, so GDPR and equivalent personal-data regimes do not attach to this output the way they would to a profile or reviewer scraper.

What can still apply is database-rights and unfair-competition law if you systematically reproduce a substantial part of Apartments.com's listing inventory as a competing product. Apartments.com Scraper By Rent, Beds & Pet Policy Filter returns only publicly accessible data. What you do with that data is your responsibility — consult legal counsel for commercial applications.

### ❓ Frequently asked questions

#### Does Apartments.com Scraper work without an Apartments.com account?

Yes. No account, login or cookie is used — every field returned is visible to an anonymous visitor on the public search and property pages. The only credential you need is your Apify token.

#### How does Apartments.com Scraper handle Apartments.com's anti-scraping measures?

Apartments.com sits behind Akamai Bot Manager, which rejects non-Firefox TLS fingerprints outright and serves a JavaScript interstitial to the rest. The Actor runs a real Firefox browser (Playwright) through Apify US Residential proxy, holds one sticky exit IP for the whole run, and rolls a fresh one only when a page comes back blocked — measured at 8 consecutive property pages fetched on a single exit IP with zero re-rolls. Page validity is decided by the presence of the page's own result markers (`data-listingid` for search pages, a parseable structured-data block for property pages), not by HTTP status alone, since the Akamai interstitial itself returns HTTP 200.

#### Can I run Apartments.com Scraper at scale without getting blocked?

There's no published uptime or block-rate figure. What's documented in the code: the Actor rolls a fresh sticky IP on each blocked page (up to 6 rolls per fetch by default), and stops the run cleanly if 3 consecutive pages come back blocked across every roll, rather than continuing to burn IP rolls against a hard block. `requestDelay` (default 1 second, plus jitter) can be raised if pages start coming back blocked more often. Apartments.com's own page cap of 28 search pages per filtered index (`lastSearchPage`, `MAX_SEARCH_PAGES` in the code) is the practical ceiling on how deep one search goes, regardless of run settings.

#### How fresh is the data Apartments.com Scraper returns?

Live. Every run fetches Apartments.com's current pages — nothing is cached or replayed from a previous run. `scrapedAt` on every row records exactly when that property was read.

#### What happens to a property that fails Apartments.com Scraper's guard filters, versus one that fails to load?

These are different, and only one costs you anything. A property that fails a card pre-filter (rent, specials, pets, amenities) or a post-fetch guard filter (`minRating`, `verifiedOnly`, `minSqft`, `minBaths`) simply never produces a row — it's dropped silently from the dataset, though the run log records the count. A property that Apartments.com refuses to serve, or that the parser can't read, produces an **uncharged** row with `errorReason` set to a typed reason (`blocked`, `http_404`, `navigation_failed`, `parse_failed`, `unsupported_page_template`) instead of vanishing without a trace. Only rows with `errorReason: null` were billed under the `row_result` event — filter on `errorReason == null` to isolate charged results from diagnostic rows.

#### Why isn't "0 bedrooms" offered as a bedrooms option?

Because Apartments.com's own `/0-bedrooms/` path returns HTTP 200 but the full, unfiltered result count — it's a filter that does nothing. The `bedrooms` enum deliberately omits it; use `"studios"` instead, which maps to the site's real `/studios/` segment.

#### Which Apartments.com fields work best for AI training and RAG indexing?

For RAG: `propertyName`, `location.fullAddress` and `breadcrumbs` give a model the identity and geographic context to answer location-based queries without a separate geocoding pass. For training data: `rent.min`/`rent.max`, `maxUnitBeds`, `maxUnitBaths`, `maxUnitSqft` and `petsAllowed` are the structurally consistent fields across every record — typed numbers and booleans requiring no normalization.

#### Does Apartments.com Scraper work with Claude, ChatGPT and other AI agent tools?

Yes, as a standard HTTP endpoint through the Apify API — any agent framework that can call an HTTP tool (LangChain, CrewAI, n8n, a custom tool definition) can invoke it and receive typed JSON with no parsing required before it enters an LLM's context window.

#### How does Apartments.com Scraper compare to other Apartments.com scrapers?

Checked on the Apify Store on 26 July 2026: `pro100chok/apartments-scraper-usage` covers the most ground — search, property detail (90+ fields) and leasing-office email extraction as three chained actions — and is the strongest choice if contact data is what you need. `sian.agency/apartments-com-property-scraper` adds walk/transit/bike scores, schools and renter reviews as a paid enrichment bundle, aimed at PropTech and underwriting use cases. `crawlerbros/apartments-scraper` is the closest in scope — a straightforward 22-field property scrape — but documents no server-side filter compiler. Apartments.com Scraper By Rent, Beds & Pet Policy Filter's difference is narrower and specific: a filter-segment URL builder that rejects Apartments.com's own known-bad syntax, a card pre-filter that costs nothing on a non-match, and guard filters for the criteria the site exposes with no URL segment at all. If your job needs contact emails or score/school enrichment, one of the above will serve you better; if it needs a precise, provable rent/beds/pet-policy filter, this Actor is built for exactly that.

### Disclaimer

Apartments.com Scraper By Rent, Beds & Pet Policy Filter extracts only publicly available data from Apartments.com. This tool is intended for lawful use cases only. Users are responsible for complying with Apartments.com's terms of service and applicable data protection laws in their jurisdiction.

# Actor input Schema

## `searchLocations` (type: `array`):

Cities, neighborhoods or ZIP codes to search, one per line. Each becomes an Apartments.com location index that the filters below are applied to.

**Examples:** `Brookline MA` · `Miami Beach FL` · `10001`

## `startUrls` (type: `array`):

Paste Apartments.com URLs directly — a location index (`/brookline-ma/`), a map search (`?bb=…`), or an individual property page. Filter segments are inserted into location-index URLs; map and property URLs are crawled unchanged.

## `propertyLimit` (type: `integer`):

Stop after this many properties have been saved. `0` = no cap. Counted AFTER the card pre-filter and guard filters, so you get this many real matches. Default is 10.

## `lastSearchPage` (type: `integer`):

Stop paginating the filtered index after this page (40 cards per page). `0` = crawl until the results run out. Apartments.com serves at most 28 pages per search, so higher values are clamped to 28.

## `bedrooms` (type: `string`):

Compiles to Apartments.com's bedroom path segment. Verified live on `/brookline-ma/` (4,978 rentals unfiltered): studios → 573, 1 bed → 1,208, 2 beds → 1,505, 3 beds → 789, 4+ beds → 827.

⚠️ `0-bedrooms` is deliberately NOT offered — the site accepts it but returns the full unfiltered result set. Use **Studios** instead.

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

Compiles to the `/under-N/` segment. Verified live on `/brookline-ma/`: `under-3000` → 1,673 rentals, `under-1500` → 22.

⚠️ Apartments.com has **no minimum-rent segment** — `min-2000-max-3000` is a 404 and is rejected by the builder. Use **Card minimum rent** below for a rent floor.

## `petPolicy` (type: `string`):

Compiles to the pet segment. Verified live on `/brookline-ma/`: dog-friendly → 1,281 rentals, cat-friendly → 2,271, any pet → 1,238.

## `extraFilterSegment` (type: `string`):

Append one more Apartments.com path segment, e.g. `furnished` or `luxury`. It is syntax-checked and rejected if it matches a known-bad pattern (`min-X-max-Y`, singular `studio`, `0-bedrooms`, `max-N`, `over-N`) — those either 404 or silently return unfiltered results. Rejections are logged and reported in `appliedFilters.rejected`.

## `cardMinRent` (type: `integer`):

Drop a property whose highest advertised search-card price is below this. Applied to the 40-card search payload, so rejected properties never cost a detail fetch. `0` = off.

## `cardMaxRent` (type: `integer`):

Drop a property whose lowest advertised search-card price is above this. Useful as a tighter ceiling than the `/under-N/` segment, which the site applies loosely. `0` = off.

## `requireSpecials` (type: `boolean`):

Keep only cards carrying the Apartments.com **Specials** badge (concessions, free rent, look-and-lease offers).

## `requirePetsOnCard` (type: `boolean`):

Keep only cards whose amenity chips mention pets. Independent of the pet path segment above — use both for the strictest pet filter.

## `requiredCardAmenities` (type: `array`):

Case-insensitive substrings that must ALL appear in a card's amenity chips.

**Examples:** `Fitness Center` · `In Unit Washer` · `Pool` · `Elevator` · `Dishwasher`

## `minRating` (type: `integer`):

Drop properties rated below this after the detail page is read. ⚠️ Apartments.com publishes a rating on roughly **1 in 3** properties — anything unrated is dropped when this is set. `0` = off.

## `verifiedOnly` (type: `boolean`):

Keep only properties carrying the Apartments.com **Verified Listing** badge on the property page.

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

Drop a property whose largest published unit is smaller than this, read from the property's unit grid. Properties that publish no square footage are dropped when this is set. `0` = off.

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

Drop a property whose largest published unit has fewer bathrooms than this. Apartments.com has **no bathroom URL segment**, so this can only ever run as a post-fetch guard — it does not narrow the search itself. `0` = off.

## `includeAllImages` (type: `boolean`):

Adds an `images` array with every gallery photo URL published for the property (28–159 per property in live testing). Read from data already on the fetched page — no extra requests.

## `includeVirtualTours` (type: `boolean`):

Adds a `virtualTours` array with video tours (URL, thumbnail, upload date) and 3D tour links. Present on roughly 8–9 of every 10 properties.

## `requestDelay` (type: `integer`):

Pause before each page load, plus a small random jitter. Raise it if pages start coming back blocked. Default is 1.

## `proxyConfiguration` (type: `object`):

Apify **US Residential** proxy is used by default and is required for Apartments.com. If you paste your own proxy URLs here they are used instead, rotated whenever a page comes back blocked.

## Actor input object example

```json
{
  "searchLocations": [
    "Brookline MA"
  ],
  "startUrls": [],
  "propertyLimit": 10,
  "lastSearchPage": 0,
  "bedrooms": "any",
  "maxRent": 0,
  "petPolicy": "any-policy",
  "cardMinRent": 0,
  "cardMaxRent": 0,
  "requireSpecials": false,
  "requirePetsOnCard": false,
  "requiredCardAmenities": [],
  "minRating": 0,
  "verifiedOnly": false,
  "minSqft": 0,
  "minBaths": 0,
  "includeAllImages": false,
  "includeVirtualTours": false,
  "requestDelay": 1,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "searchLocations": [
        "Brookline MA"
    ],
    "startUrls": [],
    "requiredCardAmenities": [],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapio/apartments-com-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 = {
    "searchLocations": ["Brookline MA"],
    "startUrls": [],
    "requiredCardAmenities": [],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapio/apartments-com-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchLocations": [
    "Brookline MA"
  ],
  "startUrls": [],
  "requiredCardAmenities": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call scrapio/apartments-com-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=scrapio/apartments-com-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/gQX5Yd5fIm7GCU5rF/builds/YOeOLpvjjJ1eduysw/openapi.json
