# Houzz Pro Scraper - Contacts, Reviews & 35+ Fields (`abotapi/houzz-scraper`) Actor

From $1/1K. Pull Houzz pro listings across global sites. Search by category and location, keyword, or URL, plus review mode for specific pros. Returns 35+ fields including ratings, reviews, awards, services, address, GPS, contacts, social links, project counts, and featured review.

- **URL**: https://apify.com/abotapi/houzz-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** Lead generation, Agents, Real estate
- **Features:** Limited permissions
- **Stats:** 56 total users, 12 monthly users, 96.4% runs succeeded, 3 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.00 / 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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Houzz Scraper: Pros, Ratings, Reviews & Profile Data

Houzz Scraper turns Houzz into a clean directory of home professionals. Search interior designers, architects, builders, general contractors, kitchen remodelers, photographers and every other trade Houzz lists, across the Houzz country sites (houzz.com, .com.au, .co.uk and others, see coverage below), with 35+ fields per pro: ratings, per-aspect scores, awards, services, full address, contact details, social links and a featured review excerpt. Pull a pro's full review history on demand, then export to JSON, CSV or Excel, or read the results straight into your app through the API.

### Why This Scraper?

- **Four ways to find pros.** Browse a category and city, run a free-text keyword search, paste any Houzz directory URL, or pull the full review history for the pros a search matches.
- **35+ fields per pro.** Ratings, per-aspect scores (communication, on time, quality, value), awards, badges, services, full address, social links across eight platforms, and a featured review excerpt.
- **Multiple Houzz country sites, one input shape.** Your category choice is mapped to that country's own Houzz category id; coverage differs by country, and an unsupported category stops the run with the list of ones that country does have instead of quietly returning the wrong pros.
- **Full review history on demand.** Review mode pulls every review per pro, rating, reviewer, text, project price and the pro's own reply, not just the headline one.
- **Filter at the source.** Minimum rating, minimum review count and a verified-only toggle keep the dataset to the pros you actually want.
- **Built for schedules.** Incremental mode classifies every pro as new, updated, unchanged, reappeared or expired between runs; Resume continues one interrupted run without re-collecting what it already has.
- **Fails loudly, not quietly.** An unsupported category, a category that needs a location you did not give it, or a connection that cannot be established stops the run with a clear message instead of finishing as a success with nothing in it.

### Use Cases

- **Lead generation and vendor sourcing:** build a shortlist of interior designers, architects or contractors in a city, filtered by rating and review count.
- **Competitive and market research:** compare how many pros of each trade a metro area has, and how their services, awards and pricing tiers stack up.
- **Reputation monitoring:** pull a pro's full review history to track sentiment, project types and recent feedback over time.
- **Directory and marketplace enrichment:** feed pro profiles and contact details into your own directory, CRM or matching tool.
- **Recurring monitoring:** schedule a search and get back only the pros that are new, changed or gone since the last run.

### Data You Get

> Sample shape, values are illustrative placeholders, not from a live profile.

| Field | Example |
| --- | --- |
| `id` | `"00000001"` |
| `userId` | `1` |
| `professionalId` | `0` |
| `displayName` | `"Sample Design Studio"` |
| `proTypeDisplayName` | `"Interior Designers & Decorators"` |
| `city` / `state` / `country` | `"New York"` / `"NY"` / `"US"` |
| `zip` / `formattedAddress` | `"10001"` / `"100 Sample Ave, New York, NY 10001"` |
| `latitude` / `longitude` | `40.0` / `-74.0` |
| `formattedPhone` | `"(000) 000-0000"` |
| `website` | `"sample-studio.com"` |
| `numReviews` | `0` |
| `reviewRating` | `0.0` |
| `aspectCommunication` / `aspectOnTime` / `aspectQuality` / `aspectValue` | `0.0` each (when Houzz publishes per-aspect scores) |
| `featuredReviewText` | `"Sample featured review excerpt appears here when present."` |
| `verified` / `hasVerifiedLicense` | `true` / `false` |
| `awards` | `[]` (Best of Houzz year and category, when present) |
| `badges` / `merits` | `[]` / `[]` |
| `aboutMe` | `"Sample about-me text describing the pro's specialty and approach."` |
| `servicesProvided` / `areasServed` | `["Bathroom Design", "..."]` / `["Manhattan", "..."]` |
| `socialFacebook` / `socialInstagram` | `"https://social.example/sample-studio"` / `null` |
| `siteOrigin` | `"houzz.com"` |
| `url` | `"https://www.houzz.com/professionals/interior-designers-and-decorators/sample-design-studio-pfvwus-pf~00000001"` |
| `mode` / `category` / `location` | `"search"` / `"interior-designers"` / `"New-York--NY"` |

Review mode (`mode: "review"`) returns one row per review instead of one row per pro: `reviewId`, `rating`, `text`, `reviewerName`, `projectPrice`, `relationship` and `proReply` (the pro's own reply, when present), plus a `proDisplayName` / `proUrl` / `proCity` / `proState` back reference to the pro the review belongs to. Turning on Fetch full profile per pro adds richer fields such as `businessHours`, `galleriesCount` and Houzz's own `jsonLdRating` when published. Turning on Incremental mode adds `changeType`, `changedFields`, `firstSeenAt` and `lastSeenAt` to every row. The full source objects are always kept under `raw_professional` and `raw_user` so no field is ever silently dropped.

#### Output views

The dataset has these views: **Overview** and **Results** (one row per pro), **Reviews** (review mode), **Detail** (pros with Fetch full profile per pro) and **Changes** (Incremental mode classification). A `summary` record with the run totals is saved under the key `OUTPUT`.

### How to Use

1. Pick a **mode**: `search` (one row per pro, filtered by category and location or keyword), `review` (one row per review, the full history for the pros the same search matches), or `url` (paste any Houzz directory link).
2. For `search` or `review`, choose a **Country** and **Category**, and optionally add **Locations** and/or **Keywords** to narrow it. For `url` mode, paste one or more directory links instead.
3. Turn on **Fetch full profile per pro** for services, awards, hours and social links, set the rating and review-count filters you need, and cap the run with **Max pages per search** and **Max pros total**.
4. Click **Start**, then download the dataset as JSON, CSV or Excel, or read it through the API.

**Search by category and location:**

```json
{
  "mode": "search",
  "site": "houzz.com",
  "category": "interior-designers",
  "locations": ["New-York--NY", "Los-Angeles--CA"],
  "maxPages": 3,
  "maxListings": 50
}
```

**Keyword search with filters, on another country site:**

```json
{
  "mode": "search",
  "site": "houzz.com.au",
  "category": "architects",
  "queries": ["sustainable architect"],
  "locations": ["Sydney--NSW"],
  "minRating": 4,
  "verifiedOnly": true
}
```

**Full review history for the pros a search matches:**

```json
{
  "mode": "review",
  "site": "houzz.com",
  "category": "kitchen-and-bath-remodelers",
  "locations": ["Austin--TX"],
  "reviewSort": "NEWEST",
  "maxReviewsPerPro": 20
}
```

**Paste a Houzz directory URL:**

```json
{
  "mode": "url",
  "urls": ["https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785"],
  "maxPages": 2,
  "fetchDetails": true
}
```

#### URL shapes (url mode)

Every shape below is covered by a test case. Only Houzz directory pages under professionals are supported; single professional profile pages (`...-pf~<id>`) are not, and pasting one logs a warning. The German, French and Japanese sites (`houzz.de`, `houzz.fr`, `houzz.jp`) are not supported: their directory pages returned "not found" when tested, so URLs from them are not scraped; a URL outside the supported Houzz professionals pages logs a warning and is skipped. `searchUrls` is accepted as an alias of `urls`.

| # | Shape | Example |
|---|---|---|
| 1 | Category directory | `https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785` |
| 2 | Paginated page (`?fi=15`) | `https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785?fi=15` |
| 3 | Category + region (`~r_`) | `https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~r_5454711` |
| 4 | Category + keyword (`~q_`) | `https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~q_mid-century` |
| 5 | Category + region + keyword | `https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~r_5454711~q_modern` |
| 6 | Location by name (`/c/City--ST`) | `https://www.houzz.com/professionals/interior-designer/c/Los-Angeles--CA` |
| 7 | City-slug canonical page | `https://www.houzz.com/professionals/interior-designer/new-york-city-ny-us-probr0-bo~t_11785~r_5128581` |
| 8 | City-slug paginated page | `https://www.houzz.com/professionals/interior-designer/new-york-city-ny-us-probr0-bo~t_11785~r_5128581?fi=15` |
| 9 | All-categories national directory | `https://www.houzz.com/professionals/probr0-bo~` |
| 10 | Sub-service / project type (`probr1`, `~sv_`) | `https://www.houzz.com/professionals/cabinets/project-type-cabinet-refinishing-probr1-bo~t_11829~sv_29581` |
| 11 | houzz.com.au category directory | `https://www.houzz.com.au/professionals/interior-designers-and-decorators/probr0-bo~t_11911` |
| 12 | houzz.co.uk all-categories directory | `https://www.houzz.co.uk/professionals/probr0-bo~` |
| 13 | Directory with extra sort parameter | `https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785?fi=30&sort=review` |

**Default behaviour change:** if you choose `url` mode and leave **Directory URLs** untouched, the actor now scrapes these 13 example URLs (one per shape) instead of a single one, which takes longer and uses more compute and proxy. Replace the list with your own URLs to scrape only those.

#### Run it from your code

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/houzz-scraper").call(run_input={"mode": "search", "site": "houzz.com", "category": "architects", "locations": ["Austin--TX"]})
for pro in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(pro["displayName"], pro["reviewRating"], pro["numReviews"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/houzz-scraper').call({ mode: 'search', site: 'houzz.com', category: 'architects', locations: ['Austin--TX'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the **Integrations** tab.

#### Country and category coverage

The Country selector still lists `houzz.de`, `houzz.fr` and `houzz.jp` so saved tasks keep validating, but those three return no professionals pages and are not advertised as working. Choose `houzz.com`, `houzz.com.au` or `houzz.co.uk` for results.

Category coverage differs per country: all 28 categories exist on houzz.com, smaller country sites carry fewer. Asking for a category a country does not have stops the run immediately, naming the categories that country does have. A handful of category and country combinations only list professionals city by city rather than as a national directory; picking one of those without a **Locations** or **Keywords** value stops the run immediately too, naming a city to add. Supplying either value makes the same category return results normally.

#### Resume and recurring updates

- **Resume** (`resumeFromRunId`) continues one interrupted run: paste its run or dataset ID and the actor skips every pro (or review, in review mode) already collected there.
- **Incremental mode** (`incrementalMode`) is for a search you run on a schedule against the same category, location and query. Each pro (or review) is classified `NEW`, `UPDATED` (with `changedFields`), `UNCHANGED` (suppressed and not billed unless `emitUnchanged` is on), `REAPPEARED`, or `EXPIRED` (pros only, never reviews; only after a run that scanned every page of every search, and only with `emitExpired`). `stateKey` names or shares the stored baseline. `UPDATED` means an output field changed. `scrapedAt`, `searchUrl`, `isProVerificationEnabled` and the per-request tracking data in `raw_professional.webProTrackInfo` are never compared (they stay in the output). The top-level `awards` and `awardsCount` lists and the `path`, `localProjectCount`, `distance` and `directoryBadge` copies are not compared directly either; they are compared through `raw_professional`, so an edit to a pro's award text still marks it `UPDATED` with `raw_professional` in `changedFields`. In Review mode the saved baseline is keyed on the Max reviews per pro value you used; the old default of 0 (all reviews) keeps its baseline, but a schedule that now runs with the new default of 20 starts a fresh baseline once, so its first run returns every review as `NEW`. `ignoreFieldsForChanges` lets you exclude extra top-level fields from change detection if something in your own setup turns out to be noisy. With Incremental mode off, output is exactly as before.

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step **after** the scrape: the Apify dataset is never changed.

**What gets written to the connector:** a condensed, human-readable **summary** of each record, not the full JSON. Each item becomes one entry with a **title** and its key fields flattened to plain text. The **complete record always stays in the Apify dataset**.

1. Authorize a connector once under **Apify → Settings → Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. (If the picker is empty, you haven't authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

### Input Parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` | string | `"search"` | `search` (one row per pro), `review` (one row per review, full history), or `url` (paste directory links). |
| `site` | string | `"houzz.com"` | Country site (houzz.com, houzz.com.au and houzz.co.uk are verified; houzz.de, houzz.fr and houzz.jp are accepted for old saved tasks but return no pros). Applied in search and review modes. |
| `category` | string | `"interior-designers"` | Service category, mapped to that country site's own Houzz category. Coverage differs per country; an unsupported category stops the run with the list of ones that do work. |
| `queries` | array | (none) | Free-text keywords, e.g. "mid century kitchen". Each one runs as its own search and narrows the chosen category and location to pros matching that text. Leave empty to browse the whole category. |
| `locations` | array | (none) | Cities, regions or country segments, e.g. "Sydney--NSW", "New-York--NY", "CA". Each one runs as its own search. Leave empty to scrape across all locations. |
| `reviewSort` | string | `"NEWEST"` | Order reviews are pulled in for review mode: `NEWEST`, `OLDEST`, `HIGHEST_RATING`, or `LOWEST_RATING`. |
| `maxReviewsPerPro` | integer | `20` | Cap how many reviews to pull per pro in review mode (maximum 1024, which is also what `0` means). Default changed from `0` (all) to `20` to keep untouched runs cheap; raise it to pull more. Each review is one billed result row. |
| `urls` | array | 13 example URLs, one per shape | Houzz directory or search URLs to paginate (url mode). |
| `minRating` | integer | `0` | Only return pros with average rating >= this value (1 to 5). `0` = include all. |
| `minReviewCount` | integer | `0` | Only return pros with at least this many reviews. |
| `verifiedOnly` | boolean | `false` | Skip pros without a verified company profile. |
| `maxPages` | integer | `1` | Stop after this many SERP pages per search (each page has 15 pros). Empty or `0` means 1 page; hard-capped at 200 pages per search. |
| `maxListings` | integer | `1000` | Hard cap on total pros emitted across all searches (maximum 1,000,000). The default changed from unlimited to 1000; send `0` for no cap beyond `maxPages`. |
| `maxItems` | integer | `0` | Alias of `maxListings` for users coming from other Houzz scrapers. `0` = not set; when both are set the smaller value applies. |
| `fetchDetails` | boolean | `false` | Visit each pro's detail page for richer fields (search and url modes). |
| `resumeFromRunId` | string | (none) | Continue one interrupted run: paste its run or dataset ID. |
| `incrementalMode` | boolean | `false` | Track a scheduled search across runs and classify every pro as new, updated, unchanged, reappeared or expired. |
| `stateKey` | string | (none) | Names or shares the Incremental mode baseline. Auto-derived from mode, category, locations, queries and filters when left empty. |
| `emitUnchanged` | boolean | `false` | Also return (and bill) rows unchanged since the last Incremental mode run. |
| `emitExpired` | boolean | `false` | Also return (and bill) a synthetic row for pros that dropped out of a fully scanned search. |
| `ignoreFieldsForChanges` | array | `[]` | Incremental mode only. Extra top-level field names to exclude from `UPDATED` change detection, on top of the built-in exclusions. |
| `proxy` | object | `{"useApifyProxy": true}` | Connection settings. Residential is optional and recommended for very large runs. |
| `mcpConnectors` | array | (none) | Optional: send a summary of each record to apps you authorized under Integrations. |
| `notionParentPageUrl` | string | (none) | Notion connector only: page under which records are created. |
| `maxNotifyListings` | integer | `50` | Cap on items written to each connector per run. |

### Output Example

> Sample shape, values are illustrative placeholders, not from a live profile.

```json
{
  "id": "00000001",
  "userId": 1,
  "professionalId": 0,
  "displayName": "Sample Design Studio",
  "userName": "sample_studio",
  "proType": 2,
  "proTypeDisplayName": "Interior Designers & Decorators",
  "country": "US",
  "state": "NY",
  "city": "New York",
  "zip": "10001",
  "formattedAddress": "100 Sample Ave, New York, NY 10001",
  "latitude": 40.0,
  "longitude": -74.0,
  "formattedPhone": "(000) 000-0000",
  "website": "sample-studio.com",
  "numReviews": 0,
  "reviewRating": 0.0,
  "aspectCommunication": null,
  "aspectOnTime": null,
  "aspectQuality": null,
  "aspectValue": null,
  "featuredReviewText": "Sample featured review excerpt appears here when present.",
  "mostRecentReviewText": "Sample most-recent review excerpt.",
  "verified": true,
  "hasVerifiedLicense": false,
  "awards": [],
  "badges": [],
  "merits": [],
  "aboutMe": "Sample about-me text describing the pro's specialty and approach.",
  "servicesProvided": ["3D Rendering", "Bathroom Design", "Kitchen Design"],
  "areasServed": ["Manhattan", "Brooklyn"],
  "socialFacebook": null,
  "socialInstagram": null,
  "siteOrigin": "houzz.com",
  "url": "https://www.houzz.com/professionals/interior-designers-and-decorators/sample-design-studio-pfvwus-pf~00000001",
  "mode": "search",
  "category": "interior-designers",
  "location": "New-York--NY",
  "raw_professional": {},
  "raw_user": {}
}
```

### Plan Requirement

A paid Apify plan with proxy access is required. Houzz answers plain requests, from any IP type, with a JavaScript "Client Challenge" page instead of results, so the actor clears it in a browser session through an Apify proxy. Datacenter proxy was measured to work; residential is not required. It is optional and recommended for very large runs, and selecting it pins the exit to the country of the Houzz site you chose.

On an Apify free plan every proxy connection is refused. The run logs "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable." If no page can then be loaded, the run ends FAILED with one of these messages:

- Proxy refused for the account: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required."
- Free plan, backup connection reachable but Houzz served nothing: "No results: residential proxies are unavailable on this run ... and the backup connection could not load the requested Houzz pages."
- Any other run with no page loaded: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search."

### FAQ

#### How much does it cost?

You pay per pro (or per review, in review mode) returned, plus a detail-enrichment surcharge only for pros actually visited when Fetch full profile per pro is switched on. Current live rates (Free tier): $0.002 per result, $0.001 per detail enrichment, and a one-time Actor start charge of $0.08 per GB of memory (minimum one). Paid Apify tiers get lower rates. The **Pricing** tab always shows the current figures. Use **Max pros total** and **Max pages per search** to cap the cost of any run.

#### Is it legal to scrape Houzz?

This actor collects only publicly available profile data Houzz shows to any visitor. You are responsible for how you use it: follow Houzz's terms and the laws that apply to you, and get legal advice before using contact details or reviews for outreach or commercial redistribution. Photos, awards and review text may carry Houzz's or the pro's own rights.

#### Can I get only new or changed pros on a schedule?

Yes. Schedule the actor from the **Schedules** tab and turn on **Incremental mode**. Each run then classifies every pro against what the same search returned last time as new, updated, unchanged, reappeared or expired, and unchanged pros are not billed unless you turn on **Emit unchanged rows**.

#### Why does a category sometimes ask me for a location?

A handful of category and country combinations only list professionals city by city rather than as a national directory. Picking one of those without a **Locations** or **Keywords** value stops the run immediately and names a city to add, instead of quietly returning an empty or unfiltered result.

#### Why did my run fail instead of returning an empty dataset?

The run fails with a clear message when it cannot do what you asked at all: an unsupported category for the chosen country, a category that needs a location you did not supply, a resume ID that could not be read, Resume combined with Incremental mode on a search that already has saved state, or a connection that could not be established. A search that reaches Houzz successfully but genuinely matches nothing, such as a keyword or a rating filter nothing meets, still returns a normal, empty dataset.

#### Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

### 🔗 Want more leads data?

Pair this actor with these related scrapers from the same team:

<table>
<tr><td>📇 <a href="https://apify.com/abotapi/2gis-places-scraper"><b>2GIS</b></a><br>From $1/1K. Extract business and place data from 2GIS.com at scale. Get names, addresses...</td><td>🏠 <a href="https://apify.com/abotapi/au-property-agents-scraper"><b>Real Estate AU Agents Scraper</b></a><br>Scrape Australian real estate agent and agency profiles by suburb or profile URLs...</td></tr>
<tr><td>📇 <a href="https://apify.com/abotapi/businessesforsale-com-scraper"><b>BusinessesForSale.com Scraper</b></a><br>From $1.5/1K. Extract businesses and franchises listed for sale on BusinessesForSale.com...</td><td>📱 <a href="https://apify.com/abotapi/clutch-directory-scraper"><b>Clutch Scraper</b></a><br>Scrape Clutch company directories and profiles. Get names, ratings, review counts, hourly...</td></tr>
<tr><td>🚗 <a href="https://apify.com/abotapi/dubizzle-com-scraper"><b>Dubizzle.com Scraper</b></a><br>From $1/1K. Scrape dubizzle.com across the UAE for property, motors, and agent listings...</td><td>📇 <a href="https://apify.com/abotapi/bizquest-scraper"><b>BizQuest Scraper</b></a><br>Extract business-for-sale, franchise, and asset listings from BizQuest. Search by...</td></tr>
</table>

👉 [Browse all abotapi scrapers](https://apify.com/abotapi)

### 💬 Support

- 🐞 **Found a bug or a missing field?** Open a ticket on the [Issues tab](https://apify.com/abotapi/houzz-scraper/issues/open). We usually reply within hours.
- 🛠️ **Need another site, extra fields or a private build?** Email <contact@abotapi.com>.
- ⭐ **Enjoying it?** A quick review on the actor page helps other users find it.

# Actor input Schema

## `mode` (type: `string`):

Pick what each output row should be. 'search' returns one row per pro (full profile). 'review' returns one row per review, pulling each matching pro's full review history. 'url' walks any directory URL you paste, one row per pro.

## `site` (type: `string`):

Houzz operates a separate site per country, each with its own category ids. All 14 are supported for browsing and keyword search on the default Proxy configuration — no Residential proxy needed (re-verified live 2026-09-03 on all 14). The number of categories available differs per country (see Category), and a few country/category combinations only list professionals city by city — the run then stops immediately and names the Locations value to add. Applied in 'search' mode.

## `category` (type: `string`):

Service category. Mapped to that country site's own Houzz category id at runtime. Coverage differs per country — all 29 categories exist on houzz.com, but the smaller country sites carry fewer (for example houzz.com.sg has 8). If a category does not exist on the country you picked, the run stops immediately with a message listing the categories that country does have, rather than silently returning the unfiltered national directory. Bathroom remodels live under 'kitchen-and-bath-remodelers'.

## `queries` (type: `array`):

Optional free-text searches (e.g. 'mid century kitchen', 'sustainable architect'). Each keyword runs as a separate search and narrows the chosen category and location to pros matching that text — different keywords return genuinely different pros. A keyword nothing matches returns an empty result for that search. Leave empty to browse the whole category.

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

Cities, regions, or country segments. Format examples: 'Sydney--NSW', 'New-York--NY', 'Berlin--BE', 'CA'. Each location runs as a separate search and combines with the chosen category and keywords. Leave empty to scrape across all locations.

## `reviewSort` (type: `string`):

Order in which each pro's reviews are pulled.

## `maxReviewsPerPro` (type: `integer`):

Cap how many reviews to pull per pro in review mode. 0 = the maximum of 1024 (the most Houzz serves per pro).

## `urls` (type: `array`):

Paste any Houzz directory or search URL (single professional profile pages are not supported). Pagination continues automatically from where you start. Multiple URLs supported. Left untouched, url mode scrapes one example per supported URL shape (13 URLs).

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

Only return pros with average rating >= this value (1 to 5). 0 = include all.

## `minReviewCount` (type: `integer`):

Only return pros with at least this many reviews. 0 = include all.

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

Skip pros without a verified company profile.

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

Stop after this many SERP pages per search. Each page has 15 pros. Leave empty or 0 for 1 page. Hard-capped at 200 pages per search in code.

## `maxListings` (type: `integer`):

Hard cap on total pros emitted across all searches (default 1000, up to 1,000,000). 0 = no cap beyond Max pages per search and the 1,000,000 ceiling.

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

Alias of 'Max pros total' for users coming from other Houzz scrapers. 0 = not set. When both are set the smaller value applies.

## `fetchDetails` (type: `boolean`):

Visit each pro's detail page for richer fields: full aboutMe, all services, awards, social links, operating hours, featured review, per-aspect ratings (communication / on-time / quality / value). Adds ~1 fetch per pro. Auto-enabled in 'review' mode.

## `proxy` (type: `object`):

The default proxy setting works on any Apify plan, including the free tier, and is enough for every one of the 14 country sites — Houzz serves them all from any exit, so no country-specific proxy is required. Residential is optional and recommended for large volumes. The proxy country is applied only when Residential is selected, where it is matched to the Houzz country site you chose.

## `resumeFromRunId` (type: `string`):

Paste a previous run ID or dataset ID to continue an interrupted crawl: records already collected there are skipped so you get only what's still missing. One-off continuation of a SPECIFIC run - for ongoing scheduled monitoring of the same search, use Incremental mode below instead.

## `incrementalMode` (type: `boolean`):

For a search you run on a schedule (e.g. daily/weekly): remembers what this exact search returned last time and classifies every pro (or review) as NEW / UPDATED / UNCHANGED / REAPPEARED / EXPIRED, so you can act on only what changed. UPDATED means an output field changed (rating, review count, badges, services, contact and social links, location and so on); changedFields lists them. An edit to a pro's award text also marks it UPDATED, listed as raw_professional. Never compared: scrapedAt, searchUrl, isProVerificationEnabled (a per-request flag) and the per-request tracking data raw_professional.webProTrackInfo; the top-level awards and awardsCount lists and the path, localProjectCount, distance and directoryBadge copies are compared through raw_professional instead. Add more exclusions under Ignore fields below. Off by default so existing scheduled runs are unaffected. Separate from Resume above, which continues one specific interrupted run. Uses State key below to isolate different searches; see Emit unchanged rows / Emit expired rows to control which of those get pushed (both bill extra rows when on).

## `stateKey` (type: `string`):

Names the saved baseline Incremental mode compares against. Leave empty to auto-derive one from your mode/category/locations/queries/filters - two differently-configured searches never share a baseline even with this left empty. Set your own text only if you want to explicitly reuse or separate baselines yourself. Ignored when Incremental mode is off.

## `emitUnchanged` (type: `boolean`):

When Incremental mode is on: also push rows classified UNCHANGED (identical to last run), not just NEW/UPDATED/REAPPEARED/EXPIRED. Off by default to save you from paying for rows that didn't change. Turning this on bills the per-result event (and the detail-enrichment surcharge, if Fetch full profile is on) for every unchanged row too.

## `emitExpired` (type: `boolean`):

When Incremental mode is on: push a synthetic EXPIRED row for pros tracked in a previous run that no longer appear in this one. Only fires after a run that scanned every page of every search with no cap/resume truncating it - a partial scan can't tell 'gone' apart from 'not reached yet', so it's skipped (with a log line) otherwise. Off by default; turning it on bills the per-result event for each EXPIRED row emitted.

## `ignoreFieldsForChanges` (type: `array`):

Optional. Top-level field names to exclude from UPDATED change detection, in addition to the built-in exclusions (scrapedAt, searchUrl, isProVerificationEnabled and the per-request tracking data inside raw_professional.webProTrackInfo). Use it if another field in your setup rotates without the pro changing. Excluded fields stay in the output and are never listed in changedFields.

## `mcpConnectors` (type: `array`):

Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON; the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "site": "houzz.com",
  "category": "interior-designers",
  "queries": [],
  "locations": [],
  "reviewSort": "NEWEST",
  "maxReviewsPerPro": 20,
  "urls": [
    "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785",
    "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785?fi=15",
    "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~r_5454711",
    "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~q_mid-century",
    "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~r_5454711~q_modern",
    "https://www.houzz.com/professionals/interior-designer/c/Los-Angeles--CA",
    "https://www.houzz.com/professionals/interior-designer/new-york-city-ny-us-probr0-bo~t_11785~r_5128581",
    "https://www.houzz.com/professionals/interior-designer/new-york-city-ny-us-probr0-bo~t_11785~r_5128581?fi=15",
    "https://www.houzz.com/professionals/probr0-bo~",
    "https://www.houzz.com/professionals/cabinets/project-type-cabinet-refinishing-probr1-bo~t_11829~sv_29581",
    "https://www.houzz.com.au/professionals/interior-designers-and-decorators/probr0-bo~t_11911",
    "https://www.houzz.co.uk/professionals/probr0-bo~",
    "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785?fi=30&sort=review"
  ],
  "minRating": 0,
  "minReviewCount": 0,
  "verifiedOnly": false,
  "maxListings": 1000,
  "maxItems": 0,
  "fetchDetails": false,
  "proxy": {
    "useApifyProxy": true
  },
  "incrementalMode": false,
  "emitUnchanged": false,
  "emitExpired": false,
  "ignoreFieldsForChanges": [],
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `results` (type: `string`):

No description

## `reviews` (type: `string`):

No description

## `detail` (type: `string`):

No description

## `changes` (type: `string`):

No description

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

No description

# 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 = {
    "mode": "search",
    "queries": [],
    "locations": [],
    "urls": [
        "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785",
        "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785?fi=15",
        "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~r_5454711",
        "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~q_mid-century",
        "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~r_5454711~q_modern",
        "https://www.houzz.com/professionals/interior-designer/c/Los-Angeles--CA",
        "https://www.houzz.com/professionals/interior-designer/new-york-city-ny-us-probr0-bo~t_11785~r_5128581",
        "https://www.houzz.com/professionals/interior-designer/new-york-city-ny-us-probr0-bo~t_11785~r_5128581?fi=15",
        "https://www.houzz.com/professionals/probr0-bo~",
        "https://www.houzz.com/professionals/cabinets/project-type-cabinet-refinishing-probr1-bo~t_11829~sv_29581",
        "https://www.houzz.com.au/professionals/interior-designers-and-decorators/probr0-bo~t_11911",
        "https://www.houzz.co.uk/professionals/probr0-bo~",
        "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785?fi=30&sort=review"
    ],
    "proxy": {
        "useApifyProxy": true
    },
    "ignoreFieldsForChanges": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/houzz-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 = {
    "mode": "search",
    "queries": [],
    "locations": [],
    "urls": [
        "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785",
        "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785?fi=15",
        "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~r_5454711",
        "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~q_mid-century",
        "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~r_5454711~q_modern",
        "https://www.houzz.com/professionals/interior-designer/c/Los-Angeles--CA",
        "https://www.houzz.com/professionals/interior-designer/new-york-city-ny-us-probr0-bo~t_11785~r_5128581",
        "https://www.houzz.com/professionals/interior-designer/new-york-city-ny-us-probr0-bo~t_11785~r_5128581?fi=15",
        "https://www.houzz.com/professionals/probr0-bo~",
        "https://www.houzz.com/professionals/cabinets/project-type-cabinet-refinishing-probr1-bo~t_11829~sv_29581",
        "https://www.houzz.com.au/professionals/interior-designers-and-decorators/probr0-bo~t_11911",
        "https://www.houzz.co.uk/professionals/probr0-bo~",
        "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785?fi=30&sort=review",
    ],
    "proxy": { "useApifyProxy": True },
    "ignoreFieldsForChanges": [],
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/houzz-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 '{
  "mode": "search",
  "queries": [],
  "locations": [],
  "urls": [
    "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785",
    "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785?fi=15",
    "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~r_5454711",
    "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~q_mid-century",
    "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785~r_5454711~q_modern",
    "https://www.houzz.com/professionals/interior-designer/c/Los-Angeles--CA",
    "https://www.houzz.com/professionals/interior-designer/new-york-city-ny-us-probr0-bo~t_11785~r_5128581",
    "https://www.houzz.com/professionals/interior-designer/new-york-city-ny-us-probr0-bo~t_11785~r_5128581?fi=15",
    "https://www.houzz.com/professionals/probr0-bo~",
    "https://www.houzz.com/professionals/cabinets/project-type-cabinet-refinishing-probr1-bo~t_11829~sv_29581",
    "https://www.houzz.com.au/professionals/interior-designers-and-decorators/probr0-bo~t_11911",
    "https://www.houzz.co.uk/professionals/probr0-bo~",
    "https://www.houzz.com/professionals/interior-designer/probr0-bo~t_11785?fi=30&sort=review"
  ],
  "proxy": {
    "useApifyProxy": true
  },
  "ignoreFieldsForChanges": []
}' |
apify call abotapi/houzz-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,abotapi/houzz-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/7LaBYpV0rbTWpOxpK/builds/ebxeND3oKgPxDFjaR/openapi.json
