Angi Scraper | Contractors, Reviews & Public Contacts
Pricing
from $2.20 / 1,000 results
Angi Scraper | Contractors, Reviews & Public Contacts
Extract public Angi contractor listings, ratings, available addresses and reviews by US ZIP, plus supported HomeStars and European profiles. Pay per delivered row plus a start fee; US contractor phones are usually unavailable.
Pricing
from $2.20 / 1,000 results
Rating
0.0
(0)
Developer
kane liu
Maintained by CommunityActor stats
2
Bookmarked
2
Total users
0
Monthly active users
3 days ago
Last modified
Categories
Features
Share
Angi Scraper
Extract public Angi contractor listings, profile details and reviews into exportable rows, with related marketplaces in Canada, the UK and Europe.
- Search US home-service trades by ZIP — plumbing, HVAC, roofing.
- Read published names, addresses, ratings and profile links.
- Collect public catalogs, sitemap entries and Angi Inc company information.
- Follow supported international profiles, including HomeStars Canada.
- Pay $3.00 per 1,000 delivered rows on the Free plan, plus a start fee.
What does Angi Scraper do?
Angi Scraper reads public information from Angi.com, formerly Angie's List. It does not log in or submit quote requests. Available fields depend on the page; selecting a mode does not guarantee that the source will make that page accessible.
- US listings:
nearmelists a service;searchuses a category ID and ZIP. - Profiles and company pages:
detail,contactandaboutreturn available public information. US profile reviews become separate rows when present. - International pages:
intl-listandintl-detailcover HomeStars (ca), MyBuilder (uk), MyHammer (de,at), Travaux (fr), Werkspot (nl) and Instapro (it).homestarsis a Canadian profile mode. - Reference rows:
catalogreturns public metadata;sitemaplists URLs without fetching the profiles. - Optional detail enrichment:
enrichDetailsis off by default. Direct profile collection can include review rows without this switch; every delivered row has the same per-row price.
What data can you extract from Angi?
Fields vary by kind. Missing source information stays empty. The tables group rows that share a shape.
Contractor rows: search, nearme, detail, intl-list, intl-detail
| Field | Description | Example |
|---|---|---|
kind | Collection type | search |
name | Business display name | Example Plumbing |
url | Canonical profile link | https://www.angi.com/companylist/us/ny/new-york/example-reviews-12345.htm |
address | Published street, locality, region, postal code and country | {"locality":"New York"} |
phones | Phone entries; empty for US contractors unless wantsPhone discloses a shared call-tracking number | [] |
phoneSource | Phone provenance; shared_tracking means an Angi call-tracking number, not the contractor's direct line | shared_tracking |
phoneIsDirect | Whether the number dials the business directly; false for tracking numbers | false |
description | Business self-description | Licensed plumbing contractor |
grade | Angi letter grade | A |
gpa | Angi numeric grade | 3.79 |
businessHighlights | Public badges (e.g. Family Owned, Emergency Services) | [{"name":"EmergencyServices"}] |
logo | Business logo object when published | {"url":"https://..."} |
rating | Rating on the source's scale | 4.8 |
reviewCount | Published review total | 42 |
reviewsId | Number from a US profile URL | 12345 |
serviceProviderId | US search identifier, distinct from reviewsId | 67890 |
ratingRaw | Original international profile rating | 8 |
ratingScale | Explicit international rating scale | {"bestRating":10,"worstRating":1} |
leadAbsences | Reasons contact fields are missing | {} |
Join US rows by canonical profile URL or reviewsId, not by assuming serviceProviderId matches. An international rating without a confirmed scale can have rating: null while retaining ratingRaw; do not compare different scales directly.
Set wantsPhone to ask the US gateway for its contact block. When the request is large enough to cover a full result page, each business row carries a phones entry with phoneSource: "shared_tracking" and phoneIsDirect: false — this is an Angi call-tracking number shared across many contractors, not a direct dial, and it is never used as a row key. Smaller requests leave phones empty.
Use intl-catalog with an international market (ca, uk, fr, nl, de) to list that market's public service categories; these are directory rows (entityType: "service"), not contractors.
Use intl-service-pro with an international market for ServicePro merchant entities (entityType: "servicePro"): set serviceProSlug for one merchant's public fields, or omit it to enumerate the directory. Phone, email and hired-count are gated.
Review rows: kind=review
| Field | Description | Example |
|---|---|---|
rowType | Identifies a separately billed review row | review |
parentId | Contractor identifier | 12345 |
parentUrl | Contractor profile link | Same as the parent row |
reviewerName | Published author name | Jane Doe |
rating | Individual review rating | 5 |
dateLabel | Date as displayed | September 2026 |
text | Review text | Example review text. |
verified | Source verification flag | true |
projectCost | Published project cost | $500 |
Company rows: contact, about
| Field | Description | Example |
|---|---|---|
name | Company, not a contractor | Angi Inc |
address | Published company address | {"locality":"Indianapolis"} |
phones | Company contact numbers when shown | [{"value":"+1 555 0100"}] |
web | Company website and social links | {"website":"https://www.angi.com/"} |
Catalog rows: categories, businessHighlights, featureflags, platformConfig
| Field | Description | Example |
|---|---|---|
kind | Metadata category | categories |
name | Entry name, when supplied | Plumbing |
raw | Category or business-highlight entry | Source object |
data | Feature or platform settings | Source object |
Sitemap rows: sitemap-category, sitemap-pro
| Field | Description | Example |
|---|---|---|
url | Listed category or profile URL | https://www.angi.com/nearme/plumbing/ |
enumerated | URL entry, not fetched profile content | true |
permalinkId | Profile number extracted from the URL | 12345 |
seed | Suggested input for a later run | {"searchType":"detail","detailUrls":["https://www.angi.com/companylist/us/ny/new-york/example-reviews-12345.htm"]} |
How to scrape Angi
- Open Angi Scraper in Apify Console.
- Choose a
searchTypeand fill the corresponding target below. - Set
maxResultsto3for a small first run. - Click Start and wait for completion.
- Open the dataset and download your rows.
Empty input, or only platform defaults, starts an example with nearme, hvac, ZIP 10001 and at most 3 rows. It is a paid run under the same event prices, not a free preview. INPUT_REPORT marks it with exampleRun: true.
A ZIP alone uses nearme. detailUrls takes priority and each supported URL determines its page type. Set searchType explicitly for other modes: entering categoryId alone does not select search.
Near-me listings
Use nearme, a service slug such as roofing, and postalCode. Results may include surrounding service areas, not only businesses inside that ZIP.
US category search
Use search, categoryId and postalCode; 107 means plumbing. Use the matching category when requesting street merging. Rows follow maxResults (maxPages is no longer used).
US profiles
Use detail with detailUrls. The contractor row comes first; available review rows use the remaining row allowance.
Company contact and About pages
Use contact or about. These return Angi Inc information, not contractor contacts; no target URL is needed.
International city lists
Use intl-list, a non-US market and that site's city slug, such as toronto or paris-01.
International profiles and HomeStars
Use intl-detail with supported profile URLs. homestars also selects Canadian profile collection. Phones appear only when publicly listed.
Catalogs
Use catalog with catalogKind: categories, businessHighlights, featureflags or platformConfig. query can select category entries.
Sitemaps
Use sitemap with category-sitemap, or pro-pool plus sitemapShard. These are URL-index rows, not contractor detail rows.
What to fill in
| Field | What to enter | Default |
|---|---|---|
searchType | Mode described above | nearme |
market | us, ca, uk, de, at, fr, nl, it | us |
category | Near-me service slug | hvac |
categoryId | Numeric US search category; set it for your trade | 107 |
postalCode | US ZIP or ZIP+4 | 10001 only without a location |
city | US city or international city slug | Empty |
region | US state with city | Empty |
detailUrls | Array of supported page URLs | [] |
slice | Built-in service/city choice, such as us/plumbing | Empty |
query | Category catalog search text; not a substitute for categoryId | Empty |
maxResults | Rows per search or detail URL, from 1 to 70 | 70; form prefill 3 |
maxPages | No longer used; delivered rows follow maxResults only | Empty |
ssaFilter | Limit US search to Super Service Award businesses | false |
enrichDetails | Add available profile fields to listing rows | false |
mergeNearmeStreets | Add streets from matching near-me listings to US search | true |
catalogKind | Metadata or sitemap type | Categories when omitted |
sitemapShard | Provider sitemap part, from 1 to 71 | First part |
harvestSeeds | Save discovered service/city choices for later reuse | false |
For US city searches, clear the form's prefilled ZIP and supply city plus optional region. An explicit ZIP wins. One representative ZIP is used, not complete city coverage. region alone is invalid. A slice replaces the US service or international city choice, not searchType.
Near-me example
{"searchType":"nearme","category":"hvac","postalCode":"75201","maxResults":3}
US search example
{"searchType":"search","category":"plumbing","categoryId":107,"postalCode":"60601","maxResults":3}
US profile example
Replace the illustrative URL with a profile URL from your results.
{"searchType":"detail","detailUrls":["https://www.angi.com/companylist/us/ny/new-york/example-reviews-12345.htm"],"maxResults":3}
Contact example
{"searchType":"contact","maxResults":1}
About example
{"searchType":"about","maxResults":1}
International list example
{"searchType":"intl-list","market":"ca","city":"toronto","maxResults":3}
International ServicePro example
One merchant by slug; empty slug enumerates the directory.
{"searchType":"intl-service-pro","market":"ca","serviceProSlug":"217845-new-canadian-drain-plumbing-ltd","maxResults":1}
{"searchType":"intl-service-pro","market":"uk","maxResults":3}
International profile example
Replace the illustrative profile URL with a real supported profile.
{"searchType":"intl-detail","market":"uk","detailUrls":["https://www.mybuilder.com/profile/example-business"],"maxResults":1}
HomeStars example
{"searchType":"homestars","market":"ca","detailUrls":["https://www.homestars.com/profile/example-business"],"maxResults":1}
Catalog example
{"searchType":"catalog","catalogKind":"categories","query":"plumbing","maxResults":3}
Sitemap example
{"searchType":"sitemap","catalogKind":"pro-pool","sitemapShard":1,"maxResults":3}
maxItems and limit are aliases for maxResults; zip and zipCode mean postalCode, and urls and startUrls mean detailUrls. Close field-name misspellings can be corrected; other unknown fields are ignored with a note. Invalid optional catalogKind values are ignored with a warning.
Each run writes its interpretation to INPUT_REPORT in the default key-value store. Inputs rejected by validation stop before row charges, with an INVALID_INPUT: message naming the field and fix. A start fee can still apply. Numeric limits can be clamped to their allowed range; inspect the report rather than assuming every invalid value fails.
Output example
Illustrative US search row; the business and profile ID are placeholders, not a live result.
{"kind": "search","id": "67890","name": "Example Plumbing","url": "https://www.angi.com/companylist/us/ny/new-york/example-reviews-12345.htm","category": "plumbing","categoryId": 107,"serviceProviderId": "67890","reviewsId": "12345","rating": 4.8,"reviewCount": 42,"phones": [],"emails": [],"address": {"street": null, "locality": "New York", "region": "NY", "country": "US"}}
Export the dataset as JSON, CSV, Excel, XML, RSS or an HTML table. INPUT_ECHO records accepted settings, RUN_SUMMARY describes completion, and ERROR_SUMMARY describes failures.
Why use this Angi scraper?
- Pay for delivered rows. Pages that produce no rows do not incur row charges; the start fee remains.
- Keep delivered data. Rows already written remain available after a stop. Saved partial results can also be delivered; an abrupt stop is not a guarantee that every collected row reaches the dataset.
- Understand missing fields. Contact restrictions are recorded rather than replaced with invented phone numbers.
- Process several URLs.
detailUrlsaccepts multiple supported pages in one run. - No proxy setup. You do not need to set up proxies or provide an Angi account.
How much does it cost to scrape Angi?
Pricing is pay-per-event. The start event costs $0.005, charged once per GB of allocated memory with a minimum of one event. At the default 512 MB, the start fee is $0.005. Platform usage is included in these prices.
| Apify plan | Start at 512 MB | Price per row | Price per 1,000 rows |
|---|---|---|---|
| Free | $0.005 | $0.003 | $3.00 |
| Starter | $0.005 | $0.003 | $3.00 |
| Scale | $0.005 | $0.0026 | $2.60 |
| Business | $0.005 | $0.0022 | $2.20 |
| Platinum | $0.005 | $0.002 | $2.00 |
| Diamond | $0.005 | $0.0016 | $1.60 |
maxResults applies to each category/ZIP search or detail URL. Its default and maximum are 70. Contractor and review rows share that allowance. Free Apify plan users have developer-set limits of 200 rows per run and 10 runs of this Actor. The whole run is also limited by Maximum cost per run (maxTotalChargeUsd in the API).
Example: one input delivering 5 rows at 512 MB on the Free plan costs 5 × $0.003 + $0.005 = $0.020. Limits are ceilings, not promises of matching results. Zero-row runs have no row charge but still have the start fee.
What happens when the run timeout is too short
When collection needs more time than the selected run timeout, automatic resumption can pause the run rather than fail it. It temporarily shows ABORTED with the message "Queued on the collection backend; this run will resume automatically when results are ready (about N s)."
When results are ready, the same run resumes and writes to the same dataset. A continuation after earlier delivery can show "Resumed: delivering N rows." Already-delivered rows are skipped rather than delivered and charged again. Successful delivery finishes as SUCCEEDED; a source failure can still fail the run.
Keep the default timeout of 3600 seconds to reduce interruptions. Synchronous endpoints (run-sync, run-sync-get-dataset-items) wait at most 300 seconds and can return an empty dataset while the run is paused. Start longer runs asynchronously and read the dataset after SUCCEEDED, or use a succeeded-event webhook.
Use with AI agents and the API
Apify MCP server
Add this tool to Claude, ChatGPT, Cursor, VS Code or another client with remote MCP support:
https://mcp.apify.com?tools=lentic_clockss/angi-scraper
Sign in with Apify through OAuth, or send Authorization: Bearer <YOUR_APIFY_TOKEN>. The tool returns run and dataset IDs; read rows with get-dataset-items. Clients without remote support can run npx @apify/actors-mcp-server --tools lentic_clockss/angi-scraper with APIFY_TOKEN configured.
Example prompt: "Find three plumbing contractors for ZIP 60601 using category 107. Return names, ratings and profile URLs."
Apify API
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("lentic_clockss/angi-scraper").call(run_input={"searchType": "search", "category": "plumbing", "categoryId": 107,"postalCode": "60601", "maxResults": 3})for row in client.dataset(run["defaultDatasetId"]).iterate_items():print(row)
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('lentic_clockss/angi-scraper').call({searchType: 'search', category: 'plumbing', categoryId: 107,postalCode: '60601', maxResults: 3});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items);
For asynchronous HTTP calls, send the input as JSON to POST https://api.apify.com/v2/acts/lentic_clockss~angi-scraper/runs with an Authorization: Bearer <YOUR_APIFY_TOKEN> header. Read rows at GET https://api.apify.com/v2/datasets/<datasetId>/items?format=json after completion.
Integrations
Use Apify integrations with Google Sheets, Make, Zapier, n8n, Slack, Airtable or your own webhook. Use Apify Schedules for recurring runs.
FAQ
Is it legal to scrape Angi?
This Actor reads public data only. You are responsible for complying with the site's terms and applicable data-protection law. Processing personal data requires a lawful basis. This is an unofficial tool, not an Angi product.
Why did my run end as ABORTED?
An ABORTED run with the automatic-resumption message is paused, not finished. Wait for its continuation. A manual abort is different; inspect the status message before starting another run.
How many results can I get?
Request 1–70 rows per input. maxPages is no longer used — delivered rows follow maxResults only. Source availability, the Free plan limits and your maximum cost can reduce delivery. A contractor plus two reviews counts as three rows, not one.
Why are some fields empty?
The source may omit them or restrict them to signed-in users. leadAbsences explains missing contact fields. The requested ZIP is not substituted for a contractor's own address.
Can I get every contractor's phone number?
No. US guest contractor pages usually hide phones. Angi Inc company contacts and HomeStars profiles may publish numbers; neither guarantees a contractor phone for every row.
Can I search a whole city?
A US city resolves to one representative ZIP, not every ZIP in that city. Near-me listings can include neighboring service areas. International lists use the site's city slug.
What does a zero-row run mean?
A confirmed no-match or unsupported input can finish successfully with zero rows. An inaccessible page or unexplained empty response is not automatically treated as no match. Check RUN_SUMMARY or ERROR_SUMMARY.
Can I collect map results or submit quote requests?
No. map, city-hub, leads-funnel and fake-tld are unavailable. Quote submissions and private account data are outside this Actor's scope.
Limitations
- Page access changes; near-me, profile and international pages may be unavailable even when search works.
- No guaranteed complete city, country, category or review coverage.
- US searches require the correct
categoryId; the default107is plumbing, not a universal trade ID. - Sitemap rows contain URLs, not fetched business details. Catalog rows are metadata, not leads.
- No guaranteed phone, email or street address for each contractor. Enrichment cannot create information absent from the public page.
- Other Angi country domains are not supported; use the named international marketplaces.
Related scrapers
More local services and lead generation scrapers from the same publisher:
- Nextdoor Business Scraper
- Google Maps Scraper for Leads, CRM, and Reviews
- AlloVoisins Scraper
- HomeStars Scraper
- Jiffy On Demand Scraper
- Care.com Scraper
- TaskRabbit Scraper
- Yelp Business Scraper
Browse all of our scrapers at apify.com/lentic_clockss.
Support
Report a problem or request a field through the Issues tab of this Actor's page. Include the run ID and the input you used.