Trulia Scraper - US Property Listings, Prices, Photos & Agents
Pricing
from $1.00 / 1,000 listing scrapeds
Trulia Scraper - US Property Listings, Prices, Photos & Agents
Scrape Trulia.com property listings: price, beds, baths, square footage, address, GPS, photos, listing agent and broker, plus price history, tax history, features and open houses on detail pages. Search by location with keyword and sort filters, or paste Trulia URLs.
Pricing
from $1.00 / 1,000 listing scrapeds
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Trulia Scraper
Extract property listings from Trulia across the United States: for sale, for rent, and recently sold. Search by location with optional keyword and sort, or paste Trulia URLs directly. Every listing comes back as one clean record with price, beds, baths, square footage, full address, GPS coordinates, photos, and the listing agent and broker. Turn on detail mode to also pull price history, tax history, the full feature list, open houses, agent contact, and affordability data from each property page.
Why this scraper
- Rich output out of the box: search results already include price, beds, baths, size, full address, neighborhood, GPS, photo gallery, listing agent name and broker, status flags, and tracking ids. No detail fetch needed for the common fields.
- Optional deep detail: one toggle adds price history, tax history, features, open houses, listing agent and broker contact, local protections, estimated rent, and more.
- Three listing channels: for sale, for rent, and recently sold.
- Real keyword filter: narrow a location to listings that mention a term like pool or waterfront.
- Two input modes: build searches from simple fields, or paste search and property URLs you already have. Multiple URLs supported with automatic pagination.
- Lean and predictable: detail mode is off by default, so a standard run is fast and low cost. One result cap (Max items) keeps every run predictable.
- Resume & recurring updates: continue one interrupted crawl with
resumeFromRunId, or turn onincrementalModeto schedule this same search daily/weekly and get back only what's NEW, UPDATED, or REAPPEARED. - Optional export: pipe results straight into Notion, Linear, Airtable, or Apify via MCP connectors.
Data you get
Sample shape, values are illustrative placeholders, not from a live listing.
| Field | Example |
|---|---|
| id | 00000001 |
| url | https://www.trulia.com/home/sample-address-ny-10000-00000001 |
| listingType | FOR_SALE |
| propertyType | SINGLE_FAMILY_HOME |
| price | 750000 |
| formattedPrice | $750,000 |
| streetAddress | 123 Sample Street |
| city | Sampletown |
| state | NY |
| zipCode | 10000 |
| neighborhood | Sample Heights |
| latitude | 40.0000 |
| longitude | -73.0000 |
| bedrooms | 3 |
| bathrooms | 2 |
| floorSpace | 1,800 sqft |
| listingAgentName | Agent Name |
| brokerName | Sample Realty |
| heroImage | https://www.trulia.com/pictures/thumbs_4/zillowstatic/fp/00000000-full.jpg |
| photos | [ "https://www.trulia.com/pictures/thumbs_6/zillowstatic/fp/00000000-full.jpg" ] |
| tags | [ "NEW", "OPEN SUN" ] |
| scrapedAt | 2026-01-01T00:00:00.000Z |
With Fetch property details enabled, each record also includes: priceHistory, taxes, features, openHouses, providerDetails (agent and broker contact), localProtections, affordability, estimatedRent, totalPhotoCount, plus the full homeDetails object.
Incremental mode only. When incrementalMode is on, every returned record also carries:
| Field | Description |
|---|---|
changeType | NEW | UPDATED | UNCHANGED | REAPPEARED | EXPIRED |
changedFields | Top-level fields that changed since last seen; non-empty only for UPDATED |
firstSeenAt | When this listing was first observed by this monitoring campaign |
lastSeenAt | When this listing was last observed |
An EXPIRED row is a tombstone (the same fields a normal record carries, minus a couple of per-fetch MLS refresh-stamp leaves), not a re-fetch: it reflects the last snapshot this actor collected before the listing stopped appearing.
How to use
Basic search:
{"mode": "search","searchLocation": "Austin,TX","searchListingType": "FOR_SALE","maxItems": 50}
Search with keyword and sort:
{"mode": "search","searchLocation": "Miami,FL","searchListingType": "FOR_SALE","searchKeyword": "pool","searchSort": "PRICE_LOW_TO_HIGH","maxItems": 100}
For rent, with full detail enrichment:
{"mode": "search","searchLocation": "Seattle,WA","searchListingType": "FOR_RENT","fetchDetails": true,"maxItems": 40}
URL mode (search URLs are paginated, property URLs return one record each):
{"mode": "url","startUrls": ["https://www.trulia.com/sold/Denver,CO/","https://www.trulia.com/home/sample-address-co-80000-00000002"],"maxItems": 60}
Input parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| mode | string | search | search (build URLs from filters) or url (paste links) |
| searchLocation | string | New_York,NY | Search mode. US location as City,STATE |
| searchListingType | string | FOR_SALE | FOR_SALE, FOR_RENT, or SOLD |
| searchKeyword | string | (empty) | Search mode. Narrows to listings mentioning this term |
| searchSort | string | RECOMMENDED | RECOMMENDED, NEWEST, PRICE_LOW_TO_HIGH, PRICE_HIGH_TO_LOW |
| startUrls | array | (empty) | URL mode. Trulia search or property URLs |
| fetchDetails | boolean | false | Add price history, taxes, features, open houses, agent contact |
| maxItems | integer | 20 | Run cap on listings. 0 for unlimited |
| maxPages | integer | none (unlimited) | Optional safety cap on pages per search (40 listings per page). Leave empty to walk every result page; the run stops at Max items |
| resumeFromRunId | string | none | Continue one specific previous run/dataset: listings already collected there are skipped, so this run only returns new ones. For recurring daily monitoring of the same search, use incrementalMode instead -- see "Resume & recurring updates" below |
| incrementalMode | boolean | false | Daily/recurring monitoring of this same search. First run returns everything as NEW; later runs return only NEW/UPDATED/REAPPEARED by default. See "Resume & recurring updates" below |
| stateKey | string | none | Optional name for a monitoring campaign, so its incremental state stays stable or is deliberately shared. Auto-derived from location/URLs, listing type, keyword, sort, and fetchDetails when left empty |
| emitUnchanged | boolean | false | Incremental mode only. Also return listings unchanged since the last run, marked UNCHANGED. Adds and bills extra rows you already have |
| emitExpired | boolean | false | Incremental mode only. Also return listings from a previous run no longer found, marked EXPIRED, once a run has fully scanned the search (not capped, not a resume). Adds and bills extra synthetic rows |
| proxy | object | Residential US | Residential US is required; datacenter is refused |
Resume & recurring updates
There are two different things here -- pick the one that matches what you're doing:
| Need | Use |
|---|---|
| A crawl stopped and should continue | resumeFromRunId / automatic checkpoint recovery |
| Run the same search every day and receive only changes | incrementalMode |
| Keep separate daily campaigns for similar searches | distinct stateKey values |
| Run a normal full snapshot | leave both off |
Resume (resumeFromRunId) continues one specific interrupted or previous large crawl: paste a run ID or dataset ID and this run skips listings already collected there, returning only the remaining new listings. An automatic same-run checkpoint also protects against platform migrations/Resurrects without any input needed.
Incremental mode (incrementalMode) is for a schedule (for example, daily): the actor remembers the previous run of the same search by itself, so you never paste a run ID. The first run returns everything as NEW. Later runs return only NEW, UPDATED, and REAPPEARED listings by default -- duplicates and unchanged listings are suppressed (and not charged, even in detail mode -- see below). Turn on emitUnchanged or emitExpired only when you also want those rows returned (and billed for). State is isolated per location/URL, listing type, keyword, sort, and fetchDetails setup automatically; set stateKey to name or deliberately share a monitoring campaign. It reuses the same listing identity (id, falling back to url) that resumeFromRunId dedups on, so the two features never disagree about what "the same listing" means.
With fetchDetails on, a listing's property page is still fetched every run (its fingerprint needs the detail data), but the detail-enrichment charge only applies to listings actually returned -- a suppressed UNCHANGED listing is neither pushed nor billed.
Scheduled-run example -- same search, run daily:
Day 1 (first run ever for this search):
{ "mode": "search", "searchLocation": "Austin,TX", "searchListingType": "FOR_SALE", "incrementalMode": true }
-> every listing comes back with "changeType": "NEW".
Day 2 (same input, run again the next day):
{ "mode": "search", "searchLocation": "Austin,TX", "searchListingType": "FOR_SALE", "incrementalMode": true }
-> only listings that are new, changed price/status/agent/etc., or reappeared come back; everything else is skipped and not billed.
Send results into your apps (MCP connectors)
Optionally pipe each result into the tools you already use. Authorize a connector under Apify, Settings, Integrations, then select it in the mcpConnectors field. For Notion, also set notionParentPageUrl. The connector receives a condensed, human-readable summary per item (address plus key fields); the complete record always stays in the Apify dataset. Leave the field empty to skip. Supported connectors: Notion, Linear, Airtable, and Apify.
Output example
Sample shape, values are illustrative placeholders, not from a live listing.
{"id": "00000001","url": "https://www.trulia.com/home/sample-address-ny-10000-00000001","listingType": "FOR_SALE","propertyType": "SINGLE_FAMILY_HOME","price": 750000,"formattedPrice": "$750,000","streetAddress": "123 Sample Street","city": "Sampletown","state": "NY","zipCode": "10000","neighborhood": "Sample Heights","latitude": 40.0000,"longitude": -73.0000,"bedrooms": 3,"bathrooms": 2,"floorSpace": "1,800 sqft","listingAgentName": "Agent Name","brokerName": "Sample Realty","heroImage": "https://www.trulia.com/pictures/thumbs_4/zillowstatic/fp/00000000-full.jpg","photos": ["https://www.trulia.com/pictures/thumbs_6/zillowstatic/fp/00000000-full.jpg"],"tags": ["NEW"],"scrapedAt": "2026-01-01T00:00:00.000Z"}
Plan requirement
Trulia admits United States residential connections only, so this actor needs an Apify Residential proxy pinned to the US (the default). Datacenter exits are refused. Free Apify plans do not include residential proxy; use a Starter plan or higher (https://apify.com/pricing). The actor rotates US then CA residential exits and can fail over to a backup gateway. If a run returns zero items, check that the proxy is set to Residential US.