# RentCafe Rental Listings Scraper (USA) (`scrapyx/rentcafe-rentals-scraper`) Actor

Scrapes US rental listings from RentCafe — apartments, houses, townhomes and condos. Returns name, full address, GPS coordinates, photos, rent range, resident rating, up to 10 reviews, leasing phone and office hours for any US city.

- **URL**: https://apify.com/scrapyx/rentcafe-rentals-scraper.md
- **Developed by:** [Ibnu Adzim](https://apify.com/scrapyx) (community)
- **Categories:** Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.26 / 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/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

## RentCafe Rental Listings Scraper (USA)

Scrapes US rental listings from [RentCafe](https://www.rentcafe.com) — one of
the largest American rental networks (Yardi Systems), covering **apartments,
houses, townhomes and condos**.

Give it a city. Get back every property RentCafe lists there, with full
address, GPS coordinates, photos, the actual rent range, the resident rating,
every published resident review, the leasing phone number and the office hours.

***

### What you get

One row per property, plus a `SEARCH_SUMMARY` row per city telling you exactly
what the crawl saw and which filters upstream actually honoured.

#### From the search page (always)

| Field | Example |
| --- | --- |
| `propertyId` | `1085845` |
| `name` | `Spicewood Springs Apartment Homes` |
| `streetAddress`, `city`, `state`, `postalCode` | `8617 Spicewood Springs Road`, `Austin`, `TX`, `78759` |
| `latitude`, `longitude` | `30.434`, `-97.7751` |
| `photos`, `photoCount` | first 12 image URLs; `25` total |
| `cardSummary` | `1 bd $925  2 bd $1,225+ … Pet friendly • Fitness center` |
| `propertyUrl` | link to the property page |

#### From the property page (`includePropertyDetails`, on by default)

| Field | Example |
| --- | --- |
| `rentLow`, `rentHigh`, `rentCurrency` | `899`, `1599`, `USD` |
| `ratingValue`, `ratingCount` | `4.5`, `10` |
| `reviewsFetched` + `propertyDetails.reviews[]` | full review text, rating and date per review |
| `phone` | `+1 (833) 481-2754` |
| `neighborhood` | `Anderson Mill - Jollyville` |
| `propertyDetails.openingHours` | leasing-office hours per weekday |
| `propertyDetails.breadcrumb` | state → county → city → neighborhood |
| `propertyDetails.images` | every photo (25–41 typical), not just the card's first few |

**Keep the detail pass on if you care about price.** RentCafe's search cards
carry no structured price at all — rent appears only as free text inside
`cardSummary`. `rentLow`/`rentHigh` come from the property page.

***

### Input

```jsonc
{
  "locations": ["austin-tx", "Chicago, IL", "seattle wa"],
  "propertyType": "apartments",     // apartments | houses | townhomes | condos
  "filters": ["1-bedroom"],         // at most ONE — see below
  "maxItems": 100,                  // 0 = every page the site offers
  "includePropertyDetails": true
}
```

`locations` accepts `city-state` slugs or plain `City, ST` text — `austin-tx`,
`Austin, TX` and `AUSTIN tx` are the same query and are de-duplicated.
`searchUrls` is available as an escape hatch for URLs copied from the site.

#### The four property types are separate inventories

Not one list re-sliced: Austin apartments and Austin houses share **zero**
property ids. Measured Austin: 14,299 apartment units / 90 houses / 272
townhomes / 13 condos.

#### Filters: pick at most one

RentCafe accepts exactly one filter segment per search. Asking for two (say
`1-bedroom` **and** `pet-friendly`) produces a URL it answers with a 404, so
this actor refuses the combination up front and tells you why, rather than
silently dropping one of them.

Every offered filter was verified to genuinely move the result count against
the Austin baseline of 14,299:

`studio` 1,096 · `1-bedroom` 7,126 · `2-bedroom` 4,929 · `3-bedroom` 1,051 ·
`4-bedroom` 190 · `cheap` 6,866 · `luxury` 7,963 · `furnished` 110 ·
`short-term` 1,257 · `utilities-included` 16 · `under-500` … `under-2000`
(`under-1000` → 1,869)

`pet-friendly` is offered but barely narrows most markets (14,105 of 14,299 in
Austin) — most US rental stock allows pets.

***

### Known limits — read these before you size a run

**1. The headline count is UNITS, not properties.** Austin's page says
"14,299 Rentals" but a complete crawl returns **334 properties**. Both numbers
are correct: RentCafe counts individually rentable units across all buildings,
while one dataset row is one property. The summary reports the site's figure
verbatim as `upstreamUnitCountText` and never uses it as a row expectation.
Expect roughly 40× fewer rows than that headline.

**2. Each query has a hard page ceiling.** Austin apartments stop at 14 pages
(~334 properties); `1-bedroom` stops at 10 (249). Past the ceiling RentCafe
answers a band of HTTP 500s and then silently re-serves page 1 forever. The
actor reads the ceiling off the site's own pagination nav and stops there;
`pageCeiling` and `paginationClampHit` are reported so you can see it happened.
**To go wider, add more cities or run one filter per query** — not more pages.

**3. Some properties are de-listed mid-crawl.** RentCafe answers a dead
property URL with a redirect to the city search page and a healthy HTTP 200 —
not a 404. Those rows come back with `_detailError` set and their list fields
intact, never with another property's data.

**4. New York's slug is `new-york-city-ny`**, not `new-york-ny`. Unrecognised
slugs return a clean 404 → one honest `ERROR` row, never another city's
listings.

***

### Anti-bot posture

**None observed.** An 8-profile TLS ladder (chrome124/131/145,
chrome99\_android, safari17\_0, firefox133/144, edge101) returned a full document
on the search page *and* the property page — cold, no warmup, no cookies, no
tokens. `chrome99_android` gets the same desktop document as everything else.

The actor still ships a rotating profile pool, a retry ladder and
challenge-marker detection, and defaults to Apify Residential pinned to the US
for cloud runs — container egress is a different posture than a home
connection, and a target being clean today is not a guarantee.

The default request pacing (0.4s between requests, across all workers) is
deliberately polite. An unthrottled crawl is how a WAF-free site stops being
WAF-free.

### Policy

RentCafe's `robots.txt` disallows the site's own filter **query string**
(`?PriceMin=`, `?PriceMax=`, `?Bedroom=`, `?Bathrooms=`, `?PropertyType=`,
`?AmenitiesIds=`, `?PetPolicy=`, `?OrderBy=`) as well as `/search/` and
`/details/`. This actor never touches any of them: it uses the SEO **path**
form RentCafe publishes for crawlers (`/apartments-for-rent/austin-tx/1-bedroom/`),
and `?page=` — which no rule disallows. Pasted query-string filter URLs are
refused rather than fetched.

# Actor input Schema

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

US cities to crawl, as 'city-state' slugs or plain 'City, ST' text — 'austin-tx', 'Chicago, IL', 'seattle wa' all work. One crawl per entry, each with its own SEARCH\_SUMMARY row. A slug RentCafe does not recognise returns a clean HTTP 404 (verified — it never silently falls back to statewide or nationwide listings), so a wrong guess costs you one honest ERROR row, never wrong data. Watch out for New York: its slug is 'new-york-city-ny', not 'new-york-ny'.

## `propertyType` (type: `string`):

Which of RentCafe's four rental inventories to crawl. These are genuinely separate listing sets, not one list re-sliced — Austin apartments and Austin houses share zero property ids. Applies to every entry in 'Cities'.

## `filters` (type: `array`):

An optional refinement applied to every city. RentCafe accepts only ONE filter per search — asking for two (e.g. 1-bedroom AND pet-friendly) produces a URL it answers with a 404, so this actor refuses the combination up front instead of silently dropping one. Every value here was verified to genuinely move the result count. Note 'pet-friendly' barely narrows most markets (14,105 of 14,299 in Austin) because most US stock allows pets.

## `searchUrls` (type: `array`):

Escape hatch: paste RentCafe search URLs copied from the site, e.g. https://www.rentcafe.com/apartments-for-rent/austin-tx/1-bedroom/. Each is parsed into the same city/type/filter triple as the fields above, so unverified filter segments are rejected rather than sent blind. RentCafe's own filter UI produces query-string URLs (?Bedroom=…\&PriceMax=…) which its robots.txt disallows — those are refused; use the fields above instead.

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

Stop after this many properties per city. Set to 0 for unlimited — the crawl then walks every page the site's own pagination offers (Austin apartments: 14 pages, 332 properties). Note RentCafe's headline count ('14,299 Rentals') counts individual rentable UNITS, not properties; one dataset row is one property, so expect far fewer rows than that number.

## `includePropertyDetails` (type: `boolean`):

Fetch each property's page via one extra request: the rent range (low/high), resident rating, up to 10 full resident reviews with text and dates, leasing phone number, office hours and the neighborhood breadcrumb. Worth keeping on — the search card carries NO structured price at all (rent appears only as free text). Turn it off for a fast address/geo-only crawl.

## `maxConcurrency` (type: `integer`):

How many requests may be in flight at once. This absorbs latency variance; it is NOT the throttle — the crawl rate is set by 'Minimum interval between requests' below.

## `minRequestInterval` (type: `number`):

The actual speed control: the shortest gap between two requests to RentCafe, across all workers. RentCafe serves no bot challenge at all, which is worth preserving — an unthrottled crawl is how a WAF-free site stops being WAF-free. Values below 0.05s are clamped.

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

RentCafe runs no bot challenge at all (8/8 TLS profiles clean on search and detail), but Residential pinned to the US is the cloud default — container egress is a different posture than a home connection, and this is a US-only rental network.

## Actor input object example

```json
{
  "locations": [
    "austin-tx",
    "seattle-wa"
  ],
  "propertyType": "apartments",
  "filters": [],
  "searchUrls": [],
  "maxItems": 100,
  "includePropertyDetails": true,
  "maxConcurrency": 5,
  "minRequestInterval": 0.4,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `items` (type: `string`):

One row per scraped record. See the dataset's default view for field definitions.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "locations": [
        "austin-tx",
        "seattle-wa"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapyx/rentcafe-rentals-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "locations": [
        "austin-tx",
        "seattle-wa",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("scrapyx/rentcafe-rentals-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "locations": [
    "austin-tx",
    "seattle-wa"
  ]
}' |
apify call scrapyx/rentcafe-rentals-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapyx/rentcafe-rentals-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/IEcqnmQxWxbZDcNGp/builds/kgpX5eqmcytdb8upZ/openapi.json
