# Angi Scraper (`solidcode/angi-scraper`) Actor

\[💰 $0.8 / 1K] Extract contractor and home-service pro listings from Angi.com - business names, phone numbers, addresses, ratings, reviews, hours, and photos. Search by keyword and location, browse by category, paste Angi URLs directly. Optional per-pro reviews extraction.

- **URL**: https://apify.com/solidcode/angi-scraper.md
- **Developed by:** [SolidCode](https://apify.com/solidcode) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, NaN bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Angi Scraper

Extract contractor and home-service pro listings from Angi.com at scale. Get business names, phone numbers, addresses, ratings, review counts, hours, sub-categories, logos, descriptions, and per-pro reviews — for any trade in any US city or ZIP code. Built for lead-gen teams, market researchers, and anyone who needs structured data on local home-service pros without paying enterprise prices.

### Why This Scraper?

- **$0.80 per 1,000 results** — among the cheapest Angi data on Apify, no per-page or compute surcharges.
- **Friendly inputs** — type a trade and a city or ZIP. No URL knowledge required.
- **887 trade categories supported** — from `Plumbing` and `HVAC` to `Junk Removal`, `Garage Doors`, `Concrete`, and `Pools & Spas`. Search terms are mapped automatically to Angi's nearest matching category.
- **ZIP code lookup built in** — paste `78701` or `Austin, TX` — both work.
- **NYC borough fan-out** — searching "New York, NY" automatically scrapes Manhattan, Brooklyn, Queens, the Bronx, and Staten Island, then de-dupes pros across them.
- **Two cost tiers** — `Listing only` for fast, cheap bulk discovery (name, city, ZIP, profile URL); `Full profile` for hours, full street address, phone, sub-categories, and description.
- **Optional review extraction** — flip on `Include Reviews` to also pull per-review rows (rating, body, author, date) into the same dataset.
- **Direct URL mode** — paste any Angi profile, listing, or category page URL when you want surgical control.
- **No setup, no configuration knobs** — works on the defaults; everything is opt-in.

### Use Cases

**Lead Generation**
- Build prospect lists of plumbers, electricians, roofers, or any trade in any city.
- Target newly-listed pros or those with low review counts for outreach.
- Pull phone and address data into a CRM for cold call campaigns.

**Market Research & Competitive Intelligence**
- Map the density of HVAC contractors across a metro area.
- Compare average ratings by trade between cities or ZIP codes.
- Track how many years pros in a category have been in business.

**Directory & Aggregator Sites**
- Populate a local-services directory with up-to-date pro listings.
- Enrich existing business records with Angi ratings and review counts.
- Build geographic coverage data for franchise expansion analysis.

**Reputation & Review Analysis**
- Pull per-pro reviews to analyze sentiment, common complaints, or pricing signals.
- Benchmark a single pro against the rest of their category in their city.
- Monitor competitor reviews on a recurring schedule via the Apify scheduler.

**Real Estate & Property Management**
- Build vendor lists for property managers in new markets.
- Identify highly-rated pros across multiple service categories in a single ZIP.

### Getting Started

#### Simplest — One trade, one city

```json
{
    "searchTerms": ["plumber"],
    "location": "Austin, TX"
}
````

#### Multi-trade in a major city by ZIP

```json
{
    "searchTerms": ["plumber", "electrician", "hvac"],
    "location": "78701",
    "maxResults": 50
}
```

#### Cheap bulk discovery (listing-only)

```json
{
    "category": "Roofing",
    "location": "Phoenix, AZ",
    "detailLevel": "listing",
    "maxResults": 50
}
```

#### With per-pro reviews

```json
{
    "searchTerms": ["roofing"],
    "location": "Phoenix, AZ",
    "includeReviews": true,
    "maxReviewsPerPro": 50
}
```

#### Direct URL — pinpoint a specific listing or category

```json
{
    "startUrls": [
        "https://www.angi.com/companylist/us/tx/austin/plumbing.htm"
    ],
    "maxResults": 100
}
```

#### Single pro profile (with reviews)

```json
{
    "startUrls": [
        "https://www.angi.com/companylist/us/tx/austin/we-plumb-reviews-10565886.htm"
    ],
    "includeReviews": true
}
```

### Input Reference

#### Search

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `searchTerms` | string\[] | `["plumber"]` | Keywords or service names (e.g. `"plumber"`, `"roof repair"`, `"HVAC contractor"`). Each term runs as its own search and is combined with the location. Mapped to Angi's nearest matching trade category. |
| `location` | string | `"Austin, TX"` | City and state (e.g. `"Austin, TX"`) or 5-digit US ZIP code (e.g. `"78701"`). Combined with each search term and category. |
| `category` | string | `null` | Optional trade to browse instead of (or alongside) free-text search terms. Pick from a dropdown of 30 common trades. |

##### Service categories available in the dropdown

`Plumbing`, `Electrical`, `Heating & Cooling (HVAC)`, `Roofing`, `Painting`, `Landscaping`, `Lawn Care`, `Tree Service`, `Handyman`, `House Cleaning`, `Pest Control`, `Remodeling`, `Kitchen Remodeling`, `Bathroom Remodeling`, `Flooring`, `Carpet Cleaning`, `Appliance Repair`, `Garage Doors`, `Fencing`, `Decks & Patios`, `Pools & Spas`, `Movers`, `Junk Removal`, `Windows`, `Siding`, `Gutters`, `Concrete`, `Masonry`, `Drywall`, `General Contractors`.

For trades outside this list, type the keyword into Search Terms — it will be auto-mapped to the closest of Angi's 887 internal categories.

#### Direct URLs

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `startUrls` | string\[] | `[]` | Paste any Angi URLs directly: pro profile pages, category hubs, city/state hubs, or listing pages. Scraped in addition to the keyword and category search above. |

#### Limits

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `maxResults` | integer | `100` | Maximum number of pros to return per search term, category, or start URL. Set to `0` for unlimited. The scraper stops requesting new pages once the cap is reached but keeps the full last page. |

#### Output Detail

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `detailLevel` | string | `"full"` | `"Listing only (faster, cheaper)"` returns just what's on the search result card. `"Full profile (recommended)"` also visits each pro's profile page for hours, photo gallery, full address, description, and the most complete contact info. |
| `includeReviews` | boolean | `false` | When on, fetches each pro's reviews and emits them as separate rows in the dataset (one row per review). Adds to your billed result count — a pro with 50 reviews counts as 51 results. |
| `maxReviewsPerPro` | integer | `20` | Cap on how many reviews to collect per pro. Set to `0` to fetch every review available. Ignored when `Include Reviews` is off. |

### Output

Two record types are emitted to the same dataset, distinguished by the `recordType` field. Pros always come first; reviews (when enabled) follow each pro.

#### Pro record (`recordType: "pro"`)

```json
{
    "recordType": "pro",
    "proId": "10565886",
    "name": "We Plumb",
    "url": "https://www.angi.com/companylist/us/tx/austin/we-plumb-reviews-10565886.htm",
    "category": "Plumbing",
    "subCategories": ["Plumbing", "Drain Cleaning", "Water Heaters"],
    "rating": 4.91,
    "reviewCount": 138,
    "phone": "5126581400",
    "email": null,
    "website": "https://weplumb.com",
    "address": "641 Arrowood Place",
    "city": "Austin",
    "state": "TX",
    "zip": "78745",
    "hours": {
        "Monday": "7:00 AM - 6:00 PM",
        "Tuesday": "7:00 AM - 6:00 PM",
        "Wednesday": "7:00 AM - 6:00 PM",
        "Thursday": "7:00 AM - 6:00 PM",
        "Friday": "7:00 AM - 6:00 PM",
        "Saturday": "Closed",
        "Sunday": "Closed"
    },
    "acceptsAppointments": null,
    "yearsInBusiness": 12,
    "description": "Family-owned plumbing company serving Austin and surrounding communities since 2014. Drain cleaning, water heater install, repipe, slab leak repair.",
    "logoUrl": "https://media.angi.com/s3fs-public/...",
    "images": [],
    "searchTerm": "plumber",
    "searchLocation": "Austin, TX",
    "scrapedAt": "2026-04-26T23:57:06.698355+00:00"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `recordType` | string | Always `"pro"`. |
| `proId` | string | Angi's stable internal pro ID. |
| `name` | string | Business name. |
| `url` | string | Canonical Angi profile URL. |
| `category` | string | Primary service category (e.g. `"Plumbing"`). |
| `subCategories` | string\[] | Other services the pro offers (full profile only). Empty list under `Listing only`. |
| `rating` | number | null | Overall star rating, rounded to 2 decimals (0–5). May be `null` under `Listing only` for cards Angi doesn't ship a rating on. |
| `reviewCount` | integer | null | Total number of reviews on Angi. May be `null` under `Listing only` for cards without an aggregate rating. |
| `phone` | string | null | Public phone number (full profile only; 10-digit US format, e.g. `"5126581400"`). |
| `email` | string | null | Always `null` — Angi routes contact through its own system. |
| `website` | string | null | External business website when shown in the description (best-effort). |
| `address` | string | null | Street address (full profile only). |
| `city` | string | null | City. |
| `state` | string | null | 2-letter state code. |
| `zip` | string | null | 5-digit ZIP code. |
| `hours` | object | null | Per-day operating hours (full profile only). |
| `acceptsAppointments` | boolean | null | Reserved for future use; currently `null`. |
| `yearsInBusiness` | integer | null | Self-reported tenure (full profile only). |
| `description` | string | null | Business description (full profile only). |
| `logoUrl` | string | null | Logo image URL. |
| `images` | string\[] | Reserved for future use; currently empty. |
| `searchTerm` | string | null | The keyword that surfaced this pro (when from a keyword search). |
| `searchLocation` | string | null | The location label used for the search (e.g. `"Manhattan, NY"`). |
| `scrapedAt` | string | ISO 8601 timestamp. |

#### Review record (`recordType: "review"`)

Emitted only when `includeReviews` is on. One row per review.

```json
{
    "recordType": "review",
    "proId": "10565886",
    "proName": "We Plumb",
    "proUrl": "https://www.angi.com/companylist/us/tx/austin/we-plumb-reviews-10565886.htm",
    "reviewId": "10565886-3",
    "rating": 5.0,
    "title": null,
    "text": "Showed up on time, fixed the leak in 30 minutes, and explained exactly what they did. Highly recommend.",
    "author": "Sarah M.",
    "authorLocation": null,
    "serviceDate": null,
    "postedAt": "2026-03-14T00:00:00",
    "serviceCategory": null,
    "cost": null,
    "scrapedAt": "2026-04-26T23:57:08.112441+00:00"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `recordType` | string | Always `"review"`. |
| `proId` | string | Angi's pro ID — links the review back to its parent pro record. |
| `proName` | string | Convenience copy of the pro's business name. |
| `proUrl` | string | Convenience copy of the pro's profile URL. |
| `reviewId` | string | Stable per-scrape review ID (`{proId}-{globalIndex}`). |
| `rating` | number | null | Review star rating (0–5). |
| `title` | string | null | Review headline (currently `null` — not exposed by Angi's structured data). |
| `text` | string | null | Full review body. |
| `author` | string | null | Reviewer display name. |
| `authorLocation` | string | null | Reviewer city (currently `null` — not in structured data). |
| `serviceDate` | string | null | Date the work was performed (currently `null`). |
| `postedAt` | string | null | ISO 8601 timestamp of when the review was posted. |
| `serviceCategory` | string | null | Category the review is about (currently `null`). |
| `cost` | string | null | Reported job cost (currently `null`). |
| `scrapedAt` | string | ISO 8601 timestamp. |

### Tips for Best Results

- **Use a 5-digit ZIP for precision** — `"78701"` is more targeted than `"Austin, TX"` and avoids ambiguity for cities that share names across states.
- **Major metros are auto-expanded** — searching `"New York, NY"` automatically fans out across Manhattan, Brooklyn, Queens, the Bronx, and Staten Island, then de-dupes pros so you don't pay twice for cross-borough listings.
- **Pick `Listing only` for cheap bulk discovery** — it returns name, city, ZIP, and profile URL on each card, with no per-pro page visits. Great for building seed lists you'll enrich later. Switch to `Full profile` when you need phone, hours, sub-categories, and the full description.
- **Reviews are billed per row** — turning on `Include Reviews` adds one billable result per review. A search returning 60 pros (typical for a single city), each with 25 reviews kept, costs ~1,560 results. Listing pool size varies by city — large metros yield 50-150 unique pros per trade, smaller markets often 5-20. Use `maxReviewsPerPro` to cap the spend.
- **Use Direct URLs for surgical scrapes** — paste a single profile URL to grab one pro and its reviews; paste a city/category URL (e.g. `https://www.angi.com/companylist/us/tx/austin/plumbing.htm`) to walk a known listing without going through the keyword mapper.
- **Search terms are mapped to a category** — Angi search is category-based, not free-text. `"exterminator"` maps to `"Pest Control"`, `"AC"` maps to `"HVAC"`, etc. For full control over which category is used, pick from the dropdown or use Direct URLs.

### Good to Know

- **Some contact fields aren't exposed by Angi.** `email` is never returned — Angi monetizes lead routing and hides the address. `website` is best-effort, parsed from the description when present. `acceptsAppointments` and the photo gallery beyond the logo are reserved fields and currently return `null` / `[]`.
- **Some review-card fields aren't in Angi's structured data.** `title`, `authorLocation`, `serviceDate`, `serviceCategory`, and `cost` are not exposed in machine-readable form; they're emitted as `null`.
- **Many markets serve "rotating featured" pros.** Walking listing rows in any city often surfaces fewer unique pros than `maxResults` because Angi repeats featured pros across pages. The scraper de-dupes by pro ID before pushing — so a `maxResults: 100` run on a typical city may yield 30-60 unique pros, not 100.
- **Phone numbers are 10-digit US strings.** No formatting — apply your own (e.g. `(512) 658-1400`) downstream if needed.

### Pricing

**$0.80 per 1,000 results.** No compute charges — you only pay per result returned.

| Results | Cost |
|---------|------|
| 100 | $0.08 |
| 1,000 | $0.80 |
| 10,000 | $8.00 |

Each pro counts as one result. When `Include Reviews` is on, each review is also one result — a pro with 50 reviews counts as 51 results.

### Integrations

Export your data in JSON, CSV, Excel, XML, or RSS. Connect to 1,500+ apps via:

- **Zapier** / **Make** / **n8n** — Workflow automation.
- **Google Sheets** — Direct spreadsheet export.
- **Slack** / **Email** — Notifications on new results.
- **Webhooks** — Custom API integrations.
- **Apify API** — Full programmatic access.

### Legal & Ethical Use

This scraper is designed for legitimate business intelligence, market research, lead generation, and directory enrichment. You are responsible for complying with applicable laws, Angi's Terms of Service, and any data-protection regulations in your jurisdiction (CCPA, GDPR, etc.). Do not use the data for spam, harassment, or any unlawful purpose. Respect opt-outs and do-not-contact requests.

# Actor input Schema

## `searchTerms` (type: `array`):

Keywords or service names to search for on Angi (e.g. "plumber", "roof repair", "HVAC contractor"). Each term runs as its own search and is combined with the Location below. Terms are auto-mapped to Angi's nearest matching trade category (close-but-not-exact terms like "plumber repair" may be skipped if no category matches well — pick the Service Category dropdown for exact control). Leave empty if you only want to use a category browse or Start URLs.

## `location` (type: `string`):

City and state (e.g. "Austin, TX") or 5-digit US ZIP code (e.g. "78701"). Combined with each search term and with the category below. Leave empty if you only want to use Start URLs.

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

Optional Angi service category to browse. Use this when you want every pro in a single trade for your location, instead of a specific keyword. Combine with Location for a city-wide trade sweep.

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

Paste any Angi URLs directly: pro profile pages, category hubs, city or state hubs, or ZIP search pages (e.g. https://www.angi.com/companylist/us/tx/austin/plumbing.htm). When provided, these are scraped in addition to the keyword and category search above.

## `maxResults` (type: `integer`):

Maximum number of pros to return per search term, category, or start URL. Set to 0 for unlimited (every result Angi returns). The actor stops requesting new pages once this cap is reached, but keeps the full last page (10 pros per page) even if it slightly overshoots. Note: small-to-medium markets may have fewer unique pros than the cap (Angi often serves only 30-60 unique pros for a single trade in a single city).

## `detailLevel` (type: `string`):

"Listing only" returns just what's shown on each search result card (cheap, fast). "Full profile" also visits each pro's profile page to get hours, photo gallery, full address, description, and the most complete contact info.

## `includeReviews` (type: `boolean`):

When on, fetches each pro's reviews and emits them as separate rows in the dataset (one row per review). This adds to your billed result count - a pro with 50 reviews counts as 51 results when reviews are on.

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

Cap on how many reviews to collect per pro. Set to 0 to fetch every review available. Reviews paginate 25 at a time, so the actor may slightly overshoot to keep the full last page. Ignored when "Include Reviews" is off.

## Actor input object example

```json
{
  "searchTerms": [
    "plumber"
  ],
  "location": "Austin, TX",
  "startUrls": [],
  "maxResults": 100,
  "detailLevel": "full",
  "includeReviews": false,
  "maxReviewsPerPro": 20
}
```

# Actor output Schema

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

Table of pros with key fields: name, category, rating, reviews, phone, location.

## `details` (type: `string`):

Full per-pro detail rows including hours, address, images, description, and contact info.

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

Per-review rows with rating, author, date, and text. Populated when "Include Reviews" is on.

# 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 = {
    "searchTerms": [
        "plumber"
    ],
    "location": "Austin, TX",
    "startUrls": [],
    "maxResults": 100,
    "detailLevel": "full",
    "includeReviews": false,
    "maxReviewsPerPro": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("solidcode/angi-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 = {
    "searchTerms": ["plumber"],
    "location": "Austin, TX",
    "startUrls": [],
    "maxResults": 100,
    "detailLevel": "full",
    "includeReviews": False,
    "maxReviewsPerPro": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("solidcode/angi-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "plumber"
  ],
  "location": "Austin, TX",
  "startUrls": [],
  "maxResults": 100,
  "detailLevel": "full",
  "includeReviews": false,
  "maxReviewsPerPro": 20
}' |
apify call solidcode/angi-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=solidcode/angi-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Angi Scraper",
        "description": "[💰 $0.8 / 1K] Extract contractor and home-service pro listings from Angi.com - business names, phone numbers, addresses, ratings, reviews, hours, and photos. Search by keyword and location, browse by category, paste Angi URLs directly. Optional per-pro reviews extraction.",
        "version": "1.1",
        "x-build-id": "JTU2Mcm0AiErzS1T5"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/solidcode~angi-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-solidcode-angi-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/solidcode~angi-scraper/runs": {
            "post": {
                "operationId": "runs-sync-solidcode-angi-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/solidcode~angi-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-solidcode-angi-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchTerms": {
                        "title": "Search Terms",
                        "type": "array",
                        "description": "Keywords or service names to search for on Angi (e.g. \"plumber\", \"roof repair\", \"HVAC contractor\"). Each term runs as its own search and is combined with the Location below. Terms are auto-mapped to Angi's nearest matching trade category (close-but-not-exact terms like \"plumber repair\" may be skipped if no category matches well — pick the Service Category dropdown for exact control). Leave empty if you only want to use a category browse or Start URLs.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "location": {
                        "title": "Location",
                        "type": "string",
                        "description": "City and state (e.g. \"Austin, TX\") or 5-digit US ZIP code (e.g. \"78701\"). Combined with each search term and with the category below. Leave empty if you only want to use Start URLs."
                    },
                    "category": {
                        "title": "Service Category",
                        "enum": [
                            "",
                            "plumbing",
                            "electrical",
                            "hvac",
                            "roofing",
                            "painting",
                            "landscaping",
                            "lawn_care",
                            "tree_service",
                            "handyman",
                            "cleaning",
                            "pest_control",
                            "remodeling",
                            "kitchen_remodeling",
                            "bathroom_remodeling",
                            "flooring",
                            "carpet_cleaning",
                            "appliance_repair",
                            "garage_door",
                            "fencing",
                            "deck_patio",
                            "pool_spa",
                            "moving",
                            "junk_removal",
                            "windows",
                            "siding",
                            "gutter",
                            "concrete",
                            "masonry",
                            "drywall",
                            "general_contracting"
                        ],
                        "type": "string",
                        "description": "Optional Angi service category to browse. Use this when you want every pro in a single trade for your location, instead of a specific keyword. Combine with Location for a city-wide trade sweep."
                    },
                    "startUrls": {
                        "title": "Start URLs",
                        "type": "array",
                        "description": "Paste any Angi URLs directly: pro profile pages, category hubs, city or state hubs, or ZIP search pages (e.g. https://www.angi.com/companylist/us/tx/austin/plumbing.htm). When provided, these are scraped in addition to the keyword and category search above.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxResults": {
                        "title": "Maximum Results per Search",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of pros to return per search term, category, or start URL. Set to 0 for unlimited (every result Angi returns). The actor stops requesting new pages once this cap is reached, but keeps the full last page (10 pros per page) even if it slightly overshoots. Note: small-to-medium markets may have fewer unique pros than the cap (Angi often serves only 30-60 unique pros for a single trade in a single city).",
                        "default": 100
                    },
                    "detailLevel": {
                        "title": "Detail Level",
                        "enum": [
                            "listing",
                            "full"
                        ],
                        "type": "string",
                        "description": "\"Listing only\" returns just what's shown on each search result card (cheap, fast). \"Full profile\" also visits each pro's profile page to get hours, photo gallery, full address, description, and the most complete contact info.",
                        "default": "full"
                    },
                    "includeReviews": {
                        "title": "Include Reviews",
                        "type": "boolean",
                        "description": "When on, fetches each pro's reviews and emits them as separate rows in the dataset (one row per review). This adds to your billed result count - a pro with 50 reviews counts as 51 results when reviews are on.",
                        "default": false
                    },
                    "maxReviewsPerPro": {
                        "title": "Max Reviews per Pro",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Cap on how many reviews to collect per pro. Set to 0 to fetch every review available. Reviews paginate 25 at a time, so the actor may slightly overshoot to keep the full last page. Ignored when \"Include Reviews\" is off.",
                        "default": 20
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
