TrustATrader Scraper — Vetted UK Trades Leads & Phones
Pricing
$4.00 / 1,000 per trader returneds
TrustATrader Scraper — Vetted UK Trades Leads & Phones
Scrape vetted UK tradespeople from TrustATrader: name, trade, area, phone, website, rating, reviews, owner name, vetting checks, insurer and insurance verification date. Pick from 1,379 real trades and 100 UK areas. Promoted adverts are deduped before billing — never pay for a repeat.
Pricing
$4.00 / 1,000 per trader returneds
Rating
0.0
(0)
Developer
Scrapers Delight
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Share
Turn TrustATrader into a clean UK tradesperson lead list. One row per trader advert, carrying business name, trade, area covered, phone, website, town, latitude/longitude, rating, review count, per-category rating breakdown, missed appointments, membership number, years as a member, business type, owner name, the five vetting checks, insurance provider, insurance verification date, qualifications and trade associations. Filter by trade, area, phone, website, rating, review count and membership tenure — or paste listing and profile URLs.
No login. No cookies. No CAPTCHA solving.
30,972 live trader adverts. 1,557 trades. 100 UK areas. 156,500 trade × area listing pages — every one of those numbers read live off TrustATrader's own sitemaps on 2026-08-12, not quoted from a marketing page. (156,500 is a clean cross-product: 1,565 trades × 100 areas. Eight trades carry listing pages without appearing in the trade sitemap.)
The wedge, measured on a 200-advert contiguous sample the same day: 100% carry an insurance provider and the date TrustATrader last verified that insurance, and 100% carry a missed-appointment count for the last six months. Google Maps has neither.
{"source": "search","trades": ["plumbers"],"locations": ["london"],"maxItems": 30}
Click Try for free and hit Start — that is the input the Actor ships prefilled with (plus a page depth of 10 and the residential-GB proxy, both already set). It returned 30 rows in 2 minutes 34 seconds on 2026-08-12, with nothing edited.
The wedge: the vetting paperwork, not another star rating
Every other UK trades scraper — ours included — gives you a name, a phone and a rating. TrustATrader is a vetted directory, and the vetting file prints on the public profile. That file is the product.
Measured on 200 trader adverts, contiguous sitemap walk, 2026-08-12:
| Field only TrustATrader publishes | Fill | What it is worth |
|---|---|---|
insuranceProvider + insuranceVerifiedOn | 100% | The firm's insurer and the date TrustATrader last checked the policy. A renewal calendar for a trade-insurance broker. 61 distinct insurer strings in 200 rows, and the big names are split across several of them: Simply Business 45 rows over three spellings, Hiscox 21 over three, Aviva 16 over two, Direct Line 15 over two, QBE 13 over four. |
missedAppointments | 100% | Missed appointments in the last 6 months. 8 of 200 traders had one or more; 192 had zero. |
vettingChecks + vettingVerifiedOn | 100% | The five checks TrustATrader ran (ID, company address, customer references, standards agreement, complaints procedure) and the date they were run. |
businessType + ownerName | 100% / 71.5% | Legal form, and where TrustATrader prints "Owned by …", a named decision-maker. In the sample: 143 "Owned by …", 39 limited companies, 18 sole traders. |
membershipNumber | 100% | The business-level ID. It is what lets this Actor collapse a firm's many adverts into one row — see below. |
None of those five are on a Google Maps pull, and none are on the listing card — they exist only on the profile page, which is why this Actor fetches it.
Read this before you buy rows
Five things that will otherwise surprise you. All measured, all facts about TrustATrader rather than about this Actor.
- A TrustATrader "profile" is an advert, not a business. Adverts are per trade and per service area, so one firm holds many. In a contiguous 100-advert sitemap window at offset 15,000, 100 adverts belonged to just 25 distinct businesses — a 75% collapse; one firm held 16 of them. A second window at offset 0 was far tamer: 100 adverts, 90 businesses, 10% collapse. Across both, 200 adverts = 115 businesses. Turn on One row per business if you want companies, not adverts; leave it off if you want the trade and area dimensions. Either way you are billed for what you receive — collapsed rows are dropped before billing.
- Three promoted adverts are pinned to the top of every listing page. They are the same three traders on page 2, page 3 and page 27. This Actor drops them at enumeration time, before anything is fetched or billed — see the uniqueness section.
- There is no street address and no postcode. TrustATrader publishes the town and a map pin only;
itemprop="streetAddress"and"postalCode"appear on 0 of 109 live profiles sampled. Rather than ship two permanently empty columns you getaddressLocalitypluslatitude/longitude(100% / 100%). - There are no e-mail addresses. TrustATrader routes contact through its own form. Nothing in this Actor can produce one, and it will not invent one.
- "Years trading" is not published. The only tenure signal on the page is the "N year member"
badge, so
membershipYearsmeans years as a TrustATrader member, not years in business.
What you get — one row per trader advert
All dates that TrustATrader prints as prose (vettingVerifiedOn, insuranceVerifiedOn) are kept
verbatim as published, e.g. "7th April 2026". scrapedAt is ISO-8601 UTC. rating is a number out
of 5, never a percentage. phone is E.164; phoneDisplay is the printed form.
| Group | Fields |
|---|---|
| Identity | traderName · profileUrl · traderSlug · traderId · membershipNumber |
| Trade & area | trade · tradeSlug · areaCovered · locationSlug · listingUrl |
| Location | addressLocality · latitude · longitude |
| Contact | phone · phoneDisplay · phones[] · website |
| Ratings | rating · reviewCount · ratingBreakdown{} · missedAppointments |
| Vetting | vettedAndApproved · vettingChecks[] · vettingVerifiedOn · businessType · ownerName · membershipYears · guaranteeEligible |
| Insurance | insuranceProvider · insuranceVerifiedOn |
| Credentials | qualifications[] · associations[] |
| Content | shortDescription · description · logo · galleryImageCount |
| Provenance | scrapedAt |
Field fill — two measured samples
Fill differs by how you reach the rows, so both samples are published. Plan against the sitemap sample if you are buying volume; the search sample is what a trade + area run looks like.
A. 200 trader adverts, contiguous sitemap walk, 2026-08-12 (67 trades, 93 towns)
| Field | Fill |
|---|---|
traderName · trade · membershipNumber · businessType | 100% |
rating · reviewCount · ratingBreakdown · missedAppointments | 100% |
addressLocality · latitude · longitude | 100% |
vettingChecks · vettingVerifiedOn · vettedAndApproved | 100% |
insuranceProvider · insuranceVerifiedOn | 100% |
membershipYears | 100% |
description · shortDescription · galleryImageCount · guaranteeEligible | 100% |
areaCovered | 99.5% |
phone · phoneDisplay · phones | 99.5% (1 of 200 had none) |
tradeSlug · locationSlug · listingUrl | 99.0% |
logo | 98.0% |
website | 83.5% |
ownerName | 71.5% |
qualifications | 70.0% |
associations | 66.5% |
0 and false count as filled, because they are real answers. missedAppointments: 0 means
TrustATrader recorded none (192 of the 200), and galleryImageCount: 0 means the trader uploaded no
photos (69 of the 230 rows scraped that day). Neither is a null, and neither is a parse failure.
Where a value is genuinely absent — website, ownerName, qualifications — the field is null or an
empty array, and that is what the percentages above measure.
B. 196 live profiles, random national sample, 2026-08-12 (79 trades, 139 towns)
| Field | Fill |
|---|---|
traderName · trade · rating · reviewCount · ratingBreakdown | 100% |
phone · phoneDisplay | 100% |
missedAppointments · addressLocality · latitude · longitude | 100% |
membershipNumber · businessType · vettingChecks · vettingVerifiedOn | 100% |
description · shortDescription | 100% |
areaCovered | 99.0% |
insuranceProvider · insuranceVerifiedOn | 98.5% |
logo | 93.9% |
tradeSlug · locationSlug · listingUrl | 94.4% |
membershipYears | 76.0% |
website | 74.0% |
ownerName | 59.7% |
qualifications | 41.3% |
associations | 35.2% |
The headline that could mislead you: this is not a 100%-website product, and the two samples disagree
about how far off it is — 83.5% on the sitemap walk, 74.0% on the national random sample. Budget
against the lower one. ownerName (59.7–71.5%) and qualifications (41.3–70.0%) swing the same way,
because they depend on which trades and which membership vintages a given slice happens to hit.
Every run prints its own measured fill in the log, so you never have to trust this table for the rows you actually bought.
How to run it
1. Search — trade + area (the usual choice)
{"source": "search","trades": ["plumbers", "electricians"],"locations": ["london", "manchester"],"maxItems": 200}
Both fields are pickers, not free-text boxes. The trade list carries 1,379 real TrustATrader trade
slugs with TrustATrader's own published names, so heating-engineers-gas-fitters and
fascias-soffits-guttering are things you click, not strings you have to guess. The area list carries
the 100 areas TrustATrader lists in its own sitemaps. Every trade is crossed with every area, so
2 × 2 = 4 listings.
Seven of the 100 areas are counties or regions rather than towns — essex, kent, hertfordshire,
lancashire, derbyshire, oxfordshire, scotland — and they cover far more traders than a single
town. They are the cheapest way to sweep a region.
Those 100 are the areas TrustATrader promotes, not every area that works. Smaller towns resolve fine
without appearing in the sitemaps — Bishop's Stortford typed into Extra areas returned rows on
2026-08-12. That is what the free-text boxes are for.
2. Sitemap — the whole UK directory
{ "source": "sitemap", "sitemapTrades": ["roofers-roofing"], "maxItems": 1000 }
Reads TrustATrader's own trader sitemap: 30,972 advert URLs (30,932 distinct — TrustATrader itself
lists 40 twice), optionally filtered by trade slug. The trade filter is applied to the sitemap XML
before any profile page is fetched, so narrowing here is free. Leave sitemapTrades empty to walk the
entire directory, and use skip to page through it across separate runs without re-buying rows.
3. Profile URLs — specific traders
{"source": "profileUrls","profileUrls": ["https://www.trustatrader.com/traders/ace-rapid-plumbing-plumbers-southwark"]}
A non-empty profileUrls list takes over the run whatever source says: only those profiles are
fetched, and no listing or sitemap is walked. Run a search and a named list as two runs, not one.
4. Listing URLs — anything the pickers do not cover
{ "startUrls": [{ "url": "https://www.trustatrader.com/electricians-in-manchester" }] }
Page numbers are appended for you; do not include ?page=N. This, plus the free-text Extra trades
and Extra areas fields, is how you reach the 178 trades TrustATrader publishes no display name for.
All four routes produce identical rows — same fields, same shape, same price.
The cheap dial
There is no listing-only mode, because the listing card carries none of the fields this Actor exists
for — no phone, no insurer, no vetting file, no geo. Every row costs exactly one profile fetch. Your
real cost dials are maxItems (hard cap) and sitemapTrades (free pre-filtering).
If a run runs out of time or budget
The Actor watches its own run-time limit and its charge cap, and stops cleanly at either — it pushes everything it has already collected, ends Succeeded, and writes a status message saying how many traders it returned and what to raise. It never ends a run with an error because TrustATrader was slow, was answering HTTP 429, or because your filters removed everything; those all finish Succeeded with a status message explaining what happened, and nothing is charged for rows you did not receive. The only conditions that hard-fail a run are the three that mean the data itself cannot be trusted: the trader sitemap coming back materially short, more than a fifth of fetched pages having unparseable markup, and the run-wide uniqueness assertion failing.
Sample row
One real row, captured on the run of 2026-08-12. Only the description is abbreviated (it is 1,900
characters of the trader's own copy); every other value is exactly as delivered.
{"traderName": "Greensted Plumbing & Heating","profileUrl": "https://www.trustatrader.com/traders/greensted-property-development-24-hour-emergency-services-medway","traderSlug": "greensted-property-development-24-hour-emergency-services-medway","traderId": "5b1a6be98811d3750a0d4815","membershipNumber": "TT9935","trade": "24 Hour Emergency Services","tradeSlug": "24-hour-emergency-services","areaCovered": "the majority of Kent and surrounding areas.","locationSlug": "gillingham","listingUrl": "https://www.trustatrader.com/24-hour-emergency-services-in-gillingham","addressLocality": "Gillingham","latitude": 51.3466,"longitude": 0.56988,"phone": "+447308500815","phoneDisplay": "07308 500815","phones": ["+447308500815"],"website": "https://www.greenstedplumbing.co.uk/","rating": 4.96,"reviewCount": 649,"ratingBreakdown": {"Initial impression": 4.96, "Punctuality": 4.92, "Cleanliness": 4.96,"Quality": 4.98, "Value": 4.94, "Overall opinion": 4.98},"missedAppointments": 0,"membershipYears": 10,"businessType": "Owned by Stephen Greensted","ownerName": "Stephen Greensted","vettedAndApproved": true,"vettingChecks": ["Identification checked","Company address verified","Customer references checked","Agreed to TrustATrader's high standards","Agreed to complaints procedure"],"vettingVerifiedOn": "26th May 2016","insuranceProvider": "SB-Simply Business","insuranceVerifiedOn": "1st September 2025","qualifications": ["Gas Safe Registered","LCL Awards Certificate of Competence - Domestic Electrical Installer","LCL Awards Level 3 Certificate - Initial Verification & Certification Of Electrical Installations","LCL Awards Certificate of Competence","City & Guilds - Certificate - Understanding The Requirements Of Electrical Installations BS767:2018"],"associations": ["Oftec", "Gas Safe Register"],"guaranteeEligible": true,"shortDescription": "24 Hour Emergency Services. Greensted Plumbing & Heating has been vetted and approved by TrustATrader. Covering the majority of Kent and surrounding areas.","description": "Welcome to Greensted Plumbing & Heating. We are a highly professional and well-established family company with more than 30 years' of combined experience …","logo": "https://assets.trustatrader.com/greensted-property-group-logo---nov-2018.zaa75o.view.m3q.jpg","galleryImageCount": 28,"scrapedAt": "2026-08-13T01:51:58.889Z"}
Fields people misread — every one of these is visible in the row above:
traderNameandtraderSlugdisagree, and that is normal. This firm trades as "Greensted Plumbing & Heating"; its TrustATrader URL still saysgreensted-property-development. Key onmembershipNumberorprofileUrl, never on the slug's business part.ratingis out of 5, not out of 10 and not a percentage. So are all sixratingBreakdownsub-scores. Median 4.95 across the 200-advert sample; the lowest was 4.6.missedAppointments: 0means "TrustATrader recorded none in six months" — a real, good value, not a missing one. Only 8 of 200 sampled traders had any.ownerNameis filled here becausebusinessTypereads"Owned by …". On a"Limited company"or"Sole trader"row it isnull, meaning TrustATrader named no individual — not that extraction failed.membershipYears: 10is ten years as a TrustATrader member. TrustATrader publishes no founding year for anybody.insuranceProvideris free text, not a code. 200 rows produced 61 distinct strings, and Simply Business alone appears asSimply Business,Simply Business InsuranceandSB-Simply Business. Normalise before you group by insurer.locationSlugis the profile's own breadcrumb area, and its vocabulary is wider than the area picker.gillinghamis not one of the 100 areas with trade × location listing pages. Of 198 rows carrying alocationSlug, 103 fell inside the picker's 100 and the rest used 56 other slugs.galleryImageCountcounts gallery tiles rendered on the page. 69 of 230 rows scraped that day had zero, and 7 sat at exactly1000, which looks like a page-side cap rather than a true count — treat large values as "lots", not as an exact figure.
Input
Twenty-two fields, grouped into five sections in the Console. Every one carries a default, and the six that make up a real demo run are prefilled, so Start works with zero edits.
| Field | Type | Default | What it does |
|---|---|---|---|
| 🔎 What to scrape | |||
source | select | search | Search listings · whole-directory sitemap · pasted profile URLs. All three cost the same per row. |
trades | multi-select | ["plumbers"] | Picker of 1,379 real trade slugs with TrustATrader's published names. Crossed with every area. SEARCH only. |
locations | multi-select | ["london"] | Picker of all 100 TrustATrader area slugs. SEARCH only. Seven are counties/regions. |
| 🔗 Off-list trades, areas and URLs | |||
extraTrades | stringList | [] | Free text for the 178 trades with no published name. Slugified for you (Painters & Decorators → painters-decorators). Merged with the picker. |
extraLocations | stringList | [] | Free text for an area added after this build. Slugified. If it is not live, the run errors rather than returning national results. |
startUrls | requestListSources | [] | Paste listing pages. Page numbers appended automatically — omit ?page=N. |
profileUrls | stringList | [] | Paste trader profile pages. Anything here overrides source: if this list is not empty the run scrapes only these URLs and no listing or sitemap is walked. One fetch, one charge each. |
sitemapTrades | stringList | [] | SITEMAP only. Filters the sitemap XML before any fetch — free, costs you nothing. |
| 🎯 Lead-quality filters | |||
onlyWithPhone | checkbox | false | Phone is 99.5–100% measured, so this normally removes nothing. |
onlyWithWebsite | checkbox | false | Discards 16.5–26% of rows. The inverse is a product: traders with no website are the agency target list. |
minRating | select | Any | Weak here — 0 of 200 and 0 of 196 sampled traders scored below 4.5. |
minReviewCount | number | 0 | The filter that actually bites. Median review count 34 on the 196-profile national sample and 71 on the 200-advert sitemap walk; range 7 → 1,606. |
minMembershipYears | number | 0 | Membership tenure, not years trading. Any value above 0 drops every trader with no badge — 24% of the national random sample, 0% of the sitemap sample. |
dedupeByBusiness | checkbox | false | Collapse a firm's many adverts onto membershipNumber. Measured collapse ranged 10% to 75% by directory window. |
| 💷 Depth, limits and cost | |||
maxItems | number | 30 | Your hard cost cap. 30 = $0.12, 1,000 = $4.00. Raise to 500–5,000 for production. |
maxPagesPerSearch | number | 10 | ~10 new traders per page. Walks stop early when a page returns nothing new, so a high value is free on a short listing. |
skip | number | 0 | Resume across runs without re-buying rows. |
includeDescription | checkbox | true | The trader's own "About" text (100% fill, longest column). Free either way. |
includeReviewsMeta | checkbox | true | Rating breakdown + missed appointments. Free either way. |
| ⚙️ Advanced | |||
maxConcurrency | number | 2 | 2 is deliberate — robots.txt declares Crawl-delay: 5. Max 5. |
requestDelayMs | number | 1500 | ~1.3 req/s at concurrency 2. Set 1 + 5000 to honour the crawl-delay literally. |
proxyConfiguration | proxy | RESIDENTIAL, GB | The rung that has never failed (233/233). Datacenter answered 200 on 18 of 20 fetches on 2026-08-13 and 0 the day before — cheaper, but unstable. |
Nothing is required. There is a dedupeByBusiness-shaped decision and a maxItems-shaped decision;
everything else has a defensible default.
Pricing
$0.004 per trader returned — $4.00 per 1,000. Charged on the trader-scraped event. No monthly
platform fee from this Actor.
Rows are charged as they are pushed (Actor.pushData(items, 'trader-scraped')), so if you hit a
budget cap you get whole rows and stop, never a half-billed dataset.
You are not charged for:
- a promoted-advert repeat — duplicates are dropped at enumeration, before the profile is even fetched;
- a trader removed by your filters, even though the Actor paid the fetch to evaluate it;
- an advert collapsed by One row per business;
- a retry, a proxy request, or a listing/sitemap page. Only delivered trader rows bill.
| Run | Traders | Cost |
|---|---|---|
| The shipped default (Plumbers in London) | 30 | $0.12 |
| One trade in one big city, walked out | 264 | $1.06 |
| A working lead list | 1,000 | $4.00 |
| Every advert in the directory | 30,932 (the sitemap's 30,972 URLs less the 40 it repeats) | $123.73 |
maxItems is the hard cost cap (default 30). Duplicates and filtered rows never count against it.
Honest limits
- No e-mail addresses. None, for anybody. TrustATrader routes contact through its own form and
publishes no address. There is no
emailfield and nothing in this Actor can produce one. You get the phone (99.5%), the website (83.5% / 74.0%) and the owner's name (71.5% / 59.7%) — enough to find one with a separate enrichment step, which this Actor does not perform. - No street address, no postcode.
itemprop="streetAddress"and"postalCode"appear on 0 of 109 live profiles sampled. That is a TrustATrader publishing decision, not a scraping failure. You get the town and a map pin instead, both at 100%. - One firm can be many rows. Measured collapse on contiguous 100-advert sitemap windows: 10% at
offset 0, 75% at offset 15,000. If you need companies rather than adverts,
dedupeByBusinessis not optional — and if you need a predictable company count, buy more rows than you think you need. - Ratings are compressed at the top and are close to useless as a filter. Median 4.95, minimum 4.6,
and 0 of 200 sampled traders below 4.5 (0 of 196 on the earlier sample too). Vetted traders who
slip get removed. Use
minReviewCountinstead — median 34 reviews on the national sample, 71 on the sitemap walk, range 7 to 1,606. membershipYearsis not years trading, and on the national random sample 24% of traders carry no badge at all (members under a year). AnyminMembershipYearsabove 0 discards them.- The website field is the one that moves. 83.5% on the sitemap walk versus 74.0% on the national random sample. Budget against 74.0%.
- The insurer name is free text. 200 rows produced 61 distinct
insuranceProviderstrings, with Simply Business appearing under three of them. The field is 100% filled and genuinely useful, but you must normalise it before you group or dedupe by insurer. This Actor delivers what TrustATrader printed rather than guessing at a canonical name. - This is a small directory and a small lane. The 30,972 adverts group into roughly 9,000
distinct businesses — that is every profile slug in the trader sitemap grouped into advert families
(3.3 adverts per business; the grouping was checked against
membershipNumberon 200 scraped rows and never merged two different firms). Either way it is a fraction of Checkatrade's coverage. If you want national UK trades coverage, this Actor is one input, not the whole answer — see the sibling table below. - It does not log in, and it collects no data behind any authentication. No CAPTCHA solving, no
challenge-bypass service. TrustATrader's
robots.txtdisallows/api/,/json/,/consumers/,/promoters/and the trader sign-in paths, and none of them is touched.
How it works, and the transport ladder
TrustATrader server-renders everything. There is no JSON-LD, no __NEXT_DATA__ and no XHR to
intercept: the record lives in schema.org microdata (itemprop="…") plus a handful of BEM-classed
blocks (profile-checks, profile-insurance, profile-rating, profile-qualifications). The Actor
reads listing pages or the public sitemap to enumerate, then fetches /traders/{slug} and parses it.
No login, no cookie jar, no API key.
Two details worth knowing: the "N year member" badge is an SVG whose filename carries the number
(…/badges/svg/year/6-year-member.<hash>.svg), and the map pin is encoded in the static map tile URL
(/static/atlas/-0.0535,51.4954,10/…). Both are read rather than guessed.
Transport ladder — measured through Apify, in this order:
| Rung | Result |
|---|---|
| Direct, no proxy | HTTP 429 nginx on every request (re-confirmed 2026-08-13) |
| Apify proxy, auto / datacenter | 18 / 20 = 90% HTTP 200 on profile pages, all parseable (2026-08-13); the 2 misses were HTTP 403. It was 0/n when first measured on 2026-08-12, so treat this rung as unstable, not free. |
| Apify RESIDENTIAL, country GB | HTTP 200 — 233 / 233 requests on 2026-08-13 |
| RESIDENTIAL + GB, fresh session per attempt | the shipped default |
Datacenter IPs therefore mostly work today, and with the Actor's retry-on-a-new-session they would probably carry a run — if you are cost-sensitive, that is a legitimate experiment. RESIDENTIAL + GB is the default because it is the only rung that has never failed on us, and this Actor tells you the measured numbers rather than pretending the cheaper rung is impossible.
Sustained load, all through Apify RESIDENTIAL + GB:
| Test | Result |
|---|---|
| 30 profile pages, concurrency 4 | 29 / 30 = 96.7%, 1.63 req/s |
| 200 profile pages, concurrency 5 | 197 / 200 = 98.5%, 1.99 req/s |
| Parse success on those 197 pages | 196 / 197 = 99.5% |
| 284 profile pages across four runs, 2026-08-12, concurrency 2 | 284 / 284 = 100%, 0 unparseable |
| 34 sitemap and trade-index requests, 2026-08-12 | 34 / 34 = 100%, first attempt |
The handful of misses at higher concurrency were Apify proxy upstream errors, not TrustATrader blocks.
Pacing. robots.txt declares Crawl-delay: 5. Defaults are deliberately gentler than the measured
ceiling: concurrency 2 with a 1,500 ms per-worker delay, about 1.3 requests/second. Set maxConcurrency
to 1 and requestDelayMs to 5000 to honour the declared crawl-delay literally.
Uniqueness and dedupe
TrustATrader pins 3 promoted adverts to the top of every page of a listing. They are the same three
traders on page 2, page 3 and page 27. Measured on contiguous walks of plumbers-in-london:
| Contiguous walk | Trader links returned | Unique traders | Duplicates |
|---|---|---|---|
| Page 1 | 13 | 13 | 0% |
| Pages 1–5 | 65 | 53 | 18.5% |
| Pages 1–7 | 91 | 73 | 19.8% |
| Pages 1–8 | 104 | 83 | 20.2% |
| Steady state, pages 2+ | 13 per page | 10 per page | 23.1% per page |
| Full walk to exhaustion (27 pages) | 344 | 263 unique | listing ends at page 28 |
Re-measured page by page on 2026-08-13: every page returns 13 trader links, and from page 2 on exactly 3 of them are the pinned promoted adverts, so each page adds 10 new traders until the listing runs out part-way through page 27. Page 1 carries no repeats, which is why a short walk shows a lower rate than the steady state. Sparse sampling would have hidden this entirely.
A run that hits its maxItems cap stops enumerating mid-page, so its own log will report a lower
duplicate rate than the table above — the shipped 30-row default stops after 59 links and 50 unique
profiles (15.3%). That is the cap talking, not a different duplicate rate.
The dedupe key is the trader profile URL, and dedupe happens at enumeration — before the profile is fetched, and therefore before anything is billed. So the promoted repeats cost you neither money nor requests. On top of that, the Actor asserts uniqueness across everything it pushed before the run is allowed to succeed; if that assertion ever fails, the run errors instead of handing you a dirty dataset. Every run logs the exact duplicate count it dropped. All four runs on 2026-08-12 verified clean: 30/30, 50/50, 100/100 and 100/100 distinct profile URLs.
The same pinning is how the Actor knows a listing has ended: the first page that returns only traders it has already seen is the last page.
Across runs, skip is the resume handle. Within a run, the sitemap route needs no dedupe at all —
0 repeats in both 100-advert windows — because TrustATrader's own sitemap is (nearly) clean; the 40
duplicated URLs it does contain are collapsed too.
Business-level dedupe is a separate switch (dedupeByBusiness, keyed on membershipNumber) because
adverts and businesses are genuinely different units here. See "Read this before you buy rows".
When a run fails
This Actor fails loudly rather than handing back a quiet empty dataset. There is no legitimate zero-row run.
- 0 rows → throws, and names the cause: how many pages were fetched, how many failed on the network, how many were unparseable, and how many your own filters removed.
- Bad trade slug → HTTP 404 is reported together with the sitemap URL that lists every valid slug.
- Bad area → caught via the page's canonical URL. TrustATrader does not 404 an unknown area — it silently serves the national trade page — so the Actor compares the canonical and stops rather than handing you the wrong traders. (The area picker makes this nearly impossible to trigger.)
- Markup change → if more than 20% of HTTP 200 pages carry no
LocalBusinessmicrodata, the run errors instead of shipping a degraded extraction. - Shrunken sitemap → if the trader sitemap lists fewer than 15,000 profiles (the live figure is 30,972), the run refuses to pass off a partial directory as the whole one.
- Duplicate leak → the uniqueness assertion fails the run.
Who buys this
- Trade-insurance and finance brokers —
insuranceProviderplusinsuranceVerifiedOnon 100% of rows is a renewal calendar. Simply Business alone held 45 of 200 sampled policies. - Tool brands, materials merchants and trade suppliers building a UK installer list segmented by
trade and area, with
qualifications(Gas Safe, NICEIC, F-Gas) as the segmentation key. - Web and marketing agencies selling to trades — the 16.5–26% with no website are a ready-made target list, and 59.7–71.5% of rows name the owner to address the pitch to.
- Franchise and lead-gen networks recruiting vetted trades —
vettingChecks,membershipYearsandmissedAppointmentsare a pre-built screening filter. - UK home-services market researchers — 67 trades × 93 towns in a single 200-row sample; coverage and review depth by trade and area.
Sibling Actors — which one to buy
| Actor | What it is | Why you would use it instead |
|---|---|---|
| Checkatrade Scraper | Verified UK tradespeople by trade and town: name, phone, rating, review count, services and reviews | Much larger directory. Go here first for coverage. |
| MyBuilder Scraper | Trade + city → ranked tradespeople with verified & featured badges, bio, services, sample reviews | When you want the ranking and badge signals rather than credentials. |
| Rated People Scraper | UK tradespeople by trade and town: rating, review count, reviews, service area, badges | A third independent rating source for cross-checking a firm. |
| FreeIndex UK Scraper | Any FreeIndex category → name, phone, website, full postal address, geo, rating | FreeIndex is where you go when you need a street address and postcode, which TrustATrader never publishes. |
The honest one-liner: Checkatrade is where you go for volume, FreeIndex is where you go for a postal address, and TrustATrader is where you go for the insurance record and the vetting file.
FAQ
Does this need an account, a login or an API key? No. Every page it reads is public and served without a session. It does not log in and it does not solve CAPTCHAs.
Does it need a proxy? Yes. A direct request gets HTTP 429, every time. Apify RESIDENTIAL with country GB is prefilled because it has never failed us (233/233 requests on 2026-08-13). Apify's datacenter pool answered 200 on 18 of 20 profile fetches the same day but returned nothing but 403 the day before, so it is the cheaper gamble, not the safe default. Change it only if you are watching the run log.
Do I have to know TrustATrader's URL slugs? No. Trades and areas are pickers carrying TrustATrader's own published names — 1,379 trades and all 100 areas. Free-text boxes exist for the 178 trades TrustATrader publishes no display name for.
Do I get e-mail addresses? No, and nobody can from this source — TrustATrader publishes none. You get phone at 99.5%, website at 83.5%/74.0% and owner name at 71.5%/59.7%.
Why is there no street address?
TrustATrader does not publish one. streetAddress and postalCode were absent on 0 of 109 sampled
profiles. You get the town plus latitude/longitude at 100%. For UK postal addresses use the FreeIndex
Actor above.
Two runs — will I get duplicates?
Within a run, never: dedupe is keyed on the profile URL and asserted before the run may succeed.
Across runs, use skip to resume where the last run stopped.
Am I charged for rows that get filtered out, or for promoted repeats? No to both. Promoted repeats are dropped before the profile is even fetched, and filtered-out traders are fetched at the Actor's cost, not yours. Only delivered rows bill, at $0.004 each.
Can I get the whole catalogue in one run?
Yes — source: "sitemap", sitemapTrades empty, maxItems: 30972. You will receive 30,932 rows (the
40 URLs TrustATrader lists twice are collapsed and not billed) for about $123.73. Most buyers should
filter by trade first, or switch on dedupeByBusiness so they pay for companies rather than adverts.
Is minRating worth setting?
Almost never. 0 of 200 and 0 of 196 sampled traders scored below 4.5, because TrustATrader removes
vetted traders who slip. minReviewCount is the filter that separates busy firms from new ones.
One company appears several times — is that a bug?
No. TrustATrader adverts are per trade and per service area, so a firm holds one per combination. Turn
on One row per business to collapse them on membershipNumber. Measured collapse ranged from 10%
to 75% depending on where in the directory you look.
Will a run ever succeed with zero rows? No. A zero-row run throws, and the error names the scope, the HTTP counts and how many rows your own filters removed.
Something looks wrong — how do I debug it? Read the run log. Every run prints the listings it walked, per-page link and duplicate counts, the total duplicates dropped, its own measured field fill, and the uniqueness assertion result.
How often should I re-run it?
Insurance verification dates and review counts move monthly; the trader roster moves slowly. Save your
input as an Apify Task, then attach a Schedule (0 6 1 * * for monthly) and use skip if you
are walking the directory in slices.
Legal and fair use
This Actor reads public TrustATrader pages and the sitemaps TrustATrader publishes in its own
robots.txt. It does not touch the paths that robots.txt disallows (/api/, /json/,
/consumers/, /promoters/, trader sign-in), it does not log in, and it collects nothing behind
authentication.
Records can contain personal data — sole-trader names, owner names and mobile numbers. You are responsible for complying with TrustATrader's terms of service and with UK GDPR and PECR in how you store the data and how you contact the people in it.
TrustATrader® is a trademark of its owner. This Actor is not affiliated with, endorsed by, or sponsored by TrustATrader.
Feedback
Found a missing field, or want a filter that is not here? Open an issue on the Issues tab. If the Actor did what you needed, a review on the store page genuinely helps a small listing like this one.