# Checkatrade Scraper (`khadinakbar/checkatrade-scraper`) Actor

Search and extract public Checkatrade tradesperson profiles with contact, service, rating, and review data.

- **URL**: https://apify.com/khadinakbar/checkatrade-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Lead generation, Automation, AI
- **Stats:** 1 total users, 0 monthly users, 71.4% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 tradesperson records

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Checkatrade Scraper

Checkatrade Scraper is an Apify Actor for finding and extracting public Checkatrade tradesperson profiles by trade and UK location, or by copied Checkatrade search and profile URLs. It accepts a trade and location, search URLs, or direct profile URLs, and returns one validated business record per public profile. Each record can include business name, profile URL, public phone number, website, rating, review count, description, service labels, service areas, location fields, optional recent reviews, and an extraction timestamp.

### Best fit and connected workflows

Use this Actor when your workflow starts with public Checkatrade discovery and needs structured records for outreach preparation, local market research, CRM enrichment, or AI-assisted shortlist building.

Typical routing patterns:

- Trade + location search: find profiles for a UK trade in a town, city, postcode, or postcode area.
- Copied search URL: reuse a Checkatrade search page from a browser session.
- Direct profile URLs: refresh or re-extract known Checkatrade profile pages.
- Filtered runs: narrow results by phone availability, minimum rating, or minimum review count.
- Detailed enrichment: enable profile scraping and recent review extraction for deeper records.

#### focused workflow

Checkatrade Scraper is designed as a focused workflow.

### Practical scenario

A local marketing analyst wants a list of electricians in Manchester with public contact details and strong public ratings. They start with `trade = "Electrician"` and `location = "Manchester"`, then set `requirePhone = true`, `minRating = 9`, and `minReviews = 10`. The run returns fields such as `businessName`, `phone`, `rating`, `reviewCount`, `services`, `locality`, and `profileUrl`. The analyst can review the returned profiles, open the linked Checkatrade pages, and use the dataset to build a call list or a verified research shortlist.

### Input fields

| Field | Type | Purpose |
| --- | --- | --- |
| `trade` | string | Trade or service to search, such as `Plumber` or `Electrician`. |
| `location` | string | UK town, city, postcode, or postcode area for the search. |
| `searchUrls` | array | Copied Checkatrade search-result URLs to crawl and paginate. |
| `directUrls` | array | Individual Checkatrade profile URLs to scrape directly. |
| `maxResults` | integer | Maximum validated profiles to return in the run. |
| `scrapeDetails` | boolean | Enrich discovered profiles with contact, service, rating, and review fields. |
| `extractReviews` | boolean | Include up to ten visible recent review objects per profile. |
| `requirePhone` | boolean | Return only profiles with a public phone number. |
| `minRating` | number | Minimum public Checkatrade rating from 0 to 10. |
| `minReviews` | integer | Minimum public review count required for a returned profile. |
| `proxyConfiguration` | object | Optional Apify proxy configuration for public Checkatrade requests. |

#### Focused JSON example

```json
{
  "trade": "Electrician",
  "location": "Manchester",
  "maxResults": 25,
  "scrapeDetails": true,
  "extractReviews": false,
  "requirePhone": true,
  "minRating": 9,
  "minReviews": 10
}
```

### Output fields

| Field | Type | Meaning |
| --- | --- | --- |
| `businessName` | string | Public Checkatrade business or tradesperson name. |
| `profileUrl` | string | Canonical public Checkatrade profile URL. |
| `phone` | string or null | Public profile phone number, when shown. |
| `website` | string or null | Public external website, when shown. |
| `email` | string or null | Always null in this Actor. |
| `rating` | number or null | Public Checkatrade rating, typically on a 0-10 scale. |
| `reviewCount` | integer or null | Public profile review count. |
| `description` | string or null | Public business description. |
| `services` | array | Public service labels. |
| `address` | string or null | Public street address, when supplied. |
| `locality` | string or null | Public town or city. |
| `region` | string or null | Public county or region. |
| `postalCode` | string or null | Public postcode, when supplied. |
| `areasServed` | array | Public service-area labels. |
| `imageUrl` | string or null | Public profile image URL. |
| `reviews` | array | Up to ten recent visible public reviews when enabled. |
| `searchTrade` | string or null | Trade supplied for the run, if any. |
| `searchLocation` | string or null | Location supplied for the run, if any. |
| `scrapedAt` | string | ISO 8601 extraction timestamp. |
| `source` | string | Constant source label: `checkatrade`. |

#### Illustrative output record

```json
{
  "businessName": "Example Electrical Services",
  "profileUrl": "https://www.checkatrade.com/trades/exampleelectricalservices",
  "phone": "+44 20 1234 5678",
  "website": "https://exampleelectricalservices.co.uk/",
  "email": null,
  "rating": 9.4,
  "reviewCount": 128,
  "description": "Public Checkatrade business description",
  "services": ["Electrician", "Rewiring", "Lighting"],
  "address": null,
  "locality": "Manchester",
  "region": "Greater Manchester",
  "postalCode": null,
  "areasServed": ["Manchester", "Salford"],
  "imageUrl": null,
  "reviews": [],
  "searchTrade": "Electrician",
  "searchLocation": "Manchester",
  "scrapedAt": "2026-07-19T12:34:56.000Z",
  "source": "checkatrade"
}
```

### How it works

This Actor searches public Checkatrade results by trade and UK location, or it processes copied Checkatrade search URLs and direct profile URLs. Search-result URLs are crawled and paginated. Direct profile URLs are scraped directly. For search discovery, `scrapeDetails` enriches each discovered profile with public profile fields. `extractReviews` adds up to ten visible recent review objects per returned profile. Results are saved as validated records in the default dataset, and the run also writes terminal output records to the default key-value store.

### Pricing

Checkatrade Scraper uses Pay per event plus Apify platform usage. The charged events are:

- Actor start
- Tradesperson record

The Tradesperson record event is charged once for each validated Checkatrade tradesperson record written to the dataset. The current pricing details are shown in the live Pricing tab in Apify. As an example, a run that saves one hundred profiles produces one hundred Tradesperson record events plus one Actor start event, along with Apify platform usage charges.

### Use with AI agents (MCP)

This Actor is available as an Apify Actor usable through Apify MCP. The precise Actor identity is `khadinakbar/checkatrade-scraper`.

Tool description: use it to discover and extract public Checkatrade tradesperson profiles, then read the dataset items for structured records and the key-value store for run outcome and summary metadata.

> Find up to 20 public electricians in London with public phone numbers and rating of at least 9. Return the dataset rows and summarize the most relevant fields for outreach review.

Output interpretation: dataset items contain one record per validated profile. The `results` output points to the default dataset items endpoint. `output` contains the terminal run outcome, and `runSummary` contains a compact execution summary. Provenance is preserved through the public `profileUrl`, `source`, and `scrapedAt` fields. Scope is limited to public Checkatrade data. Pagination is handled through search URLs and search discovery. Costs scale with the number of validated persisted records, so `maxResults` is the main control for run size.

### Apify API example

```javascript
import { ApifyClient } from "apify-client";

const client = new ApifyClient({
  token: process.env.APIFY_TOKEN,
});

const actorId = "khadinakbar/checkatrade-scraper";

const input = {
  trade: "Electrician",
  location: "Manchester",
  maxResults: 10,
  scrapeDetails: true,
  extractReviews: false,
};

const run = await client.actor(actorId).call(input);

const datasetItems = await client
  .dataset(run.defaultDatasetId)
  .listItems();

console.log("Run ID:", run.id);
console.log("Dataset items:", datasetItems.items);
```

### Best results and outcome guidance

Use a narrow trade and location pair when you want a focused public directory slice. Use `searchUrls` when you already have a browser-copied Checkatrade result page. Use `directUrls` when you already have profile URLs and want direct extraction. Set `requirePhone`, `minRating`, and `minReviews` to shape the returned list before downstream review. Enable `extractReviews` when you need a compact sample of visible review content alongside the profile fields. Keep `maxResults` aligned with the number of records you actually need.

### Continue the workflow

- Then use [Fragrantica Scraper — Perfume Profiles & Notes](https://apify.com/khadinakbar/fragrantica-scraper) to extend Checkatrade Scraper with a neighboring review and reputation research source when the brief calls for Fragrantica data.
- Then use [Capterra Reviews Scraper — Ratings, Pros & Cons](https://apify.com/khadinakbar/capterra-reviews-scraper) to extend Checkatrade Scraper with a neighboring review and reputation research source when the brief calls for Capterra data.

### Design note

I found that the dataset contract includes `email` with a fixed null meaning, which is a clear signal that this Actor returns public profile data without email enrichment.

### FAQ

#### Can I use this Actor for a trade and UK location search?

Yes. Provide `trade` and `location` to discover Checkatrade profiles for that market.

#### Can I scrape a copied Checkatrade search page?

Yes. Put the browser-copied search URL in `searchUrls`.

#### Can I scrape known Checkatrade profile links directly?

Yes. Put individual profile URLs in `directUrls`.

#### How do I narrow the output to profiles with phones and stronger public ratings?

Use `requirePhone = true`, set `minRating`, and optionally set `minReviews`.

#### Can I get recent review samples?

Yes. Set `extractReviews = true` to include up to ten visible recent review objects per profile.

#### Does this Actor return one record per profile?

Yes. The contract defines one validated business record per profile, and the primary billable event is one Tradesperson record per persisted dataset row.

### Responsible use

Use public Checkatrade data in ways that respect applicable privacy, marketing, and data protection requirements, including UK GDPR and PECR where relevant. Verify profile details before contacting a business. Use the data for lawful research, operational workflows, or other legitimate purposes that fit the public nature of the source.

# Actor input Schema

## `trade` (type: `string`):

The Checkatrade trade to find, such as 'Plumber' or 'Electrician'. Pair it with a UK location to create a Checkatrade search URL. Defaults to 'Plumber'. This is not a profile URL; use directUrls for existing profiles.

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

The UK town, city, postcode, or postcode area to search, such as 'London' or 'SW1A'. Combined with trade unless searchUrls is supplied. Defaults to 'London'. This is not a country selector or proxy setting.

## `searchUrls` (type: `array`):

Optional Checkatrade search-result URLs copied from a browser, for example 'https://www.checkatrade.com/Search/Plumber/in/London'. Each URL is crawled and paginated. Leave empty to use trade and location. Do not paste profile URLs here; put those in directUrls.

## `directUrls` (type: `array`):

Optional individual Checkatrade tradesperson profile URLs, such as 'https://www.checkatrade.com/trades/exampleltd'. Each is scraped directly and bypasses search discovery. Leave empty for a trade/location search. Do not include URLs from other directories.

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

Maximum validated tradesperson records to return across the entire run. Each persisted record is one billable tradesperson event. Defaults to 100 and accepts 1 through 1000. This is not a page limit because one page can contain multiple profiles.

## `scrapeDetails` (type: `boolean`):

Controls full-profile enrichment for profiles discovered from Checkatrade search pages. Keep this enabled to return contact, service, rating, and review fields from the profile. Defaults to true. Direct profile URLs are always handled as detailed profiles.

## `extractReviews` (type: `boolean`):

Include up to ten visible recent review objects for each returned profile. This adds review body, author when public, rating, and date when available. Defaults to false to keep items compact. This does not claim to return a profile's complete review history.

## `requirePhone` (type: `boolean`):

When enabled, excludes profiles without a public phone number. Use it for phone-first outreach lists. Defaults to false so all valid public profiles remain eligible. It does not infer or enrich hidden contact information.

## `minRating` (type: `number`):

Minimum public Checkatrade rating from 0 to 10. Profiles without a rating or below this threshold are excluded when a value above zero is used. Defaults to 0. This is not a star rating out of five.

## `minReviews` (type: `integer`):

Minimum number of public reviews a profile must show before it is returned. Profiles without enough reviews are excluded when this is above zero. Defaults to 0. This is a filter, not the number of review objects to extract.

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

Optional Apify proxy configuration used for public Checkatrade requests. The default uses the RESIDENTIAL group for consistent UK directory access. Leave the default unless you operate an approved custom proxy. This does not alter the location searched above.

## Actor input object example

```json
{
  "trade": "Electrician",
  "location": "Manchester",
  "searchUrls": [
    "https://www.checkatrade.com/Search/Plumber/in/London"
  ],
  "directUrls": [
    "https://www.checkatrade.com/trades/exampleltd"
  ],
  "maxResults": 100,
  "scrapeDetails": true,
  "extractReviews": false,
  "requirePhone": false,
  "minRating": 9,
  "minReviews": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "groups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

No description

## `output` (type: `string`):

No description

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

No description

# 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 = {
    "trade": "Plumber",
    "location": "London",
    "searchUrls": [],
    "directUrls": [],
    "maxResults": 1,
    "scrapeDetails": true,
    "extractReviews": false,
    "requirePhone": false,
    "minRating": 0,
    "minReviews": 0,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "groups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/checkatrade-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 = {
    "trade": "Plumber",
    "location": "London",
    "searchUrls": [],
    "directUrls": [],
    "maxResults": 1,
    "scrapeDetails": True,
    "extractReviews": False,
    "requirePhone": False,
    "minRating": 0,
    "minReviews": 0,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "groups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/checkatrade-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 '{
  "trade": "Plumber",
  "location": "London",
  "searchUrls": [],
  "directUrls": [],
  "maxResults": 1,
  "scrapeDetails": true,
  "extractReviews": false,
  "requirePhone": false,
  "minRating": 0,
  "minReviews": 0,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "groups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call khadinakbar/checkatrade-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/checkatrade-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/NDA7wKRcFeIfwfdjz/builds/tw6z8KVCVAaUX8yZ4/openapi.json
