How to Export UK Company Directors from Companies House in Bulk

Uses Companies House Enrichment — UK Company Directors & Filings

Short answer: Give Companies House Enrichment a list of company numbers or a SIC code, status and location filter, keep includeOfficers on, then flatten the nested officers list into one row per director. Dates of birth and personal addresses are never returned.

Companies House shows each company's officers on its own page, which is fine for one firm and tedious for a list. The free API exposes the same data, but you have to call the profile, officers and filing history endpoints separately, combine them and stay inside the rate limit of 600 requests per 5 minutes.

If what you need is a spreadsheet of directors for a set of companies, say every active scaffolding firm in Manchester incorporated since 2020, or the officers behind 300 suppliers in your purchase ledger, you want that stitched together already, with one row per person you can filter and sort.

This guide covers choosing companies by number or by filters, finding SIC codes, running the export, turning nested officers into a flat director list, and keeping the output privacy-safe.

Step by step

  1. Choose how to select companies

    There are three ways in, in this order of priority. companyNumbers enriches exactly the companies you list. If no numbers are given, the advanced filters (sicCodes, companyStatus, incorporatedFrom, incorporatedTo, location) run a targeted search. If there are neither, searchTerms runs a free-text name search such as 'plumbing manchester'.

  2. Find the SIC codes for your sector

    SIC codes are the Standard Industrial Classification codes companies declare on the register. 43991 is scaffolding, for example, and you can pass several codes at once. Combine them with companyStatus active and a location such as 'Manchester' to get a targeted list of trading companies with a registered office in that area.

    {
      "sicCodes": ["43991", "43999"],
      "companyStatus": "active",
      "incorporatedFrom": "2020-01-01",
      "location": "Manchester",
      "maxResults": 500,
      "includeOfficers": true,
      "includeFilings": false
    }
  3. Or enrich a list of company numbers you already have

    Paste company numbers into companyNumbers to enrich exactly those firms. Keep them as text: UK company numbers often start with zeros or letters, and spreadsheets tend to strip leading zeros. Mistyped numbers are skipped and never charged, so check the run's row count against your list.

    {
      "companyNumbers": ["09876543", "12345678", "SC123456"],
      "includeOfficers": true,
      "includeFilings": true
    }
  4. Flatten officers into one row per director

    Each company row has an officers list with name, role, appointedOn, resignedOn, nationality and occupation, up to 100 per company. The script below turns that into a flat CSV of current directors only (no resignation date), with the company's number, name, status and SIC codes on every line.

    import csv
    import os
    
    from apify_client import ApifyClient
    
    client = ApifyClient(os.environ["APIFY_TOKEN"])
    run = client.actor("actor-forge/uk-companies-house-enrichment").call(run_input={
        "sicCodes": ["43991"],
        "companyStatus": "active",
        "location": "Manchester",
        "maxResults": 500,
        "includeOfficers": True,
        "includeFilings": False,
    })
    
    with open("directors.csv", "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow(["companyNumber", "companyName", "status", "sicCodes",
                         "officerName", "role", "appointedOn", "occupation"])
        for company in client.dataset(run["defaultDatasetId"]).iterate_items():
            for officer in company.get("officers") or []:
                if officer.get("resignedOn"):
                    continue
                if "director" not in (officer.get("role") or "").lower():
                    continue
                writer.writerow([
                    company["companyNumber"], company["name"], company.get("status"),
                    " ".join(company.get("sicCodes") or []),
                    officer["name"], officer["role"], officer.get("appointedOn"),
                    officer.get("occupation"),
                ])
  5. Use filings to qualify the list

    With includeFilings on, each company carries its 25 most recent filings with date, category, type and description. That is enough to spot companies that have recently filed accounts or changed officers, or to drop ones whose history suggests they are winding down. Leave it off if you only need directors; the price per company is the same.

  6. Plan for throughput on big exports

    Companies House allows 600 requests per 5 minutes, and a fully enriched company uses 3 requests, so expect about 180 companies per 5 minutes on the shared key. For large or frequent exports, get a free key from developer.company-information.service.gov.uk and put it in apiKey for dedicated throughput.

  7. Handle director data responsibly

    The actor never returns officers' dates of birth or personal addresses, only statutory register fields. Directors' names and roles are still personal data, so make sure you have a lawful basis for any outreach and keep the export to what you need.

Sample input

{
  "sicCodes": [
    "43991"
  ],
  "companyStatus": "active",
  "incorporatedFrom": "2020-01-01",
  "location": "Manchester",
  "maxResults": 200,
  "includeOfficers": true,
  "includeFilings": true
}

Sample output

Each company row arrives with officers and filings nested inside it, summarised in the table below:

companyNumbernamestatusincorporatedOnregisteredAddresssicCodesofficersfilings
12345678EXAMPLE SCAFFOLDING LTDactive2019-03-141 Example Street, Unit 4, Manchester, M1 2AB, England43991, 439992 active, 1 resigned (names, roles, dates)25 most recent (date, type, description)
87654321SAMPLE JOINERY (LEEDS) LTDactive2021-09-0222 Demo Road, Leeds, LS1 4XY, England433201 active (name, role, dates)25 most recent (date, type, description)

Run it from code

cURL

curl -X POST "https://api.apify.com/v2/acts/actor-forge~uk-companies-house-enrichment/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sicCodes": ["43991"], "companyStatus": "active", "incorporatedFrom": "2020-01-01", "location": "Manchester", "maxResults": 200, "includeOfficers": true, "includeFilings": true}'

JavaScript (Node.js)

// Node.js 18+ (built-in fetch). Set APIFY_TOKEN in your environment.
const input = {
  "sicCodes": [
    "43991"
  ],
  "companyStatus": "active",
  "incorporatedFrom": "2020-01-01",
  "location": "Manchester",
  "maxResults": 200,
  "includeOfficers": true,
  "includeFilings": true
};

const res = await fetch(
  "https://api.apify.com/v2/acts/actor-forge~uk-companies-house-enrichment/run-sync-get-dataset-items",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.APIFY_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(input),
  }
);
const items = await res.json();
console.log(items.length, items[0]);

Python

# pip install apify-client   (set APIFY_TOKEN in your environment)
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run_input = {
    "sicCodes": [
        "43991"
    ],
    "companyStatus": "active",
    "incorporatedFrom": "2020-01-01",
    "location": "Manchester",
    "maxResults": 200,
    "includeOfficers": True,
    "includeFilings": True
}

run = client.actor("actor-forge/uk-companies-house-enrichment").call(run_input=run_input)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

The run-sync-get-dataset-items endpoint waits for the run (up to 5 minutes) and returns the dataset rows directly. For longer runs, start the run asynchronously and read the dataset when it finishes, as the Python example does. Replace APIFY_TOKEN with your own token from the Apify console.

What it costs

Exporting directors for 500 companies costs 500 x $0.005 = $2.50, with profile, officers and filings included in that price. Companies that are not found cost nothing.

Charged forWhenPricePer 1,000Worked example
Enriched companyOne UK company with profile, officers and filing history from the official register.$0.005$51,000 companies = $5.00; 100 companies = $0.50
Actor Start (platform start fee)Charged when the Actor starts running. Number of events charged depends on Actor memory (one event per GB, minimum one event).$0.00005—One run at up to 1 GB = $0.00005 (charged as one event)

Ready to try it? Companies House Enrichment — UK Company Directors & Filings runs on Apify, pay per result.

Run on Apify → Read the full actor page

Tips and pitfalls

FAQ

Can I download all directors of a company from Companies House for free?

Yes, one company at a time on the Companies House website or through its free API. This actor is for doing it in bulk in one dataset, at $0.005 per company.

Does the export include officers other than directors?

Yes. The officers list holds directors and other officers, up to 100 per company, each with a role, so you can keep directors only, as in the script, or include every role.

Why is my director missing a date of birth?

Dates of birth are deliberately never returned, along with personal addresses. Only statutory business-register fields are included.

Can I export dissolved companies too?

Yes. Set companyStatus to dissolved or liquidation, or to any to disable the status filter.

Actors used in this guide

Companies House Enrichment — UK Company Directors & Filings

Enrich UK companies from the official Companies House API: profile, SIC codes, current and resigned directors and officers, and the latest filing…

$5 per 1,000 · enriched company

Related guides

How to Use UK Planning Applications as Sales Leads

Pull each council's weekly list of newly validated applications with UK Planning Applications, filter the proposal text for the work you do, and…

How to Get SEC Form D Startup Funding Data as a Daily Feed

Use Startup Funding Rounds to read EDGAR's daily Form D indexes and parse each filing into a row with issuer, amounts, industry and exemption.…

How to Get Local Business Leads Without Scraping Google Maps

Query the open Overture Maps places dataset by city and category with Business Places Data to get names, addresses, phones, websites and emails for…

All guides