UK Vet Practice Leads - RCVS Register avatar

UK Vet Practice Leads - RCVS Register

Pricing

$1.50 / 1,000 per practice returneds

Go to Apify Store
UK Vet Practice Leads - RCVS Register

UK Vet Practice Leads - RCVS Register

From $1.50 per 1,000 practices, no start fee. All 5,647 UK veterinary practices on the RCVS register: direct email (79%), phone (84%), full address, postcode, lat/lng and RCVS accreditation tier. Optional detail-page enrichment adds species treated, opening hours and facilities. No API key.

Pricing

$1.50 / 1,000 per practice returneds

Rating

0.0

(0)

Developer

Scrapers Delight

Scrapers Delight

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

Share

🐾 UK Vet Practice Leads — the full RCVS register

Every veterinary practice registered with the Royal College of Veterinary Surgeons — the statutory regulator every UK vet practice must be on. 5,647 practices, with a direct email on four in five.

Name · email · phone · full address · postcode · lat/lng · RCVS accreditation tier · Practice Standards modules. Optionally: species treated, opening hours and facilities.

No API key. No account. No login. $0.0015 per practice, no start fee — the whole UK register is $8.47.


📊 The measured numbers

These are not a sample and not an estimate. The whole register was pulled and counted — all 5,647 rows, 565 requests, measured 1m12s and 2m00s on two separate full sweeps, 0 non-200 responses on either. Empty strings, whitespace, HTML-only values and the literal N/A were all counted as not filled.

fieldfillcountnotes
practiceName · practiceUrl · practiceSlug · practiceId100%5,647all 5,647 distinct
addressLine1 · postcode · postcodeArea · addressFull100%5,647postcode split out of an HTML blob
latitude · longitude100%5,647every value inside the UK bounding box
rcvsAccreditation99.98%5,6463,589 Accredited · 218 in progress · 1,839 non-accredited
town99.9%5,644
county93.6%5,286London practices publish none
phone86.6%4,889
phoneE16486.0%4,858+44… for diallers
email81.9%4,6232,099 distinct domains
accreditations · accreditationsText63.8%3,600Practice Standards modules
website4.9%279sparse — see honest limits
awards · awardsText2.9%161sparse

The email column is the product, so it was checked past "non-empty": all 4,623 pass a strict address test, and 2,099 distinct domains across 4,623 addresses proves these are real per-practice mailboxes rather than one chain address repeated. Even the corporate ones are branch-specific — llandaff.north@medivet.co.uk, northwich@vetsforpets.com, slough@companioncare.co.uk — which is exactly what a lead list needs.

⚠️ The register comes in two blocks — read this before setting a cap

RCVS does not return these 5,647 practices in a uniform order. Measured across the full census:

rowsemailphonewebsite
First block0–319 (320 practices)0%0%85.6%
Main block320–5,646 (5,327 practices)86.8%91.8%0.1%

The first email appears at row 327. 274 of the register's 279 websites sit inside that first block.

What this means for you: a small run with no filter reads only the first block and returns practices with no email addresses at all. That is the source's ordering, not a bug, and this Actor will not quietly reshuffle it on you — but it does mean:

If you want leads, set requireEmail: true. Any filter makes the Actor read the whole register and deliver only matching rows — so requireEmail: true with maxPractices: 1000 gives you 1,000 real leads drawn from all 5,647 practices, not the first 1,000 rows.

Every run also reports its own measured fill in RUN_SUMMARY.fieldFill, so you never have to take this README's word for what you actually received.

Optional: species, hours and facilities

Measured over 93 real practice pages:

fieldfill
animalsTreated97.8% (91/93)
facilities69.9% (65/93)
openingTimes67.7% (63/93)
developmentAndTraining63.4% (59/93)

These four do not exist in the register's listing API — only on each practice's own page. Turn on enrichFromDetailPages, or just set a species filter, which turns it on for you. It costs one extra request per candidate: 5,647 instead of 565 for the whole register.


📋 What one row looks like

A real row from the verified run (animalsTreated: ["Horses"], requireEmail: true):

{
"practiceId": "5e9ed532-4ca1-4962-bb4f-e25cfdcb8d0c",
"practiceName": "The Sussex Equine Hospital Ltd",
"practiceUrl": "https://www.rcvs.org.uk/animal-owners/find-a-vet/practices/the-sussex-equine-hospital-ltd-pulboroughrh20-3bb",
"email": "info@sussexequinehospital.co.uk",
"emailDomain": "sussexequinehospital.co.uk",
"phone": "01903 883050",
"phoneE164": "+441903883050",
"website": null,
"addressLine1": "Billingshurst Road",
"town": "PULBOROUGH",
"postcode": "RH20 3BB",
"postcodeArea": "RH",
"county": "West Sussex",
"country": "United Kingdom",
"addressFull": "Billingshurst Road, Ashington, PULBOROUGH RH20 3BB West Sussex, United Kingdom",
"latitude": 50.9476473,
"longitude": -0.3957418,
"rcvsAccreditation": "Accredited Practice",
"isAccredited": true,
"accreditations": ["Equine Emergency Service Clinic", "Equine Veterinary Hospital"],
"animalsTreated": ["Horses"],
"facilities": ["Client Car Park", "Disabled Public Access", "Out Of Hours", "Open At Weekends"],
"developmentAndTraining": ["Extra Mural Studies (EMS)", "VetGDP"],
"openingTimes": {
"monday": "08:30-17:30", "tuesday": "08:30-17:30", "wednesday": "08:30-17:30",
"thursday": "08:30-17:30", "friday": "08:30-17:30",
"saturday": "08:30-12:30", "sunday": "Closed"
}
}

🎯 Who buys this

  • Practice-management software (ezyVet, Provet Cloud, Vetstoria) — the full UK TAM, segmented by accreditation tier and by small-animal vs equine vs farm-animal via accreditationModules
  • Veterinary wholesalers and pharma reps — territory lists by postcodeAreas or counties, with latitude/longitude for route planning
  • Locum and recruitment agencies — filter to VetGDP and Extra Mural Studies (EMS) practices, the ones that actively take and train new graduates
  • Consolidator M&A desks (IVC Evidensia, VetPartners, CVS) — independents stand out as the practices whose emailDomain is their own rather than a group domain, and awards flags the Practice Standards high performers

⚙️ Filtering, and what it costs

The register's API has no server-side filtering at all. Measured 2026-09-16: animals_treated=209, f[0]=animals_treated:209, animals_treated[]=209, filters[animals_treated][]=209, facets[animals_treated]=209, rcvs_accreditation=accredited, keyword=, search= and a JSON POST body all return HTTP 200 with meta.count still 5,647 and the identical first ten items. Every parameter is silently ignored.

So all filtering here runs on our side, after the fetch. A narrow filter costs the same crawl as a wide one — but you are only charged for rows you actually receive. A filter matching 40 practices costs 40 × $0.0015 = $0.06, whatever the crawl cost us.

filterstagecost
requireEmail · requirePhone · requireWebsitelistingfree
accreditationTier · accreditationModuleslistingfree
postcodeAreas · counties · nameOrTownIncludeslistingfree
animalsTreated · facilities · developmentAndTrainingdetail page1 request per candidate

Setting a species, facility or training filter switches detail enrichment on automatically and says so in the log — those fields cannot be answered from the listing, and silently returning everything would look like a filter that ran. RUN_SUMMARY reports detailPagesFetched against delivered so you can see the ratio (measured example: 93 pages fetched to deliver 15 equine practices).


🤖 robots.txt and crawl rate

https://www.rcvs.org.uk/robots.txt declares, verbatim:

User-agent: *
Crawl-delay: 10

No Disallow covers /api/ or /animal-owners/. The Crawl-delay: 10 is a courtesy directive, and this Actor does not enforce it by default — it runs 5 concurrent requests with no delay, which takes one to two minutes for the whole register. To honour the declared delay exactly, set maxConcurrency: 1 and requestDelayMs: 10000; the full register then takes about 94 minutes. That is your call, and it is stated here rather than buried.

For the record, measured during the build: 0 non-200 responses across ~1,200 requests, including 20 fired back-to-back with no delay and a full 565-page sweep at concurrency 8. No rate limit, no CAPTCHA, no JS challenge. A bare curl with its default user agent and a full browser header set returned byte-identical bodies from the same URL.


🧨 Four traps in this source, and what this Actor does about them

1. The records are hidden behind sentinels. The listing API returns items shaped {id, bundle, type, markup} — no practice fields on the item at all. The real record is a string inside markup, between %%JSON_START%% and %%JSON_END%%. A scraper that reads item.email gets undefined on every row, ships a dataset where every column is empty, and still reports a green build and a SUCCEEDED run. This Actor unwraps the sentinels and fails the run if more than 2% of items stop parsing.

2. The 13 species are a filter menu, not practice data. meta.facets[animals_treated] lists Aquatic, Birds, Camelids, Cats, Cattle, Deer, Dogs, Exotic/Wild, Horses, Pigs, Poultry, Sheep/Goats and Small Mammals — identically on every page. It describes the website's filter UI. There is no per-practice species field on any of the 5,647 records. Real per-practice species exist only on the detail page, which is why animalsTreated is an enrichment field and not a free one.

3. The address is an HTML blob with the postcode buried in it. address arrives as a <p> whose middle line reads MELTON MOWBRAY LE13 1JE Leicestershire — town, postcode and county mashed together with no separator of any kind. The postcode is the only anchor: everything before it is the town, everything after is the county. That is the real parsing work here, and it is why town, postcode and county are separate columns instead of one unusable string.

4. The email on the practice page is often RCVS's own. Detail pages Cloudflare-obfuscate emails (data-cfemail, rendering as [email protected]), and the obfuscation is a trivial XOR. But a "grab the first email on the page" enrichment was built, measured over 21 pages, and cut: the detail page added zero addresses the listing API did not already have. Thirteen of thirteen matched exactly — and the eight practices with no listing email carried only info@rcvs.org.uk, the college's own switchboard, sitting beside the college's own postal address. That column would have been wrong on 38% of rows while looking perfectly filled. This Actor ships no such field.


⚠️ Honest limits

  • The two-block ordering, above. It is the single thing most likely to surprise you. An unfiltered capped run returns email-less rows. Use requireEmail: true.
  • website is 4.9% filled (279 of 5,647), and 274 of those 279 are in the first block — so in practice you can have websites or emails, almost never both. If you need practice websites, this is not the source.
  • awards is 2.9% filled (161 of 5,647). Genuinely useful for spotting Practice Standards high performers, genuinely rare.
  • county is 93.6%, and the gap is mostly London. Those rows have county: null, never a guessed value. Use postcodeAreas for London.
  • town is upper-cased the way the register writes it (MELTON MOWBRAY). It is deliberately not title-cased: that would turn ST. NEOTS and BURY ST EDMUNDS into something wrong, and a mis-cased town in a mail merge is worse than an honestly shouty one. Three practices in 5,647 publish no separate town line at all; those are null.
  • 31 phone numbers in 5,647 resist normalisation — they hold two numbers in one field (01472 347054/362 821), an Irish number, or a malformed one. phone keeps the text exactly; phoneE164 is null for them rather than a spliced number that would misdial.
  • openingTimes ignores the per-day comments. The register sometimes adds a note like "Closed between 9-2:30" beside a day's hours. Only the hours are captured.
  • A practice that publishes no species list is excluded by a species filter, not included as a maybe. 2.2% of practice pages have no species section at all.
  • Accreditation modules are split against a closed vocabulary. The register concatenates them with no delimiter, so the split is longest-match plus a residual check. If RCVS adds a module this build does not know, accreditations is null and accreditationsText still carries the raw string — an honest "not split" rather than a wrong split. This is not hypothetical: the full census found a module absent from the initial sample (Equine Veterinary Hospital, 29 practices) and it degraded exactly that way before being added. Current census: 0 unsplit.
  • The listing view id is a magic constant. The register is a Drupal view at /api/listing/6194. If RCVS repoints that id, the run fails loudly — it asserts the register still reports at least 4,000 practices — rather than quietly delivering ten rows from some other view.
  • country is always United Kingdom. It is 100% filled and 100% constant; it ships because a CRM import wants the column, not because it carries information.

💵 Pricing

Per practice delivered$0.0015
Start feenone
1,000 practices$1.50 per 1,000
The whole UK register (5,647)$8.47
A run that matches nothing$0.00

You are charged once per practice delivered to your dataset. Practices excluded by your filters are never delivered and never charged. A practice page we could not reach is never charged — it is reported separately in RUN_SUMMARY from "this practice publishes no species", because to someone working a lead list those mean different things.


❓ FAQ

What is the RCVS register? The Royal College of Veterinary Surgeons is the UK's statutory regulator for veterinary surgeons and veterinary nurses. Its "Find a Vet" register lists practice premises. It is the closest thing there is to a complete list of UK vet practices.

Is this all UK vet practices? It is every practice on the RCVS "Find a Vet" register — 5,647 when this was built, and the count moves (a recon a fortnight earlier read 5,646). The run reports the live total in RUN_SUMMARY.

How long does a full run take? Measured: 1m12s and 2m00s on two separate full sweeps of all 5,647 practices — 565 requests, because the page size is hard-locked at 10 and cannot be raised (items_per_page, page_size and limit are all silently ignored). With detail enrichment it is 6,212 requests and takes considerably longer. Honouring the declared Crawl-delay: 10 takes about 94 minutes.

Why did my 100-row run come back with no email addresses? Because of the two-block ordering described above — an unfiltered run reads the first 320 practices, which have none. Set requireEmail: true.

Can I get just equine or farm-animal practices? Yes, and cheaply. Use accreditationModules with Equine General Practice (Ambulatory), Equine Veterinary Hospital, Farm Animal General Practice or the Core Standards (…) variants — that comes from the listing and needs no detail-page fetch. It covers 63.8% of practices. For exact species coverage use animalsTreated, which enriches from detail pages.

Can I get only accredited practices? Yes — accreditationTier: ["Accredited Practice"]. Measured: 3,589 of 5,647.

Do I need a proxy? No. The register answered 200 on every request during the build with no proxy and no browser. Apify Proxy (datacenter) is the default anyway, for IP hygiene.

Do I need an API key or a login? No. Everything here is the public register as served to any visitor.

Why is website so empty? Because the register is like that. It is reported honestly at 4.9% rather than quietly dropped or padded.

What happens if a request fails? It is retried on a fresh proxy session. A non-200 is treated as a transport failure, never as the end of the data. Pages that stay unreachable are listed in RUN_SUMMARY, and if more than a quarter of the walk fails, the run fails rather than handing you a partial register that looks complete.

Will a run ever silently return a short register? No. An unfiltered full sweep floor-asserts against the count the register itself declares and fails if it recovers less than 98% of it. The verified run recovered 5,647 of 5,647.

How do I get species, hours and facilities? Set enrichFromDetailPages: true, or just set a species/facility/training filter — that switches it on automatically.

Can I re-run this to track changes? Yes. practiceId and practiceSlug are stable keys, so two runs diff cleanly.


This Actor reads the public RCVS "Find a Vet" register — the same pages and the same JSON any visitor's browser receives. No login, no account, no credential, no paywall is involved.

robots.txt is quoted verbatim above: User-agent: * / Crawl-delay: 10, with no Disallow covering the paths used. The crawl-delay knob is exposed as an input so you can honour it exactly.

The register contains business contact details — practice premises, not individuals' personal data. You are responsible for your own use of it, including UK GDPR and PECR obligations around marketing to business contacts.

Not affiliated with, endorsed by, or connected to the Royal College of Veterinary Surgeons.