Use Houzz Pro Directory Finder by City & Category with Python
Find Houzz contractors, architects, and designers by city and category across 16 countries, with ratings, reviews, hires, services, license status, and location for each professional.
1. Choose the data you need
Review the published README for supported collection modes, examples, and limits. The recipe below uses the current published input definition.
2. Prepare a source-based input
This JSON contains published prefills and required-field defaults. Review every value for your task before running it; it is not a promise of successful collection.
{
"categorySlug": "",
"city": "Los Angeles, CA",
"country": "us",
"directoryUrls": [],
"enrichEmails": false,
"fetchDetails": true,
"fetchPhotoDetails": false,
"includeReviews": false,
"keyword": "",
"maxItems": 1,
"maxPages": 0,
"maxReviewsPerPro": 20,
"minRating": 0,
"minReviewCount": 0,
"mode": "search",
"photoCategory": "kitchen",
"photoStyle": "",
"photoUrls": [],
"profession": "general-contractor",
"profileUrls": [],
"sortBy": "relevance"
}
Download input.example.json and save your reviewed copy as input.json.
| Field | Type | Required | Description |
|---|---|---|---|
mode | string | optional | What to scrape. `search` builds a directory from country + city + profession; `byUrls` reads directory URLs; `profiles` reads profile URLs; `reviews` emits review rows; `photos` browses photo inspiration. |
country | string | optional | Houzz market used for search and profile URLs. |
city | string | optional | City or city + state to search, e.g. `Los Angeles, CA`, `London`, `Berlin`. Used with profession or categorySlug in search mode. |
profession | string | optional | Universal profession mapped to the selected market's Houzz category. Used in search mode. |
categorySlug | string | optional | Exact Houzz category slug, used instead of the mapped profession, e.g. `general-contractor`, `architekten`, `architectes`. Use a direct directory URL if you are unsure. |
keyword | string | optional | Optional keyword filter for professional search, or the search term for photo mode. |
sortBy | string | optional | Server-side order for professional directory results. |
minRating | number | optional | Drop professionals below this star rating. Set 0 to keep all. |
minReviewCount | integer | optional | Drop professionals with fewer reviews. Set 0 to keep all. |
directoryUrls | array | optional | Houzz professional directory, category or search-result URLs. All live markets and localised paths are accepted. |
profileUrls | array | optional | Direct Houzz professional profile URLs, including localised paths such as /experten/, /professionnels/ and /profesionales/. |
photoUrls | array | optional | Direct Houzz photo detail URLs. Use mode=photos. |
photoCategory | string | optional | Room category for photo inspiration browsing. Use keyword to search instead. |
photoStyle | string | optional | Optional design style filter for photo inspiration. |
includeReviews | boolean | optional | Attach review history to each professional record. |
maxReviewsPerPro | integer | optional | Review cap per professional. Set 0 to fetch the full history (up to 1,024). |
fetchDetails | boolean | optional | Open each professional profile for services, awards, socials, counts and licensing. Turn off for directory-card-only records. |
fetchPhotoDetails | boolean | optional | Open each photo for full image sizes, owner, location and question count. |
enrichEmails | boolean | optional | Best-effort email lookup on each professional's own website. Adds requests and is optional. |
maxItems | integer | optional | Hard cap on emitted records. |
maxPages | integer | optional | Optional page cap. Set 0 to use the source ceiling: 100 directory pages, 30 keyword pages, 250 photo pages or 10 photo keyword pages. |
3. Start an Actor run
Set APIFY_TOKEN in your environment. Python 3.10 or newer is sufficient; this recipe uses no third-party packages.
Execution may incur charges. Review current pricing on Apify. The request asks for a 120-second timeout and a charge limit; these settings are subject to Apify’s pricing and do not guarantee an all-inclusive spending cap.
import json
import os
import urllib.request
# Save the schema-derived example as input.json; review and edit it first.
with open("input.json", encoding="utf-8") as stream:
actor_input = json.load(stream)
token = os.environ["APIFY_TOKEN"]
request = urllib.request.Request(
"https://api.apify.com/v2/acts/MLZXQoVRusx3cGvm5/runs?timeout=120&maxTotalChargeUsd=0.50",
data=json.dumps(actor_input).encode("utf-8"),
headers={"Authorization": "Bearer " + token, "Content-Type": "application/json"},
method="POST",
)
# This starts a potentially billable run. Do not automatically retry this POST.
with urllib.request.urlopen(request, timeout=40) as response:
run = json.load(response)["data"]
print("Run ID:", run["id"])
print("Status:", run["status"])
# Inspect and download results in Apify Console once the run succeeds.
4. Inspect the actual results
Open the run in Apify Console and wait for a successful completion. Use the published output schema to locate results and the dataset schema to understand declared views. Missing or optional record fields must not be treated as guaranteed values.
Houzz professional profiles with contacts, services, awards, socials and reviews, review rows, and photo inspiration records.
Questions before you run
Which inputs are required?
No top-level fields are marked required in the published schema. Conditional requirements can still apply; check the README.
What does this guide verify?
The fields, prefills, and schema links are rendered from the published build. This is a usage recipe, not a paid live extraction test. Source availability and collection results can vary.
What if the run request times out?
Check Apify Console before retrying. The first request may already have created a run. Do not automatically repeat a run-creation POST.
Generated from source build TRlqaqbv6wYcl6cdj and its README and schemas. Source changes regenerate this guide; no third-party editorial claims are inferred.