Enrich a company list with UK company records from Companies House
Give it a list of UK company numbers or company names and get back, for each one, the official register record: status, company type, incorporation date, registered office, SIC codes, next accounts and confirmation-statement due dates, previous names and a Companies House link. Numbers are matched exactly; names are matched to the exact registered name, with near matches listed. It is for finance, procurement, credit and sales-operations teams checking customers, suppliers or prospects.
What you get
From a run on 1 October 2026 on the sample list (register snapshot of 1 September 2026):
| lookup | result | company_number | company_name | company_status | incorporation_date | reg_post_town | accounts_next_due |
|---|---|---|---|---|---|---|---|
| 00445790 | found | 00445790 | TESCO PLC | Active | 1947-11-27 | WELWYN GARDEN CITY | 2027-08-26 |
| SC123456 | not_on_register | ||||||
| GREGGS PLC | found_exact_name | 00502851 | GREGGS PLC | Active | 1951-12-29 | NEWCASTLE UPON TYNE | 2027-06-30 |
| Rolls-Royce Holdings plc | found_exact_name | 07524813 | ROLLS-ROYCE HOLDINGS PLC | Active | 2011-02-10 | LONDON | 2027-06-30 |
Three companies were delivered and charged; the number not on the register was free.
The Enriched tab gets 20 columns: lookup (your text, used to avoid duplicates), lookup_type, result, company_number, company_name, company_status, company_category, incorporation_date, registered_address, reg_post_town, reg_postcode, sic_codes, accounts_next_due, accounts_last_made_up, conf_stmt_next_due, previous_names, other_matches, companies_house_url, snapshot_date and checked_at.
| result | Meaning |
|---|---|
found |
The company number is on the register |
not_on_register |
The number is not in the register file (wrong number, or a dissolved company: the file lists live companies only). Not charged |
found_exact_name |
One company has exactly this name (punctuation, "Limited"/"Ltd" and "&"/"and" ignored) |
several_exact_names |
More than one company has this exact name: check other_matches and use the number |
no_exact_name |
Similar names were found but none exactly; they are listed in other_matches |
no_match |
No company name contains all the words |
not_checked_limit_reached |
The run stopped at its per-run limit before this row could be settled; run it again |
Get it in one click
Open the Actor, Companies House Company Search & Status — UK Register, and paste your company numbers:
{"companyNumbers": ["00445790", "SC123456"], "maxRecords": 2}
That example delivers Tesco PLC and nothing for the number that is not on the register: $0.05 on the Free plan. For names, use searchQueries (put names and numbers in separate runs: within one run the Actor requires a company to match both). Two ready-made list searches show the other side of the same register: Newest UK Software Companies and Newest Restaurant Companies in Manchester.
Get it from code
curl -X POST "https://api.apify.com/v2/acts/nexgensignal~uk-company-status-records/run-sync-get-dataset-items?maxTotalChargeUsd=1" \
-H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \
-d '{"companyNumbers": ["00445790", "SC123456"], "maxRecords": 2}'
To enrich a whole list, use the Python script under Downloads: CSV in, CSV out, numbers and names handled, already-checked rows skipped.
export APIFY_TOKEN=your_apify_token # Windows: set APIFY_TOKEN=your_apify_token
python uk_company_enrich_csv.py --in companies_to_check.csv --out enriched_companies.csv
Same rules: one result row per lookup, already-checked lookups skipped (--refresh checks them again, and pays again for every company it delivers). Python 3.8+ and nothing else.
Keep a Google Sheet enriched (n8n)
- Get the workflow. In n8n choose Import from URL and paste the workflow link under Downloads (or download it and use Import from File).
- Add your Apify token. In Apify Console copy your API token (Settings → API & Integrations). In n8n create a Header Auth credential named
Apify API token: NameAuthorization, ValueBearerfollowed by your token. Select it in the six HTTP Request nodes (Get saved run, Start Apify run, Check run, Get run receipt, Get run input, Get records). - Make the sheet. Create a Google Sheet with tabs Companies to check (header
lookup; format that column as Plain text so numbers like 00445790 keep their zeros; other columns of your own are fine) and Enriched (paste the header row from Downloads). The sample list under Downloads has the four rows above. - Point the workflow at it. Paste the sheet URL into the three Google Sheets nodes and choose your Google credential.
- Click Execute workflow. Each run reads the whole monthly register file, so allow 2–3 minutes. Run it again whenever you add rows: rows already in Enriched are skipped (delete a result row to check that company again).
Numbers and names go to two runs side by side: within one run the Actor combines its filters, so a company would have to match a number and a name.
Google Sheets delivery: not yet verified
The workflow's Google Sheets nodes follow n8n 2.41.4's own Google Sheets node definition (append-or-update on lookup; values are written as plain text so numbers such as 00445790 keep their leading zeros), and the file imports into n8n. They have not yet been run against a real Google Sheet. Everything before the sheet has been tested in n8n, including scheduled runs, with a local stand-in that applies the same append-or-update rule. Try it on a copy of your sheet first.
If something is interrupted
- The sheet could not be written. Each run's ID is saved as soon as Apify answers. The next execution collects that same run instead of starting and paying for a new one, and saved progress moves on only after the rows are written. (Tested, including a scheduled run whose sheet write failed.)
- No answer when starting a run. Apify's API offers no way to make starting a run safe to repeat. If no answer comes back, the original request may have started a run; no second start is attempted automatically. The workflow stops with START OUTCOME UNKNOWN until you decide. If Apify Console → Runs shows the run, paste its ID into
resumeRunIds(one for the numbers run, one for the names run) in the settings node: its results are collected without paying again. If no run started, paste the time shown in the message intostartNewAfterUnknown. - Two executions at the same time. If the workflow starts while an earlier execution is still waiting for its run (for example a manual run while a scheduled one is still going), it first asks Apify whether a run of this Actor with the same settings is still going. If one is, it stops with ALREADY RUNNING without starting or paying for anything, and the earlier execution writes those results. A run with the same settings started another way (for example by hand in Apify Console) counts too. (Tested in n8n with two overlapping executions.) The script does not make this check, so don't start it again while an earlier run of it is still going.
- Where the memory lives. The saved run IDs are kept inside the n8n workflow. Re-importing the workflow resets them (tested).
- The script follows the same rules (
--resume-run RUN_ID,--start-new); after an uncertain start it looks for the run on its next start and reuses it if it finds exactly one.
What it costs
Existing prices, no start fee: you pay for each company delivered. Numbers not on the register cost nothing.
| Apify plan | Per company | The 4-row sample (3 companies) | 1,000 company numbers (all found) |
|---|---|---|---|
| Free | $0.05 | $0.15 | $50.00 |
| Bronze | $0.045 | $0.135 | $45.00 |
| Silver | $0.04 | $0.12 | $40.00 |
| Gold / Platinum / Diamond | $0.0335 | $0.10 | $33.50 |
A name can match several companies (every company whose name contains all its words). The workflow pays for up to 5 matches per name (PER_NAME in Plan runs; --per-name in the script) and keeps the exact one; a vague name costs more and settles less. Use numbers when you have them. Each run also stops at a spending cap (CAP_USD, default $2.00).
When things don't go to plan
- The register can't be reached, or the run fails: the workflow stops with an error that names the run; nothing is written, and an unreachable source is not charged.
- No match: the row is written as
no_matchornot_on_registerso you can see it was checked. - Stopped at a limit: affected rows say
not_checked_limit_reached; run again or raise the limit.
Know before you rely on it
- Monthly snapshot. Companies House publishes the register file on the 1st of each month;
snapshot_datesays which one was used. A status may have changed since. It is not a certificate of good standing. - Live companies only. Dissolved companies are not in the file, so they come back as not found.
- No people. Officers, directors and people with significant control are not in this file and are never returned.
- Not the filing history. You get filing due dates and charge counts, not the filings themselves.
Links
- Actor: Companies House Company Search & Status — UK Register
- Ready-made searches to try first: Newest UK Software Companies · Newest Restaurant Companies in Manchester
- Apify API reference used: Run Actor, Get run
Downloads
- n8n workflow (import from URL or file; Google Sheets step not yet verified) — save as
n8n-workflow.json - Python script (CSV instead of n8n) — save as
uk_company_enrich_csv.py - Header row for the Enriched tab — save as
sheet-headers-enriched.csv - Sample list for the Companies to check tab — save as
companies_to_check.csv - This tutorial as a web page
Published by NexGen Signal (official-source data products on Apify). Prices are the Actors' existing pay-per-record prices on 1 October 2026; check the Actor page for current prices.