Checkatrade Scraper — UK Tradespeople, Ratings & Reviews
Pricing
from $7.00 / 1,000 tradespeople
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
Maintained by CommunityActor stats
1
Bookmarked
25
Total users
4
Monthly active users
6 days ago
Last modified
Categories
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

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
maxReviewsPerTradeabove 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
| Input | Example | What it does |
|---|---|---|
| Trade + location | trade: "Plumber", locations: ["London", "Leeds"] | Builds /Search/Plumber/in/London for each town and paginates it |
| Trade with no location | trade: "Electrician", locations: [] | Falls back to a UK-wide search |
| Search-listing URL | https://www.checkatrade.com/Search/Builder/in/London | Paginates that trade/location's results |
| Profile URL | https://www.checkatrade.com/trades/gem247 | Scrapes 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 researcher | Measure score and review-volume distribution, and trade density, across UK towns |
| Trades business owner | Benchmark competitors in your patch — scores, review counts, skills, badges, membership age |
| Reputation / review analyst | Pull a trade's full review history with per-dimension scores, categories and replies |
| Directory or comparison site | Seed a UK tradesperson dataset with structured company, rating and skill rows |
| Sales / lead-gen team | Build a call list by trade + town — phone numbers are public on most listings (see the honest note on emails below) |
| Recruiter | Find verified tradespeople by skill, sub-skill and location |
How it works
- Classify. A trade + each location becomes a
/Search/{Trade}/in/{Location}URL; pasted URLs are sorted into search vs profile. - 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).
- 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=Npagination up to your cap. - Detail (optional). With
scrapeDetailson, 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. - Deep reviews (optional). With
maxReviewsPerTradeabove 0, the full review history is pulled fromapi.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 withscrapeDetailsoff and adds zero profile fetches. - Emit. One flat, deduplicated row per tradesperson, charged once.
Input configuration
| Field | Type | Default | Notes |
|---|---|---|---|
trade | string | — | Trade/category to search, e.g. Plumber, Electrician, Gas Boiler Servicing Repair. Combined with every location. |
locations | array | — | Towns/cities to search, e.g. ["London", "Manchester"]. Empty + a trade set = UK-wide. |
startUrls | array | [] | Search-listing and/or profile URLs. Auto-classified, mixable with trade. |
scrapeDetails | boolean | false | Fetch 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. |
maxReviewsPerTrade | integer | 0 | 0 = 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. |
enrichEmails | boolean | false | Opt-in, best-effort contact-email discovery. Read the limitations section before switching it on — the realistic hit rate is low. |
maxItems | integer | 1000 | Hard cap on rows for the whole run. Free-tier accounts are additionally capped at 100. |
maxItemsPerSearch | integer | 1000 | Cap per trade+location search. Checkatrade paginates ~12 per page, 60 pages max per search. |
maxConcurrency | integer | 6 | Parallel requests. Keep moderate (4–8) — the site is Cloudflare-protected. |
maxRequestRetries | integer | 15 | Retry budget per request. Each retry takes a fresh GB residential IP. |
proxy | object | built-in GB residential | Leave 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
| Field | Type | Notes |
|---|---|---|
companyId / slug / profileUrl | string | Checkatrade's numeric company ID, URL slug and canonical profile URL. companyId is the dedup key. |
name / summary / fullDescription | string | Company name, short listing blurb, full profile description (detail only — summary is the reliable one, see limitations) |
phone / phoneRaw | string | Public number as displayed + E.164 form. phoneRaw is null on some listings. |
locality / region / operatingLocation | string | Town, county, and Checkatrade's coverage line |
rating | number | Recent mean score, out of 10 |
recentReviewsCount / totalReviews | number | Recent window and all-time review counts |
reviewMetrics | object | Per-dimension all-time scores: workmanship, reliability, courtesy, communication (detail only) |
reviews | array | Up to 6 embedded (source: "profile") or the full history (source: "api") |
skills / skillLabels / allSkillLabels | array | Skill groups with sub-skills, flattened group labels, and the complete label list from the profile |
servicesOffered | string[] | e.g. Domestic Work, Free Estimates, 24 Hour Call-out (detail only) |
qualityBadges / trackingBadges / badges | string[] | Quality awards, vetting/insurance flags, listing badges |
isSponsored / memberSince / acquiredBadge | mixed | Paid-placement flag, membership sentence, longevity badge |
website / websiteDomain / hasWebsite / websiteIsBuilderOrSocial | mixed | The trade's own site when their profile exposes one — see limitations |
logoUrl / heroBannerUrl / images | string / string[] | Logo, banner and gallery photos |
searchTrade / searchLocation / sourceUrl / sourceMode | string | Which search produced the row, and whether it came from a listing or a profile |
contactEmail / contactWebsite / emailEnrichment | mixed | Only with enrichEmails on, and only when something is actually found |
Pricing
Pay-per-event. You pay for rows, not for time.
| Event | When it fires | Price |
|---|---|---|
| Actor start | Once per run | $0.005 |
| Tradesperson | Each row pushed to the dataset | $0.004 |
| Contact email found | Only 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%.
websiteisnullrather than guessed when there is none. enrichEmailsis 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: 400is 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.
memberSinceis a sentence, not a date. Checkatrade publishes it as "Approved member since February 2013"; some profiles have none.fullDescriptionis 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).summaryalways carries readable text, so use it as the fallback.courtesyinreviewMetricsis 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