# Thumbtack Professionals & Reviews Scraper (`muhammadafzal/thumbtack-scraper`) Actor

Extract public Thumbtack professionals by service and ZIP code, including ratings, review counts, categories, locations, contact details, and profile URLs.

- **URL**: https://apify.com/muhammadafzal/thumbtack-scraper.md
- **Developed by:** [Muhammad Afzal](https://apify.com/muhammadafzal) (community)
- **Categories:** Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $30.00 / 1,000 scraped professionals

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Thumbtack Professionals & Reviews Scraper

**Free plan limit:** Free-plan users can receive up to **5 result records per run**. Paid-plan and local/unknown runs retain the Actor's existing limits.

Extract public Thumbtack professional listings from a service search or known public Thumbtack pages.

### What it returns

Each dataset item is one unique public professional profile:

| Field | Description |
| --- | --- |
| `name`, `profileUrl` | Public professional name and canonical Thumbtack profile URL |
| `rating`, `reviewCount` | Public rating metrics when visible |
| `categories`, `description` | Visible services and profile description when available |
| `phone`, `website`, `location` | Publicly displayed contact, external site, and location only when available |
| `sourceUrl`, `sourceService`, `sourceLocation` | The page, service, and ZIP-code context that produced the record |

Use `service` and a five-digit US ZIP code in `location` for a normal public search, or `startUrls` for exact search/profile pages. `maxResults` caps delivered professionals; `maxPages` only follows a visible public next-page link. Set `includeProfileDetails` to `false` for search-card-only output.

```json
{
  "service": "house cleaning",
  "location": "78701",
  "maxResults": 10,
  "maxPages": 1,
  "includeProfileDetails": true
}
```

Example result:

```json
{
  "name": "Sparkle Home Cleaning",
  "profileUrl": "https://www.thumbtack.com/tx/austin/house-cleaning/sparkle-home-cleaning/service/123",
  "rating": 4.9,
  "reviewCount": 86,
  "categories": ["House Cleaning"],
  "description": "Reliable residential cleaning for Austin homes.",
  "phone": null,
  "website": null,
  "location": "Austin, TX",
  "sourceUrl": "https://www.thumbtack.com/k/house-cleaning/near-me/",
  "sourceService": "house cleaning",
  "sourceLocation": "78701",
  "scrapedAt": "2026-09-02T00:00:00.000Z"
}
```

### Access and reliability

The Actor uses a browser with a consistent US residential proxy session and a low request rate. Profile enrichment preserves the search-card rating, review count, category, and location whenever the detail page omits them. It only extracts data displayed on public pages and does not use accounts, CAPTCHA-solving, paywall bypassing, or hidden/private endpoints.

The result cap also bounds profile visits: a run with `maxResults: 10` schedules at most ten profile-detail pages. If a detail page is blocked after the search card was collected, the Actor preserves that valid card record and reports the fallback in `OUTPUT`.

Some Thumbtack routes may present an access challenge. In that case the Actor writes no fabricated dataset rows and puts a `BLOCKED` result with actionable warnings in the `OUTPUT` key-value record. A valid public search with no matching profiles returns `EMPTY` the same way. Check `OUTPUT` after every zero-result run.

### Pay per event

| Event | Price | When charged |
| --- | ---: | --- |
| Actor start | $0.005 | Per GB of allocated memory when a run starts (two events with the 2 GB default) |
| Scraped professional | $0.04 | Once per schema-valid professional written to the default dataset |

Both events are emitted by Apify: the code never charges them manually, so a record is never double charged. With the 2 GB default, a one-result run costs $0.04010 in events. Platform usage is covered by the Actor owner, and no result event is charged for empty, blocked, invalid, or failed pages.

### Responsible use

Use only for lawful collection of public information and comply with Thumbtack's terms, privacy rules, and applicable data-protection laws. Do not use results to contact people in ways they did not expect, or to make decisions about individuals without appropriate safeguards.

### Pricing

This Actor uses **pay-per-event** pricing. These are the current Apify Store event prices:

| Event | Price (USD) | When it is charged |
|---|---:|---|
| `apify-default-dataset-item` | FREE: $0.04; BRONZE: $0.037; SILVER: $0.033; GOLD: $0.03; PLATINUM: $0.03; DIAMOND: $0.03 | Scraped professional — One unique, schema-valid public Thumbtack professional record written to the default dataset. |
| `apify-actor-start` | $0.005 | Actor Start — Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event). — Charged once per run. |

Apify platform usage for this Actor run is included alongside the event prices above; no separate per-run platform-usage fee is passed to users.

This covers Apify platform usage for this Actor run. Other Apify products or usage outside this Actor run may still follow your account plan.

# Actor input Schema

## `service` (type: `string`):

Use this when starting a Thumbtack service search. Enter a service phrase, for example "house cleaning". Pair it with location, or use Start URLs for exact pages.

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

Use this with Service to localize a search. Enter a five-digit US ZIP code, for example "78701". City names are not accepted because Thumbtack's public search route can ignore them.

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

Use this when you already have public Thumbtack search or professional-profile URLs. Accepts full https://www.thumbtack.com URLs, for example \[{"url":"https://www.thumbtack.com/k/house-cleaning/near-me/"}].

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

Use this to cap unique professionals written to the dataset. Defaults to 10; permitted range is 1 to 100. This is a result cap, not a page count.

## `maxPages` (type: `integer`):

Use this to limit visited search pages. Defaults to 1; pagination is followed only when a public next-page link is present.

## `includeProfileDetails` (type: `boolean`):

Use this to visit each discovered public profile for richer visible details. Defaults to true and can increase runtime and target-site load.

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

Use this when target access requires a proxy. Defaults to Apify Residential with US routing; custom proxy URLs are also accepted through Apify's standard proxy editor. Do not supply login cookies or credentials.

## Actor input object example

```json
{
  "service": "house cleaning",
  "location": "78701",
  "startUrls": [],
  "maxResults": 1,
  "maxPages": 1,
  "includeProfileDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

Schema-valid professional records.

## `summary` (type: `string`):

Outcome, counts, and any access warnings.

# 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 = {
    "service": "house cleaning",
    "location": "78701",
    "maxResults": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("muhammadafzal/thumbtack-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 = {
    "service": "house cleaning",
    "location": "78701",
    "maxResults": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("muhammadafzal/thumbtack-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 '{
  "service": "house cleaning",
  "location": "78701",
  "maxResults": 1
}' |
apify call muhammadafzal/thumbtack-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,muhammadafzal/thumbtack-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/9Ly5dD3XxWw9FcdJb/builds/fdPnKnjIaSdI39ZHd/openapi.json
