# Porch Contractor Scraper (`mrdoe/porch-contractor-scraper`) Actor

- **URL**: https://apify.com/mrdoe/porch-contractor-scraper.md
- **Developed by:** [MrDoe](https://apify.com/mrdoe) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

![Porch Contractor Scraper hero](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/porch-contractor-scraper--hero.png)

### What does Porch Professional & Pro Scraper do?

Porch Professional & Pro Scraper collects professional profiles from Porch, a US directory that combines professional listings with building-permit and license records. Open a directory page on the site — a trade in a city — copy the URL, paste it into **Start URLs**, and run the Actor. You get back a clean, structured dataset of every listed professional: business name, trade, license number, bond, rating and review count, phone, address and profile description — ready for lead lists, professional verification, or market research.

### Why use Porch Professional & Pro Scraper?

- **Every trade** — general professionals, remodelers, roofers, electricians, plumbers, HVAC, landscapers and more, by city.
- **Verification data** — license number, bond and permit activity alongside the basics.
- **Contact-ready output** — business name, phone and address in one row.
- **Reputation signals** — Porch rating and review count.
- **Simple input** — paste a directory URL, set how many results you want, run.
- **Automation-ready** — schedule recurring runs to track professionals in a market.

### What makes this different

Porch is one of the few professional directories tied to public permit and license records, so this Actor returns license number, bond and permit-activity fields that pure review sites don't have — useful for vetting a professional, not just finding one.

### What data can you extract?

![Porch Contractor Scraper dataset output](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/porch-contractor-scraper--output.png)

![Porch Contractor Scraper data fields](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/porch-contractor-scraper--fields.png)

| Field | Description |
| --- | --- |
| `id` | Porch professional slug |
| `name` | Business name |
| `url` | Porch profile URL |
| `category` | Trade / category |
| `description` | Profile description |
| `rating` / `reviewCount` | Porch rating and number of reviews |
| `phone` | Business phone number |
| `website` | Business website, where linked |
| `street` / `city` / `state` / `postalCode` / `country` | Business address |
| `latitude` / `longitude` | Coordinates, where published |
| `license` | Professional license number |
| `bond` | Bond amount, where shown |
| `permitsPulled` | Building-permit activity indicator, where shown |
| `yearEstablished` / `employees` | Where the profile shows them |
| `imageUrl` | Profile image |
| `scrapedAt` | ISO timestamp of collection |

### How to use Porch Professional & Pro Scraper

![How Porch Contractor Scraper works](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/porch-contractor-scraper--how-it-works.png)

1. Open [porch.com](https://www.porch.com) and browse to a trade + city directory.
2. Copy the URL from your browser's address bar.
3. Open this Actor, paste the URL into **Start URLs** (you can add several).
4. Set **Max professionals per start URL** — start small (3–5) to test, then raise it.
5. Click **Start** and wait for the run to finish.
6. Download the dataset as JSON, CSV or Excel from the **Dataset** tab, or connect it via API.

### Input Parameters

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `startUrls` | Array | Yes | LA general professionals | Porch directory pages or direct `/professional/<slug>` profile URLs. |
| `maxItems` | Integer | No | 5 | Maximum professional profiles to collect per start URL. |
| `useCache` | Boolean | No | false | Reuse data collected for a professional in an earlier run. |
| `proxyConfiguration` | Object | No | US residential | Proxy settings. Porch blocks datacenter and non-US traffic, so US residential proxy is used by default. |

### Output Data

Each dataset item is one professional. Example:

```json
{
  "id": "acme-building-co",
  "name": "Acme Building Co",
  "url": "https://www.porch.com/professional/acme-building-co",
  "category": "General Professional",
  "description": "Licensed general professional serving Los Angeles County.",
  "rating": 4.7,
  "reviewCount": 52,
  "phone": "+1 213-555-0100",
  "street": "100 Main St",
  "city": "Los Angeles",
  "state": "CA",
  "postalCode": "90012",
  "country": "US",
  "license": "CSLB 1065685",
  "bond": "$25,000",
  "scrapedAt": "2026-09-01T00:00:00.000Z"
}
```

### Usage Examples

- **General professionals in Los Angeles:** `https://www.porch.com/california/los-angeles/general-professionals`
- **Roofers in Austin:** `https://www.porch.com/texas/austin/roofing-professionals`
- **A single professional:** paste any `.../professional/<slug>` URL.

### Tips for Best Results

- Use a specific trade + city directory URL for the most relevant results.
- Add multiple directory URLs in one run (for example one per city) — `maxItems` applies to each URL separately.

### Known Limitations

- `bond`, `permitsPulled`, `yearEstablished` and `employees` are only returned where Porch shows them.
- `website` is returned only when the profile links out to one.
- Porch is US-only; non-US professionals are not covered.
- Individual customer reviews are not collected; the aggregate rating and review count are.

### Integrations

Connect results to Google Sheets, Make, Zapier, Slack or your CRM via the Apify API and webhooks. Schedule recurring runs from the Actor's **Schedule** tab.

### Export Formats

JSON, CSV, Excel, XML and RSS via the **Dataset** tab or the Apify API.

### Frequently Asked Questions

**How many results can I get per run?** As many as you set in `maxItems`, up to the directory's pagination limit. `maxItems` is per start URL.

**Can I scrape a specific trade or city?** Yes — pick the trade and city on porch.com and use the resulting directory URL.

**Are duplicates removed?** Yes. Each profile URL is only collected once per run.

**Why are some fields null?** Porch didn't publish that field for that professional. Missing values are always `null`, never guessed.

**Does caching affect freshness?** With `useCache` on, a professional already collected in a previous run is reused instead of re-fetched. Leave it off (the default) for current data.

**Can I schedule it?** Yes, from the Actor's **Schedule** tab, or via the API.

### Support

Found a bug or a missing field? Open an issue from the **Issues** tab on the Actor's page and include the run ID and the input you used.

### Legal / Responsible Use

You are responsible for ensuring your use of this Actor complies with Porch's terms of service and all applicable laws. Profiles contain personal and business contact data; if you collect personal data you are responsible for complying with applicable privacy and data-protection laws (for example CCPA) and for using that data lawfully, including for any marketing outreach.

### Preview

![Porch Contractor Scraper input options](https://api.apify.com/v2/key-value-stores/kE36venAoVchGsE6b/records/porch-contractor-scraper--input.png)

# Actor input Schema

## `startUrls` (type: `array`):

One or more Porch directory pages (for example https://porch.com/austin-tx/general-contractors), or a direct Porch pro profile URL. Build the search you want on porch.com, then paste the address bar URL here.

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

Maximum number of professional profiles to collect for each start URL. Keep this low for quick test runs and raise it for full exports.

## `useCache` (type: `boolean`):

Reuse data collected for a professional in an earlier run to speed up recurring runs. Disabled by default so every run returns fresh data.

## `debug` (type: `boolean`):

Save the raw pages of the first directory and profile to the run's key-value store for troubleshooting.

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

Proxy settings. Houzz blocks datacenter traffic, so US residential proxy is used by default and strongly recommended.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://porch.com/austin-tx/general-contractors"
    }
  ],
  "maxItems": 5,
  "useCache": false,
  "debug": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `listings` (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 = {
    "startUrls": [
        {
            "url": "https://porch.com/austin-tx/general-contractors"
        }
    ],
    "maxItems": 5,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrdoe/porch-contractor-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 = {
    "startUrls": [{ "url": "https://porch.com/austin-tx/general-contractors" }],
    "maxItems": 5,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("mrdoe/porch-contractor-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 '{
  "startUrls": [
    {
      "url": "https://porch.com/austin-tx/general-contractors"
    }
  ],
  "maxItems": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call mrdoe/porch-contractor-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mrdoe/porch-contractor-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/mUediqr6RKzVZ9ll6/builds/yAFtSdBpNmceyPqAn/openapi.json
