Angi Scraper | Contractors, Reviews & Public Contacts avatar

Angi Scraper | Contractors, Reviews & Public Contacts

Pricing

from $2.20 / 1,000 results

Go to Apify Store
Angi Scraper | Contractors, Reviews & Public Contacts

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

kane liu

Maintained by Community

Actor stats

2

Bookmarked

2

Total users

0

Monthly active users

3 days ago

Last modified

Categories

Features

Limited permissions

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: nearme lists a service; search uses a category ID and ZIP.
  • Profiles and company pages: detail, contact and about return available public information. US profile reviews become separate rows when present.
  • International pages: intl-list and intl-detail cover HomeStars (ca), MyBuilder (uk), MyHammer (de, at), Travaux (fr), Werkspot (nl) and Instapro (it). homestars is a Canadian profile mode.
  • Reference rows: catalog returns public metadata; sitemap lists URLs without fetching the profiles.
  • Optional detail enrichment: enrichDetails is 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

FieldDescriptionExample
kindCollection typesearch
nameBusiness display nameExample Plumbing
urlCanonical profile linkhttps://www.angi.com/companylist/us/ny/new-york/example-reviews-12345.htm
addressPublished street, locality, region, postal code and country{"locality":"New York"}
phonesPhone entries; empty for US contractors unless wantsPhone discloses a shared call-tracking number[]
phoneSourcePhone provenance; shared_tracking means an Angi call-tracking number, not the contractor's direct lineshared_tracking
phoneIsDirectWhether the number dials the business directly; false for tracking numbersfalse
descriptionBusiness self-descriptionLicensed plumbing contractor
gradeAngi letter gradeA
gpaAngi numeric grade3.79
businessHighlightsPublic badges (e.g. Family Owned, Emergency Services)[{"name":"EmergencyServices"}]
logoBusiness logo object when published{"url":"https://..."}
ratingRating on the source's scale4.8
reviewCountPublished review total42
reviewsIdNumber from a US profile URL12345
serviceProviderIdUS search identifier, distinct from reviewsId67890
ratingRawOriginal international profile rating8
ratingScaleExplicit international rating scale{"bestRating":10,"worstRating":1}
leadAbsencesReasons 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

FieldDescriptionExample
rowTypeIdentifies a separately billed review rowreview
parentIdContractor identifier12345
parentUrlContractor profile linkSame as the parent row
reviewerNamePublished author nameJane Doe
ratingIndividual review rating5
dateLabelDate as displayedSeptember 2026
textReview textExample review text.
verifiedSource verification flagtrue
projectCostPublished project cost$500

Company rows: contact, about

FieldDescriptionExample
nameCompany, not a contractorAngi Inc
addressPublished company address{"locality":"Indianapolis"}
phonesCompany contact numbers when shown[{"value":"+1 555 0100"}]
webCompany website and social links{"website":"https://www.angi.com/"}

Catalog rows: categories, businessHighlights, featureflags, platformConfig

FieldDescriptionExample
kindMetadata categorycategories
nameEntry name, when suppliedPlumbing
rawCategory or business-highlight entrySource object
dataFeature or platform settingsSource object

Sitemap rows: sitemap-category, sitemap-pro

FieldDescriptionExample
urlListed category or profile URLhttps://www.angi.com/nearme/plumbing/
enumeratedURL entry, not fetched profile contenttrue
permalinkIdProfile number extracted from the URL12345
seedSuggested 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

  1. Open Angi Scraper in Apify Console.
  2. Choose a searchType and fill the corresponding target below.
  3. Set maxResults to 3 for a small first run.
  4. Click Start and wait for completion.
  5. 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.

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

FieldWhat to enterDefault
searchTypeMode described abovenearme
marketus, ca, uk, de, at, fr, nl, itus
categoryNear-me service slughvac
categoryIdNumeric US search category; set it for your trade107
postalCodeUS ZIP or ZIP+410001 only without a location
cityUS city or international city slugEmpty
regionUS state with cityEmpty
detailUrlsArray of supported page URLs[]
sliceBuilt-in service/city choice, such as us/plumbingEmpty
queryCategory catalog search text; not a substitute for categoryIdEmpty
maxResultsRows per search or detail URL, from 1 to 7070; form prefill 3
maxPagesNo longer used; delivered rows follow maxResults onlyEmpty
ssaFilterLimit US search to Super Service Award businessesfalse
enrichDetailsAdd available profile fields to listing rowsfalse
mergeNearmeStreetsAdd streets from matching near-me listings to US searchtrue
catalogKindMetadata or sitemap typeCategories when omitted
sitemapShardProvider sitemap part, from 1 to 71First part
harvestSeedsSave discovered service/city choices for later reusefalse

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. detailUrls accepts 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 planStart at 512 MBPrice per rowPrice 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 ApifyClient
client = 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

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 default 107 is 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.

More local services and lead generation scrapers from the same publisher:

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.