Checkatrade Scraper — UK Tradespeople, Ratings & Reviews avatar

Checkatrade Scraper — UK Tradespeople, Ratings & Reviews

Pricing

from $7.00 / 1,000 tradespeople

Go to Apify Store
Checkatrade Scraper — UK Tradespeople, Ratings & Reviews

Checkatrade Scraper — UK Tradespeople, Ratings & Reviews

Checkatrade scraper — search any trade + town, or paste profile/search URLs. One flat row per tradesperson: phone, locality, score out of 10, review counts, skills, badges, vetting and member-since. Opt-in full review history from Checkatrade's public API. Pure HTTP, no browser.

Pricing

from $7.00 / 1,000 tradespeople

Rating

0.0

(0)

Developer

Muhamed Didovic

Muhamed Didovic

Maintained by Community

Actor stats

1

Bookmarked

25

Total users

4

Monthly active users

6 days ago

Last modified

Share

Turn any Checkatrade search into structured data. Search by trade + location (Plumber in London), or paste search-listing and trade-profile URLs — and get one flat row per tradesperson: name, phone, locality, score out of 10, review counts, skills and sub-skills, badges, vetting flags, membership and profile URL. Turn on deep reviews and each row also carries that trade's full customer review history, straight from Checkatrade's own public reviews API.

How it works

How the Checkatrade Scraper works


Why use this scraper?

  • Rich rows with nothing switched on. ~36 fields per tradesperson straight from the search listing: company name, phone (formatted + E.164), locality/region, recent score out of 10, recent + all-time review counts, every skill group with its sub-skills, quality and vetting badges, sponsorship flag, logo and gallery images, profile URL.
  • The full review history, not the six on the page. A profile page embeds at most 6 recent reviews. Set maxReviewsPerTrade above 0 and the actor pulls the complete history from Checkatrade's public reviews API — with per-dimension scores (workmanship, reliability, communication), reviewer name, work category, price band, the trade's reply and review photos.
  • Gets past the Cloudflare wall. Checkatrade fronts the site with a Cloudflare managed challenge. Every page request goes out with a real browser TLS/HTTP-2 fingerprint over GB residential IPs, rotating the session on each retry, so you get the real page instead of "Just a moment…".
  • Two ways in, mixed freely. Build searches from a trade + a list of towns, paste search-listing URLs, paste profile URLs — or all three in one run. Results are deduplicated by company across every source.
  • Not brittle DOM scraping. Rows are parsed out of Checkatrade's embedded Next.js data stream, so a layout change doesn't silently empty your dataset.
  • Costs are capped before the first request. The run trims itself to what your maximum-cost setting can actually pay for, so you never burn proxy bandwidth producing rows the charge limit will not bill.

Overview

One dataset row = one tradesperson (company), never one review and never one page. Reviews, skills, services and images are nested arrays inside that row, so a run of 500 tradespeople gives you exactly 500 rows however deep you scrape.

Scores are Checkatrade's own scale — out of 10, not out of 5. rating is the recent mean score; reviewMetrics.totalScore is the all-time one.


Supported inputs

InputExampleWhat it does
Trade + locationtrade: "Plumber", locations: ["London", "Leeds"]Builds /Search/Plumber/in/London for each town and paginates it
Trade with no locationtrade: "Electrician", locations: []Falls back to a UK-wide search
Search-listing URLhttps://www.checkatrade.com/Search/Builder/in/LondonPaginates that trade/location's results
Profile URLhttps://www.checkatrade.com/trades/gem247Scrapes that single tradesperson, always in full detail

Search and profile URLs are auto-classified — you do not have to sort them. Anything that is not a checkatrade.com /Search/… or /trades/{slug} URL is reported in the log and skipped.

Not supported: anything behind a Checkatrade login, buyer messages, quote and booking flows, and account-only data. The actor reads public search-listing pages, public profile pages and the public reviews API.


Use cases

You are a…Use it to…
Market researcherMeasure score and review-volume distribution, and trade density, across UK towns
Trades business ownerBenchmark competitors in your patch — scores, review counts, skills, badges, membership age
Reputation / review analystPull a trade's full review history with per-dimension scores, categories and replies
Directory or comparison siteSeed a UK tradesperson dataset with structured company, rating and skill rows
Sales / lead-gen teamBuild a call list by trade + town — phone numbers are public on most listings (see the honest note on emails below)
RecruiterFind verified tradespeople by skill, sub-skill and location

How it works

  1. Classify. A trade + each location becomes a /Search/{Trade}/in/{Location} URL; pasted URLs are sorted into search vs profile.
  2. Fetch. Each page is requested with a real browser TLS fingerprint over a GB residential IP. A Cloudflare challenge or a 403/429/5xx rotates to a fresh session and retries (15 attempts by default).
  3. Parse. The page's embedded Next.js RSC data stream is reassembled and every company object extracted — a search page carries ~11–12 tradespeople and reports its own totalResults/totalPages, which drives ?page=N pagination up to your cap.
  4. Detail (optional). With scrapeDetails on, each tradesperson's profile page is fetched for the full description, the complete skill list, services offered, review metrics, up to 6 embedded reviews and — where the trade published one — their own website.
  5. Deep reviews (optional). With maxReviewsPerTrade above 0, the full review history is pulled from api.checkatrade.com/v1/consumer-public/reviews — 25 per request, no auth, no Cloudflare, so it is fetched directly without spending residential bandwidth. It needs only the company ID that listing rows already carry, so it works with scrapeDetails off and adds zero profile fetches.
  6. Emit. One flat, deduplicated row per tradesperson, charged once.

Input configuration

FieldTypeDefaultNotes
tradestringTrade/category to search, e.g. Plumber, Electrician, Gas Boiler Servicing Repair. Combined with every location.
locationsarrayTowns/cities to search, e.g. ["London", "Manchester"]. Empty + a trade set = UK-wide.
startUrlsarray[]Search-listing and/or profile URLs. Auto-classified, mixable with trade.
scrapeDetailsbooleanfalseFetch each profile page for the full description, all skills, services, review metrics, up to 6 embedded reviews and the trade's own website. ~2× the requests. Pasted profile URLs are always detailed.
maxReviewsPerTradeinteger00 = only the up-to-6 reviews embedded in the profile page (needs scrapeDetails). Above 0 = that many from the public reviews API, 25 per request, works with scrapeDetails off.
enrichEmailsbooleanfalseOpt-in, best-effort contact-email discovery. Read the limitations section before switching it on — the realistic hit rate is low.
maxItemsinteger1000Hard cap on rows for the whole run. Free-tier accounts are additionally capped at 100.
maxItemsPerSearchinteger1000Cap per trade+location search. Checkatrade paginates ~12 per page, 60 pages max per search.
maxConcurrencyinteger6Parallel requests. Keep moderate (4–8) — the site is Cloudflare-protected.
maxRequestRetriesinteger15Retry budget per request. Each retry takes a fresh GB residential IP.
proxyobjectbuilt-in GB residentialLeave empty. The actor ships its own GB residential routing at no extra cost; set this only to force your own proxies.

Example input

{
"trade": "Plumber",
"locations": ["London"],
"scrapeDetails": true,
"maxReviewsPerTrade": 5,
"maxItems": 6
}

That exact input is the actor's smoke test: 6 tradespeople in 20 seconds, 10 page requests plus 6 review-API requests, nothing blocked.


Output overview

Every row is rowType: "tradesperson". Listing fields are always present. Detail fields (fullDescription, allSkillLabels, servicesOffered, reviewMetrics, website, embedded reviews) appear when scrapeDetails is on or when you pasted a profile URL. Deep reviews from the API appear whenever maxReviewsPerTrade is above 0, with or without profile scraping.

Each review carries a source field: "profile" (the free embedded copy, max 6) or "api" (the deep history — strictly richer, with per-dimension scores, reviewer name, reply date and photos).


Output samples

Tradesperson row (search + scrapeDetails + deep reviews)

{
"rowType": "tradesperson",
"companyId": "9730955",
"name": "GEM 24/7",
"slug": "gem247",
"profileUrl": "https://www.checkatrade.com/trades/gem247",
"summary": "GEM Environmental Building Services is a plumbing, heating and engineering company with over 30 years of experience…",
"logoUrl": "https://lh3.googleusercontent.com/Ah-u3o-y6CP…",
"heroBannerUrl": "https://lh3.googleusercontent.com/DdHO6rK41Qs…",
"locality": "London",
"region": null,
"operatingLocation": "Operates in your area",
"rating": 9.59, // recent mean score, out of 10
"recentReviewsCount": 9,
"totalReviews": 9,
"phone": "07577 412278",
"phoneRaw": "+447577412278", // E.164; null on some listings
"skills": [
{ "id": 20, "label": "Plumber", "subSkills": ["Blocked Toilets", "Emergency Plumber Service", "Power Flushing"] },
{ "id": 10, "label": "Central Heating", "subSkills": ["Gas Boiler Installation", "Gas Safety Checks - CP12"] }
],
"skillLabels": ["Central Heating", "Electrician", "Plumber"],
"badges": [], // e.g. ["Sponsored"] on paid placements
"qualityBadges": [], // e.g. ["GREAT_COMMUNICATOR"]
"trackingBadges": ["new_member", "guaranteed"],
"isSponsored": false,
"memberSince": null, // elsewhere: "Approved member since February 2013" — a sentence, not a date
"acquiredBadge": "None", // e.g. "fiveYear" / "tenYear"
"images": ["https://lh3.googleusercontent.com/EVd21ZqUkDe…"],
"searchTrade": "Plumber",
"searchLocation": "London",
"sourceUrl": "https://www.checkatrade.com/Search/Plumber/in/London",
"sourceMode": "search",
"scrapedAt": "2026-08-12T20:15:47.674Z",
// ---- detail fields (scrapeDetails / profile URLs) ----
"detailScraped": true,
"fullDescription": "GEM Environmental Building Services is a plumbing, heating and engineering company with over 30 years…",
"allSkillLabels": ["Central Heating", "Emergency Central Heating Repair", "Gas Boiler Installation"],
"servicesOffered": [], // e.g. ["Domestic Work", "Free Estimates", "24 Hour Call-out"]
"reviewMetrics": { "totalReviewCount": 9, "totalScore": 9.59, "recentReviewCount": 9, "workmanship": 9.44, "reliability": 9.78, "courtesy": 0, "communication": 9.56 },
"reviewsTotal": 9,
"website": "https://gemenvironmentalbuildingservices.co.uk/", // present on roughly 1 profile in 3
"websiteDomain": "gemenvironmentalbuildingservices.co.uk",
"hasWebsite": true,
"websiteIsBuilderOrSocial": false,
"reviews": [ /* see below */ ]
}

Review from the public API (maxReviewsPerTrade > 0)

{
"id": "019fc885-7dcf-7fbf-a310-1afd7c05c13d",
"title": "Kitchen tap replacement",
"body": "Excellent communication, excellent service and plumbing work was completed on time.",
"createdAt": "2026-08-03T16:47:00.439Z",
"publishedAt": "2026-08-04T17:00:09.033Z",
"rating": 10, // out of 10
"ratingWorkmanship": 10,
"ratingReliability": 10,
"ratingCommunication": 10,
"verified": true,
"reviewerName": "Shiv M", // null when the reviewer is anonymous
"reviewerProfileUrl": "/profile/019c9022-bc39-7213-9e89-c4a7a394db1c",
"location": "E14", // outward postcode
"category": "Tap Repair",
"categoryId": 1591,
"tradeReply": "Hi Shiv, thank you for your 10/10 review…",
"tradeReplyDate": "2026-08-05T09:56:45.299Z",
"priceBand": null,
"hiredViaCheckatrade": true,
"images": ["https://api.checkatrade.com/v1/media-service/media/019fc885-7d5d-797f-92ff-105cee54d4c8/content"],
"source": "api"
}

Key output fields

FieldTypeNotes
companyId / slug / profileUrlstringCheckatrade's numeric company ID, URL slug and canonical profile URL. companyId is the dedup key.
name / summary / fullDescriptionstringCompany name, short listing blurb, full profile description (detail only — summary is the reliable one, see limitations)
phone / phoneRawstringPublic number as displayed + E.164 form. phoneRaw is null on some listings.
locality / region / operatingLocationstringTown, county, and Checkatrade's coverage line
ratingnumberRecent mean score, out of 10
recentReviewsCount / totalReviewsnumberRecent window and all-time review counts
reviewMetricsobjectPer-dimension all-time scores: workmanship, reliability, courtesy, communication (detail only)
reviewsarrayUp to 6 embedded (source: "profile") or the full history (source: "api")
skills / skillLabels / allSkillLabelsarraySkill groups with sub-skills, flattened group labels, and the complete label list from the profile
servicesOfferedstring[]e.g. Domestic Work, Free Estimates, 24 Hour Call-out (detail only)
qualityBadges / trackingBadges / badgesstring[]Quality awards, vetting/insurance flags, listing badges
isSponsored / memberSince / acquiredBadgemixedPaid-placement flag, membership sentence, longevity badge
website / websiteDomain / hasWebsite / websiteIsBuilderOrSocialmixedThe trade's own site when their profile exposes one — see limitations
logoUrl / heroBannerUrl / imagesstring / string[]Logo, banner and gallery photos
searchTrade / searchLocation / sourceUrl / sourceModestringWhich search produced the row, and whether it came from a listing or a profile
contactEmail / contactWebsite / emailEnrichmentmixedOnly with enrichEmails on, and only when something is actually found

Pricing

Pay-per-event. You pay for rows, not for time.

EventWhen it firesPrice
Actor startOnce per run$0.005
TradespersonEach row pushed to the dataset$0.004
Contact email foundOnly when enrichEmails actually returns an email$0.05

1,000 tradespeople ≈ $4.01 all-in. Pagination, retries, proxy bandwidth, profile fetches and deep review-API calls are included — they are never billed separately, so a row with 400 reviews attached costs the same as a bare listing row.

The email event is priced at exactly $0.05 on purpose. The shared enrichment module bills a found email as round($0.05 ÷ unit price) units of additional-data; setting the unit price to $0.05 makes that exactly one unit, so a found email is one $0.05 charge and never a multiple.

Nothing is charged for a tradesperson the run does not emit. If your maximum-cost-per-run setting cannot pay for a single row, the run stops immediately and tells you, instead of scraping and discarding.


Notes & limitations

Read this before you build a workflow on it.

  • This is a reviews and public-listing scraper, not a finished lead list. Phones are public and present on most listings; email addresses mostly are not (below).
  • Website coverage is partial by design. Checkatrade only renders a trade's own website when that profile has the flag set — measured live, 25–35% of profiles expose one, and roughly 30% of those domains are dead or stale. That leaves an effective, usable website rate of about 17–18%. website is null rather than guessed when there is none.
  • enrichEmails is experimental and often returns nothing. It seeds from the trade's own website when one exists, otherwise it tries to discover a domain from the business name. In a 7-row test it found 0 emails. It is off by default, it only bills when it actually finds an address, and it should be treated as an occasional bonus — not as the reason to run this actor.
  • Reviews out of 10, not 5. Every score — row-level and per-review — is on Checkatrade's 10-point scale.
  • Deep reviews cost requests, not extra charges. maxReviewsPerTrade: 400 is 16 API calls for that row. Runtime grows; the per-row price does not.
  • Pagination has a ceiling. Each search follows up to 60 pages (~700 tradespeople). Split a big trade across towns to go wider.
  • Cloudflare is flaky, not impossible. A blocked request rotates IP and retries. If Checkatrade blocks every request, the run fails loudly with the block count rather than silently reporting zero rows — re-running usually gets a session that works.
  • memberSince is a sentence, not a date. Checkatrade publishes it as "Approved member since February 2013"; some profiles have none.
  • fullDescription is not reliable on every profile. On some profiles Checkatrade's data stream stores the description as an internal reference (the field then reads "$38" rather than prose — it happened on 3 of 6 profiles in the last test run). summary always carries readable text, so use it as the fallback.
  • courtesy in reviewMetrics is frequently 0 — that is Checkatrade's own data, not a parsing miss.
  • Free-tier accounts are capped at 100 rows per run.

FAQ

Do I get the tradesperson's phone number? Yes — the public number is on most listings, both as displayed (07577 412278) and E.164 (+447577412278). A minority of listings have no E.164 form; phoneRaw is then null.

Do I get their email address? Usually not. Checkatrade does not publish emails, and the optional enrichment can only work from a website the trade published — which is about a third of profiles, of which many domains are dead. Plan for phone-first outreach.

How many tradespeople are behind one search? Checkatrade returns ~12 per page and reports its own total: Plumber in London was 133 tradespeople across 12 pages when this README was written. Use maxItemsPerSearch to cap it.

Do I need scrapeDetails to get reviews? No. maxReviewsPerTrade uses the public reviews API keyed on the company ID that listing rows already carry, so deep reviews work with profile scraping off. scrapeDetails is what adds the description, full skill list, services, review metrics and the trade's website.

What is the difference between the two review sources? source: "profile" is the free copy embedded in the profile page — max 6, no per-dimension scores. source: "api" is the full history with workmanship/reliability/communication scores, reviewer name, category, trade reply and photos.

Do I need to configure proxies? No. GB residential routing is built in at no extra cost. The proxy input exists only if you insist on your own pool.

Which locations work? Any town, city or area Checkatrade supports — London, Manchester, Birmingham, Leeds, Milton Keynes. Multi-word places are Title-Cased and dash-joined automatically.

Why did my run return 0 rows? If Cloudflare blocked everything, the run fails with the block count in the message — re-run it. If the input was a trade/town combination Checkatrade has no results for, the log says so per search.

Can I re-run this on a schedule? Yes. Rows are deduplicated within a run by company ID; across runs, dedupe on companyId on your side.


💬 Support

Found a bug or need an extra field? Open an issue on the actor's Issues tab — issues are read and answered.

🛠 Additional services

Need a custom field, another UK trades directory (Rated People, MyBuilder, TrustATrader), or a scheduled tradesperson feed into your CRM or warehouse? Custom scraping and pipeline work is available on request.

🔎 Explore more scrapers

More directory, local-business and review scrapers — Capterra, G2, Trustpilot-style review sources, job boards and lead directories — are published under the same account on the Apify Store.


🤖 For AI Agents & LLM Apps

Purpose: extract UK tradespeople from Checkatrade — company profile, contact phone, ratings and full customer review history.

Minimal tested input:

{ "trade": "Plumber", "locations": ["London"], "maxItems": 6, "scrapeDetails": true, "maxReviewsPerTrade": 5 }

Also accepts: startUrls with https://www.checkatrade.com/Search/{Trade}/in/{Location} and/or https://www.checkatrade.com/trades/{slug} (auto-classified, mixable with trade).

Output: one flat JSON row per tradesperson, rowType: "tradesperson". Fields: companyId, name, slug, profileUrl, summary, logoUrl, heroBannerUrl, locality, region, operatingLocation, rating, recentReviewsCount, totalReviews, phone, phoneRaw, skills[], skillLabels[], badges[], qualityBadges[], trackingBadges[], isSponsored, memberSince, acquiredBadge, images[], searchTrade, searchLocation, sourceUrl, sourceMode, scrapedAt. With scrapeDetails: detailScraped, fullDescription, allSkillLabels[], servicesOffered[], reviewMetrics{}, reviewsTotal, website, websiteDomain, hasWebsite, websiteIsBuilderOrSocial. With maxReviewsPerTrade > 0: reviews[] with source: "api".

Scales: ratings are out of 10. rating = recent mean; reviewMetrics.totalScore = all-time.

Billing: $0.005 per run start + $0.004 per tradesperson row + $0.05 per contact email actually found (enrichEmails only, off by default). Reviews, pagination and profile fetches are not billed separately.

Agent-relevant behaviour: no login and no browser; companyId is the dedup key; a search caps at 60 pages; free-tier runs cap at 100 rows; the run trims maxItems to what the charge limit can pay for; if every request is blocked the run FAILS with the block count rather than returning an empty success.

Do not assume: an email on every row (measured ~0 on a 7-row test), a website on every row (~1 in 3, and ~30% of those are dead), a 5-point rating scale, or prose in fullDescription (some profiles return an internal reference like "$38" — fall back to summary).


⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Checkatrade or any of its subsidiaries or affiliates. All trademarks mentioned are the property of their respective owners.

The scraper accesses only publicly available Checkatrade search-listing pages, trade-profile pages and the public consumer reviews API — no authenticated endpoints, no login-only or private data. Users are responsible for ensuring their use complies with Checkatrade's Terms of Service, applicable data-protection law (including UK GDPR) and their own organisation's contractual obligations. Use personal data such as tradesperson names, phone numbers and reviewer names lawfully, respect rate limits, honour opt-out and do-not-contact requirements, and do not republish scraped review content in violation of copyright.

No scraped data is stored by the Actor's author — it is returned directly to your own Apify dataset.


SEO Keywords

checkatrade scraper, scrape checkatrade, checkatrade data extraction, checkatrade api, checkatrade reviews scraper, tradesperson scraper, uk trades directory scraper, checkatrade phone number scraper, builder scraper uk, electrician scraper, plumber scraper uk, local trades data, uk tradesmen data, checkatrade listings scraper, checkatrade profiles, checkatrade search scraper, trade reviews dataset, uk contractor data, home services data, apify checkatrade, trades lead generation, local business directory scraper