CompanyStack
APISamplesPricingDocsGuides
Explore data

The register

IndustriesIndustries by SIC code: key figures, the largest companies by turnover and the newest.Towns and citiesCompanies registered in each UK town, its main industries and the newest arrivals.New incorporationsThe companies formed each day, newest first, with their industry and town.Company status guidesWhat active, dissolved, liquidation and proposal to strike off mean for you.

Look closer

Search companiesAny UK company by name or number: profile, health score and filed accounts.Financial screenerFilter companies by the figures in their latest filed accounts.Sample outputsReal reports, exports and API responses to look through.
Log inCreate free account
APISamplesPricingDocsGuides

Explore data

IndustriesTowns and citiesNew incorporationsCompany status guidesSearch companies
Log inCreate free account
  1. Home
  2. Guides
  3. How to parse UK iXBRL company accounts in Python

How-to for developers and data teams

How to parse UK iXBRL company accounts in Python

Last updated 4 October 20269 minute read

Answer

Install ixbrlparse (version 0.11.2 tested here), open the file with IXBRL.open, then pick each figure by its FRC concept name, its period (the balance sheet date, or the year ending on it) and its dimensions (none, for totals). Skip nil facts, which the library reads as zero, and check scale and sign on anything that looks odd.

Contents

  • What is in a UK iXBRL accounts file?
  • Which Python library should you use?
  • How do you take a first look at the facts?
  • How do periods, contexts and dimensions work?
  • The complete script
  • How did we test it?
  • What are the pitfalls?
  • Which concepts hold the headline figures?
  • How do FRC taxonomy versions affect parsing?
  • How fast is it?
  • How CompanyStack helps
  • Frequently asked questions
  • Sources

Everything below was run, not just written. We tested the script against 54 real filings from the Companies House Accounts Data Product, with balance sheet dates from 2009 to 2026 and taxonomies ranging from a 2008 Companies House schema to the 2026 FRC suite, and against 24 group accounts from the daily file published on 3 October 2026. The pitfalls section lists what those files actually contain, including a scale error in about one in nine of the filings that tag a head count.

What is in a UK iXBRL accounts file?

An iXBRL file is an XHTML page you can open in a browser. Hidden in its markup, each tagged figure is wrapped in an ix:nonFraction tag and each piece of tagged text in an ix:nonNumeric tag. A numeric fact carries:

  • a concept name, such as core:TurnoverRevenue, from the taxonomy the file references;
  • a context, which names the company, the period (an instant such as the balance sheet date, or a start and end date) and, optionally, dimension members that break the figure down;
  • a unit, usually iso4217:GBP for money or xbrli:pure for counts;
  • presentation attributes: format (how the displayed text is written), scale (a power of ten), sign (whether the value is the negative of what is displayed) and decimals.

You can get files in bulk from the Accounts Data Product, or one company at a time from the Document API by asking for application/xhtml+xml. How to get UK company financial data through an API covers both routes.

Which Python library should you use?

ixbrlparse is a small, MIT-licensed library that reads iXBRL and older XBRL files into Python objects and applies the format, scale and sign rules for you. It does not load the taxonomy, so it gives you concept names, not labels, and it does not validate. We tested version 0.11.2 on Python 3.10.12, with beautifulsoup4 4.15.0 and lxml 6.1.3.

Arelle is an open-source XBRL platform under the Apache 2.0 licence that loads the full taxonomy, validates filings and supports Inline XBRL 1.1. Use it when you need labels, calculation checks or validation; it is heavier, and it fetches taxonomy files.

python3 -m venv .venv
. .venv/bin/activate
pip install ixbrlparse==0.11.2

How do you take a first look at the facts?

This prints turnover and creditors from a 2025 filing in the daily Accounts Data Product (company 00645715, chosen because it includes a profit and loss account).

from ixbrlparse import IXBRL

doc = IXBRL.open("Prod223_4316_00645715_20251231.html")
print(doc.schema)
for fact in doc.numeric:
    if fact.name in ("TurnoverRevenue", "Creditors"):
        ctx = fact.context
        period = ctx.instant or f"{ctx.startdate} to {ctx.enddate}"
        members = [s["value"] for s in ctx.segments]
        print(fact.name, period, fact.value, fact.unit, members)
https://xbrl.frc.org.uk/FRS-102/2024-01-01/FRS-102-2024-01-01.xsd
TurnoverRevenue 2025-01-01 to 2025-12-31 3221180.0 iso4217:GBP []
TurnoverRevenue 2024-01-01 to 2024-12-31 3229496.0 iso4217:GBP []
Creditors 2025-12-31 896278.0 iso4217:GBP ['core:CurrentFinancialInstruments', 'core:WithinOneYear']
Creditors 2024-12-31 1029344.0 iso4217:GBP ['core:CurrentFinancialInstruments', 'core:WithinOneYear']
Creditors 2025-12-31 2914374.0 iso4217:GBP ['core:Non-currentFinancialInstruments', 'core:AfterOneYear']
Creditors 2024-12-31 2901370.0 iso4217:GBP ['core:Non-currentFinancialInstruments', 'core:AfterOneYear']
Creditors 2025-12-31 896278.0 iso4217:GBP ['core:CurrentFinancialInstruments', 'core:WithinOneYear']
Creditors 2024-12-31 1029344.0 iso4217:GBP ['core:CurrentFinancialInstruments', 'core:WithinOneYear']

fact.name is the concept's local name (the library keeps the prefix in fact.schema), and fact.value is the number with scale and sign already applied. Note what the output shows: turnover is a duration, creditors are instants, the creditors are split by dimension members, and the same creditors figure appears twice because it is tagged in two places in the document.

How do periods, contexts and dimensions work?

Periods. Balance sheet items are instants at the balance sheet date; profit and loss items are durations ending on it. An instant written as a date means the end of that day, so last year's balance sheet sits at the day before this year's period starts: 31 December 2024 for a year that starts on 1 January 2025.

Dimensions. A dimension breaks a concept down: creditors by when they fall due, equity by reserve, fixed assets by class. The FRC's tagging guide says most dimensions have a default member that applies when no member is given, which for breakdowns is the total. In practice the headline total is the fact with no dimension at all.

Group and company. The FRC defines Consolidated and Company [default] members to separate a group's figures from the parent company's, with company as the default. A parent's own balance sheet is therefore the undimensioned fact, and the group's is the fact with the Consolidated member (in the business taxonomy, dimension GroupCompanyDataDimension).

So to read a headline figure you match three things: the concept name, the period, and the exact set of dimension members.

The complete script

The script below reads the balance sheet date, finds the prior year, and returns twelve headline figures for both years, on the company basis or, with --group, the consolidated one. It skips nil facts, refuses duplicates that disagree, understands the three ways creditors are tagged, falls back to older UK GAAP names, and flags results that need a human look.

"""Read headline figures from a UK iXBRL (or older XBRL) accounts file.

Tested on Python 3.10.12 with ixbrlparse 0.11.2, beautifulsoup4 4.15.0
and lxml 6.1.3. Usage: python accounts_figures.py accounts.html [--group]
"""
import json
import sys
from collections import defaultdict
from datetime import date, timedelta

from ixbrlparse import IXBRL

# Concepts by local name: FRC taxonomy names first, then the older
# UK GAAP names used in filings made before FRS 102.
CONCEPTS = {
    "turnover": ["TurnoverRevenue"],
    "profit_before_tax": ["ProfitLossOnOrdinaryActivitiesBeforeTax"],
    "profit_after_tax": ["ProfitLoss"],
    "fixed_assets": ["FixedAssets"],
    "current_assets": ["CurrentAssets"],
    "cash": ["CashBankOnHand", "CashBankInHand"],
    "net_current_assets": ["NetCurrentAssetsLiabilities"],
    "net_assets": ["NetAssetsLiabilities", "NetAssetsLiabilitiesIncludingPensionAssetLiability"],
    "equity": ["Equity", "ShareholderFunds"],
    "employees": ["AverageNumberEmployeesDuringPeriod"],
}
# FRC taxonomies tag creditors as one concept, Creditors, split by dimension
# members: a maturity member, a current/non-current member, or both.
# UK GAAP filings used separate concepts instead.
WITHIN = ("MaturitiesOrExpirationPeriodsDimension", "WithinOneYear")
AFTER = ("MaturitiesOrExpirationPeriodsDimension", "AfterOneYear")
CURRENT = ("FinancialInstrumentCurrentNon-currentDimension", "CurrentFinancialInstruments")
NON_CURRENT = ("FinancialInstrumentCurrentNon-currentDimension", "Non-currentFinancialInstruments")
# Group accounts tag consolidated figures with this member; company figures
# are the default and carry no group/company dimension at all.
GROUP = ("GroupCompanyDataDimension", "Consolidated")
CREDITORS = {
    "creditors_within_one_year": (
        [{WITHIN}, {CURRENT}, {CURRENT, WITHIN}],
        ["CreditorsDueWithinOneYear", "CreditorsDueWithinOneYearTotalCurrentLiabilities"],
    ),
    "creditors_after_one_year": (
        [{AFTER}, {NON_CURRENT}, {NON_CURRENT, AFTER}],
        ["CreditorsDueAfterOneYear", "CreditorsDueAfterOneYearTotalNoncurrentLiabilities"],
    ),
}


def local(qname):
    """'core:Equity' -> 'Equity'. Prefixes vary between filings (core:, uk-core:, ns5:)."""
    return qname.rsplit(":", 1)[-1]


def load(path):
    doc = IXBRL.open(path, raise_on_error=False)
    facts = defaultdict(set)  # (concept, period, dimensions) -> values seen
    for fact in doc.numeric:
        ctx = fact.context
        if isinstance(ctx, str) or fact.value is None:
            continue  # no matching context, or a format that carries no number
        if fact.soup_tag.get("xsi:nil") == "true":
            continue  # nil means "not reported"; ixbrlparse would read it as 0
        dims = frozenset(
            (local(s["dimension"]), local(s["value"]))
            for s in ctx.segments or []
            if s.get("dimension")
        )
        period = ctx.instant or (ctx.startdate, ctx.enddate)
        facts[(local(fact.name), period, dims)].add(round(fact.value, 6))  # drop float noise
    return doc, facts


def text_fact(doc, name):
    for item in doc.nonnumeric:
        if local(item.name) == name and item.value:
            return item.value
    return None


def balance_sheet_date(doc, facts):
    """The tagged BalanceSheetDate if it reads as a date, else the latest instant."""
    tagged = text_fact(doc, "BalanceSheetDate")
    if isinstance(tagged, date):
        return tagged
    try:
        return date.fromisoformat(tagged)
    except (TypeError, ValueError):
        return max(p for (_, p, _) in facts if isinstance(p, date))


def prior_date(facts, current):
    """The day before the current period starts (an XBRL instant is the end of that day)."""
    starts = [p[0] for (_, p, _) in facts if isinstance(p, tuple) and p[1] == current]
    if starts:
        return min(starts) - timedelta(days=1)
    earlier = [p for (_, p, _) in facts if isinstance(p, date) and p < current]
    return max(earlier) if earlier else None


def value(facts, names, when, dims=frozenset()):
    """A concept at an instant, or for the longest period ending on that date."""
    for name in names:
        matches = {}
        for (concept, period, d), values in facts.items():
            end = period if isinstance(period, date) else period[1]
            if concept == name and d == dims and end == when:
                matches[period] = values
        if matches:
            longest = max(matches, key=lambda p: 0 if isinstance(p, date) else (p[1] - p[0]).days)
            values = matches[longest]
            if len(values) > 1:
                raise ValueError(f"{name} at {when}: duplicate facts disagree {sorted(values)}")
            return next(iter(values))
    return None


def creditors(facts, when, splits, legacy, basis):
    for dims in splits:
        found = value(facts, ["Creditors"], when, frozenset(dims) | basis)
        if found is not None:
            return found
    return value(facts, legacy, when, basis)


def figures(facts, when, group=False):
    basis = frozenset({GROUP}) if group else frozenset()
    row = {key: value(facts, names, when, basis) for key, names in CONCEPTS.items()}
    for key, (splits, legacy) in CREDITORS.items():
        row[key] = creditors(facts, when, splits, legacy, basis)
    if row["net_assets"] is None and not group:
        row["net_assets"] = row["equity"]  # a company's total equity equals its net assets
    return row


def checks(row):
    problems = []
    staff = row["employees"]
    if staff is not None and staff != int(staff):
        problems.append(f"employees is {staff}: not a whole number, so check the scale attribute")
    if None not in (row["net_assets"], row["equity"]) and row["net_assets"] != row["equity"]:
        problems.append("net assets and equity differ: look for non-controlling interests")
    return problems


if __name__ == "__main__":
    group = "--group" in sys.argv
    path = next(arg for arg in sys.argv[1:] if arg != "--group")
    doc, facts = load(path)
    current = balance_sheet_date(doc, facts)
    prior = prior_date(facts, current)
    result = {
        "company_number": text_fact(doc, "UKCompaniesHouseRegisteredNumber"),
        "taxonomy": doc.schema,
        "basis": "group" if group else "company",
        "balance_sheet_date": str(current),
        "current": figures(facts, current, group),
        "prior": figures(facts, prior, group) if prior else None,
        "parse_errors": len(doc.errors),
    }
    result["checks"] = checks(result["current"])
    print(json.dumps(result, indent=2, default=str))

Running python accounts_figures.py Prod223_4316_00645715_20251231.html prints:

{
  "company_number": "00645715",
  "taxonomy": "https://xbrl.frc.org.uk/FRS-102/2024-01-01/FRS-102-2024-01-01.xsd",
  "basis": "company",
  "balance_sheet_date": "2025-12-31",
  "current": {
    "turnover": 3221180.0,
    "profit_before_tax": 99070.0,
    "profit_after_tax": 70123.0,
    "fixed_assets": 11697197.0,
    "current_assets": 1681434.0,
    "cash": 8964.0,
    "net_current_assets": 785156.0,
    "net_assets": 8771622.0,
    "equity": 8771622.0,
    "employees": 20.0,
    "creditors_within_one_year": 896278.0,
    "creditors_after_one_year": 2914374.0
  },
  "prior": {
    "turnover": 3229496.0,
    "profit_before_tax": 430590.0,
    "profit_after_tax": 368901.0,
    "fixed_assets": 11830623.0,
    "current_assets": 1697215.0,
    "cash": 19540.0,
    "net_current_assets": 667871.0,
    "net_assets": 8779823.0,
    "equity": 8779823.0,
    "employees": 20.0,
    "creditors_within_one_year": 1029344.0,
    "creditors_after_one_year": 2901370.0
  },
  "parse_errors": 0,
  "checks": []
}

The values are floats because ixbrlparse returns floats; the script rounds them to six decimal places to remove binary noise. If you need exact amounts, rebuild them from the displayed text and the scale attribute with decimal.Decimal.

How did we test it?

We compared the script's output for the 54 filings in CompanyStack's parser test set with reference values the test suite produces by loading each filing in Arelle with its full taxonomy and applying CompanyStack's field definitions. The filings cover FRS 102 accounts tagged with FRC suites from 2014 to 2026, FRS 105 micro-entity accounts, IFRS and Charities filings, the 2009 UK GAAP taxonomy, and plain XBRL from 2009 and 2012.

OutcomeFigures
Matched the reference exactly510
Not tagged in the filing (the reference records zero; the script returns None)26
A total the filing does not tag (fixed assets where the filing tags only the individual asset lines, and a charity's funds, which the Charities taxonomy tags under its own concept)17
Head counts tagged with a negative scale (the script flags all of them)6

We also ran the script with --group on the 24 filings in the 3 October 2026 daily file that tag at least 40 consolidated figures. It returned consolidated figures for all 24 and consolidated net assets for 21; 18 tagged net assets on both the group and the company basis, and one flagged a difference explained by non-controlling interests. None raised an error.

What are the pitfalls?

Nil facts read as zero

A fact marked xsi:nil="true" means "not reported". It has no text, and ixbrlparse turns empty text into 0. The script skips nil facts so that a missing figure stays None.

Scale is usually right, but not always

scale="3" means the displayed number is in thousands, so 699,194 becomes 699,194,000, and ixbrlparse applies it correctly. The trouble is filings that use the wrong scale. In the daily file of 3 October 2026, 766 of the 6,774 filings that tag an average head count tag it with scale="-2", and every one of those facts displays a whole number, so a strict reading turns 12 employees into 0.12. The taxonomy allows a decimal head count, so the script flags a fractional result for checking rather than correcting it.

Sign follows the concept's label

The FRC's rule is that values are entered as positive unless the label puts a term in brackets, as in "Operating profit (loss)" or "Net current assets (liabilities)": a loss is a negative ProfitLoss, and net liabilities are a negative NetAssetsLiabilities. The sign="-" attribute is how a filing shows a positive number while storing a negative value, and ixbrlparse applies it. Expect the occasional filing that breaks the rule, and sanity-check signs on concepts that should never be negative.

Prefixes and namespaces vary

The same FRC core taxonomy appears as core:, uk-core: and ns5: in our test files, and the namespace changes with every annual version. Match concepts and dimension members by local name, as the script's local() function does.

Duplicates must agree

The same figure is often tagged more than once, for example on the balance sheet and again in a note. The FRC's tagging guide says one concept must not have different values in the same context, so the script accepts duplicates that agree and raises an error when they do not.

Totals and lines are not always tagged

A company with only tangible fixed assets may tag the tangible assets line and never tag the fixed assets total. Some filings tag only Equity, not NetAssetsLiabilities; for a single company they are the same total, so the script falls back to equity. One charity filing in our set tagged only six numbers in the whole document. Absence in the tags is not absence in the accounts, so do not turn a missing tag into zero.

Group figures, company figures and non-controlling interests

A group filing may tag both bases, only the consolidated figures or only the parent's, so check which exist before you choose. In one group filing we tested, Equity was tagged as the amount attributable to the parent's shareholders, with non-controlling interests tagged separately, so net assets and equity differ. The script does not fall back from net assets to equity on the group basis for that reason. The guide to group accounts and company accounts explains which figures to rely on.

Old taxonomies and plain XBRL

Filings before FRS 102 used the 2009 UK GAAP taxonomy, and some of the oldest electronic accounts in the archive, from 2009, are plain XBRL .xml files that reference a Companies House schema. The concepts are named differently (ShareholderFunds, CashBankInHand, CreditorsDueWithinOneYear), so the script lists them as alternatives.

Formats, errors and zipped filings

ixbrlparse raises an error on a format it does not implement. Open files with raise_on_error=False, as the script does, and log doc.errors. The daily Accounts Data Product also contains a few zipped iXBRL packages (8 of the 7,859 filings on 3 October 2026), which you must unzip first.

Which concepts hold the headline figures?

FigureFRC conceptOlder UK GAAP conceptNotes
TurnoverTurnoverRevenueDuration; absent from most small company filings
Profit before taxProfitLossOnOrdinaryActivitiesBeforeTaxNegative for a loss
Profit after taxProfitLossAlso tagged with equity dimensions in reserve movements
Fixed assetsFixedAssetsFixedAssetsNot always tagged as a total
Current assetsCurrentAssetsCurrentAssets
CashCashBankOnHandCashBankInHand
Creditors within one yearCreditors with WithinOneYear or CurrentFinancialInstrumentsCreditorsDueWithinOneYearMembers of the maturity and current or non-current dimensions
Net current assetsNetCurrentAssetsLiabilitiesNetCurrentAssetsLiabilitiesNegative for net current liabilities
Net assetsNetAssetsLiabilitiesNetAssetsLiabilitiesIncludingPensionAssetLiabilityNegative for net liabilities
Total equityEquityShareholderFundsUndimensioned fact is the total
Average employeesAverageNumberEmployeesDuringPeriodUnit xbrli:pure; watch the scale

Every FRC name in the table appears in the FRC's 2025 core taxonomy schema, and the balance sheet names matched in our test filings tagged with FRC suites from 2014 to 2026.

How do FRC taxonomy versions affect parsing?

The FRC publishes a new suite each year; the 2026 suite was published on 18 November 2025. Its accounts design document says the FRS 102 entry point serves both FRS 102 and FRS 105 accounts, which is why micro-entity filings reference an FRS 102 schema. The FRC leaves the choice of accepted versions to data collectors such as Companies House, which announced on its software filing forum in December 2025 that, from April 2026, it would accept the 2026, 2025, 2024, 2023 and 2022 suites.

The result is that one day's filings mix versions. The 7,851 iXBRL filings in the daily file of 3 October 2026 referenced the 2022 suite (19 filings), 2023 (2,123), 2024 (415), 2025 (4,293) and 2026 (1,001), through the FRS 102 entry point (7,810), IFRS (25), Charities (12) and FRS 101 (4). Never hard-code a namespace.

How fast is it?

ixbrlparse reads the whole document with BeautifulSoup's XML parser, which took about a second per filing on our test machine, start-up included. That is fine for on-demand lookups. For a daily file of several thousand filings, or a monthly file of several gigabytes, run files in parallel across processes and store the extracted facts, not just the twelve figures, so you can add fields later without parsing again.

How CompanyStack helps

CompanyStack has already read the figures from every year of filed accounts it holds, from iXBRL filings and, for some companies, from scanned PDF accounts read by software and checked. Each year is labelled filed, scanned or prior-year comparative, company and group figures are kept apart, and amounts stay in the currency filed. The API's accounts endpoint returns them in one request per company, as described in the API docs and on CompanyStack for developers, and how to get UK company financial data through an API compares that with parsing the files yourself.

This guide is general information about UK rules and practice, not legal, tax or financial advice. Last checked 4 October 2026. How we write our guides.

Frequently asked questions

Do I need the FRC taxonomy files to parse iXBRL accounts?

Not to read figures by concept name: the facts, their periods, dimensions and units are all in the file. You need the taxonomy for labels, calculation checks and validation, which a full XBRL processor such as Arelle loads for you.

Why is turnover missing from most accounts?

Small companies can choose not to send their profit and loss account to Companies House, and micro-entities can send only a balance sheet. CompanyStack's analysis of the register on 3 October 2026 found that only 1.8% of the latest accounts of active companies, where those accounts are dated within the last 24 months, disclose turnover.

Can ixbrlparse read the older XBRL accounts?

Yes. It parsed plain XBRL files from 2009 and 2012 in our tests, through the same IXBRL.open call. The concept names differ from the FRC ones, for example ShareholderFunds and CashBankInHand, so map both.

Why does a head count come out as 0.12?

The filing tags the number 12 with scale="-2", which by the Inline XBRL rules means 0.12. It is a tagging error, and a common one: 766 of the 6,774 filings that tag a head count in the daily file of 3 October 2026 did it.

How do I get group figures rather than the parent company's?

Consolidated figures carry the Consolidated member of the group and company dimension, while the parent's own figures carry no such dimension. Run the script with --group to read the consolidated facts.

Sources

  1. ixbrlparse on PyPI pypi.org
  2. Arelle (open-source XBRL platform) on GitHub github.com
  3. XBRL International: Inline XBRL Part 1 Specification 1.1 xbrl.org
  4. XBRL International: Dates in XBRL xbrl.org
  5. FRC: XBRL Tagging Guide, FRC Taxonomies 2026 frc.org.uk
  6. FRC: Accounts Taxonomies Design 2026 frc.org.uk
  7. FRC: 2026 UK and Irish digital reporting taxonomies frc.org.uk
  8. FRC: Current FRC Taxonomy Suites frc.org.uk
  9. Companies House software filing forum: 2026 FRC Taxonomies Update xmlforum.companieshouse.gov.uk
  10. Companies House: Accounts Data Product (daily files) download.companieshouse.gov.uk
  11. GOV.UK: Prepare annual accounts: micro-entities, small and dormant companies gov.uk

Related guides

  • How to get UK company financial data through an APIHow-to

    The Companies House API returns no figures. How to get turnover, assets and profit from filed accounts: the Document API, bulk iXBRL files or a parsed API.

  • Companies House bulk data products explainedGuide

    What Companies House publishes in bulk for free: the company snapshot, daily and monthly accounts files and the PSC snapshot, with formats and pitfalls.

  • Group accounts or company accounts: which figures to rely onComparison

    Consolidated or parent-only? Why a parent's own balance sheet can mislead, how the section 408 exemption works, and when group strength reaches a creditor.

  • How to read a UK company balance sheet in ten minutesGuide

    Read any UK company balance sheet line by line: the statutory format, filleted and micro-entity versions, the notes that matter, and what is missing.

  • Net current liabilities and net liabilities: what they meanDefinition

    What net current liabilities and net liabilities mean on a UK balance sheet, how each is calculated, how they differ, and what they do and do not prove.

  • Companies House API rate limits explainedGuide

    The Companies House API allows 600 requests per five minutes per application. How the limit works, what a 429 means and how to design around it.

Use the data in your own systems

The CompanyStack API serves the same company records, filed accounts, health scores and KYB checks as JSON, with OpenAPI documentation and a free key to start.

See the API CompanyStack for developers and data teams

All guides

Data from Companies House. Contains public sector information licensed under the Open Government Licence v3.0.

The same data is available through the CompanyStack API (OpenAPI spec). Company status meanings · Data freshness

CompanyStack

The UK company register, made useful. Company profiles, health scores and financials in the web app, and the same data through the CompanyStack API.

Talk to us

CompanyStack web app

  • Dashboard
  • Financial screener
  • Watchlist and alerts
  • Map
  • Web app pricing
  • Create a free account

CompanyStack API

  • UK company data API
  • API documentation
  • API explorer
  • API pricing
  • Signals add-on
  • Get a free API key
  • Enterprise and bulk data

Built for

  • Accountants and bookkeepers
  • Compliance and procurement
  • Lenders and credit
  • Sales and business development
  • Investors and corporate finance
  • Insolvency and business recovery
  • Developers and data teams
  • Recruitment agencies

See the data

  • Sample outputs
  • Guides
  • Data sources
  • Book a 20-minute call
  • Monthly UK company report
  • UK private company data
  • Company status meanings
  • SIC codes list
  • Compare providers

© 2026 CompanyStack.

TermsPrivacyCookiesRefundsLegalBrand and pressAboutHelp centreContactDocs