# Angi Scraper — Pros, Reviews & Contacts (`b2b_leads/angi-real-time-data-scraper`) Actor

Search any US trade by city and get Angi's home-service pros as clean JSON: ratings, reviews, services, service areas, addresses, websites, emails, phones, and social profiles — streamed to your dataset in real time. Free plans return a sample.

- **URL**: https://apify.com/b2b_leads/angi-real-time-data-scraper.md
- **Developed by:** [Emmanuel](https://apify.com/b2b_leads) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.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.

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

## Angi Real-Time Data

Collect Angi's home-service pro directory as clean, structured JSON — search any trade in any US market, read full business profiles, capture public reviews, and enrich every business with the contact details it publishes (website, emails, phones, social profiles). Results stream straight to your dataset as they are collected, so you can watch rows arrive and start working with them immediately.

Angi is the largest US marketplace for home services: roofers, plumbers, HVAC pros, electricians, cleaners, landscapers, general contractors and hundreds more trades, each with ratings, review counts, service lists, service areas, and verification badges. This Actor turns that directory into a dataset your CRM, outreach tool, or research pipeline can use.

> **Free trial:** on a free Apify plan this Actor returns a small sample (2 results) per run so you can confirm the output before upgrading. Paid plans get the full, uncapped output.

***

### Who it is for

- **Local marketing and SEO agencies** building prospect lists by trade and city
- **Lead-gen teams** feeding CRM and outreach sequences with verified business contact details
- **Home-service brands and distributors** mapping who operates in a market and what they offer
- **Market researchers** sizing trades across metros and tracking ratings and review volumes
- **Data teams and AI agents** that need a steady, structured feed of business and review rows

### Use cases

1. **Build a city prospect list** — every roofing company in Austin, TX with rating, review count, phone, and website.
2. **Niche trade expansion** — run house cleaning in 25 metros and compare review volumes to find underserved markets.
3. **CRM enrichment** — match on business name and profile link, then write in the verified website, emails, and social profiles.
4. **Reputation monitoring** — collect public reviews per business on a schedule and watch new feedback land in your dataset.
5. **Competitive mapping** — pull all general contractors in a market and compare service lists, amenities, and warranties.
6. **AI agent research** — let an agent search a trade, read the rows, and summarise the competitive landscape.

***

### Features at a glance

| Checkbox | Default | What it returns |
| --- | --- | --- |
| 🔎 **Pro search** | **on** | One row per business from a trade + US city search. |
| 📋 **Profile details** | off | Enriches each business in place: street address, published website, full service list, star breakdown, about text, business highlights, amenities, accepted payments, FAQs. |
| ⭐ **Reviews** | off | One row per public review: reviewer, date, stars, verified flag, recommendation, project cost, text, and the pro's reply. |
| 🎯 **Lead details** | on | Enriches each business in place: verified website, email addresses, phone numbers, and social profiles. |
| 🔗 **Scrape By URL** | off | Reads specific Angi business profile links instead of searching. |

Profile details and lead details **enrich the same row** — they never remove businesses and never create a second row, so your result count (and your cost) stays predictable. Every business found is exported.

***

### Quick start

The default input runs a roofers-in-Austin search and returns 10 businesses. Press **Start** and rows begin streaming to the dataset.

```json
{
  "enableProSearch": true,
  "searchTasks": [{ "category": "roofing", "location": "Austin, TX", "maxResults": 10 }],
  "enableLeadDetails": true
}
```

For the fullest record per business, turn on **Profile details** as well:

```json
{
  "enableProSearch": true,
  "searchTasks": [{ "category": "plumber", "location": "Chicago, IL", "maxResults": 50 }],
  "enableProfileDetails": true,
  "enableReviews": true,
  "maxReviewsPerBusiness": 25,
  "enableLeadDetails": true,
  "maxItems": 2000
}
```

***

### Input reference

#### 🔎 Pro search

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `enableProSearch` | boolean | `true` | Primary feature. |
| `searchTasks` | array | roofers in Austin, TX | One row per trade + market. |
| `searchTasks[].category` | string | `"roofing"` | Trade or service. Everyday names work: `plumber`, `ac repair`, `house cleaning`, `tree service`. |
| `searchTasks[].location` | string | `"Austin, TX"` | US city with state. The state is required. |
| `searchTasks[].maxResults` | integer | from `maxResultsPerTask` | Cap for this row. |
| `maxResultsPerTask` | integer | `10` | Default cap per row. |
| `maxPagesPerTask` | integer | `5` | Safety cap on how deep a single search may go. |

Verified examples: `roofing` in `Austin, TX` · `plumbing` in `Los Angeles, CA` · `hvac` in `Chicago, IL` · `house cleaning` in `Seattle, WA` · `handyman-service` in `Manhattan, NY` · `tree service` in `Atlanta, GA`.

Everyday trade names are matched to the trade Angi publishes, so `plumber` finds plumbers and `ac repair` finds HVAC pros. Some very large metros are split into named areas — if a search comes back empty, try the specific area (for example `Manhattan, NY` instead of `New York, NY`).

#### 📋 Profile details

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `enableProfileDetails` | boolean | `false` | Enriches each business in place. Every business is still exported. |

#### ⭐ Reviews

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `enableReviews` | boolean | `false` | Adds one row per public review. Review rows count toward `maxItems`. |
| `maxReviewsPerBusiness` | integer | `10` | 1–200. |

#### 🎯 Lead details

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `enableLeadDetails` | boolean | `true` | Adds verified website, email(s), phone(s), and social profiles where publicly available. Enriches rows in place — never filters them. |

#### 🔗 Scrape By URL

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `enableScrapeByUrl` | boolean | `false` | Reads specific business profiles instead of searching. |
| `scrapeUrls` | array | `[]` | Angi business profile links, one per line. |

Example link: `https://www.angi.com/companylist/us/tx/austin/quick-roofing-llc-reviews-10944876.htm`

#### ⚙️ Output & limits

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `maxItems` | integer | `10000` | Global cap on all rows (businesses + reviews). The run also respects your maximum cost for this run. |
| `concurrency` | integer | `6` | Parallel detail lookups (1–8). |
| `delayBetweenRequestsMs` | integer | `250` | 0–5000. Higher is gentler and slower. |

#### 🔔 Notifications

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `webhookUrl` | string | `""` | Optional. Every record is always saved to the dataset — this adds a real-time POST per record. |
| `webhookFormat` | string | `"json"` | `json` sends the full record; `slack` sends a Slack-ready message. |

#### 🌐 Connection

Apify Residential connection is used by default, pinned to the United States. Change the country or supply your own connections under **Proxy settings** if you need to.

***

### Output

Every row is written to the default dataset. `OUTPUT` in the key-value store holds the run summary.

**Summary shape**

```json
{
  "totalPushed": 10,
  "totalPros": 10,
  "totalReviews": 0,
  "tasksRequested": 1,
  "tasksCompleted": 1,
  "profileDetailsEnabled": false,
  "reviewsEnabled": false,
  "leadDetailsEnabled": true,
  "errors": [],
  "spendingLimitReached": false,
  "paywall": {
    "detected": true,
    "isPaying": true,
    "pricingTier": "BRONZE",
    "limited": false,
    "blocked": false,
    "freeTierMaxItems": null
  }
}
```

#### Business rows (`type: "pro"`)

| Field | Description |
| --- | --- |
| `name` | Business name |
| `profileUrl` | Link to the business profile |
| `proId` | Directory id parsed from the link |
| `category` / `categoryLabel` | Trade slug and readable trade |
| `services` | Services the business offers |
| `rating` / `reviewCount` / `reviewBreakdown` | Star rating, total reviews, and per-star percentages |
| `location` | Full address when Profile details is on |
| `street` / `city` / `state` / `zipCode` | Address parts |
| `areaServed` | Area the business serves |
| `phone` / `phones` | Phone numbers found publicly |
| `website` / `websiteDomain` / `websiteConfidence` / `websiteScore` | Verified website and how strongly it was matched |
| `email` / `emails` | Email addresses found publicly |
| `socials` / `facebookUrl` / `instagramUrl` / `linkedinUrl` | Social profiles |
| `description` | About-the-business text |
| `businessHighlights` | Highlights such as veteran owned or emergency service |
| `amenities` | Amenities such as free estimates and warranties |
| `badges` | Directory badges such as Approved |
| `acceptedPayments` | Accepted payment methods |
| `faqs` | Business FAQs with answers |
| `inBusinessSince` / `yearsInBusiness` | Trading history |
| `responseTime` / `homeownerRecommendation` / `recentQuoteRequests` | Response and demand signals |
| `reviewSnippet` | Featured review excerpt |
| `logoUrl` / `imageUrl` / `images` | Branding and project images |
| `detailsFetched` | `true` once the full profile has been merged |
| `leadDetails` | `true` once contact details have been merged |
| `searchTaskLabel` / `searchTaskIndex` / `position` | Which search produced the row and where it ranked |
| `scrapedAt` | Collection timestamp (ISO 8601) |

#### Review rows (`type: "review"`)

| Field | Description |
| --- | --- |
| `proName` / `proId` / `profileUrl` | The business the review belongs to |
| `author` | Reviewer name as published |
| `date` / `dateText` | ISO date and the date exactly as shown |
| `rating` | Star rating |
| `verified` | Whether the review is marked verified |
| `recommend` | Whether the reviewer recommends the business |
| `projectCost` | Project cost when the reviewer shared it |
| `body` | Review text |
| `responseFromPro` | The business's reply |
| `scrapedAt` | Collection timestamp (ISO 8601) |

Dataset views **Overview**, **Businesses**, and **Reviews** are preconfigured in the Apify Console.

***

### Webhooks

Set `webhookUrl` and every record is POSTed the moment it is saved — the dataset always receives it too. Delivery problems never stop the run.

**JSON format** posts the full record object:

```json
{
  "type": "pro",
  "name": "Quick Roofing LLC",
  "rating": 4.9,
  "reviewCount": 98,
  "website": "https://quickroofing.com/",
  "email": "office@quickroofing.com",
  "profileUrl": "https://www.angi.com/companylist/us/tx/austin/quick-roofing-llc-reviews-10944876.htm"
}
```

**Slack format** posts a short message:

```json
{
  "text": ":hammer_and_wrench: *Quick Roofing LLC*\n*Trade:* Roofing\n*Rating:* 4.9 (98 reviews)\n*Website:* https://quickroofing.com/"
}
```

Paste a Slack incoming-webhook URL and choose `slack` to get a card per business (and a review card per review). Works equally well with Zapier, Make, n8n, or your own receiver.

***

### Use it from an AI agent (Apify MCP)

This Actor is callable as a tool through Apify's MCP server, so an assistant can pull live home-service data on demand. Add the Actor to your MCP client and ask in plain language.

Example question:

> "Find roofers in Austin, TX with lead details on, then rank them by rating and review count and tell me which three have the strongest online presence."

Your agent calls the Actor, reads the dataset rows, and answers with real businesses, ratings, and links.

***

### FAQ

**Do I need my own proxies?**
No. Apify's Residential connection is preconfigured and pinned to the United States.

**How much does a run cost?**
You are charged per result exported. Set `maxItems` and your maximum cost for the run to stay in full control; the run finishes gracefully when either limit is reached.

**What happens on a free plan?**
A free run returns a small sample (2 results) so you can inspect the output. Upgrading removes the cap.

**How fresh is the data?**
Every run reads live data at the moment it runs. Schedule the Actor to keep a dataset current.

**Why did a search return no businesses?**
Either the trade and market have no listed pros, or the metro is split into named areas — try the specific area, for example `Manhattan, NY` instead of `New York, NY`.

**Do profile details and lead details change how many rows I get?**
No. Both enrich a business in place. The number of businesses exported is exactly the number found by your search.

**Can I get one row per review instead of one row per business?**
Yes — turn on Reviews. Each review becomes its own row linked to its business, and review rows count toward `maxItems`.

**Are phone numbers and emails always present?**
They are included when the business publishes them publicly. When none are found the row is still exported with the fields left empty — nothing is invented.

**Can I collect a specific business I already know?**
Yes. Turn on **Scrape By URL** and paste the profile link.

# Actor input Schema

## `enableProSearch` (type: `boolean`):

Search Angi's pro directory by trade and market. Enabled by default. Each row returns name, rating, review count, services, area served, badges, and response signals.

## `searchTasks` (type: `array`):

Add one row per search: pair a trade with a US city + state. Everyday trade names work ("plumber", "ac repair"), and they are matched to the trade Angi publishes.

## `maxResultsPerTask` (type: `integer`):

Default maximum businesses per search task. Override per task in the list above.

## `maxPagesPerTask` (type: `integer`):

Maximum depth to page through per search (safety cap for very large runs).

## `enableProfileDetails` (type: `boolean`):

Enrich every business with its full profile: street address, published website, complete service list, star breakdown, about text, business highlights, amenities, warranties, accepted payments, and FAQs. Enriches rows in place — it never removes businesses and never adds a second row. Adds a little extra time per business.

## `enableReviews` (type: `boolean`):

Collect individual public reviews as their own rows: reviewer, date, star rating, verified flag, recommendation, project cost, review text, and the pro's reply. Review rows count toward the total item cap.

## `maxReviewsPerBusiness` (type: `integer`):

Maximum reviews to collect per business (only used when Reviews is enabled).

## `enableLeadDetails` (type: `boolean`):

Enrich every business with the contact details it publishes — verified website, email addresses, phone numbers, and social profiles — where they are publicly available. Every business is still exported even when no contact details are found. Adds a little extra time per business.

## `enableScrapeByUrl` (type: `boolean`):

Collect specific Angi business profiles directly instead of searching. Same output as search, enriched when profile details and lead details are enabled.

## `scrapeUrls` (type: `array`):

Angi business profile links (one per line). A full profile is always read for these.

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

Global cap on total dataset rows across all features (businesses + reviews). Set high for large runs. The run also respects your maximum cost for this run.

## `concurrency` (type: `integer`):

How many businesses to enrich in parallel (1–8). Higher is faster; 6 is a good default.

## `delayBetweenRequestsMs` (type: `integer`):

Polite pacing between directory reads (0–5000 ms). Higher values are slower but gentler.

## `webhookUrl` (type: `string`):

Optional. Every record is always saved to the run's dataset — this webhook is an ADDITIONAL real-time push. When set, each new record is also POSTed to this URL (CRM, Slack incoming webhook, Zapier, Make, Google Sheets).

## `webhookFormat` (type: `string`):

json = full record object; slack = Slack-friendly message payload.

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

Apify residential proxy (US) is enabled by default for reliable collection.

## Actor input object example

```json
{
  "enableProSearch": true,
  "searchTasks": [
    {
      "category": "roofing",
      "location": "Austin, TX",
      "maxResults": 10
    }
  ],
  "maxResultsPerTask": 10,
  "maxPagesPerTask": 5,
  "enableProfileDetails": false,
  "enableReviews": false,
  "maxReviewsPerBusiness": 10,
  "enableLeadDetails": true,
  "enableScrapeByUrl": false,
  "scrapeUrls": [],
  "maxItems": 10000,
  "concurrency": 6,
  "delayBetweenRequestsMs": 250,
  "webhookUrl": "",
  "webhookFormat": "json",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

Complete dataset with every business and review row from all enabled features in this run.

## `businesses` (type: `string`):

Home-service businesses with ratings, services, area served, and enriched contact details.

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

Individual public reviews collected when the Reviews feature is enabled.

## `runSummary` (type: `string`):

Per-run metadata: totals, enabled features, spending-limit status, and the paywall object (detected, isPaying, pricingTier, limited, blocked).

# 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 = {
    "enableProSearch": true,
    "searchTasks": [
        {
            "category": "roofing",
            "location": "Austin, TX",
            "maxResults": 10
        }
    ],
    "maxResultsPerTask": 10,
    "maxPagesPerTask": 5,
    "enableProfileDetails": false,
    "enableReviews": false,
    "maxReviewsPerBusiness": 10,
    "enableLeadDetails": true,
    "enableScrapeByUrl": false,
    "scrapeUrls": [],
    "maxItems": 10000,
    "concurrency": 6,
    "delayBetweenRequestsMs": 250,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("b2b_leads/angi-real-time-data-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 = {
    "enableProSearch": True,
    "searchTasks": [{
            "category": "roofing",
            "location": "Austin, TX",
            "maxResults": 10,
        }],
    "maxResultsPerTask": 10,
    "maxPagesPerTask": 5,
    "enableProfileDetails": False,
    "enableReviews": False,
    "maxReviewsPerBusiness": 10,
    "enableLeadDetails": True,
    "enableScrapeByUrl": False,
    "scrapeUrls": [],
    "maxItems": 10000,
    "concurrency": 6,
    "delayBetweenRequestsMs": 250,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("b2b_leads/angi-real-time-data-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 '{
  "enableProSearch": true,
  "searchTasks": [
    {
      "category": "roofing",
      "location": "Austin, TX",
      "maxResults": 10
    }
  ],
  "maxResultsPerTask": 10,
  "maxPagesPerTask": 5,
  "enableProfileDetails": false,
  "enableReviews": false,
  "maxReviewsPerBusiness": 10,
  "enableLeadDetails": true,
  "enableScrapeByUrl": false,
  "scrapeUrls": [],
  "maxItems": 10000,
  "concurrency": 6,
  "delayBetweenRequestsMs": 250,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call b2b_leads/angi-real-time-data-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,b2b_leads/angi-real-time-data-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/BUPSZKVFnJnqh2RGl/builds/YcMKUa6wxBWZFW3yL/openapi.json
