UK Trading Disclosure Scraper - Company No, VAT & Contact
Pricing
$6.00 / 1,000 per trading disclosure returneds
UK Trading Disclosure Scraper - Company No, VAT & Contact
Turn UK company domains into registry-grade B2B leads from each site's statutory trading disclosure (Companies Act 2006 s.82): registered name, Companies House number, jurisdiction, registered office, mod-97-checked VAT number, charity and ICO numbers, regulator, email, phone. $0.006 per disclosure.
Pricing
$6.00 / 1,000 per trading disclosure returneds
Rating
0.0
(0)
Developer
Scrapers Delight
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
🇬🇧 UK Trading Disclosure Scraper — Company Number, VAT, Registered Office & Contacts
Turn a plain list of UK company domains into registry-grade B2B leads, read straight from the statutory trading disclosure every UK company is legally required to publish on its own website.
Paste domains. Get back the registered name, the Companies House number, the part of the UK it is registered in, the registered office address, a checksum-validated VAT number, plus email, phone, charity number, ICO registration and regulator — one flat row per company.
⚖️ Why this data exists, and why it is clean
Companies Act 2006 s.82 and The Company, Limited Liability Partnership and Business (Names and Trading Disclosures) Regulations 2015 (SI 2015/17), reg. 25 require every UK company and LLP to disclose, on its websites:
- its registered name
- the part of the United Kingdom in which it is registered
- its registered number
- the address of its registered office
Regulations 24–25 extend the name and address-for-service disclosure to unincorporated businesses trading under a name that is not the proprietor's own.
So this is not scraped inference and it is not a private profile. It is a statement the business is legally obliged to publish about itself, in public, on its own site. That is what makes it the cleanest UK B2B starting point there is — and the same shape that already works in Germany (Impressum), France (mentions légales) and Spain (aviso legal).
The corpus is the whole UK commercial web, not one directory with a member list. If a UK company has a website, it is in scope.
🔍 What it does, per domain
- Fetches the homepage and reads its footer. On the UK corpus the disclosure is often right there — measured over 598 real domains, the homepage footer carried it for 53.4% of all delivered rows (14.9% homepage-only, 38.5% homepage plus a second page). That is the opposite of the German/French pattern, where the legal notice is always its own page.
- If fields are still missing, ranks the site's own links and fetches the best ones — terms & conditions > legal > company information > privacy policy > about > contact — then merges field by field, because UK sites routinely split the disclosure across a terms page (company number, registered office) and a contact page (email, phone).
- Falls back to the XML sitemap, the WordPress REST page index and a list of conventional paths when a site publishes no footer link at all.
- Validates what it found: the GB VAT number against the published mod-97 checksum (both variants), the company number against the Companies House format and prefix table, and derives the jurisdiction from the prefix.
No browser. Plain HTTP + cheerio, on the Apify datacenter proxy, with a residential retry only when a host actually refuses us.
📦 What you get — every field
One flat row per company. null means the company did not publish it; nothing is ever invented.
Identity
| Field | What it holds |
|---|---|
registeredName | The registered company name as the disclosure states it (Arrow Fresh Ltd) |
tradingName | The "trading as" / t/a name where one is declared |
companyName | Best available name — the registered name, else JSON-LD legalName, else the site name |
legalForm | Private limited company, PLC, LLP, CIC, CIO, Company limited by guarantee, Limited partnership, Registered society, Sole trader |
entityKind | What the number's prefix implies: LLP, Limited partnership, Overseas company, Registered society, Charitable incorporated organisation, Royal charter… |
Registry
| Field | What it holds |
|---|---|
companyNumber | The Companies House number, normalised to its canonical 8-character form — 00032762, SC216217, OC301234, R1234567 |
companyNumberRaw | Exactly as the page printed it (SC 216217), for audit |
companyNumberSource | Which statement shape it came from: label-alt, jurisdiction, jurisdiction-label, label, bare |
companyNumberFormatValid | Format + known-prefix check. Companies House numbers carry no checksum — see Honest limits |
companyNumberScheme | GB-COH |
jurisdiction | England and Wales, Scotland, Northern Ireland or Overseas, from the prefix and the wording |
jurisdictionStated | The words the page actually used, verbatim |
registerUrl | A direct deep link into the public Companies House register for that number |
registeredOffice | The registered office address line |
registeredOfficePostcode / registeredOfficeCity | Parsed out of that address block, never by a page-wide postcode scan |
vatNumber | Normalised VAT id (GB372138852), including the 12-digit branch form and the checksum-free GBGD### / GBHA### government forms |
vatNumberValid | The mod-97 checksum result, true / false / null |
vatChecksumVariant | Which published algorithm it satisfied: mod-97, mod-97-55, government-department, health-authority, or non-GB (no GB checksum applies) |
vatCountry / vatBranch | Country code and the 3-digit branch identifier when present |
charityNumber | Registered charity number, in its own field — a Scottish charity number looks exactly like a Scottish company number |
icoRegistration | ICO data-protection registration (ZA######) where published |
regulator / regulatorNumber | FCA, SRA, RICS, GDC, GMC, CQC, GPhC, Ofsted, Gambling Commission, ATOL, Gas Safe, NICEIC, ICAEW, ACCA and others, plus the reference number where published |
Contact
| Field | What it holds |
|---|---|
email / emails | Contact addresses, including Cloudflare-obfuscated ones (see below). The company's own domain wins the primary slot |
emailConflict | Set when the primary email is on somebody else's domain and is not a free mailbox — flagged, never silently dropped |
phone / phones | Normalised to E.164 (+441312431453). Ofcom's reserved drama range and placeholder runs are rejected |
addressLine / postcode / city | The trading/contact address, which is often not the registered office (an accountant's address is a very common registered office) |
officerName / officerRole | A named director / proprietor / company secretary where the page labels one |
socialLinks | LinkedIn, Facebook, Instagram, X, YouTube, TikTok |
termsUrl / privacyPolicyUrl | The policy pages linked from the site |
Provenance & accounting
| Field | What it holds |
|---|---|
disclosureUrl | The page the disclosure was read from |
disclosureSource | homepage, legal-page or merged |
discoveryChannel | homepage, anchor, sitemap, wpjson, guess, jsassets, input |
pagesParsed / pagesChecked | How many pages were parsed, and how many URLs were tried |
fieldSources | Optional: the exact URL each individual field came from |
fieldCount | How many of the 19 value fields are populated |
stableId | The company number when well-formed, else the registrable domain |
status / missReason | ok, or why nothing was returned |
elapsedMs / fetchedAt | Per-row timing and timestamp |
📊 Measured results — real numbers, not claims
Everything below is from one real run on the Apify platform over 598 UK business domains,
sourced from OpenStreetMap across 18 UK cities (London, Manchester, Birmingham, Leeds, Glasgow,
Edinburgh, Bristol, Cardiff, Belfast, Newcastle, Liverpool, Sheffield, Nottingham, Brighton,
Aberdeen, Norwich, Reading, Southampton) and picked without any reference to whether they publish
a disclosure. Run wRVb4PWXuKSdMv4sL, 1,085 s, SUCCEEDED.
598 domains attempted148 billed rows 24.7% of all domains · 32.7% of the 453 REACHABLE domains303 publish no disclosure never charged96 dead hosts (stale website entries) never charged49 refused / challenged never charged2 duplicates collapsed before a request never charged
Delivered rows == chargedEventCounts exactly: 148 and 148.
Per-field fill, measured on the 148 billed rows:
| Field | Fill | Field | Fill | |
|---|---|---|---|---|
email | 88.5% | registeredOfficePostcode | 66.9% | |
companyNumber | 85.8% | addressLine / postcode | 62.2% | |
jurisdiction | 85.8% | registeredOfficeCity | 61.5% | |
registeredName | 75.0% | city | 57.4% | |
legalForm | 75.0% | vatNumber | 38.5% | |
registeredOffice | 71.6% | regulator | 20.3% | |
phone | 70.3% | charityNumber / tradingName | 10.8% | |
regulatorNumber | 7.4% | icoRegistration | 5.4% · officerName 2.0% |
VAT checksum: 57 VAT numbers found, 55 pass the GB mod-97 check — 96.5%. That is the number to look at. A parser that grabs the wrong nine digits produces checksum failures, so a high pass rate is evidence the extraction is right, not merely that a column is populated.
Where the disclosure was found: the homepage footer carried it for 79 of 148 rows (53.4%) — 22 homepage-only, 57 homepage plus a second page — and a dedicated legal/terms page was needed for the other 69 (46.6%). By discovery channel: ranked footer links 74, homepage footer 71, XML sitemap 2, guessed paths 1.
Transport: 3,822 requests for 598 domains = 6.4 per domain; 2,022 OK, 769 fast 404s on the guessed-path channel, 187 refusals, 105 dead hosts, 104 parked stubs. Residential escalation fired 128 times and recovered 26. Peak memory 691 MB in a 1,024 MB container.
Speed: 598 domains in 18 minutes at concurrency 12. The six-domain demo run finishes in 9–20 seconds.
Second run, country-wide corpus
A confirmation run on a different corpus and the current build: 400 domains drawn country-wide
from OpenStreetMap (office + shop + craft, no high-street amenity bias), run
TbGcBtEMY848MicQk, 687 s, SUCCEEDED.
400 domains -> 110 billed 27.5% of all · 36.7% of the 300 reachabledelivered == charged: 110 and 110NOT charged: 190 publish no disclosure · 71 dead hosts · 29 refusedfill: email 88.2 · jurisdiction 88.2 · companyNumber 87.3 · phone 80.9 · registeredName 71.8legalForm 70.9 · addressLine/postcode 65.5 · registeredOffice 61.8 · vatNumber 41.8VAT: 46 found, 45 pass mod-97 = 97.8%
The numbers hold across two independent corpora, and vatNumber fill rose from 38.5% to 41.8%
after the under-collection fix described in the FAQ below.
Which lists convert — yield by business type
The same 598-domain run, split by the OpenStreetMap key each domain came from. This is the single most useful number for planning a job, and it varies by more than 2x:
| Domains came from | Attempted | Billed | Yield of reachable |
|---|---|---|---|
office (agencies, professional services, B2B) | 87 | 35 | 53.8% |
shop (retail) | 167 | 40 | 32.8% |
tourism | 29 | 7 | 33.3% |
craft (trades) | 14 | 3 | 25.0% |
amenity (cafés, pubs, restaurants, banks) | 283 | 56 | 25.3% |
| all | 598 | 148 | 32.7% |
A café is usually a sole trader or a partnership trading under the owner's own name, and reg. 25's company disclosure does not bind one — there is no company number for it to publish. A professional services firm is almost always a limited company or an LLP. Feed this Actor a B2B list and the hit rate roughly doubles.
A real row, from that run
Not a mock-up — rox.co.uk, exactly as delivered (long arrays trimmed):
{"domain": "rox.co.uk","resolvedUrl": "https://www.rox.co.uk/","disclosureUrl": "https://www.rox.co.uk/contactus","disclosureSource": "legal-page","discoveryChannel": "anchor","pagesParsed": 2,"pagesChecked": 3,"registeredName": "ROX (UK) LTD","registeredNameSource": "suffix","companyName": "ROX (UK) Ltd","legalForm": "Private limited company","companyNumber": "SC216217","companyNumberRaw": "SC 216217","companyNumberSource": "jurisdiction","companyNumberFormatValid": true,"companyNumberScheme": "GB-COH","jurisdiction": "Scotland","jurisdictionStated": "Scotland","registerUrl": "https://find-and-update.company-information.service.gov.uk/company/SC216217","registeredOffice": "ROX (UK) LTD, 42-43 Argyll Arcade, Glasgow, G2 8BG","registeredOfficePostcode": "G2 8BG","registeredOfficeCity": "Glasgow","email": "help@rox.co.uk","emails": ["help@rox.co.uk", "marketing@rox.co.uk"],"phone": "+448081646448","socialLinks": ["https://www.instagram.com/ROXJewellery", "https://www.tiktok.com/@roxjewellery"],"country": "United Kingdom","status": "ok","fieldCount": 12,"elapsedMs": 4455}
Note companyNumberRaw: "SC 216217" — the page prints the prefix with a space, and the canonical
SC216217 is what goes to Companies House. That is the kind of detail a digits-only regex loses.
🧰 Every input
| Input | What it does |
|---|---|
| UK domains | Bare domains, homepage URLs or direct legal-page URLs. Any TLD |
| Start URLs | The same list as requestListSources, so Make / Zapier / Clay / Sheets can pass it natively |
| Enrich an existing dataset | Dataset ID of a previous run — the real agency workflow |
| Domain list file URL | A CSV / TXT / JSON / JSONL file, for lists too big to paste |
| Suppression list / previous dataset | Never re-deliver, and never re-charge for, a company you already bought |
| Max results (billed rows) | Hard cap on rows delivered AND billed |
| Max domains attempted | Sample a big list cheaply |
| Max discovery requests / pages parsed per domain | The two cost levers |
| Discovery channels | Turn off sitemap / wp-json / path-guess to make a big run much cheaper |
| Proxy, proxy country, residential escalation, Unblocker escalation | The full transport ladder |
| TLD filter | Off by default, deliberately — see below |
| Only rows with a registry ID / valid VAT / a contact | Quality gates. Filtered rows are never charged |
| Jurisdictions | Keep only England & Wales, Scotland, Northern Ireland or overseas-registered companies |
| Minimum populated fields | A hard quality floor |
| Email policy | Keep all, role addresses only (info@, enquiries@), or named mailboxes only |
| Deduplicate by | Company number, else domain (recommended) — two domains owned by one company collapse to one billed row |
| Field extraction toggles | VAT checksum, regulator, ICO, charity, officer, socials, policy URLs |
| Include unbilled miss rows | Coverage accounting: every domain that produced nothing, with the reason |
| Include per-field provenance | Which URL each field came from |
| Flat columns | Flat CSV-ready row, or grouped company{} registry{} contact{} people{} policies{} |
Example:
{"domains": ["rox.co.uk", "batchd.co.uk", "nq64.co.uk", "alzscot.org"],"maxItems": 1000,"requireRegistryId": true,"dedupeBy": "company-number-then-domain"}
💷 Pricing
Pay per result — $0.006 per trading disclosure returned.
| You are charged | You are NOT charged |
|---|---|
| Each UK company whose disclosure was found and parsed into a lead carrying at least one registry identifier | A host that does not resolve |
| A host that refused us (403 / challenge) | |
| A domain that publishes no trading disclosure | |
| A duplicate collapsed by your dedupe key | |
| A row your own filters removed | |
An unbilled coverage row (includeMissRows) |
Delivery and billing are atomic (Actor.pushData(record, 'disclosure-scraped')), so if you hit a
charge cap you can never keep a row you were not billed for, or be billed for a row you did not get.
On the 598-domain run above, delivered rows and chargedEventCounts matched exactly: 148 and 148.
There is no start fee and there are no stacked auto-events — one event, one price.
For context, measured: 148 billed rows from 598 cold UK domains, so a 1,000-domain list typically costs around $1.50, not $6.
❓ FAQ
Is this legal to collect? The fields come from a disclosure the company is legally required by the Companies Act to publish on its own website. That is about as public as company data gets. You are still responsible for the target site's Terms of Service and for how you use the output — see Legal, below.
Does it work on .com domains?
Yes, and this matters more than it sounds. Measured on a country-wide OpenStreetMap pull of
every UK office, shop and craft with a website — 46,863 unique business hosts — only
66.3% are .uk of any kind. 13,491 are .com, plus .org, .net, .co, .scot,
.london and more. Filtering the corpus to .uk would silently discard about a third of it,
skewed toward the larger companies. There is no TLD filter by default; it is an opt-in input.
Does it handle Scottish, Northern Irish and LLP numbers?
Yes. SC (Scotland), NI (Northern Ireland), OC / SO / NC (LLPs), LP / SL / NL (limited
partnerships), FC / SF / NF (overseas), R + 7 digits (pre-partition Northern Ireland), plus the
society, assurance, protected-cell, CIO, Royal-charter and government ranges — and bare 8-digit England
& Wales numbers. A digits-only regex under-collects badly: several disclosures in the first sample
were SC-prefixed, and one real company publishes a five-digit number (32762, Companies House
00032762) which a \d{6,8} regex drops entirely.
Is the VAT number actually checked, or just extracted?
Checked. Every GB VAT number is run through the published mod-97 checksum, in both the standard
and the "97-55" variant, and the result and the variant are in the row. The 12-digit branch form
validates on its first nine digits; the GBGD### and GBHA### government forms have no checksum and
are validated on their published ranges instead.
Why isn't the company number checksum-validated too?
Because Companies House numbers do not have a checksum. companyNumberFormatValid is a format and
known-prefix check and the field is named accordingly. Any actor claiming to "validate" a UK company
number without a register call is claiming something that does not exist.
Does it find emails hidden behind Cloudflare?
Yes. Cloudflare rewrites mailto: links on proxied pages into /cdn-cgi/l/email-protection#<hex> and
renders the literal text [email protected]. This Actor decodes them. Without that, a large slice of
UK SME sites ship with email: null while the address sits right there in the bytes.
What about the charity number — Scottish charity numbers look like company numbers?
They do, and that is a real trap: alzscot.org is company SC149069 and Scottish charity
SC022315, one line apart. They are parsed into separate fields with a nearest-label rule, so the
charity number never ends up in companyNumber.
Why do so many domains return nothing?
Three different reasons, kept apart in RUN_SUMMARY and none of them charged. On the 598-domain
run: 96 dead hosts (16% — any OSM-sourced list carries stale website tags), 49 refused, and
303 that publish no disclosure. That last group is the biggest and it is mostly genuine: sole
traders and partnerships trading under the owner's own name have no company number to publish, and a
long tail of micro-businesses is simply non-compliant with reg. 25.
How do you know the "publishes no disclosure" ones really publish nothing? Because they were re-probed. 60 of those 303 were run again through a deliberately extravagant cascade — 30 requests, 10 pages, 26 guessed paths, sitemap, WordPress index, JS bundles and the Unblocker escalation switched on. 4 of the 60 (6.7%) changed their mind; the other 56 genuinely publish nothing findable. So the default settings leave roughly 7% of that bucket on the table, on purpose, because recovering it costs about four times the requests. If you want them, raise Max discovery requests per domain and Max pages parsed, and switch on the Unblocker escalation — the levers are all inputs, and the rows you do not get are not charged either way.
Can I get only the companies with a VAT number / only Scottish companies / only ones with an email?
Yes — requireValidVat, jurisdictionFilter and requireContact. Filtered rows are never charged, so
these are cost controls as well as quality controls.
Can I run it monthly without paying twice for the same company?
Yes. Pass the previous run's dataset ID as previousDatasetId; every id it already delivered is
suppressed before a single request is made.
How do you know the parser is not just missing fields that are there?
Because it was tested in the negative direction, which ordinary testing cannot do. 144 of the
delivered pages were re-fetched and re-scanned with a separately written implementation of the
GB mod-97 checksum — a 9-weight dot product, where the parser uses a 7-weight sum compared against
the check digits, so the two cannot share a bug. Results: 0 disagreements on every VAT number
emitted, 0 non-deterministic re-parses, and 4 values the parser had missed out of 144 pages.
Three of the four were the same fixable bug (the VAT label separated from its number by a clause —
"The VAT number of 200 Degrees is: 284361686"); that is fixed, and those three strings are now
regression assertions. The sweep was then repeated on a fresh 400-domain run with the fix in
place: 108 pages re-read, 0 VAT numbers missed, 0 company numbers missed, 0 checksum disagreements,
0 non-deterministic re-parses.
The same sweep measured conditional fill — of the pages that actually carry a company-number label, how many yielded a number:
| Jurisdiction | Pages with a label | Number emitted | Conditional yield |
|---|---|---|---|
| England and Wales | 102 | 102 | 100.0% |
| Scotland | 15 | 15 | 100.0% |
| Northern Ireland | 1 | 1 | 100.0% |
That is the number that tells you whether a parser works. The headline companyNumber fill of 85.8%
is not a parser gap: where a company number is published, it is read, in every jurisdiction. The
rest of the rows qualified on a VAT or charity number instead, because their page carries no company
number at all.
How do I audit a field I do not trust?
Turn on Include per-field provenance. Every field then carries the exact URL it was read from, so
you can open the page and check it. disclosureUrl, companyNumberRaw and jurisdictionStated are
there for the same reason.
Does it respect robots.txt?
There is a toggle, off by default. Measured on a UK sample: of the domains that served a parseable
robots.txt at all, 0 disallowed any of /, /terms, /terms-and-conditions, /legal,
/privacy-policy, /about-us, /contact — these are pages sites want indexed. Turn it on if your
own compliance policy requires it; it costs one extra request per domain.
Will it break on Cloudflare-protected sites?
Some. The Actor retries a genuine refusal once on a residential GB IP — measured on the
598-domain run: 128 escalations, 26 recovered. There is an opt-in second escalation to Apify
Unblocker, which recovered 4 of the 5 hardest refusals in ladder testing, where both the
datacenter and the residential IP got a Cloudflare managed 403 (those same hosts also serve a plain
home broadband IP a 202 + 170-byte JS challenge, so the wall is real and is not the Apify proxy).
Blocked hosts are reported as blocked with the reason, and are never charged.
What if I already have a domain list in a Google Sheet / Clay / a previous Actor?
Use startUrls (requestListSources), domainsFileUrl (a CSV/TXT/JSON URL) or sourceDatasetId
(another Actor's output). They all merge and deduplicate.
⚠️ Honest limits
- This is an enrichment tool, not a discovery tool. It does not find UK companies for you; it turns the domain list you supply into company records.
- It reads what the site publishes, nothing more. It does not call the Companies House API, so it
cannot tell you whether a company is still active, who its directors are, or whether the number the
site prints is genuinely theirs.
registerUrlis provided so you can check in one click. - Companies House numbers have no checksum (repeated because it matters):
companyNumberFormatValidis a format and prefix check. - A named officer is rare — about 1.4% fill. UK trading-disclosure rules, unlike the German Impressum, do not require naming a director on the website. The field is extracted where a page labels one and is honestly empty the rest of the time.
- ICO registration is rare too — about 4.5%. Kept because when it is there it is unambiguous.
registeredOfficeis often an accountant's address. That is what the company filed; it is the registered office, not necessarily where they work.addressLineis the trading address when the site publishes a different one.- About 1 domain in 4 on a cold list yields a row (148 of 598 measured; 32.7% of the domains
that were actually reachable). The three kinds of nothing are itemised in
RUN_SUMMARYand none are charged. If you need a higher hit rate, feed it a list of limited companies rather than a general business list — sole traders have no company number to publish. - A
.comin a UK list is sometimes not a UK entity. One sampled site was a Netherlands operator with a KvK number and an NL VAT id; the row recordsvatCountry: "NL"honestly rather than forcing it into a GB field.
🧾 Legal & fair use
This Actor reads statutory public disclosures — the trading-disclosure statement that Companies Act 2006 s.82 and the Names and Trading Disclosures Regulations 2015 reg. 25 require UK companies to publish on their own websites, together with the contact details published alongside them.
- You are responsible for complying with each target site's Terms of Service.
- Output may contain personal data (a named director, a personal email address). Handling it is your responsibility under UK GDPR / the Data Protection Act 2018, and any outreach is yours to make compliant with PECR and the Privacy and Electronic Communications Regulations.
- This is not a credit, risk or due-diligence product. It reports what a company published; it does not assess that company.
- No login, no paywall and no credential is used or required at any point.
Part of a family of statutory-disclosure scrapers: DACH Impressum, French mentions légales, Spanish aviso legal — and now the UK.