{"slug": "how-to-scrape-zillow", "title": "How to scrape Zillow", "summary": "SerpApi's Zillow Search API enables developers and AI agents to scrape structured real estate data from Zillow, including homes for sale, rental listings, recently sold homes, property details, valuation data, and location information. The API returns live search results as JSON or Markdown and requires a SerpApi account with a private API key, with official libraries available for Python, JavaScript, Ruby, and Java. Users must identify a Zillow region ID from the URL or page source to perform searches.", "body_md": "Homes for sale, rental properties, recently sold homes, open houses, foreclosures, price histories. If you need real estate data, chances are Zillow has it. This is useful for market research, property monitoring, investment analysis, rental discovery, and real estate applications. But what if you need easy access to Zillow structured data from your programs or AI agents?\n\nThe [Zillow Search API](https://serpapi.com/zillow-search-api) from SerpApi lets you fetch live Zillow search results as structured JSON or Markdown with many natively supported SDKs or even a simple cURL call. SerpApi handles the page retrieval and parsing, so you can focus on the interesting part of filtering, analyzing, and storing all the property data. Or use SerpApi MCP and let your agents fetch what you need.\n\n## What can you scrape from Zillow?\n\nHere are some of the types of data you can pull from Zillow using SerpApi:\n\n**Homes for sale:** Active listings, coming-soon properties, Zillow previews, pending homes, foreclosures, auctions, and new construction.**Rental listings:** Individual rental properties and apartment buildings, including prices, available units, pet policies, amenities, and availability dates when present.**Recently sold homes:** Sold prices, sold dates, property characteristics, and valuation data. Sold prices may not be available in non-disclosure states.**Property details:** Addresses, prices, bedrooms, bathrooms, square footage, lot size, home type, broker name, and the number of days on Zillow.**Valuation data:** Zestimate, Rent Zestimate, tax-assessed value, and recent price changes when Zillow provides them.**Location data:** Latitude and longitude for listings, as well as the geographic boundaries of the searched region.**Listing media and features:** Thumbnails, property images, open house schedules, 3D tour availability, videos, badges, and showcase status.**Search information:** The total number of results, results per page, total pages, region details, and pagination links.**Nearby results:** Relaxed results from surrounding areas when there are not enough exact matches for a search.\n\n## Getting started with SerpApi\n\nYou need a SerpApi account to use the Zillow Search API. If you have not already created one, [register for a SerpApi account](https://serpapi.com/users/sign_up), verify your email address, and copy your private API key from the account dashboard.\n\nKeep your API key out of public source code. Store it in an environment variable or a secrets manager, especially when publishing an application or sharing a repository. If a key is accidentally exposed, you can regenerate it from the SerpApi dashboard.\n\n### Install a SerpApi library\n\nSerpApi provides official libraries for Python, JavaScript, Ruby, Java, and other languages. These libraries wrap the HTTP API and make it easier to pass parameters and work with the JSON response.\n\nYou can also call the API with a regular GET request using cURL, `fetch()`\n\nin Node.js, or any HTTP client. This guide covers both direct requests and several official integrations.\n\nThe [Zillow Search API documentation](https://serpapi.com/zillow-search-api) lists all supported search parameters, filters, response fields, and code examples. You can also experiment with every parameter in the [interactive playground](https://serpapi.com/playground?engine=zillow) before writing any code.\n\n## Finding the Zillow region ID\n\nAll searches on Zillow will need a location identifier. A Zillow region can represent a city, neighborhood, ZIP code, county, or state. To find its ID, search for the location on Zillow and look for the number before `_rid`\n\nin the resulting URL.\n\nFor example, this URL identifies Austin, Texas, with region ID `10221`\n\n:\n\n```\nhttps://www.zillow.com/homes/10221_rid/\n```\n\nNewer Zillow URLs often use a readable slug such as `https://www.zillow.com/austin-tx/`\n\nand hide the region ID. If you do not see `_rid`\n\nin the URL, open the page source and search for `regionId`\n\n, which appears in the embedded search state JSON.\n\nYou can also confirm an ID by opening `https://www.zillow.com/homes/<ID>_rid/`\n\n, which redirects to the matching region page.\n\nThe API can also search an arbitrary map area. The `map_bounds`\n\nvalue contains four comma-separated coordinates in this order:\n\n```\nnorth,east,south,west\n```\n\nYou can use `region_id`\n\nand `map_bounds`\n\ntogether to search only one portion of a larger region.\n\n## How to scrape Zillow search results\n\nOnce you have an API key and a region ID, you can start fetching property listings. The examples below search Austin, Texas, for houses and condos listed for sale between $300,000 and $800,000, with at least two bedrooms and two bathrooms.\n\nThe main parameters are:\n\n`region_id=10221`\n\nfor Austin, Texas.`status_type=sale`\n\nfor properties currently for sale. This is the default, so it can be omitted.`price=300000,800000`\n\nfor the minimum and maximum price.`beds=2`\n\nfor two or more bedrooms.`baths=2`\n\nfor two or more bathrooms.`home_type=house,condo`\n\nto include only houses and condos.`sort_by=pricea`\n\nto sort by price from lowest to highest.\n\nRemember that every request must include:\n\n`engine=zillow`\n\nto select the Zillow Search API.`api_key`\n\nwith your private SerpApi API key.- At least one search area, using\n`region_id`\n\n,`map_bounds`\n\n, or both.\n\n### GET request\n\nYou can make the search with a single GET request:\n\n```\nhttps://serpapi.com/search?engine=zillow&region_id=10221&status_type=sale&price=300000,800000&beds=2&baths=2&home_type=house,condo&sort_by=pricea&api_key=YOUR_API_KEY\n```\n\nThe response includes search metadata and an `organic_results`\n\narray containing the matching Zillow listings. An abridged response looks like this:\n\n```\n{\n  \"search_information\": {\n    \"region\": {\n      \"region_id\": 10221,\n      \"name\": \"Austin\",\n      \"display_name\": \"Austin TX\"\n    },\n    \"total_results\": 5830,\n    \"results_per_page\": 41,\n    \"total_pages\": 20\n  },\n  \"organic_results\": [\n    {\n      \"position\": 1,\n      \"zpid\": \"29505949\",\n      \"title\": \"8536 Birmingham Dr, Austin, TX 78748\",\n      \"link\": \"https://www.zillow.com/homedetails/8536-Birmingham-Dr-Austin-TX-78748/29505949_zpid/\",\n      \"status\": \"FOR_SALE\",\n      \"price\": \"$439,000\",\n      \"extracted_price\": 439000,\n      \"beds\": 3,\n      \"baths\": 3,\n      \"square_feet\": 1398,\n      \"home_type\": \"SINGLE_FAMILY\",\n      \"gps_coordinates\": {\n        \"latitude\": 30.181974,\n        \"longitude\": -97.806564\n      },\n      \"broker_name\": \"Engel & Volkers Austin\"\n    }\n  ],\n  \"serpapi_pagination\": {\n    \"current\": 1,\n    \"next\": \"https://serpapi.com/search.json?engine=zillow&page=2&region_id=10221\"\n  }\n}\n```\n\nUse `extracted_price`\n\nfor calculations and sorting in your application. The `price`\n\nfield is the human-readable version displayed by Zillow.\n\nEach response also carries `search_metadata.status`\n\n, which moves from `Processing`\n\nto `Success`\n\nor `Error`\n\n. If a search fails, the response includes an `error`\n\nmessage describing what went wrong.\n\n`lot_id`\n\ninstead of a Zillow property ID (`zpid`\n\n), and their results can include unit groups and a range of rents instead of one price.### cURL\n\nYou can make the same request from the command line without installing a library:\n\n```\ncurl --get https://serpapi.com/search \\\n  --data-urlencode engine=\"zillow\" \\\n  --data-urlencode region_id=\"10221\" \\\n  --data-urlencode status_type=\"sale\" \\\n  --data-urlencode price=\"300000,800000\" \\\n  --data-urlencode beds=\"2\" \\\n  --data-urlencode baths=\"2\" \\\n  --data-urlencode home_type=\"house,condo\" \\\n  --data-urlencode sort_by=\"pricea\" \\\n  --data-urlencode api_key=\"YOUR_API_KEY\"\n```\n\n### Python\n\nInstall the official SerpApi Python library:\n\n```\npip install serpapi\n```\n\nThis example performs the Austin search and prints a compact summary for each result:\n\n``` python\nimport os\nimport serpapi\n\nclient = serpapi.Client(api_key=os.environ[\"SERPAPI_API_KEY\"])\nresults = client.search({\n    \"engine\": \"zillow\",\n    \"region_id\": \"10221\",\n    \"status_type\": \"sale\",\n    \"price\": \"300000,800000\",\n    \"beds\": \"2\",\n    \"baths\": \"2\",\n    \"home_type\": \"house,condo\",\n    \"sort_by\": \"pricea\",\n})\n\nfor listing in results.get(\"organic_results\", []):\n    print(\n        f'{listing.get(\"title\")} — {listing.get(\"price\")} — '\n        f'{listing.get(\"beds\")} beds, {listing.get(\"baths\")} baths'\n    )\n```\n\nUsing `.get()`\n\nis helpful because fields can vary between properties. A land listing might not have bedrooms, for example, while a rental building uses a different price structure from an individual home.\n\n### Ruby\n\nInstall the official SerpApi Ruby gem:\n\n```\ngem install serpapi\n```\n\nThen make the same search and print each property's address and price:\n\n```\nrequire \"serpapi\"\n\nclient = SerpApi::Client.new(\n  engine: \"zillow\",\n  region_id: \"10221\",\n  status_type: \"sale\",\n  price: \"300000,800000\",\n  beds: \"2\",\n  baths: \"2\",\n  home_type: \"house,condo\",\n  sort_by: \"pricea\",\n  api_key: ENV.fetch(\"SERPAPI_API_KEY\")\n)\n\nclient.search.fetch(:organic_results, []).each do |listing|\n  puts \"#{listing[:title]} — #{listing[:price]}\"\nend\n```\n\n### JavaScript and Node.js\n\nInstall the official JavaScript package:\n\n```\nnpm install serpapi\n```\n\nThis example fetches the listings and displays the address, price, and property URL:\n\n``` js\nimport { getJson } from \"serpapi\";\n\nconst results = await getJson({\n  engine: \"zillow\",\n  region_id: \"10221\",\n  status_type: \"sale\",\n  price: \"300000,800000\",\n  beds: \"2\",\n  baths: \"2\",\n  home_type: \"house,condo\",\n  sort_by: \"pricea\",\n  api_key: process.env.SERPAPI_API_KEY,\n});\n\nresults.organic_results?.forEach((listing) => {\n  console.log(`${listing.title} — ${listing.price}`);\n  console.log(listing.link);\n});\n```\n\n### Other languages and no-code solutions\n\nAny language that can send an HTTP GET request and parse JSON can use the Zillow Search API. SerpApi also integrates with tools such as Make, n8n, Google Sheets, and other workflow platforms, so you do not need to build a complete application to collect or process listing data.\n\n## How to search Zillow by map area\n\nA region ID is useful for known cities, ZIP codes, counties, and neighborhoods. For a custom geographic area, use `map_bounds`\n\ninstead.\n\nThe following request searches an area around downtown Denver. Remember that the coordinate order is `north,east,south,west`\n\n, rather than two conventional latitude-longitude coordinate pairs:\n\n```\nhttps://serpapi.com/search?engine=zillow&map_bounds=39.778,-104.940,39.716,-105.025&status_type=sale&api_key=YOUR_API_KEY\n```\n\nYou can also combine the map with a region (`11093`\n\nis Denver's region ID):\n\n```\nhttps://serpapi.com/search?engine=zillow&region_id=11093&map_bounds=39.778,-104.940,39.716,-105.025&status_type=sale&api_key=YOUR_API_KEY\n```\n\nIn that case, Zillow searches the portion of the specified region that falls inside the map boundaries. This can be useful for applications where users select an area on a map or where a city-wide search is too broad.\n\nHere is the equivalent map search in Python:\n\n``` python\nimport os\nimport serpapi\n\nclient = serpapi.Client(api_key=os.environ[\"SERPAPI_API_KEY\"])\nresults = client.search({\n    \"engine\": \"zillow\",\n    \"map_bounds\": \"39.778,-104.940,39.716,-105.025\",\n    \"status_type\": \"sale\",\n})\n\nfor listing in results.get(\"organic_results\", []):\n    print(listing.get(\"title\"), listing.get(\"price\"))\n```\n\n## How to scrape Zillow rental listings\n\nSet `status_type`\n\nto `rent`\n\nto search for rental properties. Rental searches support additional filters such as:\n\n`space`\n\nfor an entire place or a room.`move_in_date`\n\nfor rentals available by a specific date.`hide_no_date_listings`\n\nto exclude results without an availability date.`pets`\n\nfor cat and dog policies.`listing_features`\n\nfor 3D tours, Zillow applications, or instant tours.`short_term_lease`\n\nfor listings that offer short-term leases.- Rental-specific\n`amenities`\n\n, including in-unit laundry, parking, elevators, fitness centers, and furnished units.\n\nThis request searches Seattle for rentals that allow cats and small dogs, have at least two bedrooms, and cost no more than $3,500 per month:\n\n```\nhttps://serpapi.com/search?engine=zillow&region_id=16037&status_type=rent&price=,3500&beds=2&pets=cats,small_dogs&api_key=YOUR_API_KEY\n```\n\nThe leading comma in `price=,3500`\n\nmeans there is no minimum price and the maximum is $3,500. The same range format works with filters such as `beds`\n\n, `baths`\n\n, `sqft`\n\n, `year_built`\n\n, and `lot_size`\n\n.\n\nRental results can represent either an individual property or an apartment building. An apartment building can include fields such as:\n\n```\n{\n  \"title\": \"1800 S Jackson St, Seattle, WA\",\n  \"status\": \"FOR_RENT\",\n  \"building_name\": \"Pratt Park\",\n  \"units\": [\n    {\n      \"price\": \"$1,622+\",\n      \"beds\": \"0\"\n    },\n    {\n      \"price\": \"$2,118+\",\n      \"beds\": \"1\"\n    },\n    {\n      \"price\": \"$2,555+\",\n      \"beds\": \"2\"\n    }\n  ],\n  \"available_units\": 12,\n  \"min_base_rent\": 1616,\n  \"max_base_rent\": 3249,\n  \"lot_id\": 1001476492\n}\n```\n\nIn Python, you can handle both kinds of results like this:\n\n``` python\nimport os\nimport serpapi\n\nclient = serpapi.Client(api_key=os.environ[\"SERPAPI_API_KEY\"])\nresults = client.search({\n    \"engine\": \"zillow\",\n    \"region_id\": \"16037\",\n    \"status_type\": \"rent\",\n    \"price\": \",3500\",\n    \"beds\": \"2\",\n    \"pets\": \"cats,small_dogs\",\n})\n\nfor listing in results.get(\"organic_results\", []):\n    name = listing.get(\"building_name\") or listing.get(\"title\")\n    price = listing.get(\"price\")\n    if not price and listing.get(\"min_base_rent\"):\n        price = f'${listing[\"min_base_rent\"]:,}+'\n    if not price and listing.get(\"units\"):\n        price = listing[\"units\"][0].get(\"price\")\n    print(name, price)\n```\n\nWhen processing rentals, check for `zpid`\n\non individual listings and `lot_id`\n\non rental buildings. Do not assume that every result has fixed values for `price`\n\n, `beds`\n\n, and `baths`\n\n.\n\n## How to scrape recently sold properties\n\nSet `status_type`\n\nto `sold`\n\nto fetch recently sold homes. The response can include `sold_date`\n\n, and `price`\n\nrepresents the sale price when Zillow publishes it.\n\nThis request searches for recently sold properties in Boston with at least three bedrooms:\n\n```\nhttps://serpapi.com/search?engine=zillow&region_id=44269&status_type=sold&beds=3&sort_by=days&api_key=YOUR_API_KEY\n```\n\nA sold result can look like this:\n\n```\n{\n  \"zpid\": \"59141370\",\n  \"title\": \"32 Jewett St, Boston, MA 02131\",\n  \"status\": \"SOLD\",\n  \"price\": \"$832,950\",\n  \"extracted_price\": 832950,\n  \"sold_date\": \"2026-07-08\",\n  \"zestimate\": 982700,\n  \"rent_zestimate\": 4766,\n  \"tax_assessed_value\": 888900,\n  \"beds\": 4,\n  \"baths\": 3,\n  \"square_feet\": 2047,\n  \"home_type\": \"SINGLE_FAMILY\"\n}\n```\n\nThe Python version prints each sale date, address, and price:\n\n``` python\nimport os\nimport serpapi\n\nclient = serpapi.Client(api_key=os.environ[\"SERPAPI_API_KEY\"])\nresults = client.search({\n    \"engine\": \"zillow\",\n    \"region_id\": \"44269\",\n    \"status_type\": \"sold\",\n    \"beds\": \"3\",\n    \"sort_by\": \"days\",\n})\n\nfor listing in results.get(\"organic_results\", []):\n    print(listing.get(\"sold_date\"), listing.get(\"title\"), listing.get(\"price\"))\n```\n\nSome U.S. states do not publicly disclose sale prices. For properties in those states, `price`\n\nand `extracted_price`\n\nmay be missing even when the rest of the sold listing is available.\n\n## How to filter Zillow results\n\nThe Zillow Search API supports many of Zillow's property filters. You can combine them to refine a search for your use case.\n\nFor all listing statuses, useful filters include:\n\n`price`\n\n,`beds`\n\n,`baths`\n\n, and`sqft`\n\nfor numeric ranges.`home_type`\n\nfor houses, condos, townhomes, apartments, land, manufactured homes, and other supported types.`year_built`\n\n,`has_garage`\n\n, and`single_story`\n\nfor property characteristics.`amenities`\n\n,`view`\n\n, and`keywords`\n\nfor features such as pools, waterfront views, and terms in the listing.`price_reduction`\n\nand`time_on_zillow`\n\nfor recently changed or newly listed properties.`sort_by`\n\nfor price, newest listings, bedrooms, bathrooms, square feet, lot size, and other available orders.\n\nSale and sold searches also support `hoa_max`\n\n, `parking_spots`\n\n, `lot_size`\n\n, and `basement`\n\n. Sale searches add `listing_type`\n\n, `listing_status`\n\n, and `tours`\n\n. The rent-only filters, such as `pets`\n\nand `move_in_date`\n\n, are covered in the rental section above.\n\nFor example, the following request finds Austin homes with a garage and a pool that were listed in the last seven days, then sorts the results from newest to oldest:\n\n```\nhttps://serpapi.com/search?engine=zillow&region_id=10221&status_type=sale&has_garage=true&amenities=pool&time_on_zillow=7&sort_by=days&api_key=YOUR_API_KEY\n```\n\nIn Python:\n\n``` python\nimport os\nimport serpapi\n\nclient = serpapi.Client(api_key=os.environ[\"SERPAPI_API_KEY\"])\nresults = client.search({\n    \"engine\": \"zillow\",\n    \"region_id\": \"10221\",\n    \"status_type\": \"sale\",\n    \"has_garage\": \"true\",\n    \"amenities\": \"pool\",\n    \"time_on_zillow\": \"7\",\n    \"sort_by\": \"days\",\n})\n\nfor listing in results.get(\"organic_results\", []):\n    print(listing.get(\"days_on_zillow\"), listing.get(\"title\"), listing.get(\"price\"))\n```\n\nSome list parameters are complete selections rather than additions to Zillow's defaults. For example, `listing_type=foreclosure,auction`\n\nreturns only foreclosures and auctions. Check the documentation before assuming that a value is added to a default list.\n\n## How to paginate through Zillow results\n\nThe `page`\n\nparameter selects a result page. Page `1`\n\nis the default, while `page=2`\n\nrequests the second page:\n\n```\nhttps://serpapi.com/search?engine=zillow&region_id=10221&page=2&api_key=YOUR_API_KEY\n```\n\nThe response contains two pagination objects:\n\n`pagination`\n\ncontains links to pages on Zillow.`serpapi_pagination`\n\ncontains ready-to-use SerpApi links for the previous and next pages.\n\nThe `search_information.total_pages`\n\nfield reports the total number of available pages. Here is a Python example that continues until there is no next page:\n\n``` python\nimport os\nimport serpapi\n\nclient = serpapi.Client(api_key=os.environ[\"SERPAPI_API_KEY\"])\nparams = {\n    \"engine\": \"zillow\",\n    \"region_id\": \"10221\",\n    \"status_type\": \"sale\",\n    \"time_on_zillow\": \"7\",\n    \"sort_by\": \"days\",\n    \"page\": 1,\n}\n\nwhile True:\n    results = client.search(params)\n\n    for listing in results.get(\"organic_results\", []):\n        print(listing.get(\"zpid\"), listing.get(\"title\"), listing.get(\"price\"))\n\n    if not results.get(\"serpapi_pagination\", {}).get(\"next\"):\n        break\n\n    params[\"page\"] += 1\n```\n\nZillow limits every search to about 20 result pages, no matter how many total results are reported. The first JSON example above shows 5,830 matching homes but only 20 reachable pages of 41 results each. To cover a large market completely, split it into smaller searches: query neighborhood or ZIP code region IDs, or tile the area with `map_bounds`\n\nrectangles, and deduplicate the merged results by `zpid`\n\n.\n\nIf a narrow search returns only a few exact matches, the final page can also contain `relaxed_results`\n\nfrom nearby areas. These entries have the same general structure as `organic_results`\n\n, but they do not strictly match the requested location. Process them separately if geographic precision matters to your application.\n\n`no_cache=true`\n\nwhen you need immediate fresh results instead.## How to reduce the Zillow API response size\n\nSerpApi's [JSON Restrictor](https://serpapi.com/json-restrictor) can return only the fields your application needs. This reduces the response size and can simplify downstream processing.\n\nFor example, this request returns only each listing's Zillow ID, title, extracted price, and URL:\n\n```\nhttps://serpapi.com/search?engine=zillow&region_id=10221&json_restrictor=organic_results[].{zpid,title,extracted_price,link}&api_key=YOUR_API_KEY\n```\n\nThe Python client accepts the restrictor as a regular parameter:\n\n``` python\nimport os\nimport serpapi\n\nclient = serpapi.Client(api_key=os.environ[\"SERPAPI_API_KEY\"])\nresults = client.search({\n    \"engine\": \"zillow\",\n    \"region_id\": \"10221\",\n    \"json_restrictor\": \"organic_results[].{zpid,title,extracted_price,link}\",\n})\n\nfor listing in results.get(\"organic_results\", []):\n    print(listing.get(\"zpid\"), listing.get(\"title\"), listing.get(\"extracted_price\"))\n```\n\nThis can be especially useful when passing results to an LLM, storing frequent snapshots, or sending data through an automation platform with payload limits.\n\nYou can also request Markdown output with `output=md`\n\n, use the `/search.md`\n\nendpoint, or send an `Accept: text/markdown`\n\nheader. Markdown output is optimized for LLM and AI-agent workflows.\n\n## Scraping real estate data\n\nIf you need more than data from Zillow, have a look at working with real estate data from Google Maps:\n\n## Conclusion\n\nThe Zillow Search API from SerpApi turns Zillow search pages into structured data for homes for sale, rentals, and recently sold properties. You can search with a Zillow region ID or map boundaries, combine property filters, sort results, and paginate through the available listings.\n\nSerpApi handles retrieval and parsing, so you don't have to scrape these data yourself. Your application gets a consistent JSON response every time and can focus on the primary goals of your real estate business. And if you need more than real estate data, have a look at [100+ other APIs](https://serpapi.com/search-engine-apis) we support.", "url": "https://wpnews.pro/news/how-to-scrape-zillow", "canonical_source": "https://serpapi.com/blog/how-to-scrape-zillow/", "published_at": "2026-09-04 08:48:26+00:00", "updated_at": "2026-09-04 08:54:12.286701+00:00", "lang": "en", "topics": ["ai-tools", "developer-tools"], "entities": ["SerpApi", "Zillow", "Zillow Search API"], "alternates": {"html": "https://wpnews.pro/news/how-to-scrape-zillow", "markdown": "https://wpnews.pro/news/how-to-scrape-zillow.md", "text": "https://wpnews.pro/news/how-to-scrape-zillow.txt", "jsonld": "https://wpnews.pro/news/how-to-scrape-zillow.jsonld"}}